Home > Software design >  Removing only checkerboard pattern while reading a png file in opencv python
Removing only checkerboard pattern while reading a png file in opencv python

Time:11-12

Facing problem while removing checkerboard pattern. I'm using cv2.Threshold but it selected unexpected pixels too (red marked) .

import cv2
import numpy as np

input = cv2.imread('image.png')
ret, logo_mask = cv2.threshold(input[:,:,0], 0, 255, cv2.THRESH_BINARY|cv2.THRESH_OTSU)
cv2.imshow(logo_mask)

Input image: input image

Output image: enter image description here

Anyone can help?

CodePudding user response:

Getting perfect results that covers all cases is challenging.

The following solution assumes that the white checkerboard color is (255, 255, 255), and gray is (230, 230, 230).
Another assumptions is that the clusters with that specific colors in the other parts of the image are very small.

We may use the following stages:

  • Find "white mask" and "gray mask" where color is (255, 255, 255) and (230, 230, 230).
  • Create unified mask using bitwise or.
  • Find contours, and remove small contours from the mask (assumed to be "noise").

Code sample:

import cv2
import numpy as np

input = cv2.imread('image.png')

white_mask = np.all(input == 255, 2).astype(np.uint8)*255  # cv2.inRange(input, (255, 255, 255), (255, 255, 255))
gray_mask = np.all(input == 230, 2).astype(np.uint8)*255  # gray_mask = cv2.inRange(input, (230, 230, 230), (230, 230, 230))

mask = cv2.bitwise_or(white_mask, gray_mask)  # Create unified mask

ctns = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[-2]  # Find contours

# Remove small contours from mask
for c in ctns:
    area = cv2.contourArea(c)  # Find the area of each contours
    if (area < 10):  # Ignore small contours (assume noise).
        cv2.drawContours(mask, [c], 0, 0, -1)

mask = cv2.dilate(mask, np.ones((3, 3), np.uint8))  # Dilate the mask - "cosmetics"

output = cv2.copyTo(input, 255-mask)  # Put black color in the masked part.

# Show images for testing
cv2.imshow('input', input)
cv2.imshow('mask', mask)
cv2.imshow('output', output)
cv2.waitKey()
cv2.destroyAllWindows()

white_mask:
enter image description here

gray_mask:
enter image description here

mask:
enter image description here

output:
enter image description here


In case there are large white areas or gray areas in the foreground part, the above solution may not work.

I thought of a process for finding only the areas that overlaps a boundary between white and gray rectangle.
It's not working, because there are small parts between the tree branches that are excluded.

The following code may give you inspirations:

import cv2
import numpy as np

input = cv2.imread('image.png')
#ret, logo_mask = cv2.threshold(input[:,:,0], 0, 255, cv2.THRESH_BINARY|cv2.THRESH_OTSU)

white_mask = np.all(input == 255, 2).astype(np.uint8)*255  # cv2.inRange(input, (255, 255, 255), (255, 255, 255))
gray_mask = np.all(input == 230, 2).astype(np.uint8)*255  # gray_mask = cv2.inRange(input, (230, 230, 230), (230, 230, 230))

cv2.imwrite('white_mask.png', white_mask)
cv2.imwrite('gray_mask.png', gray_mask)

# Apply opening for removing small clusters
opened_white_mask = cv2.morphologyEx(white_mask, cv2.MORPH_OPEN, np.ones((3, 3), np.uint8))
opened_gray_mask = cv2.morphologyEx(gray_mask, cv2.MORPH_OPEN, np.ones((3, 3), np.uint8))

cv2.imwrite('opened_white_mask.png', opened_white_mask)
cv2.imwrite('opened_gray_mask.png', opened_gray_mask)

white_mask_shell = cv2.dilate(opened_white_mask, np.ones((3, 3), np.uint8)) - opened_white_mask  # Dilate white_mask and keep only the "shell"
gray_mask_shell = cv2.dilate(opened_gray_mask, np.ones((3, 3), np.uint8)) - opened_gray_mask # Dilate gray_mask and keep only the "shell"
white_mask_shell = cv2.dilate(white_mask_shell, np.ones((3, 3), np.uint8)) # Dilate the "shell"
gray_mask_shell = cv2.dilate(gray_mask_shell, np.ones((3, 3), np.uint8)) # Dilate the "shell"

cv2.imwrite('white_mask_shell.png', white_mask_shell)
cv2.imwrite('gray_mask_shell.png', gray_mask_shell)

overlap_shell = cv2.bitwise_and(white_mask_shell, gray_mask_shell)
cv2.imwrite('overlap_shell.png', overlap_shell)

dilated_overlap_shell = cv2.dilate(overlap_shell, np.ones((17, 17), np.uint8))

mask = cv2.bitwise_or(cv2.bitwise_and(white_mask, dilated_overlap_shell), cv2.bitwise_and(gray_mask, dilated_overlap_shell))

cv2.imshow('input', input)
cv2.imshow('white_mask', white_mask)
cv2.imshow('gray_mask', gray_mask)
cv2.imshow('white_mask', white_mask)
cv2.imshow('gray_mask', gray_mask)
cv2.imshow('opened_white_mask', opened_white_mask)
cv2.imshow('opened_gray_mask', opened_gray_mask)
cv2.imshow('overlap_shell', overlap_shell)
cv2.imshow('dilated_overlap_shell', dilated_overlap_shell)
cv2.imshow('mask', mask)
cv2.waitKey()
cv2.destroyAllWindows()
  • Related