功能簡介:通過拖動滑鼠實現指定區域水印或是斑點的去除。
實現原理:利用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效果展示:
?幾點要說:
- 關於滑鼠操作(滑鼠的回撥函式和響應函式),可參考:opencv——感興趣區域(ROI)的分析和選取[詳細總結] - 唯有自己強大 - 部落格園 (cnblogs.com)
- 將整形資料改為字串(sprintf函式和sprintf_s函式)
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);