OpenCV开发笔记(三十三):红胖子8分钟带你深入了解漫水填充算法(图文并茂+浅显易懂+程序源码)

若该文为原创文章,未经允许不得转载
原博主博客地址:https://blog.csdn.net/qq21497936
原博主博客导航:https://blog.csdn.net/qq21497936/article/details/102478062
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/104891183
各位读者,知识无穷而人力有穷,要么改需求,要么找专业人士,要么自己研究

红胖子(红模仿)的博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中...(点击传送门)

OpenCV开发专栏(点击传送门)

上一篇:《OpenCV开发笔记(三十二):红胖子8分钟带你深入了解半阈值化(图文并貌+浅显易懂+程序源码)》

下一篇:《OpenCV开发笔记(三十四):红胖子带你傻瓜式编译Qt+openCV3.4.1+opencv_contrib(全网最浅显易懂)》

 

前言

红胖子来也!!!

今天来说说漫水填充,顾名思义,漫水填充就是放水,水漫上去,那么连通的区域不就都有水,就形成了一片漫水的区域,该区域就是要分离的。

通俗一点:漫水的整个过程,首先要选择一点作为防水点,然后开始放水,放水多少就能向外围扩散多大面积,可以把像素的bgr值想象成高度,谁放的越多,能覆盖的相邻高度差就越大。

 

Demo

 

漫水填充

概述

      漫水填充是一种用特定的颜色填充连通区域,通过设置可联通像素的上下限以及联通方式来达到不同的填充效果的方法。它是在很多图形绘软件中常用的填充算法。

      漫水填充被用来标记或分离图像的一部分,以便对其进行一步处理或分析,也可以用来从输入图像获取掩码区域,掩码会加速处理过程,或只处理掩码指定的像素点,操作的结果总是某个连续的区域。

原理

      漫水填充的原理简单来说,就是从一个点开始水漫(放水,像素rgb的差理解为高度差)附近像素点,填充成新的颜色,直到封闭区域内的所有像素点都被填充成新颜色位置。

      漫水填充的实现方法也有多种:4邻域像素填充法、8邻域像素填充法、基于扫描线的填充方法。

函数原型

(注意:下面的函数不带掩码输入)

CV_EXPORTS_W int floodFill( InputOutputArray image,
                         Point seedPoint,
                         Scalar newVal,
                         CV_OUT Rect* rect=0,
                         Scalar loDiff = Scalar(),
                         Scalar upDiff = Scalar(),
                         int flags = 4 );

(注意:下面的函数带掩码输入)

CV_EXPORTS_W int floodFill( InputOutputArray image,
                         InputOutputArray mask,
                         Point seedPoint,
                         Scalar newVal,
                         CV_OUT Rect* rect=0,
                         Scalar loDiff = Scalar(),
                         Scalar upDiff = Scalar(),
                         int flags = 4 );
  • 参数一:InputOutputArray类型,一般是cv::Mat,参数图像输入/输出1或3通道、8位或浮点图像。此cv::Mat将同时作为输出,除非在函数的第二个变量中设置了“FLOODFILL_MASK_ONLY”标志。
  • 参数二:InputOutputArray InputOutputArray类型的mask,这是第 二个版本的 floodFill独享的参数,表示操作掩模。它应该为单通道8 位,长和  宽上都比输入图像 image大两个像素点。第二个版本 的floodFill需要使用以及更新掩膜 , 所以对 于这个 mask 参数,我们一定要将其准备好并填在此处。需要注意的是,漫水填充不会填充掩膜mask的非零像素区域。例如,一个边缘检测算子的输出可以用来作为掩膜,以防止填充到边缘。同样的,也可以在多次的函数调用中使用同一个掩膜,以保证填充的区域不会重叠。另外需要注意的是,掩膜mask会比需填充的图像大,所以mask中与输入图像(x ,y)像素点相对应的点的坐标为(x+ l, y+ l)。
  • 参数三:Point类型seedPoint,起始像素点。
  • 参数四:Scalar类型的newVla,重绘像素区域新的填充颜色。
  • 参数五:Rect类型的rect,可选输出参数,返回重绘区域的最小绑定矩形。
  • 参数六: Scalar类型的loDiff,当前选定像素与其连通区中相邻像素中的一个像素,或者与加入该连通区的一个seedPoint像素,二者之间的最大下行差异值。
  • 参数七:Scalar类型的upDiff,当前选定像素与其连通区中相邻像素中的一个像素,或者与加入该连通区的一个seedPoint像素,二者之间的最大上行差异值。
  • 参数八: FloodFillFlags类型的flags标志,一个32bit的int类型数据,其由3部分组成: 0-7bit表示邻接性(4邻接、8邻接);8-15bit表示mask的填充颜色;16-31bit表示填充模式。

OpenCV开发笔记(三十三):红胖子8分钟带你深入了解漫水填充算法(图文并茂+浅显易懂+程序源码)_第1张图片

 

Demo源码

void OpenCVManager::testDiffuseFill()
{
    QString fileName1 = "I:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/11.jpg";
    cv::Mat srcMat = cv::imread(fileName1.toStdString());

    int width = 300;
    int height = 200;
    cv::resize(srcMat, srcMat, cv::Size(width, height));

    cv::String windowName = _windowTitle.toStdString();
    cvui::init(windowName);

    cv::Mat windowMat = cv::Mat(cv::Size(srcMat.cols * 3, srcMat.rows * 4),
                                srcMat.type());

    int x = 100;
    int y = 100;

    int b = 255;
    int g = 0;
    int r = 0;

    int loB = 5;
    int loG = 5;
    int loR = 5;

    int upB = 5;
    int upG = 5;
    int upR = 5;

    while(true)
    {
        windowMat = cv::Scalar(0, 0, 0);
        // 原图先copy到左边
        cv::Mat leftMat = windowMat(cv::Range(0, srcMat.rows),
                                    cv::Range(0, srcMat.cols));
        cv::addWeighted(leftMat, 1.0f, srcMat, 1.0f, 0.0f, leftMat);

        // 选取原图坐标点
        cvui::printf(windowMat, width * 1 + 50, 30 + height * 0, "x");
        cvui::trackbar(windowMat, width * 1 + 50, 40 + height * 0, 200, &x, 0, width);

        cvui::printf(windowMat, width * 1 + 50, 90 + height * 0, "y");
        cvui::trackbar(windowMat, width * 1 + 50, 100 + height * 0, 200, &y, 0, height);

        // 修改的新颜色
        cvui::printf(windowMat, width * 2 + 50, 0 + height * 0, "b");
        cvui::trackbar(windowMat, width * 2 + 50, 10 + height * 0, 200, &b, 0, 255);

        cvui::printf(windowMat, width * 2 + 50, 60 + height * 0, "g");
        cvui::trackbar(windowMat, width * 2 + 50, 70 + height * 0, 200, &g, 0, 255);

        cvui::printf(windowMat, width * 2 + 50, 120 + height * 0, "r");
        cvui::trackbar(windowMat, width * 2 + 50, 130 + height * 0, 200, &r, 0, 255);

        // 低像素差
        cvui::printf(windowMat, width * 1 + 50, 0 + height * 1, "loB");
        cvui::trackbar(windowMat, width * 1 + 50, 10 + height * 1, 200, &loB, 0, 255);

        cvui::printf(windowMat, width * 1 + 50, 60 + height * 1, "loG");
        cvui::trackbar(windowMat, width * 1 + 50, 70 + height * 1, 200, &loG, 0, 255);

        cvui::printf(windowMat, width * 1 + 50, 120 + height * 1, "loR");
        cvui::trackbar(windowMat, width * 1 + 50, 130 + height * 1, 200, &loR, 0, 255);

        // 高像素差
        cvui::printf(windowMat, width * 2 + 50, 0 + height * 1, "upB");
        cvui::trackbar(windowMat, width * 2 + 50, 10 + height * 1, 200, &upB, 0, 255);

        cvui::printf(windowMat, width * 2 + 50, 60 + height * 1, "upG");
        cvui::trackbar(windowMat, width * 2 + 50, 70 + height * 1, 200, &upG, 0, 255);

        cvui::printf(windowMat, width * 2 + 50, 120 + height * 1, "upR");
        cvui::trackbar(windowMat, width * 2 + 50, 130 + height * 1, 200, &upR, 0, 255);

        // 标志
        cvui::printf(windowMat, width * 0 + 50, 60 + height * 2, "flags: default");

        cvui::printf(windowMat, width * 1 + 50, 60 + height * 2, "flags: 4 | FLOODFILL_FIXED_RANGE");

        cvui::printf(windowMat, width * 2 + 50, 60 + height * 2, "flags: 8 | FLOODFILL_FIXED_RANGE");

        // circle
        cv::circle(windowMat, cv::Point(x, y), 5, cv::Scalar(0, 0, 255), -1);

        {
            cv::Rect rect;
            cv::Mat tempMat;
            cv::Mat dstMat;
            // 填充
            tempMat = srcMat.clone();
            cv::floodFill(tempMat,
                          cv::Point(x, y),
                          cv::Scalar(b, g, r),
                          &rect,
                          cv::Scalar(loB, loG, loR),
                          cv::Scalar(upB, upG, upR));
            dstMat = windowMat(cv::Range(srcMat.rows * 3, srcMat.rows * 4),
                               cv::Range(srcMat.cols * 0, srcMat.cols * 1));
            cv::addWeighted(dstMat, 0.0f, tempMat, 1.0f, 0.0f, dstMat);

            // 填充
            tempMat = srcMat.clone();
            cv::floodFill(tempMat,
                          cv::Point(x, y),
                          cv::Scalar(b, g, r),
                          &rect,
                          cv::Scalar(loB, loG, loR),
                          cv::Scalar(upB, upG, upR),
                          4 | cv::FLOODFILL_FIXED_RANGE);
            dstMat = windowMat(cv::Range(srcMat.rows * 3, srcMat.rows * 4),
                               cv::Range(srcMat.cols * 1, srcMat.cols * 2));
            cv::addWeighted(dstMat, 0.0f, tempMat, 1.0f, 0.0f, dstMat);

            // 填充
            tempMat = srcMat.clone();
            cv::floodFill(tempMat,
                          cv::Point(x, y),
                          cv::Scalar(b, g, r),
                          &rect,
                          cv::Scalar(loB, loG, loR),
                          cv::Scalar(upB, upG, upR),
                          8 | cv::FLOODFILL_FIXED_RANGE);
            dstMat = windowMat(cv::Range(srcMat.rows * 3, srcMat.rows * 4),
                               cv::Range(srcMat.cols * 2, srcMat.cols * 3));
            cv::addWeighted(dstMat, 0.0f, tempMat, 1.0f, 0.0f, dstMat);
        }
        // 更新
        cvui::update();
        // 显示
        cv::imshow(windowName, windowMat);
        // esc键退出
        if(cv::waitKey(25) == 27)
        {
            break;
        }
    }
}

 

工程模板:对应版本号v1.28.0

      对应版本号v1.28.0

 

上一篇:《OpenCV开发笔记(三十二):红胖子8分钟带你深入了解半阈值化(图文并貌+浅显易懂+程序源码)》

下一篇:《OpenCV开发笔记(三十四):红胖子带你傻瓜式编译Qt+openCV3.4.1+opencv_contrib(全网最浅显易懂)》


原博主博客地址:https://blog.csdn.net/qq21497936
原博主博客导航:https://blog.csdn.net/qq21497936/article/details/102478062
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/104891183

 

你可能感兴趣的:(#,OpenCV,图形图像处理)