在本教程中,我们将学习如何填充二进制图像中的孔。考虑一下图1左侧的图像。假设我们想找到一个二进制蒙版,它将硬币与背景分离开,如右图所示。在本教程中,包含硬币的圆形区域也称为前景。
请注意,硬币的边界很暗,与白色背景不同。因此,我们使用简单的图像阈值处理将边界与背景分开。换句话说,我们说强度高于特定值(阈值)的像素是背景,其余像素是前景。上示中间图像显示此阈值图像(黑色代表背景,白色代表前景)。不幸的是,即使边界已被很好地提取(纯白色),硬币的内部强度也与背景相似。因此,阈值操作无法将其与背景区分开。我们如何用白色填充圆形边界内的所有像素?
MATLAB具有称为imfill的功能,该功能允许您填充孔,并且可以按以下方式使用它。
% MATLAB code for filling holes in a binary image.
im = imfill(im,'holes');
OpenCV中的imfill
OpenCV中没有插入功能,但是我们可以肯定地写一个!这个想法很简单。我们知道像素(0,0)连接到背景。因此,我们可以通过简单地从像素(0,0)进行泛洪操作来提取背景。不受泛洪操作影响的像素必须在边界内。反转并与阈值图像组合时,充满洪水的图像将提供前景遮罩!
用C ++代码填充二进制图像中的孔
具体代码如下:
#include "opencv2/opencv.hpp"
using namespace cv;
int main(int argc, char **argv)
{
// Read image
Mat im_in = imread("nie.png", IMREAD_GRAYSCALE);
// Threshold.
// Set values equal to or above 220 to 0.
// Set values below 220 to 255.
Mat im_th;
threshold(im_in, im_th, 220, 255, THRESH_BINARY_INV);
// Floodfill from point (0, 0)
Mat im_floodfill = im_th.clone();
floodFill(im_floodfill, cv::Point(0, 0), Scalar(255));
// Invert floodfilled image
Mat im_floodfill_inv;
bitwise_not(im_floodfill, im_floodfill_inv);
// Combine the two images to get the foreground.
Mat im_out = (im_th | im_floodfill_inv);
// Display images
imshow("Thresholded Image", im_th);
imshow("Floodfilled Image", im_floodfill);
imshow("Inverted Floodfilled Image", im_floodfill_inv);
imshow("Foreground", im_out);
waitKey(0);
}
其他技术
还有其他方法可以解决相同的问题。一种方法是使用形态学闭运算。但是,要进行形态学操作,您需要知道孔的最大尺寸。另一种方法是使用findContours查找轮廓,然后使用drawContours填充轮廓。我更喜欢本文中描述的技术的简单性和速度。