c++ - Opencv का उपयोग करके छवि से वॉटरमार्क निकालना




image-processing watermark (2)

यदि आपके मामले में निम्नलिखित समाधान स्वीकार्य है, तो मुझे यकीन नहीं है। लेकिन मुझे लगता है कि यह थोड़ा बेहतर प्रदर्शन करता है, और वॉटरमार्क के आकार की परवाह नहीं करता है।

  • रूपात्मक फ़िल्टरिंग का उपयोग करके स्ट्रोक निकालें। इससे आपको बैकग्राउंड इमेज मिलनी चाहिए।

  • अंतर छवि की गणना करें: अंतर = पृष्ठभूमि - प्रारंभिक, और इसे सीमा: द्विआधारी = दहलीज (अंतर)

  • पृष्ठभूमि छवि को थ्रेसहोल्ड करें और वॉटरमार्क द्वारा कवर किए गए अंधेरे क्षेत्र को निकालें

  • प्रारंभिक छवि से, वॉटरमार्क क्षेत्र के भीतर पिक्सेल निकालें और इन पिक्सेल को थ्रेशोल्ड करें, फिर उन्हें पहले की बाइनरी छवि पर पेस्ट करें

ऊपर एक मोटा वर्णन है। नीचे दिए गए कोड को इसे बेहतर तरीके से समझाना चाहिए।

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++];
        }
    }
}

सबसे पहले मेरे पास यह छवि है और मैं एक ऐसा एप्लिकेशन बनाना चाहता हूं जो इसके जैसी छवियों का पता लगा सके और इसमें से सर्कल (वॉटरमार्क) को हटा सके।

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. मैं हूप सर्कल का उपयोग करके सबसे बड़े सर्कल का पता लगाता हूं और फिर एक नई छवि में समान त्रिज्या के साथ एक सर्कल बनाता हूं
  3. इस नए सर्कल के साथ एक ( bitwise_and ) का उपयोग करके मुझे उस सर्कल के साथ एक छवि bitwise_and है
  4. उस नई छवि को थ्रेसहोल्ड करें
  5. bitwise_or दहलीज के परिणाम के लिए

मेरी समस्या यह है कि इस सर्कल के अंदर घुमावदार सफेद रेखा पर कोई भी काला पाठ दिखाई नहीं दिया। मैंने थ्रेशोल्ड के बजाय पिक्सेल मूल्यों का उपयोग करके रंग को हटाने की कोशिश की, लेकिन समस्या वही है जो कोई समाधान या सुझाव है?

ये परिणाम हैं:


के 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')

यहाँ अंतिम परिणाम है:
अंकुरण का उपयोग करते हुए प्रसंस्करण समय बहुत कम है

time python back_rm.py 

real    0m0.391s
user    0m0.518s
sys     0m0.185s





watermark