pythonopencv

How to use OpenCV (Python) to change specific colors without loss of quality?


I have this floor plan (link removed)

And I want to change its colors so I can use OCR to read the room numbers. To do this, I want to do the following: change all red to white, and every other color to black, so all that is left is the room numbers. I wanted to try thresholding, but I saw on the documentation that it should only be done on grayscale images, so I first ran the following code to grayscale it:

    import cv2
    import os
    from ConvertSVG import svg_2_png
    
    # Convert the SVG to a PNG
    output_path = os.path.join('converted svgs', 'Level 3.png')
    
    svg_2_png(os.path.join('svg', 'Level 3.svg'), output_path)
    
    img = cv2.imread(output_path)
    gray_image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
    cv2.imshow("Grayscale", gray_image)
    
    cv2.waitKey(0)

And I got this output (link removed)

As you can see, the grayscale did work, but the room numbers got blockier and harder for OCR to read.

How could I use OpenCV-python to change all red to white, and every other color to black, with as little "blockage" as possible?


Solution

  • Here's a method that should work reasonably well:

    Results:

    Code:

    import cv2
    import numpy as np
    
    # load image in BGR
    input_image = cv2.imread("floorplan.png").astype(np.float32) / 255.0
    
    # get scalar redness - this is smooth and mostly correct, 
    # but it includes lots of stuff we don't want
    redness = input_image[:, :, 2] - np.mean(input_image[:, :, :2], -1)
    
    # create a blocky mask around the highly-red pixels
    mask_coarse = cv2.dilate((redness > 0.7).astype(np.uint8), np.ones((3, 3)), iterations=5)
    mask_fine = cv2.dilate(
        (mask_coarse * (redness > 0.3)).astype(np.uint8), np.ones((3, 3)), iterations=2
    )
    
    # mask redness with the blocky mask
    output = redness * mask_fine * 255
    
    cv2.imwrite("mask.png", output)