carving:基于Seam-Carving算法的图像拉伸收缩matlab仿真

up目录

一、理论基础

二、核心程序

三、测试结果


一、理论基础

       基于Seam Carving(缝隙塑造)算法的图像拉伸和收缩是一种用于改变图像尺寸的技术。这个算法最初是为了改变图像的宽度和高度而设计的,而不引起主要变形。Seam Carving算法最初由Avidan和Shamir在2007年提出,用于图像内容感知的图像缩放。它的主要思想是通过删除或插入像素线(seam)来调整图像的大小,同时最大程度地保持图像的重要内容不变,减少对图像的变形。

1. 图像拉伸(Enlargement):

  • 水平拉伸:要对图像进行水平拉伸,首先确定在水平方向上要插入的seam线,通常在对象边缘附近插入,以保持对象的形状。然后,沿着这些seam线插入像素,将图像的宽度增加到所需尺寸。
  • 垂直拉伸:要进行垂直拉伸,同样是选择合适的seam线,然后在这些seam线上插入像素,从而增加图像的高度。

2. 图像收缩(Reduction):

  • 水平收缩:为了收缩图像的宽度,选择最不重要的seam线,通常是图像中间的seam线,然后在这些seam线上删除像素,将图像的宽度减小到所需尺寸。
  • 垂直收缩:为了垂直收缩,同样是选择最不重要的seam线,通常在图像中间,然后删除这些seam线上的像素,从而减小图像的高度。

       seam carving缝隙切割,就是在图像中找到一条缝,将这条缝插入或删除以达到缩放的目的。是一种用于图像缩放的技术,这种技术可以感知图像的内容,在缩小时保留图像中的重要内容;在放大时,放大图像的重要内容。该方法在保留图像中重要物体方面相对于基于裁剪的缩放方法和等比例缩放技术有明显的优势。
seam carving的基本思想是:图像中不同的位置“能量”不同,有重要内容的地方能量大,反之,可有可无的位置能量小。这个能量函数可以是梯度,梯度大的地方亮度变化剧烈、纹理丰富,一般是重要内容;梯度小的位置亮度变化小,比如蓝天,删除一条缝隙对图像影响较小。

         Seam Carving算法是一种图像缩放算法,它能够将图像缩放也不影响图片的主要内容。它主要分为:
一、计算图像的能量图
二、通过能量图计算代价图以及路径图
三、通过代价图以及路径图寻找能量最低的seam
四、重复上述步骤

       “能量”是用来衡量像素的重要程度。如果一个像素有较大的梯度,说明这个像素很大可能Wie边缘。而边缘往往是一幅图像的重要内容。定义能量函数如下去计算每个像素的能量。

       遍历图像中每个像素,计算其能量,输出一个与图像相同尺寸的能量图。能量图中边缘像素具有较大亮度,且能量图像也能显现图像的内容。 

       seam定义为像素从上到下(或从左到右)的连接路径。对于从上到下的像素,从每一行中选取一个像素,这些连接的路径就组成了一条seam。竖直seam(连接方式)为:

        n为行数,即相邻两行的连接线只能是当前行像素位置的八连通域子集,即列编号最多相隔一个像素,而非随便连接。同理水平seam定义为:

       计算图像的能量图,能量图一般是图像像素的梯度模值,为了简化计算可先转换成灰度图像,然后直接采用如下公式(直接用x、y方向上的差分取绝对值,然后相加),其实这一步就是相当于边缘检测算法一样: 通过能量图寻找最小能量线。最小能量线指的是需要被移除的那一列:首先需要以图像第一行或最后一行为开始行进行迭代。下面实现的为从图像最后一行开始,往上迭代。 

       接缝裁剪(Seam carving),是一个可以针对照片内容做正确缩放的算法(由 Shai Avidan 和 Ariel Shamir 所发表)。概念上,这个算法会找出好几条 seams,而这些 seams 是在照片中最不重要的一连串像素,接着再利用这些 seams,对照片做缩放。如果是要缩小照片,则移除这些 seams,若是放大,则在这些 seams 的位置上,插入一些像素。

      为了评价像素点的重要性,我们需要个函数计算能量,作业这里使用双梯度(dual-gradient)能量函数。图片里颜色变化区域的像素能量高,像塔和天空间的边界区域,seam carving 就会避免移除这些区域的像素。

二、核心程序

%%% main loop %%% %%% remove and add one seam at a time while ( x1 > 0 && x1 < size(input_img,2) && y1 > 0 && y1 < size(input_img,1) ) prev_img = input_img; for i = 0:distance %%% generate energy map %%% [path_left path_right] = Energy_Path( edge_img, weight_img, x0, y0 ); %%% remove/add seams according to cursor position %%% if ( x1 > x0 ) [output_img weight_img] = Remove_Add_Path( input_img, path_right, path_left, weight_img); x0 = x0+1; else [output_img weight_img] = Remove_Add_Path( input_img, path_left, path_right, weight_img); x0 = x0-1; end %%% update images %%% input_img = output_img; gray_img = double(rgb2gray(input_img)); edge_img = Edge_Detect(gray_img); %%% draw seams on image %%% output_img_seam = output_img; for y=1:size(input_img,1) output_img_seam(y,path_left(y),:) = [255 0 0]; output_img_seam(y,path_right(y),:) = [255 0 0]; end %%% show image with seams %%% figure(1) imshow(output_img_seam);% imshow(edge_img, [min(min(edge_img)) max(max(edge_img))]); end %%% show clear image and ready for the next input %%% imshow(output_img_seam); x0 = x1; [x1 y1] = ginput(1); distance = abs(x1 - x0); end %%% GUI functions function loadbutton_Callback(source,eventdata) filenamein = uigetfile({'*.jpg;*.tif;*.png;*.gif','All Image Files'},'mytitle'); VPC(filenamein,'out.jpg'); end function undobutton_Callback(source,eventdata) imwrite(prev_img,'temp.jpg','jpg'); VPC('temp.jpg','out.jpg'); end function savebutton_Callback(source,eventdata) [filenameout,path] = uiputfile('out.jpg','Save file name'); imwrite(output_img_seam,filenameout,'jpg') end end%% function to generate edge imagefunction [edge_img] = Edge_Detect(gray_img) prewitt_Y = fspecial('prewitt'); prewitt_X = prewitt_Y'; edge_img_Y = imfilter(gray_img, prewitt_Y); edge_img_X = imfilter(gray_img, prewitt_X); edge_img = abs(edge_img_X) + abs(edge_img_Y); end%% function to generate energy mapfunction [path_left path_right] = Energy_Path(edge_img, weight_img, click_x, click_y) height = size(edge_img,1); width = size(edge_img,2); energy_img = zeros( height, width ); left_or_right = [ zeros(height,round(click_x)) ones(height,width - round(click_x)) ]; %%% initialize first rowenergy_img(1,:) = edge_img(1,:); %%% find the minimum accumulated energy for y = 2:height %%% use shift operation to find the minimum of the three prev = energy_img(y-1,:); flag = prev(1:end-1) < prev(2:end); prev([false flag]) = prev(flag); flag = prev(2:end) < prev(1:end-1); prev(flag) = prev([false flag]); energy_img(y,:) = edge_img(y,:) + weight_img(y,:) + prev; %%% record if the seam is at the left or right side of click_x if ( y > click_y ) prev = left_or_right(y-1,:); prev([false flag]) = prev(flag); prev(flag) = prev([false flag]); left_or_right(y,:) = prev; end end% imshow(energy_img, [min(min(energy_img)) max(max(energy_img))]);%%% find the minimum energy path of the right/left side separately [m min_idx] = sort( energy_img( height, : ) ); left_or_right_sort = left_or_right( height, min_idx ); min_left = min_idx( find(left_or_right_sort == 0, 1) ); min_right = min_idx( find(left_or_right_sort == 1, 1) ); %%% hack to prevent error when all seams are in one side if ( isempty(min_left) ) min_left=1; elseif ( isempty(min_right) ) min_right = width; end %%% generate the path from bottom to top path_left = Generate_Path( energy_img, min_left ); path_right = Generate_Path( energy_img, min_right ); end%% function to generate minimum-energy pathfunction [path] = Generate_Path( energy_img, min_x ) x = min_x; %%% generate the path from bottom to top for y = size(energy_img,1):-1:1 %%% row y: x-1 x x+1 %%% idx: -1 0 1 if ( x == 1 ) [m idx] = min( [ energy_img(y,x) energy_img(y,x+1) ] ); idx = idx-1; elseif ( x == size(energy_img,2) ) [m idx] = min( [ energy_img(y,x-1) energy_img(y,x) ] ); idx = idx-2; else [m idx] = min( [ energy_img(y,x-1) energy_img(y,x) energy_img(y,x+1) ] ); idx = idx-2; end x = x+idx; path(y) = x; end end%% function to remove and add the minimum-energy pathsfunction [dest_img weight_img] = Remove_Add_Path(source_img, path_remove, path_add, weight_img) dest_img = uint8(zeros( size(source_img,1), size(source_img,2), size(source_img,3) )); for y = 1:size(source_img,1) %%% hack to prevent index going beyond matrix bound if (path_add(y)==size(source_img,2)) path_add(y) = path_add(y)-1; end %%% new pixel is the average of its neighbors new_pixel = source_img(y,path_add(y),:)./2 + source_img(y,path_add(y)+1,:)./ 2; %%% remove path in image dest_img(y,1:end-1,:) = [ source_img(y,1:path_remove(y)-1,:) source_img(y,path_remove(y)+1:end,:) ]; %%% add path in image dest_img(y,:,:) = [ dest_img(y,1:path_add(y),:) new_pixel dest_img(y,path_add(y)+1:end-1,:) ]; %%% remove path in weight map weight_img(y,1:end-1) = [ weight_img(y,1:path_remove(y)-1) weight_img(y,path_remove(y)+1:end) ]; %%% put a big weight on added path to prevent choosing it again if ( path_add(y) > path_remove(y) ) weight_img(y,:) = [ weight_img(y,1:path_add(y)-2) 1000 1000 weight_img(y,path_add(y):end-1) ]; else weight_img(y,:) = [ weight_img(y,1:path_add(y)-1) 1000 1000 weight_img(y,path_add(y)+1:end-1) ]; end endendup28

三、测试结果

matlab2022a测试结果如下

相关推荐

相关文章