Opencv 中floodfill函数的某个奇怪bug

在使用Opencv的floodfill函数处理带有孔洞的图像时,遇到一个奇怪的bug。当直接填充图像时,结果为整张图全白;而通过先加边再填充的方式,能正确填充孔洞。此问题在C++环境下出现,可能与其他编程语言也有关联。

最近在填充图像孔洞的时候,发现了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上可能也有这种情况。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值