cv2.inRange on HSV image always empty

Hello! I am running into a strange issue involving the use of cv2.inRange and could use some help.

For context, I am trying to identify the colors of each individual circle for this board game.

Since some of the colors look very similar, I had the idea to “tune” the colors to find the min and max HSV values for each color.

To do this, I first crop the area I am interested in.

def crop_circle(img, i, j):
    h, w = img.shape[:2]
    mask = np.zeros((h, w), np.uint8)  # Empty black mask
    cv2.circle(mask, calculate_center(i, j), CIRCLE_RADIUS, CIRCLE_COLOR, -1)  # Fill in white circle
    result = cv2.bitwise_and(img, img, mask=mask)
    x, y, w, h = cv2.boundingRect(mask)
    return result[y : y + h, x : x + w]

Then I split the image and calculate those min / max HSV values.

def split_image(img):
    v, v2, v3 = cv2.split(img)
    v_avg = int(cv2.mean(v)[0])
    v2_avg = int(cv2.mean(v2)[0])
    v3_avg = int(cv2.mean(v3)[0])
    return v_avg, v2_avg, v3_avg

def calculate_optimal_colors(hsv_img, colors):
    def _update_colors(hsv_img, letter, colors):
        def _helper(img, color_detection, letter, colors):
            v, v2, v3 = split_image(img)
            if len(colors[letter][color_detection.name]) == 0:
                colors[letter][color_detection.name] = [[v, v2, v3], [v, v2, v3]]
            else:
                values = colors[letter][color_detection.name]
                values[0][0] = min(values[0][0], v)
                values[0][1] = min(values[0][1], v2)
                values[0][2] = min(values[0][2], v3)
                values[1][0] = max(values[1][0], v)
                values[1][1] = max(values[1][1], v2)
                values[1][2] = max(values[1][2], v3)

        if letter not in colors:
            colors[letter] = {
                COLOR_DETECTION.HSV.name: []
            }

        _helper(hsv_img, COLOR_DETECTION.HSV, letter, colors)

Then I use those min / max HSV values in attempt to determine what the most likely color is by passing those values to cv2.inRange. I try to calculate the percentage of matching pixels that are in that range.

    def _calculate_letter_percentage(img, lower_range, upper_range, threshold=0.5):
        mask = cv2.inRange(img, np.array(lower_range), np.array(upper_range))

        # Calculate the percentage of matching pixels
        total_pixels = mask.shape[0] * mask.shape[1]
        matching_pixels = np.sum(mask > 0)
        percentage = matching_pixels / total_pixels
        return percentage if percentage > threshold else 0

However, the mask ALWAYS results in being all black (see below image). The number of matching pixels is always 0.

Imgur

And I have confirmed that the incoming image to determine that percentage is in fact HSV (see below image).

Imgur

Any ideas what is going on here? Thanks so much!

also posted on