如何在MATLAB中重新采样图像的边缘?

时间:2015-04-09 15:25:07

标签: image matlab image-processing edge-detection

我试图减少检测到的图像边缘的点数,但是我没有获得好的结果。我希望结果包含恰好200个像素的边缘,但必须很好地选择这些点,以便形状保持非常清晰。我怎么能这样做?

以下是我正在使用的示例图片:

以下是我收到的一些我写的代码的结果:

编写的代码

function y = echantillonnage(x)
contour_image = x;
[lignes,colonnes]=size(x);
n = nombre/200;
contour_image_200px = contour_image;
ok=0;
for i=1:lignes
    for j=1:colonnes
        if (contour_image_200px(i,j)>0 )
                ok=ok+1;
                if ( mod(ok,round(n))>0 )
                   contour_image_200px(i,j)=0;
                end                 
         end      
    end
end
figure,imshow(contour_image_200px);
%résultat
y = contour_image_200px;
end

1 个答案:

答案 0 :(得分:1)

您可以使用bwboundaries跟踪对象/边的边界,然后从这些点阵列中采样以减少边缘点的数量。跟踪按顺时针顺序完成,因此您可以确信,当您从此数组中进行子采样时,您将获得一个相似的顺序。但是,bwboundaries还会返回外部内部轮廓边界,因此您只需要输出中的一定量的跟踪。我们稍后会讨论这个问题。

bwboundaries适用于多个对象,因此您需要做的就是遍历每个对象,对边缘点进行采样并将其写入输出结果。请注意,使用bwboundaries甚至不需要找到边...只要对象是干净的,那么就没有必要了。但是,我不确定你正在做什么的目的,所以让我们只对边缘检测结果进行操作。

假设我们有以下示例:

>> A = false(256, 256);
>> A(100:170,100:170) = true;
>> A(3:40,3:40) = true;
>> A(190:220,200:230) = true;
>> imshow(A)

我们得到这张图片:

enter image description here

如果我们执行边缘检测:

>> B = edge(A, 'canny');
>> imshow(B);

我们会得到这个:

enter image description here

现在,如果您想进行子采样,可以这样方式调用bwboundaries

[bound,L,N] = bwboundaries(B);

bwboundaries返回边界的单元格数组bound,其中每个单元格是定义边界的N x 2空间坐标数组。第一列是行位置,第二列是边界点的列位置。 L是一个标签矩阵,用于指示每个边界属于哪个点。我们不需要这个用于您的目的,但我不妨谈谈它。 N是最重要的参数。这定义了有多少对象边界。这也告诉您N的第一个bound单元格告诉您那些属于外部对象边界的单元格。

因此,您可以执行以下操作以对边缘点进行子采样并将其放入新矩阵中,假设您的边缘图像存储在B中。另外,你声明你希望每条边有200点。我们将该参数定义为num_edge_points。但是,如果您的边缘 小于此数量,那么我将假设您只想选择所有边缘点。

out = false(size(B)); %// Initialize output image
num_edge_points = 200; %// Define number of edge points

%// For each object boundary
for idx = 1 : N
    boundary = bound{idx}; %// Get boundary

    %// Determine how many points we have
    num_pts = size(boundary,1);

    %// Generate indices for sampling the boundary
    %// If there are less than the minimum, just choose this amount
    if num_pts < num_edge_points
        ind = 1:num_pts;
    else
        ind = floor(linspace(1,num_pts,num_edge_points));
    end

    %// Subsample the edge points
    pts = boundary(ind,:);

    %// Mark points in output
    out(sub2ind(size(B), pts(:,1), pts(:,2))) = true;
end

out将包含您的边缘图像二次采样。为了说明我们做对了,让我们创建一个新的RGB图像,我们将边缘和子采样边缘点放在彼此的顶部,其中子采样边缘为红色:

out_red = 255*uint8(B);
out_greenblue = out_red;
out_greenblue(out) = 0;
out_rgb = cat(3, out_red, out_greenblue, out_greenblue);
imshow(out_rgb);

这是我们得到的(放大):

enter image description here

正如您所看到的,顶部和底部矩形具有完整的边缘点,因为边缘点少于200个。但是,中间的那个是稀疏采样的,因为有超过200个边缘点,但现在我们只显示其中的200个。


如果您想要一个功能来帮助您实现此目的,您可以使用以下方法。我基本上复制了上面的所有代码,输入是带边的二进制图像,输出是带有子采样边的二进制图像:

function [out] = subsample_edge(B)

    %// Obtain boundaries for edge image
    [bound,L,N] = bwboundaries(B);

    out = false(size(B)); %// Initialize output image
    num_edge_points = 200; %// Define number of edge points

    %// For each object boundary
    for idx = 1 : N
        boundary = bound{idx}; %// Get boundary

        %// Determine how many points we have
        num_pts = size(boundary,1);

        %// Generate indices for sampling the boundary
        %// If there are less than the minimum, just choose this amount
        if num_pts < num_edge_points
            ind = 1:num_pts;
        else
            ind = floor(linspace(1,num_pts,num_edge_points));
        end

        %// Subsample the edge points
        pts = boundary(ind,:);

        %// Mark points in output
        out(sub2ind(size(B), pts(:,1), pts(:,2))) = true;
    end
end

如果您想调用此功能,只需执行以下操作:

out = subsample_edge(B);