Use OpenCV to remove the watermark in the picture, show it!

Reference link: https://stackoverflow.com/questions/32125281/removing-watermark-out-of-an-image-using-opencv

Long time no see, hello everyone, I have been too busy lately, I haven’t made more original articles for a long time (after all, I’m lazy),

In the past two days, I saw an interesting case on Stackoverflow. It was a discussion about OpenCV. The topic of discussion was how to use OpenCV to remove the watermark in the picture below. The original picture is as follows;

shuiyin.jpg

The subject wants to remove the black circle from the paper and only leave the background, so some interested CV enthusiasts write down their ideas and paste their own solution code below

After seeing the answer on this topic, I can only sigh that the real bosses solve problems from practical scenarios.

Due to limited space, only the two question-and-answer ideas and codes with the highest votes are posted in the article, let us feel the ingenuity of their ideas!

Author: Joel G

This old man’s thoughts are divided into five parts in total

  • 1. First, convert the image into a grayscale image and mark it as A;

  • 2. Use the Hough circle to detect the largest ellipse in A, and then create a circle with the same radius in the new image to get B;

  • 3, and draws a circle on the grayscale image, application of OpenCV bitwise_andand operation, extracts the original grayscale image A includes only the image region oval referred to are C;

  • 4. Set an appropriate threshold for image C to extract text and finally get D;

  • 5. Perform bitwise_oroperations on images A and D to get the final image E;

The following is the result of running on my own machine, from left to right corresponding to the above A, C, D, E; the effect is as follows

threshold1.jpg

The overall idea of ​​this method is to first extract the part of the ring in the image, perform threshold segmentation to extract the text in the ring, and finally replace the extracted image area in the original image .

A main mainly used here are three important algorithms: 图像位运算(和、或), 阈值分割, 霍夫圆检测,

The following is the code part of this idea. The original respondent used C++it because I was doing a Python tutorial, so I converted it with Python

import cv2
import numpy as np

if __name__ =='__main__':
    img_path = "F:/Data/Ceshi1/shuiyin.jpg"

    img1 = cv2.imread(img_path)
    cv2.namedWindow('img1',cv2.WINDOW_FREERATIO)
    cv2.imshow('img1',img1)

    # 转化为 灰度图
    gray = cv2.cvtColor(img1,cv2.COLOR_BGR2GRAY)
    # 创建一个白画布
    ellipse_img = np.full((img1.shape[0],img1.shape[1],3),0,dtype = np.uint8)
    print(ellipse_img.shape,ellipse_img[0][0])
    gray = cv2.GaussianBlur(gray,(5,5),0) # 高斯处理
    # 应用霍夫圆检测,检测出所有圆
    circles = cv2.HoughCircles(gray,cv2.HOUGH_GRADIENT,1,gray.shape[0]/8,100,100,100,0)


    # 找到最大的圆
    measure = 0.0
    x = 0.0
    y = 0.0
    for circle in (circles[0]):
        if circle[2] > measure:
            measure = circle[2]
            x = circle[0]
            y = circle[1]

    # 绘制圆
    cv2.circle(img1,(x,y),3,(0,255,0),-1,8,0)
    cv2.circle(img1,(x,y),int(measure),(0,255,0),2,8,0)
    # 绘制相同大小的圆
    ellipse_img =  cv2.ellipse(ellipse_img,(x,y),(int(measure),int(measure)),0,0,360,(255,255,255),-1,8)
    print(f'center x is {x} ,y is {y}, radius is {measure}')
    ellipse_img = cv2.cvtColor(ellipse_img,cv2.COLOR_BGR2GRAY)

    result = cv2.bitwise_and(gray,ellipse_img)


    cv2.namedWindow('bitwise and',cv2.WINDOW_FREERATIO)
    cv2.imshow('bitwise and',result)

    # 估计圆图像像素强度
    x = result[int(x+30)][int(y)]
    print(f'intensity is  {x}')


    # 阈值分割
    _,ellipse_img = cv2.threshold(result,int(x) - 10,250,cv2.THRESH_BINARY)
    # print('ellipse_img shape is {}'.format(ellipse_img.shape))
    cv2.namedWindow('threshold',cv2.WINDOW_FREERATIO)
    cv2.imshow('threshold',ellipse_img)

    # 使用 bitwise_or 方法
    print('shape ------------\n')
    print(ellipse_img.shape,gray.shape)
    res = cv2.bitwise_or(gray,ellipse_img)

    cv2.namedWindow('bitwise_or',cv2.WINDOW_FREERATIO)
    cv2.imshow('bitwise_or',res)

    cv2.waitKey(0)

Final result preview comparison

reslut_1.jpg

The above is the first implementation method. This method mainly uses threshold segmentation. From the final result, the watermark is indeed removed, but there are still certain flaws:

  • For example, the background of the text inside the circle is different from the background outside the circle, there is a large color difference, and the text extraction results in the circle are incomplete;
  • This method is not universal, because this type of method can only be used for circular watermarks. If the watermark is an irregular polygon, this method may fail

The second way of thinking is introduced below. It has similarities with the first, and uses 阈值分割、图像像素位运算related algorithms, but at the same time it has its own uniqueness. From an objective point of view, the final result of this method will be better.

作者 : dhanushka

The idea is mainly divided into four parts

  • 1. The source image is marked as A, and the text area in the image is deleted with a morphological filter, and the obtained image is marked as B;

Snipaste_2020-12-11_21-17-22.jpg

  • 2. Obtain the difference between the A and B images, use AB, and then use the threshold segmentation to process after the difference is obtained, to get C;

Snipaste_2020-12-11_21-17-53.jpg

  • 3. Threshold segmentation of the background image, extract the black part covered by the watermark and mark it as D,

Snipaste_2020-12-11_21-18-00.jpg

  • 4. Extract the pixels in area D from A, and then divide the pixels by threshold segmentation, and finally paste the extracted pixels to B to get the final watermarked image

Snipaste_2020-12-11_21-18-11.jpg

The code is posted below

import cv2
import numpy as np

if __name__ =='__main__':
    img_path = "F:/Data/Ceshi1/shuiyin.jpg"
    im = cv2.imread(img_path)

    gray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)

    background = gray.copy()
    for i in range(1,5):
        kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(2*i+1,2*i+1))
        # print('kernel size is ',kernel)
        background = cv2.morphologyEx(background,cv2.MORPH_CLOSE,kernel)
        background = cv2.morphologyEx(background,cv2.MORPH_CLOSE,kernel)

    diff = background - gray # 计算差距

    cv2.namedWindow('diff',cv2.WINDOW_FREERATIO) # 获取图像中前景背景之差
    cv2.imshow('diff',background)
    # 阈值分割获取黑色字体
    _,bw = cv2.threshold(diff,0,255,cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)
    # 阈值分割获取黑色区域
    cv2.namedWindow('bw_before', cv2.WINDOW_FREERATIO)
    cv2.imshow('bw_before', bw)


    _,dark = cv2.threshold(background,0,255,cv2.THRESH_BINARY_INV|cv2.THRESH_OTSU)

    darkpix = cv2.countNonZero(dark)# 获取 dark非0d图像像素个数
    darkpix = [0]*darkpix
    index = 0
    cv2.namedWindow('gray', cv2.WINDOW_FREERATIO)
    cv2.imshow('gray', gray)



    for r in range(dark.shape[0]):
        for c in range(dark.shape[1]):
            if(dark[r][c]):
                darkpix[index]  = gray[r][c]
                index = index +1

    # 阈值分割 dark 区域 因此我们在里面得到更深的像素
    darkpix = np.array(darkpix)
    _,darkpix = cv2.threshold(darkpix,0,255,cv2.THRESH_BINARY | cv2.THRESH_OTSU)

    cv2.namedWindow('darkpix', cv2.WINDOW_FREERATIO)
    cv2.imshow('darkpix', darkpix)

    # 把 取到的像素粘贴到 其渠道的 darker pixels

    cv2.namedWindow('dark',cv2.WINDOW_FREERATIO)
    cv2.imshow('dark',dark)

    index = 0
    for r in range(dark.shape[0]):
        for c in range(dark.shape[1]):
            if (dark[r][c]):
                bw[r][c] =  darkpix[index]
                index = index +1

    cv2.namedWindow('bw',cv2.WINDOW_FREERATIO)
    cv2.imshow('bw',bw)
    cv2.waitKey(0)

Effect preview comparison

Snipaste_2020-12-12_17-04-44.jpg

Compared with the first method, the second method is more practical, regardless of the shape of the image foreground watermark, this method is applicable (the watermark area has a large difference in intensity from other background pixels, and the watermark area is connected together) ,

If commercial approaches are taken into consideration, it is unrealistic to use OpenCV only to solve the picture watermark problem in complex scenes, and manual intervention is required; but unrealistic does not mean it is useless. For watermarks with large front and rear pixel values ​​and simple scenes , OpenCV is completely feasible, and if a batch operation is added, it becomes even more feasible, greatly liberating our hands!

And the two methods used in the idea is worth learning, such as 图像像素或与和操作、形态学过滤、霍夫圆检测techniques, by means of these methods can be applied to other scenarios such as the circular region extraction images, pedestrians crossing detecting remove irregular image Connection area, etc.

Okay, the above is the whole content of this article. If you think it is good, please don't be stingy with your hands, like, forward, and leave a message. Thank you Sanlian!

Guess you like

Origin blog.csdn.net/weixin_42512684/article/details/111149898