使用opencv从图像中去除水印

首先,我有这个图像,我想做一个应用程序,可以检测像这样的图像,并从中删除圆(水印)。

图像有水印

int main(){ Mat im1,im2,im3,gray,gray2,result; im2=imread(" (2).jpg"); namedWindow("x",CV_WINDOW_FREERATIO); imshow("x",im2); //converting it to gray cvtColor(im2,gray,CV_BGR2GRAY); // creating a new image that will have the cropped ellipse Mat ElipseImg(im2.rows,im2.cols,CV_8UC1,Scalar(0,0,0)); //detecting the largest circle GaussianBlur(gray,gray,Size(5,5),0); vector<Vec3f> circles; HoughCircles(gray,circles,CV_HOUGH_GRADIENT,1,gray.rows/8,100,100,100,0); uchar x; int measure=0;int id=0; for(int i=0;i<circles.size();i++){ if(cvRound(circles[i][2])>measure && cvRound(circles[i][2])<1000){ measure=cvRound(circles[i][2]); id=i; } } Point center(cvRound(circles[id][0]),cvRound(circles[id][1])); int radius=cvRound(circles[id][2]); circle(im2,center,3,Scalar(0,255,0),-1,8,0); circle(im2,center,radius,Scalar(0,255,0),2,8,0); ellipse(ElipseImg,center,Size(radius,radius),0,0,360,Scalar(255,255,255),-1,8); cout<<"center: "<<center<<" radius: "<<radius<<endl; Mat res; bitwise_and(gray,ElipseImg,result); namedWindow("bitwise and",CV_WINDOW_FREERATIO); imshow("bitwise and",result); // trying to estimate the Intensity of the circle for the thresholding x=result.at<uchar>(cvRound(circles[id][0]+30),cvRound(circles[id][1])); cout<<(int)x; //thresholding the output image threshold(ElipseImg,ElipseImg,(int)x-10,250,CV_THRESH_BINARY); namedWindow("threshold",CV_WINDOW_FREERATIO); imshow("threshold",ElipseImg); // making bitwise_or bitwise_or(gray,ElipseImg,res); namedWindow("bitwise or",CV_WINDOW_FREERATIO); imshow("bitwise or",res); waitKey(0); } 

到目前为止,我所做的是:

  1. 我把它转换成灰度
  2. 我用霍夫圆检测最大的圆,然后在一个新的图像中创build一个具有相同半径的圆
  3. 这个新的圆圈( bitwise_and )使用( bitwise_and )给我一个只有那个圆圈的图像
  4. 新图像的阈值
  5. bitwise_or或阈值的结果

我的问题是,这个圆圈内部的白色曲线上的黑色文字没有出现。 我试图通过使用像素值而不是阈值来去除颜色,但问题是相同的,所以任何解决scheme或build议?

这是结果: 在这里输入图像说明

我不确定以下解决scheme是否可以接受您的情况。 但是我觉得它performance稍好,并不在乎水印的形状。

  • 使用形态过滤删除笔画。 这应该给你一个背景图片。 背景

  • 计算差异图像:差异=背景 – 初始,阈值它:二进制=阈值(差异)

binary1

  • 对背景图像进行阈值提取,并提取水印覆盖的黑暗区域

黑暗

  • 从最初的图像中提取水印区域内的像素,并将这些像素设为阈值,然后将其粘贴到较早的二值图像

binary2

以上是粗略的描述。 下面的代码应该更好地解释它。

 Mat im = [load the color image here]; Mat gr, bg, bw, dark; cvtColor(im, gr, CV_BGR2GRAY); // approximate the background bg = gr.clone(); for (int r = 1; r < 5; r++) { Mat kernel2 = getStructuringElement(MORPH_ELLIPSE, Size(2*r+1, 2*r+1)); morphologyEx(bg, bg, CV_MOP_CLOSE, kernel2); morphologyEx(bg, bg, CV_MOP_OPEN, kernel2); } // difference = background - initial Mat dif = bg - gr; // threshold the difference image so we get dark letters threshold(dif, bw, 0, 255, CV_THRESH_BINARY_INV | CV_THRESH_OTSU); // threshold the background image so we get dark region threshold(bg, dark, 0, 255, CV_THRESH_BINARY_INV | CV_THRESH_OTSU); // extract pixels in the dark region vector<unsigned char> darkpix(countNonZero(dark)); int index = 0; for (int r = 0; r < dark.rows; r++) { for (int c = 0; c < dark.cols; c++) { if (dark.at<unsigned char>(r, c)) { darkpix[index++] = gr.at<unsigned char>(r, c); } } } // threshold the dark region so we get the darker pixels inside it threshold(darkpix, darkpix, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU); // paste the extracted darker pixels index = 0; for (int r = 0; r < dark.rows; r++) { for (int c = 0; c < dark.cols; c++) { if (dark.at<unsigned char>(r, c)) { bw.at<unsigned char>(r, c) = darkpix[index++]; } } }