【问题标题】:Removing watermark out of an image using OpenCV使用 OpenCV 从图像中去除水印
【发布时间】:2015-11-14 12:15:41
【问题描述】:

首先我有这张图片,我想制作一个可以检测类似图片并从中删除圆圈(水印)的应用程序。

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) 给了我一张只有那个圆圈的图像
  4. 新图像的阈值
  5. bitwise_or阈值结果

我的问题是这个圆圈内的弯曲白线上的任何黑色文字都没有出现。我试图通过使用像素值而不是阈值来去除颜色,但问题是一样的。 那么有什么解决方案或建议吗?

结果如下:

【问题讨论】:

    标签: c++ opencv image-processing watermark


    【解决方案1】:

    我不确定您的情况是否可以接受以下解决方案。但我认为它的性能稍微好一点,并且不关心水印的形状。

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

    • 计算差异图像:差异 = 背景 - 初始值,并对其进行阈值处理:二进制 = 阈值(差异)

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

    • 从初始图像中提取水印区域内的像素并对这些像素进行阈值处理,然后将它们粘贴到之前的二值图像中

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

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

    【讨论】:

    • 太棒了,它工作得很好,但我遇到了较暗页面的问题 - 较暗的水印 - 它只是将整个水印复制到 bw 图像,所以最后就像什么都没做,我该如何处理像那样?
    • 检查中间图像:差异背景水印掩码中间二进制。这里我们使用 Otsu 方法,所以经过阈值处理的图像最好是双峰的。您可以通过裁剪包含文本的水印部分并对其应用 Otsu 阈值来检查水印内的字母是否按预期分割。这也可能是 CV_THRESH_BINARY 与 CV_THRESH_BINARY_INV 的问题。
    • @dhanushka 请有人帮忙处理向量循环部分的 Java 代码。我在 Java 中找不到等效的东西。我在这里发布了问题 --> answers.opencv.org/question/130997/…
    • @VishalNair 我对opencv java接口不是很熟悉。但是一个简单的谷歌搜索指向herehere。所以,基本上你可以使用Mat::getMat::put 方法。 darkpix 必须是一个 opencv Mat 如果 java 接口不能在 java 向量上运行。
    • @dhanushka 是的,我已经做了那个简单的谷歌搜索:)。问题不是那样的。也许我没有正确沟通。问题出在 unsigned char 部分:) .. 无论如何感谢您的帮助!想出了解决方案......干杯!
    【解决方案2】:

    dhanushkaanswer 的 Python 版本

    # 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')
    

    这是最终结果:
    使用 numpy 处理时间非常短

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

    【讨论】:

      猜你喜欢
      • 2021-11-17
      • 2023-01-08
      • 1970-01-01
      • 2022-06-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-22
      相关资源
      最近更新 更多