I can not find the largest color area in a picture

Viewed 57

I am trying to detect the most repeated color range in an image, put a bounding box around it and label it with the color name, but while running, face this error ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all() on the 60th line. what should I do about it?

import cv2
import numpy as np

img = cv2.imread("image path") 
img = cv2.resize(img, (0, 0), fx= 0.5, fy= 0.5)
img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)




red_lower = np.array([136, 87, 111], np.uint8)
red_upper = np.array([180, 255, 255], np.uint8)

blue_lower = np.array([78, 158, 124], np.uint8)
blue_upper = np.array([138, 255, 255], np.uint8)
    
yellow_lower = np.array([22, 60, 200], np.uint8)
yellow_upper = np.array([60, 255, 255], np.uint8)

green_lower = np.array([40, 100, 100], np.uint8)
green_upper = np.array([80, 255, 255], np.uint8)

white_lower = np.array([0, 0, 0], np.uint8)
white_upper = np.array([0, 0, 255], np.uint8)



red_mask = cv2.inRange(img, red_lower, red_upper)
blue_mask = cv2.inRange(img, blue_lower, blue_upper)
yellow_mask = cv2.inRange(img, yellow_lower, yellow_upper)
green_mask = cv2.inRange(img, green_lower, green_upper)
white_mask = cv2.inRange(img, white_lower, white_upper)



kernal = np.ones((5, 5), "uint8")

red = cv2.dilate(red_mask, kernal)
res = cv2.bitwise_and(img, img, mask = red_mask)

blue = cv2.dilate(blue_mask,kernal)
res1 = cv2.bitwise_and(img, img, mask = blue_mask)

yellow = cv2.dilate(yellow_mask,kernal)
res2 = cv2.bitwise_and(img, img, mask = yellow_mask)  

green = cv2.dilate(green_mask,kernal)
res3 = cv2.bitwise_and(img, img, mask = green_mask)    

white = cv2.dilate(white_mask, kernal)
res4 = cv2.bitwise_and(img, img, mask= white_mask)





colors  = [red, blue, yellow, green, white]
l1 = ["RED", "BLUE", "YELLOW", "GREEN", "WHITE"]

max_color = max(colors)  # line 60 # 

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

i = colors.index(max_color)
max_name  = l1[i]



#Tracking the red Color
l2 = []
l3 = []
contours, hierarchy = cv2.findContours(max_color, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)   
for pic, contour in enumerate(contours):
    area = cv2.contourArea(contour)
    l2.append(area)
    l2.append(contour)
    d = {}
    for i in range(len(l2)):
        d[l2[i]] = l3[i]
    max_area = max(l2)
    max_contour = d[max_area]
    x, y, w, h = cv2.boundingRect(max_contour)
    img = cv2.rectangle(img, (x, y) ,(x + w, y + h), (255 , 255, 255) ,2)
    cv2.putText(img, max_name, (x, y), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255))



cv2.imshow("Color Tracking",img)
#cv2.imwrite("result", img)
cv2.waitKey(5000)
cv2.destroyAllWindows()
1 Answers

The variables red, blue etc. contain image masks stored as 2-dim -arrays. So colors is a list of those masks. max will try to find the maximum value of the elements of this list by applying the comparison operator to pairs of the elements. If you compare two -arrays the result will be an array of the same shape that is consisting of True or False values. This can't be used for retrieving a maximum value, because more than one boolean values can't be used to decide which of those image is "greater".

If you want to sort the masks by the count of non-zero values, then you can use cv2.countNonZero() like this:

i, max_color = max(enumerate(colors), key=lambda x:cv2.countNonZero(x[1]))
max_name = l1[i]

Explanation:

  1. enumerate(colors) generates a list of pairs of index positions and masks
  2. max will get the maximum pair while using ...
  3. cv2.countNonZero(x[1]) on the second item of each pair as key value for comparison
Related