C/C++ 图像处理(14)------图像の轮廓填充

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/oHanTanYanYing/article/details/52969441

所谓图像的轮廓填充,是建立在图像的轮廓已然查找完成的情况下的,以下面图像为例:
这里写图片描述
我们首先需要查找到图像中的圆形和正方形的几个轮廓,之后才能对这些轮廓进行处理(查找的过程我们用到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<Point> > contours; vector<Vec4i> 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等软件出来的图形最多只会有两层),再多层的嵌套则需要修改代码中的判断部分。

展开阅读全文

没有更多推荐了,返回首页