问题:目标物和图像边界相连,怎么填充内部孔洞?
上一篇 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上面。
中间图及结果图:
问题暂时解决。