3

I would like to click on an object and get the pixel coordinates which are the color that I picked before. I found this code on the internet

import cv
tolerancia = 30
def evento_mouse(event,x,y,flags,param):
    if event==cv.CV_EVENT_LBUTTONDOWN:
        pixel=cv.Get2D(imagen,y,x) 
        print 'X =',x,'  Y =',y
        print 'R =',pixel[2],'G =',pixel[1],'B =',pixel[0]
        cv.InRangeS(imagen,(pixel[0]-tolerancia,pixel[1]-tolerancia,pixel[2]-                                               tolerancia),(pixel[0]+tolerancia,pixel[1]+tolerancia,pixel[2]+tolerancia),temporal)
        cv.ShowImage('Color',temporal)
        c = cv.Get2D(temporal,y,x) 
        print c[0],c[1],c[2] # I always get: 255, 0, 0
   imagen=cv.LoadImage('prueba2.png')
   cv.ShowImage('Prueba',imagen)
   temporal=cv.CreateImage(cv.GetSize(imagen),cv.IPL_DEPTH_8U,1)
   cv.SetMouseCallback('Prueba',evento_mouse)
   cv.WaitKey(0)

I am trying to see if the pixel is white or black. but I always get the same value: 255, 0, 0 (blue = 255)

Andrea Diaz
  • 1,168
  • 4
  • 13
  • 29

2 Answers2

3

There are a couple of things you need to understand.

You are using old 'cv' interface of OpenCV. In that case, to get a pixel value, you use the function 'cv2.Get2D' which returns you a tuple of corresponding BGR values.

1. Why blue color, ie (255,0,0) for binary images ?

For both color images and grayscale/binary images, same tuple of 3 elements is returned, but for grayscale images, first element is the pixel value, remaining two are irrelevant, so they are zeros. So you get values like (255,0,0) etc since you are reading pixel values of binary image(temporal).

2. Why always (255,0,0) ?

When you click on the original image, a corresponding binary image is created, where the region corresponding to color you clicked become white and all other region become black. If you clicked on a RED color in original image, your binary image will be such that, all red region will be white and remaining black. So obviously, the pixel you clicked is always WHITE. So if you read that pixel from binary image, you get only (255,0,0) always.

I would like to recommend you to migrate to OpenCV new Python interface, 'cv2' module. It has a lot of advantages. Main advantage is the Numpy support which is a big deal. You can check this SOF for some comparison : What is different between all these OpenCV Python interfaces?

You can also get some startup tutorials on cv2 from here : www.opencvpython.blogspot.com

Community
  • 1
  • 1
Abid Rahman K
  • 51,886
  • 31
  • 146
  • 157
  • What is cv2's version of Get2D called? – beardc Nov 29 '12 at 16:32
  • Not such thing in cv2. You can simply access pixel by indexing. For example, img[100,100] like that. – Abid Rahman K Nov 29 '12 at 17:29
  • OK, I may be misunderstanding the question, but I thought Get2D was able to get the coordinates where the mouse click is. There's no way to get the mouse click coordinates in cv2? – beardc Nov 29 '12 at 18:07
  • There are some flags for that, like cv2.EVENT_LBUTTONUP etc. Please check mouse_and_match.py in opencv/samples/python2 folder in the official OpenCV download. You can see how to use it in cv2. – Abid Rahman K Nov 29 '12 at 18:55
0

Firstly, I think you need to check that your lower and upper bound is within the range of 0 to 255.

Secondly, your "temporal" variable is a "mask". It is set to 255 at location (x, y) if the pixel value at that location is within your lower and upper bound. It does not contain all the pixels that lies in the given range.

Below is some code I tried on a test image. Note that I made use of some numpy but converted to CvMat using cv2.cv.fromarray() to match your code.

#!/usr/bin/env python

import cv2
import numpy as np

def main():
    image = cv2.imread("forest.jpg")
    imageMat = cv2.cv.fromarray(image)
    dst = cv2.cv.fromarray(np.zeros((imageMat.rows, imageMat.cols), np.uint8))

    x = 250 # Manually set pixel location. You can get this from your mouse event handler.
    y = 500
    pixel = image[y, x] # Note y index "row" of matrix and x index "col".
    tolerance = 10
    # Ensure your bounds are within 0 and 255.
    lower = tuple(map(lambda x: int(max(0, x - tolerance)), pixel))
    upper = tuple(map(lambda x: int(min(255, x + tolerance)), pixel))
    # Get mask of all pixels that satisfy range condition and store it in dst.
    cv2.cv.InRangeS(imageMat, lower, upper, dst)

    mask = np.asarray(dst) # Convert back to numpy array.
    cv2.imshow("Mask", mask) # The mask indicating which pixels satisfy range conditions
    cv2.imshow("Image", image)
    extracted = np.zeros_like(image) # The pixels that satisfy range condition.
    extracted[np.where(mask)] = image[np.where(mask)]
    cv2.imshow("extracted", extracted)

    cv2.waitKey()

if __name__ == "__main__":
    main()

And this is the python2 version:

#!/usr/bin/env python

import cv2
import numpy as np

def main():
    image = cv2.imread("forest.jpg")
    x = 230 # Manually set pixel location. You can get this from your mouse event handler.
    y = 300
    pixel = image[y, x] # Note y index "row" of matrix and x index "col".
    tolerance = 30
    # Ensure your bounds are within 0 and 255.
    lower = map(lambda x: max(0, x - tolerance), pixel)
    upper = map(lambda x: min(255, x + tolerance), pixel)
    lower = np.asarray(lower)
    upper = np.asarray(upper)
    mask = cv2.inRange(image, lower, upper) # Notice we can just get mask without having to allocate it beforehand.

    cv2.imshow("Mask", mask) # The mask indicating which pixels satisfy range conditions
    cv2.imshow("Image", image)
    extracted = np.zeros_like(image) # The pixels that satisfy range condition.
    extracted[np.where(mask)] = image[np.where(mask)]
    cv2.imshow("extracted", extracted)

    cv2.waitKey()

if __name__ == "__main__":
    main()
lightalchemist
  • 10,031
  • 4
  • 47
  • 55