I've been trying to get single color blob tracking thru OpenCV on Python. The below code is working, but it finds the centroid of all the tracked pixels, not just the centroid of the biggest blob. This is because I'm taking the moments of all the pixels, but I'm not sure how else to color track. I'm kind of stuck on what exactly I need to do to make this a single blob tracker instead of a multi-blob average-er.
Here's the code:
#! /usr/bin/env python #if using newer versions of opencv, just "import cv" import cv2.cv as cv color_tracker_window = "Color Tracker" class ColorTracker: def __init__(self): cv.NamedWindow( color_tracker_window, 1 ) self.capture = cv.CaptureFromCAM(0) def run(self): while True: img = cv.QueryFrame( self.capture ) #blur the source image to reduce color noise cv.Smooth(img, img, cv.CV_BLUR, 3); #convert the image to hsv(Hue, Saturation, Value) so its #easier to determine the color to track(hue) hsv_img = cv.CreateImage(cv.GetSize(img), 8, 3) cv.CvtColor(img, hsv_img, cv.CV_BGR2HSV) #limit all pixels that don't match our criteria, in this case we are #looking for purple but if you want you can adjust the first value in #both turples which is the hue range(120,140). OpenCV uses 0-180 as #a hue range for the HSV color model thresholded_img = cv.CreateImage(cv.GetSize(hsv_img), 8, 1) cv.InRangeS(hsv_img, (120, 80, 80), (140, 255, 255), thresholded_img) #determine the objects moments and check that the area is large #enough to be our object moments = cv.Moments(thresholded_img, 0) area = cv.GetCentralMoment(moments, 0, 0) #there can be noise in the video so ignore objects with small areas if(area > 100000): #determine the x and y coordinates of the center of the object #we are tracking by dividing the 1, 0 and 0, 1 moments by the area x = cv.GetSpatialMoment(moments, 1, 0)/area y = cv.GetSpatialMoment(moments, 0, 1)/area #print 'x: ' + str(x) + ' y: ' + str(y) + ' area: ' + str(area) #create an overlay to mark the center of the tracked object overlay = cv.CreateImage(cv.GetSize(img), 8, 3) cv.Circle(overlay, (x, y), 2, (255, 255, 255), 20) cv.Add(img, overlay, img) #add the thresholded image back to the img so we can see what was #left after it was applied cv.Merge(thresholded_img, None, None, None, img) #display the image cv.ShowImage(color_tracker_window, img) if cv.WaitKey(10) == 27: break if __name__=="__main__": color_tracker = ColorTracker() color_tracker.run()
You need to do it like this :
1) Get the thresholded image using inRange function, and you can apply some erosion and dilation to remove small noisy particles. It will help to improve the processing speed.
2) find Contours using 'findContours' function
3) find areas of contours using 'contourArea' function and select one with maximum area.
4) Now find its center as you did, and track it.
Below is a sample code for this in new cv2 module :
import cv2 import numpy as np # create video capture cap = cv2.VideoCapture(0) while(1): # read the frames _,frame = cap.read() # smooth it frame = cv2.blur(frame,(3,3)) # convert to hsv and find range of colors hsv = cv2.cvtColor(frame,cv2.COLOR_BGR2HSV) thresh = cv2.inRange(hsv,np.array((0, 80, 80)), np.array((20, 255, 255))) thresh2 = thresh.copy() # find contours in the threshold image contours,hierarchy = cv2.findContours(thresh,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE) # finding contour with maximum area and store it as best_cnt max_area = 0 for cnt in contours: area = cv2.contourArea(cnt) if area > max_area: max_area = area best_cnt = cnt # finding centroids of best_cnt and draw a circle there M = cv2.moments(best_cnt) cx,cy = int(M['m10']/M['m00']), int(M['m01']/M['m00']) cv2.circle(frame,(cx,cy),5,255,-1) # Show it, if key pressed is 'Esc', exit the loop cv2.imshow('frame',frame) cv2.imshow('thresh',thresh2) if cv2.waitKey(33)== 27: break # Clean up everything before leaving cv2.destroyAllWindows() cap.release()
You can find some samples on tracking colored objects here : https://github.com/abidrahmank/OpenCV-Python/tree/master/Other_Examples
Also, try to use new cv2 interface. It is a lot simpler and faster than old cv. For more details, checkout this : What is different between all these OpenCV Python interfaces?
After thresholding use the blob detection or cvfindcontours to get individual blobs.