1

I'm new to opencv, I've managed to detect the object and place a ROI around it but I can't managed it so detect if the object is black or white. I've found something i think but i don't know if this is the right solution. The function should return True of False if it's black or white. Anyone experience with this?

def filter_color(img):
        hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
        lower_black = np.array([0,0,0])
        upper_black = np.array([350,55,100])
        black = cv2.inRange(hsv, lower_black, upper_black)
John
  • 728
  • 2
  • 15
  • 37
  • Did the answer I posted work for you? If not, let me know or you can post your own solution as an answer for future users. – KobeJohn Mar 30 '14 at 09:42

2 Answers2

1

If you are certain that the ROI is going to be basically black or white and not worried about misidentifying something, then you should be able to just average the pixels in the ROI and check if it is above or below some threshold.

In the code below, after you set an ROI using the newer numpy method, you can pass the roi/image into the method as if you were passing a full image.

Copy-Paste Sample

import cv2
import numpy as np


def is_b_or_w(image, black_max_bgr=(40, 40, 40)):
    # use this if you want to check channels are all basically equal
    # I split this up into small steps to find out where your error is coming from
    mean_bgr_float = np.mean(image, axis=(0,1))
    mean_bgr_rounded = np.round(mean_bgr_float)
    mean_bgr = mean_bgr_rounded.astype(np.uint8)
    # use this if you just want a simple threshold for simple grayscale
    # or if you want to use an HSV (V) measurement as in your example
    mean_intensity = int(round(np.mean(image)))
    return 'black' if np.all(mean_bgr < black_max_bgr) else 'white'

# make a test image for ROIs
shape = (10, 10, 3)  # 10x10 BGR image
im_blackleft_white_right = np.ndarray(shape, dtype=np.uint8)
im_blackleft_white_right[:, 0:4] = 10
im_blackleft_white_right[:, 5:9] = 255

roi_darkgray = im_blackleft_white_right[:,0:4]
roi_white = im_blackleft_white_right[:,5:9]


# test them with ROI
print 'dark gray image identified as: {}'.format(is_b_or_w(roi_darkgray))
print 'white image identified as: {}'.format(is_b_or_w(roi_white))

# output
# dark gray image identified as: black
# white image identified as: white
Community
  • 1
  • 1
KobeJohn
  • 7,390
  • 6
  • 41
  • 62
  • Hi sorry for the delay! Uhm if i run your example it works but with my image it won't work. It returns the next error:"TypeError: an integer is required" at mean_bgr = np.round .... But I've found another solution that worked for me. – John Mar 31 '14 at 07:41
  • @laurens That is strange. Could you investigate more so we can get a solid answer for future users? I updated my answer by separating the line that has the error. Please tell me which line now has the error. Also, more importantly, can you show me how you get an image and how you get an ROI? I also updated my answer with the technique to get an ROI. – KobeJohn Mar 31 '14 at 21:40
  • hi, sorry for the very late response, was busy and out of town. Uhm Yeah i copied your example from above and it returns an error at line 8 at mean_bgr_float = np.mean(image, exis=(0,1)). It says that it is an TypeError: an integer is required. – John Apr 07 '14 at 08:12
  • @laurens How about my second question? There is something strange going on and the second part is probably the key. – KobeJohn Apr 07 '14 at 23:31
-1

I don't know if this is the right approach but it worked for me.

black = [0,0,0]
Thres = 50
h,w = img.shape[:2]
black = 0
not_black = 0
for y in range(h):
    for x in range(w):
        pixel = img[y][x]
        d = math.sqrt((pixel[0]-0)**2+(pixel[1]-0)**2+(pixel[2]-0)**2)
        if d<Thres:
            black = black + 1
        else:
            not_black = not_black +1

This one worked for me but like i said, don't know if this is the right approach. It's ask a lot of processing power therefore i defined a ROI which is much smaller. The Thres is currently hard-coded...

John
  • 728
  • 2
  • 15
  • 37