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

Posted fpga和matlab

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于Seam-Carving算法的图像拉伸收缩matlab仿真相关的知识,希望对你有一定的参考价值。

up目录

一、理论基础

二、核心程序

三、测试结果


一、理论基础

       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 image
function [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 map
function [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 row
	energy_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 path
function [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 paths
function [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
    end

end
up28

三、测试结果

matlab2022a测试结果如下

 

以上是关于基于Seam-Carving算法的图像拉伸收缩matlab仿真的主要内容,如果未能解决你的问题,请参考以下文章

Flex 过渡:拉伸(或收缩)以适应内容

如何在 TWebBrowser 中居中和拉伸/收缩 SVG 显示?

安卓布局TableLayout初学之拉伸按钮收缩按钮

[IOS] 详解图片局部拉伸 + 实现图片局部收缩

基于FPGA的腐蚀膨胀算法实现

基于MATLAB的腐蚀膨胀算法实现