oepncv實現——影像去水印

唯有自己強大發表於2021-06-01

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

實現原理:利用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);

 

相關文章