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 }

猜你喜欢

转载自www.cnblogs.com/Long-w/p/9669541.html