我正在使用Python3& amp; OpenCV的。
我们可以使用SIFT关键点作为帧上行人轮廓的标识符,然后在两组SIFT关键点之间(即在一帧和下一帧之间)执行强力匹配,以在下一帧中找到行人。 为了在帧序列上可视化,我们可以绘制一个界定行人的边界矩形。这就是它的样子:
主要问题是使用关键点来表征行人的运动。这里的想法是使用2个连续帧上的关键点的坐标来找到仿射变换(即在x& y,旋转和缩放中的平移)。理想情况下,这种仿射变换在某种程度上对应于行人的运动。为了跟踪这个行人,我们只需要在边界矩形坐标上应用相同的仿射变换。 最后一部分效果不佳。如下图或上图所示,矩形在几帧内不断缩小,不可避免地消失或偏离行人:
要指定,我们使用2个极值点来定义边界矩形:
有一些内置的cv2函数可以对图像应用仿射变换,比如cv2.warpAffine(),但是我想将它仅应用于边界矩形坐标(即2点或1点+宽度和放大器) ;身高)。
为了找到两组关键点之间的仿射变换,我编写了自己的函数(如果有帮助,我可以发布代码),但是我在使用cv2.getAffineTransform()时观察到类似的结果。
您知道如何将仿射变换正确应用于此边界矩形吗?
编辑:这里有一些解释&更好的上下文代码:
行人检测是通过openCV中提供的预先训练的SVM分类器完成的:hog.setSVMDetector(cv2.HOGDescriptor_getDefaultPeopleDetector())
& hog.detectMultiScale()
一旦检测到第一个行人,SVM就会返回相关边界矩形(xA, yA, w, h)
的坐标(我们在第一次检测后停止使用SVM,因为它很慢,我们专注于一个现在是行人)
我们使用image[yA: yA+h, xA: xA+w]
选择当前帧的相应区域,并使用surf.detectAndCompute()
这会返回keypoints&它们的相关描述符(每个关键点的64个特征数组)
我们基于描述符之间的L2范数和关键点之间的像素距离来执行强力匹配,以构建当前帧和之间的关键点对。前一个。此函数的代码很长,但应与cv2.BFMatcher(cv2.NORM_L2, crossCheck=True)
一旦我们有了匹配的关键点对,我们就可以用它们来找到这个函数的仿射变换:
previousKpts = previousKpts[:5] # select 4 best matches
currentKpts = currentKpts[:5]
# build A matrix of shape [2 * Nb of keypoints, 4]
A = np.ndarray(((2 * len(previousKpts), 4)))
for idx, keypoint in enumerate(previousKpts):
# Keypoint.pt = (x-coord, y-coord)
A[2 * idx, :] = [keypoint.pt[0], -keypoint.pt[1], 1, 0]
A[2 * idx + 1, :] = [keypoint.pt[1], keypoint.pt[0], 0, 1]
# build b matrix of shape [2 * Nb of keypoints, 1]
b = np.ndarray((2 * len(previousKpts), 1))
for idx, keypoint in enumerate(currentKpts):
b[2 * idx, :] = keypoint.pt[0]
b[2 * idx + 1, :] = keypoint.pt[1]
# convert the numpy.ndarrays to matrix :
A = np.matrix(A)
b = np.matrix(b)
# solution of the form x = [x1, x2, x3, x4]' = ((A' * A)^-1) * A' * b
x = np.linalg.inv(A.T * A) * A.T * b
theta = math.atan2(x[1, 0], x[0, 0]) # outputs rotation angle in [-pi, pi]
alpha = math.sqrt(x[0, 0] ** 2 + x[1, 0] ** 2) # scaling parameter
bx = x[2, 0] # translation along x-axis
by = x[3, 0] # translation along y-axis
return theta, alpha, bx, by
然后我们必须将相同的仿射变换应用于边界矩形的角点:
# define the 4 bounding points using xA, yA
xB = xA + w
yB = yA + h
rect_pts = np.array([[[xA, yA]], [[xB, yA]], [[xA, yB]], [[xB, yB]]], dtype=np.float32)
# warp the affine transform into a full perspective transform
affine_warp = np.array([[alpha*np.cos(theta), -alpha*np.sin(theta), tx],
[alpha*np.sin(theta), alpha*np.cos(theta), ty],
[0, 0, 1]], dtype=np.float32)
# apply affine transform
rect_pts = cv2.perspectiveTransform(rect_pts, affine_warp)
xA = rect_pts[0, 0, 0]
yA = rect_pts[0, 0, 1]
xB = rect_pts[3, 0, 0]
yB = rect_pts[3, 0, 1]
return xA, yA, xB, yB
保存更新的矩形坐标(xA, yA, xB, yB)
,所有当前关键点和&描述符,并迭代下一帧:使用我们之前保存的image[yA: yB, xA: xA]
选择(xA, yA, xB, yB)
,获取SURF关键点等。
答案 0 :(得分:0)
正如Micka所说,cv2.perspectiveTransform()
是实现这一目标的简单方法。您只需要通过在底部添加值为[0, 0, 1]
的第三行,将您的仿射变形转换为全透视变换(单应性)。例如,让我们在点w, h = 100, 200
放置(10, 20)
的框,然后使用仿射变换来移动点,以便将框移动到(0, 0)
(即移位)左边10个像素,向上20个像素):
>>> xA, yA, w, h = (10, 20, 100, 200)
>>> xB, yB = xA + w, yA + h
>>> rect_pts = np.array([[[xA, yA]], [[xB, yA]], [[xA, yB]], [[xB, yB]]], dtype=np.float32)
>>> affine_warp = np.array([[1, 0, -10], [0, 1, -20], [0, 0, 1]], dtype=np.float32)
>>> cv2.perspectiveTransform(rect_pts, affine_warp)
array([[[ 0., 0.]],
[[ 100., 0.]],
[[ 0., 200.]],
[[ 100., 200.]]], dtype=float32)
这样可以完美地按预期工作。您也可以通过矩阵乘法简单地转换点:
>>> rect_pts.dot(affine_warp[:, :2]) + affine_warp[:, 2]
array([[[ 0., 0.]],
[[ 100., 0.]],
[[ 0., 200.]],
[[ 100., 200.]]], dtype=float32)