Ross Wardrup
Ross Wardrup

Reputation: 321

Obtaining pixel values within CV2 contours

I'm trying to get pixel values within contours. I've followed along with answers to similar questions but my results are off.

This block of code finds contours for an image and then iterates through them to find the contour containing the largest area. I added the ending if statement that tries to get the RGB value of the code if it is during daylight hours. The original image (video frame) is passed to a function I wrote (grab_rgb), along with the contour.

    thresh = cv2.dilate(thresh, None, iterations=2)
    (_, cnts, _) = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

    # look for motion
    motion_found = False
    biggest_area = 0

    # examine the contours, looking for the largest one
    for c in cnts:
        (x, y, w, h) = cv2.boundingRect(c)
        # get an approximate area of the contour
        found_area = w * h
        # find the largest bounding rectangle
        if (found_area > MIN_AREA) and (found_area > biggest_area):
            biggest_area = found_area
            motion_found = True

            if not is_nighttime():
                rgb = grab_rgb(image, c)
            else:
               rgb = 'nighttime'

This is the function I wrote:

def grab_rgb(image, c):
    pixels = []

    # TODO: Convert to real code
    # Detect pixel values (RGB)
    mask = np.zeros_like(image)
    cv2.drawContours(mask, c, -1, color=255, thickness=-1)

    points = np.where(mask == 255)

    for point in points:
        pixel = (image[point[1], point[0]])
        pixel = pixel.tolist()
        pixels.append(pixel)

    pixels = [tuple(l) for l in pixels]
    car_color = (pixels[1])

    r = car_color[0]
    g = car_color[1]
    b = car_color[2]

    pixel_string = '{0},{1},{2}'.format(r, g, b)

    return pixel_string

The code runs, but returns only three RGB values, with only the second value containing anything meaningful (values 0 and 2 are [0,0,0],[0,0,0]. There should definitely be more than three pixels within the contours, so I'm not sure where I went wrong.

EDIT: I realized it might be helpful to include what is actually being stored in the variables.

mask:

[[[  0   0   0]
  [  0   0   0]
  [  0   0   0]
  ...,
  [  0   0   0]
  [  0   0   0]
  [  0   0   0]]

 [[  0   0   0]
  [255   0   0]
  [  0   0   0]
  ...,
  [  0   0   0]
  [  0   0   0]
  [  0   0   0]]

 [[  0   0   0]
  [  0   0   0]
  [  0   0   0]
  ...,
  [  0   0   0]
  [  0   0   0]
  [  0   0   0]]

 ...,
 [[  0   0   0]
  [  0   0   0]
  [  0   0   0]
  ...,
  [  0   0   0]
  [  0   0   0]
  [  0   0   0]]

 [[  0   0   0]
  [  0   0   0]
  [  0   0   0]
  ...,
  [  0   0   0]
  [  0   0   0]
  [  0   0   0]]

 [[  0   0   0]
  [  0   0   0]
  [  0   0   0]
  ...,
  [  0   0   0]
  [  0   0   0]
  [  0   0   0]]]

points:

(array([ 1,  1,  3,  5, 10, 11, 11, 12, 12, 13, 13, 14, 14], dtype=int32), array([ 1, 22, 22, 24, 24, 21, 23, 16, 20,  9, 15,  1,  8], dtype=int32), array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], dtype=int32))

pixel:

[0, 0, 0] [136, 89, 96] [0, 0, 0]

pixels:

[(0, 0, 0), (136, 89, 96), (0, 0, 0)]

car_color:

(136, 89, 96)

Upvotes: 1

Views: 3302

Answers (1)

gunshi
gunshi

Reputation: 66

It seems like what you've asked the code to return is the RGB value of just the second point in the pixel values list (called 'pixels' here ) of the points in every contour passed to grab_rgb, with

car_color = (pixels[1])

r = car_color[0]

g = car_color[1]

b = car_color[2]

So the output should mean that your image has atleast three detected contours satisfying your area constraints, and that the RGB values of the second point in the contours' point lists are what you mentioned([0,0,0],[x,y,z] and [0,0,0]).

Upvotes: 2

Related Questions