How to use OpenCV (Python) to change specific colors without loss of quality?
Question:
So, I have this floor plan
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
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?
Answers:
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)
So, I have this floor plan
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
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?
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)