So I have the following code and works fine when displaying the colors on a image. I know it uses a mask over the original image and only shows the colors which are defined in the declared boundaries. So basically it does not "detect" color, rather covers everything else which is not in the ranges.
usage: python code.py
An example image you can find here
code:
import numpy as np
import cv2
import sys
image = cv2.imread(sys.argv[1])
colors = {
"red_lower" : "[ 0 0 255]",
"red_upper" : "[ 0 0 127]",
"blue_lower" : "[255 38 0]",
"blue_upper" : "[255 38 0]",
"yellow_lower" : "[ 0 216 255]",
"yellow_upper" : "[ 0 216 255]",
"gray_lower" : "[160 160 160]",
"gray_upper" : "[160 160 160]"
}
boundaries = [
([0, 0, 255], [127, 0, 255]), #red
([255, 38, 0], [255, 38, 0]), #blue
([0, 216, 255], [0, 216, 255]), #yellow
([160, 160, 160], [160, 160, 160]) #gray
]
# loop over the boundaries
for (lower, upper) in boundaries:
# create NumPy arrays from the boundaries
lower = np.array(lower, dtype = np.uint8)
upper = np.array(upper, dtype = np.uint8)
# find the colors within the specified boundaries and apply the mask
mask = cv2.inRange(image, lower, upper)
output = cv2.bitwise_and(image, image, mask = mask)
# show the images
cv2.imshow("Climbing Holds", np.hstack([image, output]))
cv2.waitKey(0)
I am trying to catch the color on console through an If statement when matching one of the boundaries. If I compare directly with my colors dictionary wont work as expected, since all the boundaries go through the loop.
Example of If statement:
if str(lower) == colors["red_lower"]:
print "red"
elif str(upper) == colors["red_upper"]:
print "dark red"
elif str(lower) == colors["blue_lower"]:
print "blue"
elif str(lower) == colors["yellow_lower"]:
print "yellow"
elif str(lower) == colors["gray_lower"]:
print "gray
I tried to debug by printing mask and output, but these return only zero tuples:
[0 0 0 ... 0 0 0]
[0 0 0 ... 0 0 0]
[0 0 0 ... 0 0 0]]
Does anyone know how to return the mask matching? Is it possible using cv2.imshow or cv2.read?
You could combine colors
and boundaries
into one object to iterate over. Combining the data is a good idea anyhow, as the lower/upper bounds are duplicated currently, once in boundaries
and once as strings in the colors
values. That duplication is not great, as it can lead to subtle errors. Some of the values already seem out of sync, so it's less error-prone to have them just in a single place.
color_boundaries = {
"red": ([0, 0, 255], [127, 0, 255]),
"blue": ([255, 38, 0], [255, 38, 0]),
"yellow": ([0, 216, 255], [0, 216, 255]),
"gray": ([160, 160, 160], [160, 160, 160])
}
for color_name, (lower, upper) in color_boundaries.items():
# create NumPy arrays from the boundaries
lower = np.array(lower, dtype = np.uint8)
upper = np.array(upper, dtype = np.uint8)
# find the colors within the specified boundaries and apply the mask
mask = cv2.inRange(image, lower, upper)
output = cv2.bitwise_and(image, image, mask = mask)
if mask.any():
print(f"{color_name}: {mask.sum()}")