opencv(27)---分水岭算法及图像修补

分水岭算法

基本概念

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

这里写图片描述

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

这里写图片描述

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

这里写图片描述

函数原型–watershed()

void watershed( InputArray image, InputOutputArray markers );
  • image: 输入图像, 需为8位三通道彩色图像
  • markers: 参数调用后的结果, 输入/输出32位单通道图像标记结果, 需和原图一样的大小

应用实例

这里写图片描述

代码

///分水岭算法

Mat srcImg = imread("bird.jpg");
imshow("src", srcImg);
Mat dstImg = srcImg.clone();
//medianBlur(srcImg, srcImg, 5);
//GaussianBlur(srcImg, srcImg, Size(5, 5), 0, 0);
Mat imgMask(srcImg.size(), CV_8U, Scalar(0));
//标示背景图像
rectangle(imgMask, Point(1,1), Point(srcImg.cols-2, srcImg.rows-2), Scalar(255), 1);
//标示鸟
rectangle(imgMask, Point(srcImg.cols/2-10, srcImg.rows/2-10),Point(srcImg.cols/2+10,srcImg.rows/2+10), cv::Scalar(128), 10);
//标示岩石
rectangle(imgMask, Point(264, 353),Point(314, 395), Scalar(64), 10);
imshow("mask", imgMask);

imgMask.convertTo(imgMask, CV_32S);
watershed(srcImg, imgMask);  //调用分水岭算法
Mat mark1, mark2;
imgMask.convertTo(mark1, CV_8U);
imshow("marker", mark1);

Mat mark3 = mark1.clone();
bitwise_not(mark1, mark2);
threshold(mark1, mark1, 64, 255, CV_THRESH_TOZERO_INV);
threshold(mark2, mark2, 127, 255, CV_THRESH_TOZERO_INV);
threshold(mark3, mark3, 128, 255, CV_THRESH_BINARY);
vector<vector<Point>> contours;
vector<Vec4i> hierarcy;
findContours(mark1, contours, hierarcy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
drawContours(dstImg, contours, -1, Scalar(0, 255, 0), -1, 8);

vector<vector<Point>> contours2;
vector<Vec4i> hierarcy2;
findContours(mark2, contours2, hierarcy2, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
drawContours(dstImg, contours2, -1, Scalar(0, 0, 255), -1, 8);

vector<vector<Point>> contours3;
vector<Vec4i> hierarcy3;
findContours(mark3, contours3, hierarcy3, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
drawContours(dstImg, contours3, -1, Scalar(255, 0, 0), -1, 8);

Mat result = srcImg*0.5 + dstImg*0.5;
imshow("result", result);

waitKey(0);

图像修补

需添加opencv_photo248d.lib与photo.hpp

基本概念

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

函数原型

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

src: 输入图像, 需为8位单通道或三通道色图像
inpaintMask: 修复掩膜, 为八位单通道图像, 其中非0像素表示需要修补的区域
dst: 函数调用后输出图像, 和原图一样的尺寸和类型
inpaintRadius: 需要修补的每个点的圆形邻域, 为修复算法的参考半径
flags: 修补方法的标识符, 有如下两种:

这里写图片描述

基于Navier-Stokes方程方法和Alexandru Telea

应用实例1—景物修复

代码

///图像修补
Mat srcImg = imread("D:\\1\\snow.jpg");

Mat mask(srcImg.size(), CV_8U, Scalar(0));
rectangle(mask, Point(45, 270),Point(180, srcImg.rows), Scalar(255), -1, 8);

Point org =  Point(185, 335);
putText( srcImg, "OpenCV", org, CV_FONT_HERSHEY_SIMPLEX, 2.2f, CV_RGB(255, 0, 0),2);
imshow("src", srcImg);

//putText( mask, "OpenCV", org, CV_FONT_HERSHEY_SIMPLEX, 2.2f, CV_RGB(255,255,255),2);
rectangle(mask, Point(185, 270),Point(srcImg.cols, srcImg.rows), Scalar(255), -1, 8);
imshow("mask", mask);

Mat result;
inpaint(srcImg, mask, result, 3, CV_INPAINT_NS); //图像修复

imshow("result", result);

waitKey(0);

运行结果

这里写图片描述

这里写图片描述

这里写图片描述

应用实例2—人脸去痘

这里写图片描述

思路:只需要在原图的复制图上绘制白色的线条作为掩码图

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值