基于Mean-shift算法跟踪对象
重磅干货,第一时间送达
跟踪对象是计算机视觉领域的重要应用。这在监控系统、国防、自动驾驶汽车等方面都有用例。在本文中,我们将讨论一种称为均值漂移算法的基本跟踪算法,并将通过在视频中跟踪汽车来了解其应用。
在进入均值漂移跟踪之前,让我们了解直方图及其应用,以创建均值漂移跟踪的预处理输入。图像由不同值的像素组成。像素的分布是每幅图像的一个重要特征。直方图对于通过计算每个像素的值数量来表征图像内容非常有用。要为图像生成直方图,我们可以使用 opencv 库。以下代码片段将为给定图像创建直方图。
img = cv2.imread('image.jpg’)
color = {'b','g','r'}
for i,col in enumerate(color):
hist = cv2.calcHist([img],[i],None,[256],[0,256])
上面的代码将为每个通道创建一个直方图。
如果我们想检测一个特定的物体或区域,那个位置的像素值将是一个重要的特征。因为它与不同的对象不同。例如,狗和汽车的像素值会不同。
某个区域的直方图可以看作是一个函数,它给出了一个特定像素属于某个对象的概率。通过对获得的图像直方图进行归一化,我们可以得到给定强度值属于我们感兴趣区域的概率。获得直方图后,我们可以将其反投影到我们想要测试对象是否存在的任何图像上。
在反向投影的情况下,我们用我们为感兴趣的对象计算的归一化直方图的相应概率值替换输入图像的每个像素值。与感兴趣区域相似的位置的强度值比不相似的区域具有更高的概率值。简而言之,我们可以说反投影表示我们的测试图像包含参考图像对象的概率。
Mean-shift 是我们将用来跟踪视频中对象的算法。考虑一个区域中的一组点,如下所示。
初始窗口显示为名称为 C1 的蓝色圆圈。现在,当我们计算窗口的质心与中心 C1 不匹配时。所以我们移动窗口,使 c1_r 成为窗口的新中心。现在我们的窗口已经移动了,让我们再次计算质心并继续相同的过程。这样我们的窗口就会移动到点数较多的部分。这将一直持续到质心停止移动或任何特定的停止标准。
因此,我们需要一个指示函数,它可以为我们正在跟踪的对象的像素值输出更高的概率值,并为所有其他像素输出更低的值。Meanshift 将在每次迭代中进行加权质心计算,因此它会偏向具有更高权重(概率)的像素,这正是我们想要的,因为与 roi 相似的像素将具有更高的概率值。
我们的目标是跟踪视频中出现的黄色汽车。为此,让我们首先加载视频。
这里我们将使用 opencv 库。我们将创建一个视频捕捉对象。视频应作为参数传递。以下代码片段为我们完成了工作。
import cv2
cap = cv2.VideoCapture('6.mp4’)
如前所述,我们必须从应用均值平移算法的地方随机初始化 roi。我手动计算了初始位置,因为 meanshift 本身无法做到。
frame_h,frame_w = frame.shape[:2]
size = (frame_h,frame_w)
w =frame_w//8
h =frame_h//8
x =600
y =320
track_window = (x,y,w,h)
从视频中可以看出,汽车的颜色是黄色,很容易与其他物体的颜色区分开来。因此,我们想将 RGB 色彩空间转换为 HSV。HSV 模型的色调成分帮助我们更好地理解物体的颜色。考虑下面的代码片段。
roi =frame[y:y+h, x-w:x]
hsv_roi = cv2.cvtColor(roi,cv2.COLOR_BGR2HSV)
mask = None
roi_hist = cv2.calcHist([hsv_roi], [0], mask, [180], [0,180])
cv2.normalize(roi_hist,roi_hist,0,255,cv2.NORM_MINMAX)
在第一行中,我们定义了感兴趣的区域。然后我们将帧从bgr 颜色空间转换为 hsv 颜色空间。Mask 被声明为 none,因为我们要计算整个帧的直方图。在第 4 行中,我们计算了感兴趣区域的直方图。为此,我们仅考虑了第 4 行的第二个参数中隐含的色调通道。Opencv 通常有 180 个色调值(尽管也可以有 360 个),我们在这里考虑了 180 个 bin(每个值 1 个 bin)。最后一个参数是我们考虑了所有 180 个色调值的范围。在下一步中,我们将 roi 归一化在 0-255 范围内。
term_crit =(cv2.TERM_CRITERIA_COUNT | cv2.TERM_CRITERIA_EPS,10,1)
表示均值漂移算法的终止标准也很重要。我们将在 10 次迭代后或当偏移不超过 1 个像素时停止计算质心。
true,frame = cap.read()
while true:
hsv =cv2.cvtColor(frame,cv2.COLOR_BGR2HSV)
back_project = cv2.calcBackProject([hsv], [0],roi_hist, [0,180],1)
num_iters,window = cv2.meanShift(back_proj,track_window,term_crit)
x,y,w,h =window
cv2.rectangle(frame,(x,y),(x+w,y+h),(255,0,0),2)
cv2.imshow('back-projection’,back_project)
cv2.imshow('meanshift',frame)
cap.read() 返回一个布尔值。如果帧被正确读取,它将是真的。获得帧后,我们会将其转换为 hsv 颜色空间。将帧转换为 hsv 颜色空间后,我们将使用预先计算的直方图进行反向投影,以了解帧的哪一部分具有我们感兴趣的对象。然后我们应用了meanshift算法来跟踪对象。然后我们的工作是将结果可视化,这是由 imshow 函数完成的。
尽管该算法在这种情况下表现出色,但仍然几乎没有缺点。例如,我们必须手动给出我们感兴趣的对象的位置,这对于任何现实生活中的实现都是不可取的。此外,窗口大小不会随着被跟踪帧中对象的大小而改变。