-1

image example

I know using images is frowned upon in SO, but my question directly involves analysing the colour of letters, so as an example I will attach a letter and its colour.

Each picture will only have one letter, and most of the image consists of this letter.

I will be analysing multiple letters, but each letter will either be RED, GREEN, BLUE or BLACK.

Any suggestions would help, I am not looking for code, just ideas on any best practices.

I tried using openCV, but it is quite tricky to:

  1. Detect the colour of the letter specifically, since there is a background that has colours in the images.
  2. I am quite new to detecting colours but it seems using a lower and higher HSV seems to be the way forward in terms of detecting which colour the letter is.
fedor
  • 3
  • 3

1 Answers1

0

The answer depends on how precise you need this detection to be. If the required precision is not too high, simply taking the average of the image numpy array for each channel should suffice as mentioned in one of the answers to this question:

import cv2
import numpy
myimg = cv2.imread('image.jpg')
avg_color_per_row = numpy.average(myimg, axis=0)
avg_color = numpy.average(avg_color_per_row, axis=0)
print(avg_color)

Output: [ 197.53434769  217.88439451  209.63799938] # [R,G,B]

Within that same question referenced above is another answer that uses k-means clustering for more precision when measuring the color of the contents.

Now for even more precision, you could 'extract' the letter from the image and apply the above mentioned procedures to only the extracted letter. I've done this before starting with code like the one below:

img = cv2.imread('image.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 50, 255, 0)
contours, hierarchy = cv2.findContours(thresh, 1, 2)

# Find largest rectangle to crop img to
largest_contour = max(contours, key=cv2.contourArea)

# Approximate the contour to a polygon with 4 corners
epsilon = 0.1 * cv2.arcLength(largest_contour, True)
approx = cv2.approxPolyDP(largest_contour, epsilon, True)

# Get the corners on the original image
corner_coords = []
for corner in approx:
    x, y = corner.ravel()
    corner_coords.append([[x, y]])

# If there are only 4 corners proceed
if len(corner_coords) == 4: #Assuming the letter has 4 corners
...

Once you get the average of the RGB channels, a simple comparison between the averages should tell you the color of the letter, and a setting a threshold to where 'if R + G + B < threshold ' Then the letter is black.

There are other ways to solve a problem like this but this should be the fastest ones to implement (especially the first one).

AR Osornio
  • 28
  • 4
  • Thanks for the solution @AR, but after I get the output like [150, 151, 150], how do I know what colour that is? – fedor May 06 '23 at 08:13
  • No problem, once you get the RGB values as you mentioned, simple range checking should be enough. Since there is almost an infinite amount of colors possible from RGB values ranging from 1 to 255, you'll most likely have to hardcode some ranges. Example: [0,0,0] = black, [255.255.255] = white, R = G = B: Gray – AR Osornio May 16 '23 at 17:34