在本教程中,我们将学习如何填充二值图像中的孔。参考图1左侧的图像,假设我们想要找到一个二值模板,它将硬币与背景分开,如右图所示。在本教程中,包含硬币的圆形区域也将被称为前景。
请注意,硬币的边界是黑色的,与白色背景不同。因此,我们使用简单的图像阈值来将边界与背景分开。换句话说,我们说强度高于某个值(阈值)的像素是背景,其余像素是前景。中心图像显示此阈值图像(黑色代表背景,白色代表前景)。不幸的是,即使边界被很好地提取(它是纯白色),硬币的内部也具有类似于背景的强度。因此,阈值操作不能将其与背景区分开。我们如何用白色填充圆形边界内的所有像素?
MATLAB有一个名为imfill的函数 ,允许您填充孔,您可以通过以下方式使用它。
% MATLAB code for filling holes in a binary image.
im = imfill(im,'holes');
OpenCV中没有imfill功能,但我们肯定可以写一个!这个想法很简单。我们知道像素(0,0)连接到背景。因此,我们可以通过从像素(0,0)执行填充操作来提取背景。不受洪水填充操作影响的像素必然位于边界内。反转并与阈值图像组合的泛洪图像就是前景蒙版了!
图2 在OpenCV中实现imfill的流程
阅读以下步骤时请参考图2.
读取图片。
将输入图像二值化。
从像素(0,0)填充颜色。请注意,步骤2和步骤3的输出之间的差异在于步骤3中的图像的背景现在是白色的。
反转洪水填充的图像(即黑色变为白色,白色变为黑色)。
使用按位OR运算将阈值图像与反向洪水填充图像组合以获得填充有孔的最终前景掩模。步骤4中的图像在边界内具有一些黑色区域。通过步骤2,填充了图像中的孔。因此,我们将两者结合起来得到前景蒙版。
以下是它在代码
C ++实现:
#include "opencv2/opencv.hpp"
using namespace cv;
int main(int argc, char **argv)
{
// Read image
Mat im_in = imread("nickel.jpg", 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);
}
Python实现:
import cv2;
import numpy as np;
# Read image
im_in = cv2.imread("nickel.jpg", cv2.IMREAD_GRAYSCALE);
# Threshold.
# Set values equal to or above 220 to 0.
# Set values below 220 to 255.
th, im_th = cv2.threshold(im_in, 220, 255, cv2.THRESH_BINARY_INV);
# Copy the thresholded image.
im_floodfill = im_th.copy()
# Mask used to flood filling.
# Notice the size needs to be 2 pixels than the image.
h, w = im_th.shape[:2]
mask = np.zeros((h+2, w+2), np.uint8)
# Floodfill from point (0, 0)
cv2.floodFill(im_floodfill, mask, (0,0), 255);
# Invert floodfilled image
im_floodfill_inv = cv2.bitwise_not(im_floodfill)
# Combine the two images to get the foreground.
im_out = im_th | im_floodfill_inv
# Display images.
cv2.imshow("Thresholded Image", im_th)
cv2.imshow("Floodfilled Image", im_floodfill)
cv2.imshow("Inverted Floodfilled Image", im_floodfill_inv)
cv2.imshow("Foreground", im_out)
cv2.waitKey(0)
原文地址:https://www.learnopencv.com/filling-holes-in-an-image-using-opencv-python-c/