功能簡介:通過拖動滑鼠實現指定區域水印或是斑點的去除。

實現原理:利用opencv滑鼠操作setMouseCallback函式框選(左上到右下)需要處理的區域,按下滑鼠開始選中,鬆開滑鼠結束,對選中區域進行畫素替換(根據不同影象,可選不同方式),再對選中區域周圍高斯濾波,平滑處理,再對整體影象雙邊濾波(人像可美顏,增強立體感),對影象做進一步平滑處理。


oepncv實現:

Mat  img, tmp;
Mat org = imread("D:/opencv練習圖片/去水印.jpg");
Mat src = org;
Mat dst = Mat(src.size(), src.type(), CV_8UC3);
static Point pre_pt;//初始座標 (選中區域左上角)
static Point cur_pt;//實時座標 (選中區域右下角)
void on_mouse(int event, int x, int y, int flags, void *ustc);
int main()
{
org.copyTo(img);
org.copyTo(tmp);
namedWindow("img", WINDOW_AUTOSIZE);//定義一個img視窗
setMouseCallback("img", on_mouse);//呼叫回撥函式
waitKey(0);
return 0;
}
void on_mouse(int event, int x, int y, int flags, void *ustc)//event滑鼠事件代號,x,y滑鼠座標,flags拖拽和鍵盤操作的代號
{
char temp[16];//定義座標顯示字元陣列
if (event == EVENT_LBUTTONDOWN)//左鍵按下,讀取初始座標
{
//獲取選中區域矩形左上角座標
pre_pt = Point(x, y);
imshow("img", img);
}
else if (event == EVENT_MOUSEMOVE && !(flags & EVENT_FLAG_LBUTTON))//左鍵沒有按下的情況下,滑鼠移動
{
img.copyTo(tmp);//將img複製到臨時影象tmp上,用於顯示實時座標
sprintf_s(temp, "(%d,%d)", x, y);//座標
cur_pt = Point(x, y);//獲取實時座標
putText(tmp, temp, cur_pt, FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 0, 255));//實時顯示滑鼠移動的座標
imshow("img", tmp);
}
else if (event == EVENT_MOUSEMOVE && (flags & EVENT_FLAG_LBUTTON))//左鍵按下時,滑鼠移動,則在影象上劃矩形
{
imshow("img", img);
}
else if (event == EVENT_LBUTTONUP)//左鍵鬆開,將在影象上劃矩形
{
//獲取實時座標(選中區域矩形右下角)
cur_pt = Point(x, y);
//對選中區域進行畫素替換,偏移2個畫素,根據實際情況調節
for (int i = min(pre_pt.y, cur_pt.y); i < max(cur_pt.y, pre_pt.y); i++)
{
for (int j = min(pre_pt.x, cur_pt.x); j < max(cur_pt.x, pre_pt.x); j++)
{
src.at<Vec3b>(i, j)[0] = src.at<Vec3b>(i, j - 2)[0];
src.at<Vec3b>(i, j)[1] = src.at<Vec3b>(i, j - 2)[1];
src.at<Vec3b>(i, j)[2] = src.at<Vec3b>(i, j - 2)[2];
}
}
//對選中區域周圍進行平滑處理
Mat imageroi = src(Range(pre_pt.y - 3, cur_pt.y + 3), Range(pre_pt.x - 3, cur_pt.x + 3));
GaussianBlur(imageroi, imageroi, Size(15, 15), 0, 0);
//對整體影象雙邊濾波(對人像有美顏效果)
bilateralFilter(src, dst, 15, 30, 9);
//儲存處理後的影象(如有必要)
//imwrite("D:txa.jpg", dst);
//標記選中區域
circle(img, pre_pt, 2, Scalar(255, 0, 0, 0), -1, LINE_AA, 0);
rectangle(img, pre_pt, cur_pt, Scalar(0, 255, 0, 0), 1, 8, 0);
//顯示結果
imshow("結果", dst);
}

GIF效果展示:

 幾點要說:

sprintf_s是sprintf的安全版本,指定緩衝區長度來避免sprintf()存在的溢位風險,主要差在sprintf_s第二個引數,可以控制緩衝區大小。

int sprintf( char *buffer, const char *format, [ argument]  );
//buffer:char型指標,指向將要寫入的字串的緩衝區。
//format:格式化字串。(%d 是格式化為整型 %s 是格式化為字串 )
//[argument]:可選引數,可以是任何型別的資料。 int sprintf_s(char *buffer,size_t sizeOfBuffer,const char *format,[ argument] );
//buffer:char型指標,指向將要寫入的字串的緩衝區。
//sizeOfBuffer:緩衝區大小。
//format:格式化字串。
//[argument]:可選引數,可以是任何型別的資料。

例如:(要把x,y座標的位置轉為字串(x,y)在圖上顯示)

char Txt_Point[50] = { 0 };
sprintf(Txt_Point, "(%d,%d)", x, y);
putText(image, Txt_Point, p ,FONT_HERSHEY_PLAIN, 2, Scalar(255, 255, 255), 2);