oepncv实现——图像去水印
功能简介:通过拖动鼠标实现指定区域水印或是斑点的去除。
实现原理:利用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);