使用 OpenCV 从图像中去除水印

Removing watermark out of an image using OpenCV(使用 OpenCV 从图像中去除水印)
本文介绍了使用 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.

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. 我将其转换为灰度
  2. 我使用霍夫圆检测最大的圆,然后在新图像中制作一个具有相同半径的圆
  3. 这个带有灰度的新圆圈使用 (bitwise_and) 给了我一个只有那个圆圈的图像
  4. 设定新图像的阈值
  5. bitwise_or 阈值的结果
  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?

结果如下:

推荐答案

我不确定以下解决方案是否适用于您的情况.不过我觉得性能稍微好一点,不关心水印的形状.

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.

计算差值图像:difference = background - initial,阈值:binary = threshold(difference)

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

  • 对背景图像设置阈值并提取水印覆盖的暗区

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

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

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

这篇关于使用 OpenCV 从图像中去除水印的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本站部分内容来源互联网,如果有图片或者内容侵犯您的权益请联系我们删除!

相关文档推荐

Rising edge interrupt triggering multiple times on STM32 Nucleo(在STM32 Nucleo上多次触发上升沿中断)
How to use va_list correctly in a sequence of wrapper functions calls?(如何在一系列包装函数调用中正确使用 va_list?)
OpenGL Perspective Projection Clipping Polygon with Vertex Outside Frustum = Wrong texture mapping?(OpenGL透视投影裁剪多边形,顶点在视锥外=错误的纹理映射?)
How does one properly deserialize a byte array back into an object in C++?(如何正确地将字节数组反序列化回 C++ 中的对象?)
What free tiniest flash file system could you advice for embedded system?(您可以为嵌入式系统推荐什么免费的最小闪存文件系统?)
Volatile member variables vs. volatile object?(易失性成员变量与易失性对象?)