如何找到二值图像中一个区域周围的所有边缘像素?
How to find all edge pixels around one region in binary image?
该区域的洞已经填满,我想找到逆时针方向的所有边缘像素。
一开始,我的解决方案是
1、找出边缘的所有像素
2、获取质心与像素之间的x方向
3、排序
如何改进?
图片和代码如下,但是我测试代码的时候,发现凹凸不平,因为在这些角度上可能有很多点。
function nAngle = create_angle_array(nPosition,centroid)
a = repmat(centroid,[size(nPosition,1),1])
nAngle = mod(angle((nPosition-a)*[1;1j]),2*pi)
end
se = strel('rect',[3,3]);
erodeImage = imerode(binaryImage,se);
erodeImageLeft = binaryImage - erodeImage;
% countPixel = sum(erodeImageLeft(:)== true);
[edgeRow_a,edgeCol_a] = find(erodeImageLeft);
if isscalar(edgeRow_a)
edgeRow = [edgeRow_a];
else
edgeRow = edgeRow_a;
end
if isscalar(edgeCol_a)
edgeCol = [edgeCol_a];
else
edgeCol = edgeCol_a;
end
disp(edgeRow);
disp(edgeCol);
angleValue = create_angle_array(cat(2,edgeRow,edgeCol),centroid);
disp(angleValue);
nPixel = cat(2,angleValue,edgeRow,edgeCol);
fprintf('size(nPixelA) is [%s]\n', int2str(size(nPixel)));
disp(nPixel)
nEdgePixel = sortrows(nPixel)
如您所见,沿轴对像素进行排序并不能保证顺序一致。一种更可靠的方法是取一个像素并在正确的方向上找到与其相邻的下一个像素。
为此,我们需要以正确的顺序搜索相邻像素。对于 counter-clockwise 排序,我们将方向定义为:
1 0 7
\ | /
\|/
2--+--6
/|\
/ | \
3 4 5
对于当前像素点,我们会在前一个像素点加1(模8)的方向上开始搜索下一个像素点。因此,如果前一个像素在方向 6,我们将首先查看方向 7,然后是 0,然后是 1,直到找到下一个周边像素。然后重复,直到我们再次到达起始像素。
当我们 select 开始像素时,我们没有“前一个”像素,因此确保我们不会错过任何像素的最简单方法是从其中一个极端开始(说,最左边)。然后将“前一个”像素的方向设置为你知道没有更多像素的方向,即向左或方向2。所以,
- 设置
current_pixel
并分配previous_direction
如上。将 current_pixel
添加到 perimeter_list
。
- 重复:
- 从
previous_direction + 1
(模 8)开始,按顺序搜索相邻像素,直到找到另一个周边像素。
- 如果新像素等于起始像素,
break
。
- 将新的周边像素添加到列表中。如果发现新像素的方向是d,则将
previous_direction
设置为d+4 mod 8
。将 current_pixel
设置为 newly-found 像素。
这将以正确的顺序找到一个区域的所有周边像素,而无需先明确找到周边像素。从该区域突出的任何“尖峰”或一个像素宽的线将列出两次像素,一次在每个方向上穿过该线,因此您的最终列表可能比周边像素数长。您也可以跳过填充孔,除非您需要在以后的步骤中填充它们。
需要注意的一些事情是确保您不会看向图像边界之外,并让 MATLAB 的基于 1 的数组索引与 mod
一起使用。就个人而言,我有一个 mod1
函数来执行 one-based 模运算。如果这样做,只需将方向数字更改为 1 到 8,而不是 0 到 7。我选择从最左边的像素开始,因为这就是 find(bwimg, 1)
将变为 return。
该区域的洞已经填满,我想找到逆时针方向的所有边缘像素。 一开始,我的解决方案是
1、找出边缘的所有像素
2、获取质心与像素之间的x方向
3、排序
如何改进? 图片和代码如下,但是我测试代码的时候,发现凹凸不平,因为在这些角度上可能有很多点。
function nAngle = create_angle_array(nPosition,centroid)
a = repmat(centroid,[size(nPosition,1),1])
nAngle = mod(angle((nPosition-a)*[1;1j]),2*pi)
end
se = strel('rect',[3,3]);
erodeImage = imerode(binaryImage,se);
erodeImageLeft = binaryImage - erodeImage;
% countPixel = sum(erodeImageLeft(:)== true);
[edgeRow_a,edgeCol_a] = find(erodeImageLeft);
if isscalar(edgeRow_a)
edgeRow = [edgeRow_a];
else
edgeRow = edgeRow_a;
end
if isscalar(edgeCol_a)
edgeCol = [edgeCol_a];
else
edgeCol = edgeCol_a;
end
disp(edgeRow);
disp(edgeCol);
angleValue = create_angle_array(cat(2,edgeRow,edgeCol),centroid);
disp(angleValue);
nPixel = cat(2,angleValue,edgeRow,edgeCol);
fprintf('size(nPixelA) is [%s]\n', int2str(size(nPixel)));
disp(nPixel)
nEdgePixel = sortrows(nPixel)
如您所见,沿轴对像素进行排序并不能保证顺序一致。一种更可靠的方法是取一个像素并在正确的方向上找到与其相邻的下一个像素。
为此,我们需要以正确的顺序搜索相邻像素。对于 counter-clockwise 排序,我们将方向定义为:
1 0 7
\ | /
\|/
2--+--6
/|\
/ | \
3 4 5
对于当前像素点,我们会在前一个像素点加1(模8)的方向上开始搜索下一个像素点。因此,如果前一个像素在方向 6,我们将首先查看方向 7,然后是 0,然后是 1,直到找到下一个周边像素。然后重复,直到我们再次到达起始像素。
当我们 select 开始像素时,我们没有“前一个”像素,因此确保我们不会错过任何像素的最简单方法是从其中一个极端开始(说,最左边)。然后将“前一个”像素的方向设置为你知道没有更多像素的方向,即向左或方向2。所以,
- 设置
current_pixel
并分配previous_direction
如上。将current_pixel
添加到perimeter_list
。 - 重复:
- 从
previous_direction + 1
(模 8)开始,按顺序搜索相邻像素,直到找到另一个周边像素。 - 如果新像素等于起始像素,
break
。 - 将新的周边像素添加到列表中。如果发现新像素的方向是d,则将
previous_direction
设置为d+4 mod 8
。将current_pixel
设置为 newly-found 像素。
这将以正确的顺序找到一个区域的所有周边像素,而无需先明确找到周边像素。从该区域突出的任何“尖峰”或一个像素宽的线将列出两次像素,一次在每个方向上穿过该线,因此您的最终列表可能比周边像素数长。您也可以跳过填充孔,除非您需要在以后的步骤中填充它们。
需要注意的一些事情是确保您不会看向图像边界之外,并让 MATLAB 的基于 1 的数组索引与 mod
一起使用。就个人而言,我有一个 mod1
函数来执行 one-based 模运算。如果这样做,只需将方向数字更改为 1 到 8,而不是 0 到 7。我选择从最左边的像素开始,因为这就是 find(bwimg, 1)
将变为 return。