所谓图像的轮廓填充,是建立在图像的轮廓已然查找完成的情况下的,以下面图像为例:
我们首先需要查找到图像中的圆形和正方形的几个轮廓,之后才能对这些轮廓进行处理(查找的过程我们用到OpenCV的findContours函数)。
在得到轮廓之后,难点就转变为如何填充轮廓了,对于左上角的圆来说,直接填充即可,然而对于圆环和“田”字,则一般只希望填充两个轮廓直接的区域,中间的孔洞则保留,因此在对轮廓进行填充之前需要做进一步的判断工作(通过判断findContours函数的第三个参数对象实现),具体的实现代码如下:
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "time.h"
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
long time = clock();
int r = 100;
Mat src = Mat::zeros(Size(8 * r, 4 * r), CV_8UC1);
//绘制轮廓,因为线段本身有粗细,则绘制一个圆会检测出两个轮廓,需要特别注意
//绘制三个圆,其中一个嵌套着另一个
circle(src, cvPoint(2 * r, 2 * r), 80, Scalar(255), 2);
circle(src, cvPoint(2 * r, 2 * r), 50, Scalar(255), 2);
circle(src, cvPoint(r, r), 30, Scalar(255), 2);
//绘制一个田字
rectangle(src, cvPoint(4 * r - r / 2, 2 * r - r / 2), cvPoint(4 * r + r / 2, 2 * r + r / 2), Scalar(255), 2);
rectangle(src, cvPoint(4 * r - r * 2 / 5, 2 * r - r * 2 / 5), cvPoint(4 * r - r * 1 / 20, 2 * r - r * 1 / 20), Scalar(255), 2);
rectangle(src, cvPoint(4 * r - r * 2 / 5, 2 * r + r * 1 / 20), cvPoint(4 * r - r * 1 / 20, 2 * r + r * 2 / 5), Scalar(255));
rectangle(src, cvPoint(4 * r + r * 2 / 5, 2 * r - r * 2 / 5), cvPoint(4 * r + r * 1 / 20, 2 * r - r * 1 / 20), Scalar(255), 2);
rectangle(src, cvPoint(4 * r + r * 2 / 5, 2 * r + r * 1 / 20), cvPoint(4 * r + r * 1 / 20, 2 * r + r * 2 / 5), Scalar(255), 2);
Mat raw_dist1(src.size(), CV_32FC1);
vector<vector > contours; vector hierarchy;
Mat src_copy = src.clone();
findContours(src_copy, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_NONE);//查找轮廓,并以树状图结果存储轮廓信息
for (size_t i = 0; i < contours.size(); i++)
{
if (hierarchy[i][3] != -1)//表示其为某一个轮廓的内嵌轮廓
{
if (hierarchy[hierarchy[i][3]][3] == -1)//表示其为最外层轮廓,上面检测到的是其线条的内部
{
drawContours(raw_dist1, contours, i, Scalar(255), -1);
}
else
{
drawContours(raw_dist1, contours, i, Scalar(0), -1);
}
}
else
{
drawContours(raw_dist1, contours, i, Scalar(0), -1);
}
}
printf("花费时间%dms\n", clock() - time);
char* source_window = "Source";
namedWindow(source_window, CV_WINDOW_AUTOSIZE);
imshow(source_window, src);
namedWindow("Distance1", CV_WINDOW_AUTOSIZE);
imshow("Distance1", raw_dist1);
imwrite("轮廓查找图像.jpg", src);
imwrite("轮廓查找完成图像.jpg", raw_dist1);
waitKey(0);
return(0);
}
通过上面的代码,我们把图像中的轮廓进行了白色的填充,结果如下图所示
到此,我们得到了一副轮廓填充完成的图像,其中的填充区域为白色,如果需要进一步处理,则可以通过连通域检测算法找到各个轮廓像素点的集合。
需要注意的是,上面的代码只支持到两层轮廓的嵌套(一般而言,对于CAD等软件出来的图形最多只会有两层),再多层的嵌套则需要修改代码中的判断部分。