Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Removing watermark out of an image using OpenCV

First of all I have this image and I want to make an application that can detect images like it and remove the circle (watermark) from it.

image has a watermark

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); } 

So far what I made is:

  1. I convert it to grayscale
  2. I detect the largest circle using Hough circles and then make a circle with same radius in a new image
  3. This new circle with the gray-scaled one using (bitwise_and) gives me an image with only that circle
  4. Threshold that new image
  5. bitwise_or the result of the threshold

My problem is that any black text on the curved white line inside this circle didn't appear. I tried to remove the color by using the pixel values instead of threshold, but the problem is the same. So any solutions or suggestions?

These are the results: enter image description here

like image 937
Ahmed Ramzy Avatar asked Aug 20 '15 18:08

Ahmed Ramzy


People also ask

Can you remove a watermark from an image?

Photo Stamp Remover is a photo correction tool designed to remove watermark from image. It can also delete date stamps, logos and other undesired objects from the photos. As it has a user-friendly interface, it is very easy to start your removing watermarks.


2 Answers

I'm not sure if the following solution is acceptable in your case. But I think it performs slightly better, and doesn't care about the shape of the watermark.

  • Remove the strokes using morphological filtering. This should give you a background image. background

  • Calculate the difference image: difference = background - initial, and threshold it: binary = threshold(difference)

binary1

  • Threshold the background image and extract the dark region covered by the watermark

dark

  • From the initial image, extract pixels within the watermark region and threshold these pixels, then paste them to the earlier binary image

binary2

Above is a rough description. Code below should explain it better.

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++];         }     } } 
like image 105
dhanushka Avatar answered Sep 22 '22 21:09

dhanushka


A Python version of dhanushka's answer

# Import the necessary packages import cv2 import numpy as np   def back_rm(filename):     # Load the image     img = cv2.imread(filename)      # Convert the image to grayscale     gr = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)      # Make a copy of the grayscale image     bg = gr.copy()      # Apply morphological transformations     for i in range(5):         kernel2 = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,                                             (2 * i + 1, 2 * i + 1))         bg = cv2.morphologyEx(bg, cv2.MORPH_CLOSE, kernel2)         bg = cv2.morphologyEx(bg, cv2.MORPH_OPEN, kernel2)      # Subtract the grayscale image from its processed copy     dif = cv2.subtract(bg, gr)      # Apply thresholding     bw = cv2.threshold(dif, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]     dark = cv2.threshold(bg, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]      # Extract pixels in the dark region     darkpix = gr[np.where(dark > 0)]      # Threshold the dark region to get the darker pixels inside it     darkpix = cv2.threshold(darkpix, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]      # Paste the extracted darker pixels in the watermark region     bw[np.where(dark > 0)] = darkpix.T      cv2.imwrite('final.jpg', bw)   back_rm('watermark.jpg') 

Here is the final result:
The processing time is very short using numpy

time python back_rm.py   real    0m0.391s user    0m0.518s sys     0m0.185s 

enter image description here

like image 20
singrium Avatar answered Sep 21 '22 21:09

singrium