分水岭算法及图像修补
转自:https://blog.****.net/abc8730866/article/details/69668703,感谢原创作者!
1.分水岭算法——watershed()
2.图像修补——inpaint()
先上ppt:
代码:1.分水岭算法
- ///分水岭算法
- #include "opencv2/opencv.hpp"
- using namespace cv;
- int main()
- {
- Mat srcImg = imread("bird.jpg",CV_LOAD_IMAGE_COLOR);
- imshow("srcImg", srcImg);
- Mat copyImg = srcImg.clone();
- //1.定义标记图像markers
- Mat markers(srcImg.size(),CV_8UC1,Scalar(0));
- //标记背景
- rectangle(markers,Point(1,1),Point(srcImg.cols-2,srcImg.rows-2),Scalar(255),1,8);
- //标记鸟
- rectangle(markers, Point(srcImg.cols / 2 - 20, srcImg.rows / 2 - 20), Point(srcImg.cols / 2 +20, srcImg.rows / 2 + 20), Scalar(128), -1, 8);
- //标记石头
- rectangle(markers, Point(srcImg.cols / 2 - 30, srcImg.rows - 50), Point(srcImg.cols / 2 + 60, srcImg.rows - 10), Scalar(64), -1, 8);
- imshow("markers-input",markers);
- //2.基于标记图像的分水岭算法
- //将markers转换成32位单通道图像(分水岭函数要求)
- markers.convertTo(markers,CV_32S);
- //分水岭算法
- watershed(srcImg,markers);
- //将markers转换成8位单通道
- markers.convertTo(markers, CV_8UC1);
- imshow("markers-output", markers);
- //3.提取轮廓并绘制轮廓
- Mat mark1, mark2,mark3;
- mark1 = markers.clone();//提取鸟的轮廓
- mark2 = markers.clone();//提取石头轮廓
- mark3 = markers.clone();//提取背景轮廓
- //阈值化,黑中找白,找鸟
- threshold(mark1,mark1,129,255,CV_THRESH_TOZERO_INV);
- threshold(mark1,mark1,120,255,CV_THRESH_TOZERO);
- //阈值化,黑中找白,找石头
- threshold(mark2, mark2, 65, 255, CV_THRESH_TOZERO_INV);
- //阈值化,黑中找白,找背景
- threshold(mark3, mark3, 129, 255, CV_THRESH_BINARY);
- imshow("mark1", mark1);
- imshow("mark2", mark2);
- imshow("mark3", mark3);
- //寻找背景轮廓并绘制
- vector<vector<Point>> contours3;
- findContours(mark3, contours3, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
- drawContours(copyImg, contours3, -1, Scalar(0, 0, 255), -1, 8);
- //寻找鸟轮廓并绘制
- vector<vector<Point>> contours1;
- findContours(mark1,contours1,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_NONE);
- drawContours(copyImg,contours1,-1,Scalar(255,0,0),-1,8);
- //寻找石头轮廓并绘制
- vector<vector<Point>> contours2;
- findContours(mark2, contours2, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
- drawContours(copyImg, contours2, -1, Scalar(0, 255, 0), -1, 8);
- imshow("copyImg",copyImg);
- //4.与原图像叠加
- Mat result = srcImg*0.5 + copyImg*0.5;
- imshow("result", result);
- waitKey(0);
- return 0;
- }
运行结果:
代码:2.图像修补
- ///图像修补
- #include "opencv2/opencv.hpp"
- using namespace cv;
- //定义原图像srcImg和目标图像dstImg
- Mat srcImg = imread("face.JPG", CV_LOAD_IMAGE_COLOR);
- Mat dstImg = srcImg.clone();
- //定义掩码inpaintMask,同srcImg一样大小,类型为8位单通道,初始化为纯黑(掩码非0部分起作用)
- Mat inpaintMask(srcImg.size(), CV_8UC1, Scalar(0));
- //定义鼠标左键是否按下的标志flag
- bool flag=false;
- //记录鼠标左键按下时的初始坐标
- int xStart, yStart;
- void onMouse(int event,int x,int y,int flags,void* param)
- {
- switch (event)
- {
- case CV_EVENT_LBUTTONDOWN:
- flag = true;//鼠标左键按下,flag置为true
- xStart = x;//记录鼠标左键按下时的坐标
- yStart = y;
- break;
- case CV_EVENT_MOUSEMOVE:
- if (flag)
- {
- //在srcImg中画矩形,白色,向内填充
- rectangle(srcImg, Point(xStart, yStart), Point(x, y), Scalar(255, 255, 255), -1, 8);
- //在inpaintMask中画矩形,白色,向内填充
- rectangle(inpaintMask, Point(xStart, yStart), Point(x, y), Scalar(255, 255, 255), -1, 8);
- }
- break;
- case CV_EVENT_LBUTTONUP:
- flag = false;//鼠标左键抬起,flag置为false
- break;
- default:
- break;
- }
- //重新显示原图srcImg
- imshow("inpaint", srcImg);
- //重新显示掩码图像inpaintMask
- imshow("inpaintMask", inpaintMask);
- }
- int main()
- {
- imshow("srcImg", srcImg);
- //定义窗口"inpaint"
- namedWindow("inpaint",CV_WINDOW_AUTOSIZE);
- //设置鼠标回调函数
- setMouseCallback("inpaint",onMouse);
- //使得一开始就显示窗口"inpaint",显示原图srcImg
- imshow("inpaint", srcImg);
- //使得一开始就显示窗口"inpaintMask",显示掩码图像inpaintMask
- imshow("inpaintMask", inpaintMask);
- //使得一开始就显示窗口"dstImg",显示目标图像dstImg
- imshow("dstImg", dstImg);
- //无限循环,若按下空格键(ASCII码为32),则调用inpait()函数,重新显示目标图像dstImg
- while (1)
- {
- if (waitKey(0) == 32)//若按下空格键
- {
- //调用inpait()函数, 重新显示目标图像dstImg
- inpaint(srcImg, inpaintMask, dstImg, 4, CV_INPAINT_NS);
- imshow("dstImg", dstImg);
- }
- }
- waitKey(0);
- return 0;
- }
运行结果: