最近在填充图像孔洞的时候,发现了floodfill这个函数有一个奇怪的bug,具体的复现过程如下:
(1)选取一张带有孔洞的物体的图片,最简单的方法就是用画图版画一张,比如下面这幅,实际大小是20x20像素,中间的白色方框是10x10,最里面的黑色孔洞是4x4

(2)读取图片并二值化,这一步没啥问题
Mat src = imread("D:\\aaa\\1.jpg", 0);//黑底白颗粒,黑色孔洞
threshold(src, src, 120,255,0);
(3)用floodfill函数进行漫水填充,此时用下面两种写法,都能得到最中间的黑色孔洞
第一种:给图片加个边,填充后再将边给去掉
Mat thrImg =src;
Mat Temp = Mat(src.rows + 2, src.cols + 2, CV_8UC1, Scalar(0));
thrImg.copyTo(Temp(Range(1, thrImg.rows + 1), Range(1, thrImg.cols + 1)));
Rect ccomp1;
floodFill(Temp, Point(0, 0), Scalar(255));
thrImg = Temp(Rect(1, 1, src.cols, src.rows));
namedWindow("thrImg", WINDOW_NORMAL);
imshow("thrImg", thrImg);
第二种:直接填充
Mat thrImg2 = src;
floodFill(thrImg2, Point(0, 0), Scalar(255));
namedWindow("thrImg2", WINDOW_NORMAL);
imshow("thrImg2", thrImg2);


(4)最后将thrImg或者thrImg2先取反再与src求交集,也就是同色变白,异色变黑
Mat srcimg;
srcimg = src | (~thrImg);//srcimg = src | (~thrImg2);
namedWindow("srcimg", WINDOW_NORMAL);
imshow("srcimg", srcimg);
这时候第三步两种不同写法就会产生不同的结果
第一种写法:成功,孔洞被填充为白色

第二种写法:失败,整张图全白

经过一定的实验,发现几个有意思的情况:
(1)第三步两种写法得到的图片是一模一样,在矩阵视角下看的非常清楚

(2)如果将两种写法放在一起,就不会产生成功的结果,除非将求交集放在两种写法中间
失败:
Mat thrImg =src;
Mat Temp = Mat(src.rows + 2, src.cols + 2, CV_8UC1, Scalar(0));
thrImg.copyTo(Temp(Range(1, thrImg.rows + 1), Range(1, thrImg.cols + 1)));
Rect ccomp1;
floodFill(Temp, Point(0, 0), Scalar(255));
thrImg = Temp(Rect(1, 1, src.cols, src.rows));
namedWindow("thrImg", WINDOW_NORMAL);
imshow("thrImg", thrImg);
Mat thrImg2 = src;
floodFill(thrImg2, Point(0, 0), Scalar(255));
namedWindow("thrImg2", WINDOW_NORMAL);
imshow("thrImg2", thrImg2);
cout << "thrImg1:" << thrImg << endl << "thrImg2:" << thrImg2 << endl;
//同色变白,异色为黑,使黑空洞变白
Mat srcimg;
srcimg = src | (~thrImg);
namedWindow("srcimg", WINDOW_NORMAL);
imshow("srcimg", srcimg);
成功:
Mat thrImg =src;
Mat Temp = Mat(src.rows + 2, src.cols + 2, CV_8UC1, Scalar(0));
thrImg.copyTo(Temp(Range(1, thrImg.rows + 1), Range(1, thrImg.cols + 1)));
Rect ccomp1;
floodFill(Temp, Point(0, 0), Scalar(255));
thrImg = Temp(Rect(1, 1, src.cols, src.rows));
namedWindow("thrImg", WINDOW_NORMAL);
imshow("thrImg", thrImg);
//同色变白,异色为黑,使黑空洞变白
Mat srcimg;
srcimg = src | (~thrImg);
namedWindow("srcimg", WINDOW_NORMAL);
imshow("srcimg", srcimg);
Mat thrImg2 = src;
floodFill(thrImg2, Point(0, 0), Scalar(255));
namedWindow("thrImg2", WINDOW_NORMAL);
imshow("thrImg2", thrImg2);
imwrite("D:\\3-opencv程序\\彩色识别\\4.jpg", thrImg2);
cout << "thrImg1:" << thrImg << endl << "thrImg2:" << thrImg2 << endl;
(3)如果在读取图片时,读取两次再分别赋给thrImg和thrImg2,就可以保证thrImg得到正确结果,但thrImg2依旧错误
Mat src = imread("D:\\aaa\\2.jpg", 0);//黑底白颗粒,黑色孔洞
threshold(src, src, 120,255,0);
Mat src2 = imread("D:\\aaa\\2.jpg", 0);//黑底白颗粒,黑色孔洞
threshold(src2, src2, 120, 255, 0);
目前,这个bug出现在visio15,C++语言,但在C#、python上可能也有这种情况。
在使用Opencv的floodfill函数处理带有孔洞的图像时,遇到一个奇怪的bug。当直接填充图像时,结果为整张图全白;而通过先加边再填充的方式,能正确填充孔洞。此问题在C++环境下出现,可能与其他编程语言也有关联。

9156

被折叠的 条评论
为什么被折叠?



