简体   繁体   中英

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

I have the following 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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM