Home > Mobile >  How to keep Only Black color text in the image using OpenCV Python?
How to keep Only Black color text in the image using OpenCV Python?

Time:12-13

I have the following image:

This image.

I want to keep only the black colored text 0790 and remove all from the picture. This stackoverflow question teaches to remove the color. However, I need to keep the color, not remove it.

CodePudding user response:

A possible solution involves converting the image to the CMYK color space and extracting the K (Key - black) channel, thresholding it and applying some morphology to clean up the binary image.

OpenCV does not implement the conversion from BGR to CMYK, so we have to compute the K channel manually. The code would look like this:

# Imports
import cv2
import numpy as np

# Read image
imagePath = "D://opencvImages//"
inputImage = cv2.imread(imagePath   "A6RXi.png")

# Conversion to CMYK (just the K channel):

# Convert to float and divide by 255:
imgFloat = inputImage.astype(np.float) / 255.

# Calculate channel K:
kChannel = 1 - np.max(imgFloat, axis=2)

# Convert back to uint 8:
kChannel = (255 * kChannel).astype(np.uint8)

This is the K (black) Channel:

Now, threshold the image using a fixed value. In this case, I set the threshold to 190:

# Threshold image:
binaryThresh = 190
_, binaryImage = cv2.threshold(kChannel, binaryThresh, 255, cv2.THRESH_BINARY)

This is the binary image:

It is a little noise, but we can remove the smaller blobs if we implement an area filter. The function is defined at the end of this post. Let's apply the filter with a minimum value of 100. All blobs smaller than this will be erased:

# Filter small blobs:
minArea = 100
binaryImage = areaFilter(minArea, binaryImage)

This is the filtered image:

Cool. Let's improve the morphology of the blobs with a closing filter:

# Use a little bit of morphology to clean the mask:
# Set kernel (structuring element) size:
kernelSize = 3
# Set morph operation iterations:
opIterations = 2
# Get the structuring element:
morphKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (kernelSize, kernelSize))
# Perform closing:
binaryImage = cv2.morphologyEx(binaryImage, cv2.MORPH_CLOSE, morphKernel, None, None, opIterations, cv2.BORDER_REFLECT101)

cv2.imshow("binaryImage [closed]", binaryImage)
cv2.waitKey(0)

This is the final result:

And this is the areaFilter function. It receives a minimum area and a binary image, it returns the image free of small blobs :

def areaFilter(minArea, inputImage):
    # Perform an area filter on the binary blobs:
    componentsNumber, labeledImage, componentStats, componentCentroids = \
        cv2.connectedComponentsWithStats(inputImage, connectivity=4)

    # Get the indices/labels of the remaining components based on the area stat
    # (skip the background component at index 0)
    remainingComponentLabels = [i for i in range(1, componentsNumber) if componentStats[i][4] >= minArea]

    # Filter the labeled pixels based on the remaining labels,
    # assign pixel intensity to 255 (uint8) for the remaining pixels
    filteredImage = np.where(np.isin(labeledImage, remainingComponentLabels) == True, 255, 0).astype('uint8')

    return filteredImage
  • Related