mode的值决定把找到的轮廓如何挂到轮廓树节点变量(h_prev, h_next, v_prev, v_next)上。下图展示了四种可能的mode值所得到的结果的拓扑结构。
(a) (b)
图1 (a)原图示意图,(b)mode不同类型的拓扑结构
mode
|
描述
|
轮廓结果图 |
CV_RETR_EXTERNAL |
只检测出最外轮廓即c0。图1中第一个轮廓指向最外的序列,除此之外没有别的连接。 |
|
CV_RETR_LIST |
检测出所有的轮廓并将他们保存到表(list)中,图1中描绘了这个表,被找到的9条轮廓相互之间由h_prev和h_next连接。这里并没有表达出纵向的连接关系,没有使用v_prev和v_next. |
|
CV_RETR_CCOMP |
检测出所有的轮廓并将他们组织成双层的结构,第一层是外部轮廓边界,第二层边界是孔的边界。从图1可以看到5个轮廓的边界,其中3个包含孔。最外层边界c0有两个孔,c0之间的所有孔相互间由h_prev和h_next指针连接。 |
|
CV_RETR_TREE |
检测出所有轮廓并且重新建立网状的轮廓结构。图1中,根节点是最外层的边界c0,c0之下是孔h00,在同一层中与另一个孔h01相连接。同理,每个孔都有子节点(相对于c000和c010),这些子节点和父节点被垂直连接起来。这个步骤一直持续到图像最内层的轮廓,这些轮廓会成为树叶节点。 |
Mat CreateTestImage();
int main(int argc, _TCHAR* argv[])
{
Mat src = CreateTestImage();
Mat gray;
cvtColor(src, gray, CV_BGR2GRAY);
Mat bw;
cv::threshold(gray, bw, 128, 255,THRESH_BINARY);
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
cv::findContours(gray, contours, hierarchy,CV_RETR_EXTERNAL , CV_CHAIN_APPROX_NONE );
Mat dst = Mat ::zeros(src.size(),CV_8UC3);
drawContours(dst, contours, -1, Scalar(255,255, 255));
cv::namedWindow("src",0);
cv::imshow("src",src);
cv::namedWindow("dst",0);
cv::imshow("dst",dst);
cv::waitKey();
system("pause");
return 0;
}
Mat CreateTestImage()
{
//第一层,绘制一个黑色背景的图像
int nWidth = 557;
int nHeight = 291;
Mat dst = Mat::zeros(nHeight,nWidth,CV_8UC3);
//第二层,绘制一个白色矩形,上下左右各有等距边框
int nBorder = 20;
int nX2 = nBorder;
int nY2 = nBorder;
int nWidth2 = nWidth -nBorder*2 ;
int nHeight2 = nHeight - nBorder*2;
cv::rectangle(dst,cv::Rect(nX2,nY2,nWidth2,nHeight2),cv::Scalar(255,255,255),-1);
//第三层,在第二层中间绘制两个黑色矩形,上下左右各有等距边框,两个黑色矩形间距一个边框距离
int nX3 = nX2 + nBorder;
int nY3 = nY2 + nBorder;
int nWidth3 = (nWidth2-nBorder*3)*0.5 ;
int nHeight3 =(nHeight2-nBorder*2) ;
int nX3_1 = nX3+nWidth3+nBorder;
cv::rectangle(dst,cv::Rect(nX3,nY3,nWidth3,nHeight3),cv::Scalar(0,0,0),-1);
cv::rectangle(dst,cv::Rect(nX3_1,nY3,nWidth3,nHeight3),cv::Scalar(0,0,0),-1);
//第四层,在第三层两个黑色矩形中再分别绘制两个白色矩形,上下左右各有等距边框
int nX4 = nX3 + nBorder;
int nY4 = nY3 + nBorder;
int nWidth4 = (nWidth3-nBorder*2);
int nHeight4 =(nHeight3-nBorder*2) ;
int nX4_1 = nX3_1+nBorder;
cv::rectangle(dst,cv::Rect(nX4,nY4,nWidth4,nHeight4),cv::Scalar(255,255,255),-1);
cv::rectangle(dst,cv::Rect(nX4_1,nY4,nWidth4,nHeight4),cv::Scalar(255,255,255),-1);
//第五层,在第四层两个白色矩形中再分别绘制两个黑色矩形,上下左右各有等距边框
int nX5 = nX4 + nBorder;
int nY5 = nY4 + nBorder;
int nWidth5 = (nWidth4-nBorder*2);
int nHeight5 =(nHeight4-nBorder*2) ;
int nX5_1 = nX4_1+nBorder;
cv::rectangle(dst,cv::Rect(nX5,nY5,nWidth5,nHeight5),cv::Scalar(0,0,0),-1);
cv::rectangle(dst,cv::Rect(nX5_1,nY5,nWidth5,nHeight5),cv::Scalar(0,0,0),-1);
//第六层,在第⑤层第二个矩形绘制四个白色矩形,上下左右各有等距边框,四个白色矩形间距一个边框距离,只绘制下方两个矩形
int nWidth6 = (nWidth5-nBorder*3)*0.5 ;
int nHeight6 =(nHeight5-nBorder*3)*0.5 ;
int nX6 = nX5_1 + nBorder;
int nY6 = nY5 + nBorder + nHeight6 + nBorder;
int nX6_1 = nX6 + nWidth6 + nBorder;
cv::rectangle(dst,cv::Rect(nX6,nY6,nWidth6,nHeight6),cv::Scalar(255,255,255),-1);
cv::rectangle(dst,cv::Rect(nX6_1,nY6,nWidth6,nHeight6),cv::Scalar(255,255,255),-1);
return dst;
}
|
method
|
描述 |
结果
|
CV_CHAIN_CODE |
用freeman链码输出轮廓,其他方法输出多边形(顶点的序列)。通过实验证明是无法绘制出轮廓的。 |
|
CV_CHAIN_APPROX_NONE |
将链码编码中的所有点转换为点。 |
|
CV_CHAIN_APPROX_SIMPLE |
压缩水平,垂直或斜的部分,只保存最后一个点。 |
|
CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS |
使用Teh-Chin链逼近算法中的一个。 |
|
CV_LINK_RUNS |
与上述的算法完全不同,连接所有的水平层次的轮廓。 |
Mat CreateTestImage();
int main(int argc, _TCHAR* argv[])
{
Mat src = CreateTestImage();
Mat gray;
cvtColor(src, gray, CV_BGR2GRAY);
Mat bw;
cv::threshold(gray, bw, 128, 255,THRESH_BINARY);
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
cv::findContours(gray, contours, hierarchy, CV_RETR_LIST, CV_LINK_RUNS);
Mat dst = Mat ::zeros(src.size(),CV_8UC3);
drawContours(dst, contours, -1, Scalar(255,255, 255));
for each(vector<Point> contour in contours )
{
for each(Point pt in contour)
{
cv::circle(dst,pt,1,Scalar(0,0, 255),-1);
}
}
cv::namedWindow("src",0);
cv::imshow("src",src);
cv::namedWindow("dst",0);
cv::imshow("dst",dst);
cv::waitKey();
system("pause");
return 0;
}
|
thickness=CV_FILLED
),
the contour interiors are drawn”
CV_OUT Point2f& center,//Point2f类型的center是求得的最小外接圆的中心坐标;