点击下方卡片,关注“小白玩转Python”公众号
有多种跟踪和检测对象的方法,而OpenCV提供了各种算法和函数来实现这一目的。在本文中,我将使用均值漂移和Cam漂移算法创建一个对象跟踪器。这两种算法利用对象的颜色直方图,并试图在每一帧中找到最佳匹配的直方图。
Cam漂移
均值漂移和Cam漂移
均值漂移和Cam漂移相似,但产生不同的结果。均值漂移产生更简单的结果,它不能处理旋转,并且不能正确检测对象大小变化。另一方面,Cam漂移更强大、更灵活。它可以处理旋转、不同大小等更多情况。在接下来的两个部分中,我将以简单的方式解释这两种算法。您可以阅读维基百科和OpenCV文档以获取更深入的信息。
1. 均值漂移
均值漂移是一种非参数化算法,用于聚类和模式寻找(在数据集中查找最频繁出现的值)。在对象跟踪中,均值漂移通过反复调整窗口来跟踪对象的颜色分布。它简单且计算效率高,但不能处理旋转和大小变化。当计算资源有限时,可以考虑使用均值漂移算法而不是Cam漂移算法。
均值漂移
2. Cam漂移
Cam漂移是均值漂移的高级版本,实际上,它首先应用均值漂移。它调整跟踪窗口的大小和方向以跟踪旋转或大小变化的对象。它可以在更复杂的情况下检测对象。与均值漂移相比,它需要更多的计算资源。
使用Cam漂移和均值漂移的对象跟踪器
现在是时候使用这两种算法创建一个对象检测器了。其主要思想非常简单:首先,用户用鼠标右键绘制一个矩形到感兴趣的区域(对象)的第一帧,然后按下“ESC”键。之后,一个新的窗口出现,对象在该窗口内被跟踪。下面我逐步解释了代码,如果您需要完整的代码,请直接转到文章末尾。
Cam漂移 / 代码
步骤1:用户通过在视频的第一帧上绘制一个矩形来定义对象,用户按下鼠标右键选择第一个点对和相同的按钮选择第二个点对。
# path to video
video_path=r"your_path/video.mp4"
# read only the first frame to draw a rectangle for object
ret,frame = video.read()
# I am giving big random numbers for x_min and y_min because if you initialize them as zeros whatever coordinate you go minimum will be zero
x_min,y_min,x_max,y_max=36000,36000,0,0
# function for choosing min and max coordinates
def coordinat_chooser(event,x,y,flags,param):
global go , x_min , y_min, x_max , y_max
# when you click the right button it is gonna give variables some coordinates
if event==cv2.EVENT_RBUTTONDOWN:
# if current coordinate of x lower than the x_min it will be new x_min , same rules apply for y_min
x_min=min(x,x_min)
y_min=min(y,y_min)
# if current coordinate of x higher than the x_max it will be new x_max , same rules apply for y_max
x_max=max(x,x_max)
y_max=max(y,y_max)
# draw rectangle
cv2.rectangle(frame,(x_min,y_min),(x_max,y_max),(0,255,0),1)
"""
if you didn't like your rectangle (maybe if you made some misscliks), reset the coordinates with the middle button of your mouse
if you press the middle button of your mouse coordinates will reset and you can give new 2-point pair for your rectangle
"""
if event==cv2.EVENT_MBUTTONDOWN:
print("reset coordinate data")
x_min,y_min,x_max,y_max=36000,36000,0,0
cv2.namedWindow('coordinate_screen')
# Set mouse handler for the specified window, in this case, "coordinate_screen" window
cv2.setMouseCallback('coordinate_screen',coordinat_chooser)
while True:
cv2.imshow("coordinate_screen",frame) # show only first frame
k = cv2.waitKey(5) & 0xFF # after drawing rectangle press ESC
if k == 27:
break
步骤2:程序检测用户选择的对象的颜色。
# inside of rectangle that user draw
object_image=frame[y_min:y_max,x_min:x_max,:]
hsv_object=cv2.cvtColor(object_image,cv2.COLOR_BGR2HSV)
# cx and cy are the centers of the rectangle that the user chose
height, width, _ = hsv_object.shape
cx = int(width / 2)
cy = int(height / 2)
# take the center pixel to find out which rectangle color.
pixel_center = hsv_object[cy, cx]
hue_value = pixel_center[0] # axis 0 is hue values
# from hue_value find color
color =str()
if hue_value < 5:
color = "red"
elif hue_value < 22:
color = "orange"
elif hue_value < 33:
color = "yellow"
elif hue_value < 78:
color = "green"
elif hue_value < 131:
color = "blue"
elif hue_value < 170:
color = "violet"
else:
color = "red"
# hue dict
hue_dict={ "red":[[[0, 100, 100]],[10, 255, 255]],
"orange":[[10, 100, 100],[20, 255, 255]],
"yellow":[[20, 100, 100],[30, 255, 255]],
"green":[[50, 100, 100],[70, 255, 255]],
"blue":[[110,50,50],[130,255,255]],
"violet":[[140, 50, 50],[170, 255, 255]]}
# find the upper and lower bounds of image's color
lower_bound , upper_bound = np.asarray(hue_dict[color][0]) , np.asarray(hue_dict[color][1]) # lower and upper bound sequentially
print(f"detected color : {color}" )
步骤3:跟踪对象。
# This time display all video, not just the first frame (in the first part only the first frame displayed in screen because user was choosing object by drawing rectangle)
video=cv2.VideoCapture(video_path)
# we need first frame for creating roi(region of interest)
ret,cap = video.read()
# coordinates that the user gives with his mouse
x=x_min
y=y_min
w=x_max-x_min
h=y_max-y_min
track_window = (x, y, w, h)
# set up the ROI for tracking
roi = cap[y:y+h, x:x+w]
hsv_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
# use lower_bound and upper_bound inside of inRange function
mask = cv2.inRange(hsv_roi, lower_bound,upper_bound )
roi_hist = cv2.calcHist([hsv_roi],[0],mask,[180],[0,180])
cv2.normalize(roi_hist,roi_hist,0,255,cv2.NORM_MINMAX)
# Setup the termination criteria, either 10 iterations or move by at least 1 pt
term_crit = ( cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1 )
while True:
ret, frame = video.read()
cv2.putText(frame,f"detected color : {color}" , (25,25),cv2.FONT_HERSHEY_SIMPLEX ,1,(0,0,255),1)
if ret == True:
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
dst = cv2.calcBackProject([hsv],[0],roi_hist,[0,180],1)
# apply mean-shift to get the new location
ret, track_window = cv2.meanShift(dst, track_window, term_crit)
# Draw it on the image
x,y,w,h = track_window
img2 = cv2.rectangle(frame, (x,y), (x+w,y+h), 255,2)
cv2.imshow('img2',img2)
k = cv2.waitKey(5) & 0xFF
if k == 27:
cv2.destroyAllWindows()
break
完整代码:https://github.com/siromermer/Object-Tracker-Meanshift-Camshift-Algorithm
· END ·
HAPPY LIFE
本文仅供学习交流使用,如有侵权请联系作者删除