如何查找连通域的外轮廓,OpenCv使用FindContours,比较复杂,对于一些简单的情况可使用Moore neighboorhood算法的实现,方便与OpenCv结构使用。
伪代码如下
Begin Set B to be empty. From bottom to top and left to right scan the cells of T until a black pixel, s, of P is found. Insert s in B. Set the current boundary point p to s i.e. p=s b = the pixel from which s was entered during the image scan. Set c to be the next clockwise pixel (from b) in M(p). While c not equal to s do If c is black insert c in B b = p p = c (backtrack: move the current pixel c to the pixel from which p was entered) c = next clockwise pixel (from b) in M(p). else (advance the current pixel c to the next clockwise pixel in M(p) and update backtrack) b = c c = next clockwise pixel (from b) in M(p). end While EndC++和OpenCv实现代码如下
#include "core\core.hpp"
#include "highgui\highgui.hpp"
using namespace std;
cv::Point getCWofP(cv::Point & b,cv::Point & p)//逆时针查找
{
cv::Point rt;
if(b.x<=p.x&&b.y==p.y-1)
{
rt.y=b.y;
rt.x=b.x+1;
}
else
{
if(b.x==p.x+1&&b.y<=p.y)
{
rt.x=b.x;
rt.y=b.y+1;
}
else
{
if(b.x>=p.x&&b.y==p.y+1)
{
rt.y=b.y;
rt.x=b.x-1;
}
else
{
rt.x=b.x;
rt.y=b.y-1;
}
}
}
return rt;
}
vector<cv::Point> Execuse(cv::Mat T) //查找T中连通域的轮廓,假设T中只有一个连通域
{
cv::Point p;
cv::Point b;
cv::Point c;
cv::Point s;
int wd=T.cols;
int ht=T.rows;
vector<cv::Point> B;
for (int i=0;i<ht;i++)
{
int fd=0;
for (int j=0;j<wd;j++)
{
char c=T.at<char>(i,j);
if(c==0 ) //black
{
s.x=i;
s.y=j;
fd=1;
break;
}
}
if(fd)
break;
}
B.push_back(s);
p=s;
b.x=s.x;
b.y=s.y-1;
c=getCWofP(b,p);
while (c.x!=s.x||s.y!=c.y)
{
if(T.at<char>(c.x,c.y)==0) //c是黑色
{
B.push_back(c);
b=p;
p=c;
c=getCWofP(b,p);
}
else
{
b=c;
c=getCWofP(b,p);
}
}
return B;
}
int main()
{
int i,j;
cv::Point c ;
cv::Mat b(100,100,CV_8UC1,255);
for(i=10;i<50;i++)
for(j=20;j<60;j++)
b.at<char>(i,j)=0; //置轮通域
cv::namedWindow("origin",0);
cv::imshow("origin",b);
vector<cv::Point> contour_edge=Execuse(b);
cv::Mat b_p(100,100,CV_8UC1,255);
for(i=0;i<contour_edge.size();i++)
b_p.at<char>(contour_edge[i].x,contour_edge[i].y)=0;
cv::namedWindow("moore",0);
cv::imshow("moore",b_p);
cv::waitKey();
cv::destroyAllWindows();
return 1;
}
下图为原始图片和寻找的外轮廓图片
MATLAB代码为
function [MooreNeighbour top]=findBoundary(image)%image input
[ht wd]=size(image);
imshow(image)
MooreNeighbour=zeros(ht*wd,2);
p=zeros(1,2);
c=zeros(1,2);
b=zeros(1,2);
s=zeros(1,2);
top=0;
for i=1:ht
fd=0;
for j=1:wd
if(image(i,j)==0 )
s(1)=i;
s(2)=j;
fd=1;
top=1;
MooreNeighbour(top,1)=i;
MooreNeighbour(top,2)=j;
break;
end
end
if(fd)
break;
end
end
p(1)=s(1);
p(2)=s(2);
b(1)=p(1);
b(2)=p(2)-1;
c=getCWofP(b,p);
while (c(1)~=s(1)||s(2)~=c(2))
if(image(c(1),c(2))==0) %c is black
top=top+1;
MooreNeighbour(top,:)=c;
b(1)=p(1);
b(2)=p(2);
p(1)=c(1);
p(2)=c(2);
c=getCWofP(b,p);
else
b(1)=c(1);
b(2)=c(2);
c=getCWofP(b,p);
end
end
end
function c=getCWofP(b,p)
if(b(1)<=p(1)&&b(2)==p(2)-1)
c(2)=b(2);
c(1)=b(1)+1;
else
if(b(1)==p(1)+1&&b(2)<=p(2))
c(1)=b(1);
c(2)=b(2)+1;
else
if(b(1)>=p(1)&&b(2)==p(2)+1)
c(2)=b(2);
c(1)=b(1)-1;
else
c(1)=b(1);
c(2)=b(2)-1;
end
end
end
end