opencv contours 遇到边界

来源:互联网 发布:智尚网络 培训 编辑:程序博客网 时间:2024/05/21 01:54

问题:目标物和图像边界相连,怎么填充内部孔洞?

上一篇  opencv contours 的问题 提到 如果先通过 findContours() 找到轮廓,再通过 drawContours() 画出该轮廓,两者的形状不会发生改变。

就像这样:

Mat src = imread("test2.bmp", 1);Mat gray;cvtColor(src, gray, CV_BGR2GRAY);Mat thre = gray > 1;imshow("thre", thre);int area1 = countNonZero(thre);cout<<"area1="<<area1<<endl;vector< vector<Point> > contours;vector< Vec4i> hierarchy;findContours(thre, contours, hierarchy, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);Mat mask1 = Mat::zeros(src.size(), CV_8UC1);for(int i=0; i<contours.size(); ++i) {drawContours(mask1, contours, i, 255, CV_FILLED, 8, hierarchy);}int area2 = countNonZero(mask1);cout<<"area2="<<area2<<endl;imshow("mask1", mask1); imwrite("mask1.bmp", mask1);
原图和结果图:

处理前后计算面积:


两者是一样的。


但是今天发现一个问题,当目标物和边界相连的时候,以上规律就不对了。结果变成这样:


计算结果:


处理后的图片左边界向右移了一个像素,计算出的面积小了 1550-1500=50.  也就是左边界的边长:76-27+1=50(通过四个顶点计算出)。

把method 由CV_CHAIN_APPROX_SIMPLE  改成 CV_CHAIN_APPROX_NONE 结果是一样的。

从contours里面每个像素点的坐标看,是从左上角(x=1,y=27)开始,往下沿着左边界到左下角的点(x=1,y=76),接着下边界,逆时针绕一圈,最后是点(x=2,y=27)。看来是忽略掉边界上的点了。


恰好我需要把孔洞填充,结果变成这样:


左边界上的目标物如图:


经过findContours() 函数提取过后,这个被保存为一个轮廓,一个完整的外轮廓,且没有内轮廓。

而我想要填充黑色部分,怎么办呢?

我曲折的进行了以下处理:

Mat src = imread("mask4.bmp", 1);Mat gray;cvtColor(src, gray, CV_BGR2GRAY);Mat mask4 = gray > 1;imshow("mask4", mask4);//--提取轮廓填充,得到磨粒区域mask-------vector< vector<Point> > contours1;vector< Vec4i> hierarchy1;Mat mask5 = Mat::zeros(mask4.size(), mask4.type());findContours(mask4, contours1, hierarchy1, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);for(int i=0; i<contours1.size(); ++i) {drawContours(mask5, contours1, i, 255, CV_FILLED, 8, hierarchy1);}imshow("mask5", mask5); imwrite("mask5.bmp", mask5);//----以上处理后,边界处的轮廓无法填充-------//----反色,提取靠近边界的目标物-------Mat mask5_inv;bitwise_not(mask5, mask5_inv);  imwrite("mask5_inv.bmp", mask5_inv);vector< vector<Point> > contours2;findContours(mask5_inv, contours2, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);Mat mask5_border = Mat::zeros(mask4.size(), CV_8UC1);for(int i=0; i<contours2.size(); ++i){int area = contourArea(contours2[i]);if(area<2000)drawContours(mask5_border, contours2, i, 255, CV_FILLED, 8);}imshow("mask5_border", mask5_border);//----把靠近边界的磨粒区域合并---Mat mask6;addWeighted(mask5, 1.0, mask5_border, 1.0, 0.0, mask6);imshow("mask6", mask6); imwrite("mask6.bmp", mask6);
把 mask5 反色后提取所有外轮廓,通过面积大小排除大片背景区域,取得靠近边界线的目标物区域mask5_border,再叠加到mask5上面。

中间图及结果图:


问题暂时解决。




0 0
原创粉丝点击