分水嶺算法及圖像修補
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;
}
運行結果: