• 31、【opencv入门】分水岭算法及图像修补


    一、简介

    1、分水岭算法

      原理: 任何一副灰度图像都可以被看成拓扑平面,灰度值高的区域可以被看成是 山峰,灰度值低的区域可以被看成是山谷。我们向每一个山谷中灌不同颜色的 水。随着水的位的升高,不同山谷的水就会相遇汇合,为了防止不同山谷的水 汇合,我们需要在水汇合的地方构建起堤坝。不停的灌水,不停的构建堤坝知直到所有的山峰都被水淹没,我们构建好的堤坝就是对图像的分割。这就是分水 岭算法的背后原理。

      在真实图像中,由于噪声点或者其它干扰因素的存在,使用分水岭算法常常存在过度分割的现象,这是因为很多很小的局部极值点的存在,如下图:

     

      为了解决过度分割的问题,可以使用基于标记(mark)图像的分水岭算法,就是通过先验知识,来指导分水岭算法,以便获得更好的图像分段效果。通常的mark图像,都是在某个区域定义了一些灰度层级,在这个区域的洪水淹没过程中,水平面都是从定义的高度开始的,这样可以避免一些很小的噪声极值区域的分割。

     2、分水岭算法函数 --- watershed()

    1 CV_EXPORTS_W void watershed(InputArray image, InputOutArray markers);

      image: 输入图像, 需为8位三通道彩色图像

      markers: 参数调用后的结果, 输入/输出32位单通道图像标记结果, 需和原图一样的大小

     1 //分水岭算法
     2 #include "opencv2/opencv.hpp"
     3 
     4 using namespace cv;
     5 
     6 int main()
     7 {
     8     Mat srcImg = imread("bird.jpg");
     9     imshow("src", srcImg);
    10     Mat dstImg = srcImg.clone();
    11     //medianBlur(srcImg, srcImg, 5);
    12     //GaussianBlur(srcImg, srcImg, Size(5, 5), 0, 0);
    13     Mat imgMask(srcImg.size(), CV_8U, Scalar(0));//标记图像
    14     //标示背景图像
    15     rectangle(imgMask, Point(1, 1), Point(srcImg.cols - 2, srcImg.rows - 2), Scalar(255), 4);
    16     //标示鸟
    17     rectangle(imgMask, Point(srcImg.cols / 2 - 10, srcImg.rows / 2 - 10), Point(srcImg.cols / 2 + 10, srcImg.rows / 2 + 10), Scalar(128), 10);
    18     //标示岩石
    19     rectangle(imgMask, Point(264, 353), Point(314, 395), Scalar(64), 10);
    20     imshow("mask", imgMask);
    21 
    22     imgMask.convertTo(imgMask, CV_32S);
    23     watershed(srcImg, imgMask);  //调用分水岭算法
    24     Mat mark1, mark2;
    25     imgMask.convertTo(mark1, CV_8U);
    26     imshow("mark1", mark1);
    27 
    28     Mat mark3 = mark1.clone();
    29     bitwise_not(mark1, mark2);//图像取反
    30     imshow("mark2", mark2);
    31     threshold(mark1, mark1, 64, 255, CV_THRESH_TOZERO_INV);//CV_THRESH_TOZERO_INV:大于阈值都为0,其余正常        找出岩石
    32     threshold(mark2, mark2, 127, 255, CV_THRESH_TOZERO_INV);//因为取反后背景为0,所以筛选掉岩石后剩下的即为鸟
    33     threshold(mark3, mark3, 128, 255, CV_THRESH_BINARY);//鸟为128,大于128才能为255,所以找出了背景
    34 
    35     vector<vector<Point>> contours;
    36     vector<Vec4i> hierarcy;
    37     findContours(mark1, contours, hierarcy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
    38     drawContours(dstImg, contours, -1, Scalar(0, 255, 0), -1, 8);
    39 
    40     vector<vector<Point>> contours2;
    41     vector<Vec4i> hierarcy2;
    42     findContours(mark2, contours2, hierarcy2, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
    43     drawContours(dstImg, contours2, -1, Scalar(0, 0, 255), -1, 8);
    44 
    45     vector<vector<Point>> contours3;
    46     vector<Vec4i> hierarcy3;
    47     findContours(mark3, contours3, hierarcy3, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
    48     drawContours(dstImg, contours3, -1, Scalar(255, 0, 0), -1, 8);
    49 
    50     Mat result = srcImg*0.5 + dstImg*0.5;
    51     imshow("result", result);
    52     waitKey(0);
    53     return 0;
    54 }

    三、图像修补

      OpenCV中图像修补技术由inpaint函数实现, 基本步骤是先修复区域边缘再逐步向内推进修复, 可以用来清除照片灰尘、划痕或者从静态图像及视频中去除不需要的物体。  

     图像修补---inpaint()

    1 CV_EXPORTS_W void inpaint(InputArray src, InputArray inpaintMask, OutputArray dst, double inpaintRadius, int flags);

      src: 输入图像, 需为8位单通道或三通道色图像

      inpaintMask: 修复掩膜, 为八位单通道图像, 其中非0像素表示需要修补的区域

      dst: 函数调用后输出图像, 和原图一样的尺寸和类型

      inpaintRadius: 需要修补的每个点的圆形邻域, 为修复算法的参考半径

      flags: 修补方法的标识符, 有如下两种: 

    1 INPAINT_NS=CV_INPAINT_NS, //Navier-Stokes algorithm
    2 INPAINT_TELEA=CV_INPAINT_TELEA//A. Telea algorithm

    基于Navier-Stokes方程方法和Alexandru Telea(需要添加opencv_photo库和photo.hpp)

     1 #include "opencv2/opencv.hpp"//图像修复
     2 
     3 using namespace cv;
     4 
     5 int main()
     6 {
     7     Mat srcImg = imread("snow.jpg");
     8 
     9     Mat mask(srcImg.size(), CV_8U, Scalar(0));
    10     rectangle(mask, Point(45, 270), Point(180, srcImg.rows), Scalar(255), -1, 8);
    11 
    12     Point org = Point(185, 335);
    13     putText(srcImg, "OpenCV", org, CV_FONT_HERSHEY_SIMPLEX, 2.2f, CV_RGB(255, 0, 0), 2);
    14     imshow("src", srcImg);
    15 
    16     //putText( mask, "OpenCV", org, CV_FONT_HERSHEY_SIMPLEX, 2.2f, CV_RGB(255,255,255),2);    
    17     rectangle(mask, Point(185, 270), Point(srcImg.cols, srcImg.rows), Scalar(255), -1, 8);
    18     imshow("mask", mask);
    19 
    20     Mat result;
    21     inpaint(srcImg, mask, result, 3, CV_INPAINT_NS); //图像修复
    22 
    23     imshow("result", result);
    24     waitKey(0);
    25     return 0;
    26 }
  • 相关阅读:
    微信小程序tab(swiper)切换
    微信小程序如何动态增删class类名
    Vi (Unix及Linux系统下标准的编辑器)VIM (Unix及类Unix系统文本编辑器)
    js 阻止事件冒泡和默认行为 preventDefault、stopPropagation、return false
    H5中的touch事件
    CSS3 Gradient 渐变
    CSS3动画属性Transform解读
    你所不知的 CSS ::before 和 ::after 伪元素用法
    javascript移动设备Web开发中对touch事件的封装实例
    那些过目不忘的H5页面
  • 原文地址:https://www.cnblogs.com/Long-w/p/9669541.html
Copyright © 2020-2023  润新知