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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With