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

2020年10月18日 阅读数:8
这篇文章主要向大家介绍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分钟带你深刻了解半阈值化(图文并貌+浅显易懂+程序源码)ui

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

 

前言

红胖子来也!!!.net

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

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

 

Demo

 

漫水填充

概述

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

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

原理

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

      漫水填充的实现方法也有多种: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表示填充模式。

 

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