天天看点

光流传感器 定位精度_光流定位原理是什么??

在无人机上光流定位通常是借助于无人机底部的一个摄像头采集图像数据,然后采用光流算法计算两帧图像的位移,进而实现对无人机的定位,这种定位手段配合GPS可以在室外实现对无人机的精准控制,并且在市内没有GPS信号的时候,也可以实现对无人机的高精度的定位,实现更加平稳的控制。

在光流理论中,前提是下面两个假设成立:

1)摄像头采集到的两帧图像之间的像素灰度不变;

2)相邻的两帧像素具有相对运动;

根据第一个假设,如果两帧的灰度值不变,那么有以下关系成立:

光流传感器 定位精度_光流定位原理是什么??

其中 I(x,y,t)表示在时间dt后移动到第二帧图像(x+dx,y+dy)的位置,采用泰勒级数对两边进行展开,消去相同的项,就可以得到如下方程:

其中:

光流传感器 定位精度_光流定位原理是什么??

以上就是光流方程,其中fx和fy表示图像的梯度,ft表示时间梯度,但是上述方法是无法得到(u,v),因为一个等式无法求解两个未知数,为了解决这个问题,我们可以采用经典的lucas-Kanade方法来进行求解。

在lucas-Kanade方法中,我们需要用到我们第二个假设了,即在目标点的邻域内所有的点都具有相似的运动,这就是lucas-kanade方法的核心,基于该假设,其利用一个3X3邻域中的9个点具有相同运动得到9个光流方程,然后采用最小二乘进行拟合求解,最终得到(u,v)如下:

光流传感器 定位精度_光流定位原理是什么??

以上就是光流法计算像素点的移动速度的方法,在使用的时候,我们只需要对图像中的一些点去跟踪,采用上面的方法就可以计算得到光流向量,根据得到的光流向量,就可以进一步优化无人机的姿态控制,实现更加准确的控制。后期我们将在该理论的基础上,结合dragonboard 410c和OpenCV图像处理库,进一步介绍如何在dragonboard 410c上用opencv来实现光流跟踪。

在dragonboard 410c上来用Python编程实现光流算法,虽然python语言编写出来的处理效率不高,但是便于我们理解整个光流算法应用方法,并且后续我们使用C或者其他高效率的语言来实现光流算法会变得更简单。

在实现光流分析的过程中,我们使用cv2模块提供的算法接口来实现光流计算,在cv2中也就是OpenCV提供的Python接口,lucas-kanade算法被封装在cv2.calcOpticalFlowPyrLK()函数中,通过该接口可以方便的创建光流处理程序。但是在实现中我们首先要确定我们要跟踪的点,然后才能使用lucas-kanade算法来对这些点进行迭代跟踪,接下来参考cv2中提供的Python例程代码详细介绍利用cv2提供的光流计算处理函数接口如何完成基于光流的跟踪实现,其核心代码如下:

首先为了方便调用cv2.calcOpticalFlowPyrLK算法,我们需要定义一个算法参数结构体,确定算法参数,用Python定义如下:

lk_params = dict( winSize = (15, 15),

maxLevel = 2,

criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03),

derivLambda = 0.0 )

同时在调用cv2.calcOpticalFlowPyrLK算法的时候我们还需要调用cv2.goodFeatureToTrack函数来确定需要跟踪的点,所以还需要给该接口传递一个参数,具体定义如下:

feature_params = dict( maxCorners = 500,

qualityLevel = 0.3,

minDistance = 7,

blockSize = 7 )

完成参数定义后,就可以开始编写核心代码了,这里我们在读取视频帧的时候,根据前文的分析可以知道,光流算法需要依靠前后帧的数据来进行分析,所以在读取视频第一帧的时候,我们还需要在第0帧的时候进行初始化处理,这里使用便利frame_idx和detect_interval两个参数来进行控制,对第一帧进行处理,其中前者为帧数,后者为检测间隔,在这里初始化处理主要是需要找到适合跟踪的点,具体代码如下:

if self.frame_idx % self.detect_interval == 0:

mask = np.zeros_like(frame_gray)

mask[:] = 255

for x, y in [np.int32(tr[-1]) for tr in self.tracks]:

cv2.circle(mask, (x, y), 5, 0, -1)

p = cv2.goodFeaturesToTrack(frame_gray, mask = mask, **feature_params)

if p is not None:

for x, y in np.float32(p).reshape(-1, 2):

self.tracks.append([(x, y)])

完成第一帧处理后,就需要进一步对后续帧进行处理,这里处理其实就是一个循环迭代的过程,不断的根据前后帧来执行光流算法,调用cv2calcOpticalFlowPyrLK函数来计算光流数据,这里通过tracks参数来进行控制,核心代码如下:

if len(self.tracks) > 0:

img0, img1 = self.prev_gray, frame_gray

p0 = np.float32([tr[-1] for tr in self.tracks]).reshape(-1, 1, 2)

p1, st, err = cv2.calcOpticalFlowPyrLK(img0, img1, p0, None, **lk_params)

p0r, st, err = cv2.calcOpticalFlowPyrLK(img1, img0, p1, None, **lk_params)

d = abs(p0-p0r).reshape(-1, 2).max(-1)

good = d < 1

new_tracks = [] for tr, (x, y),

good_flag in zip(self.tracks, p1.reshape(-1, 2), good):

if not good_flag:

continue

tr.append((x, y))

if len(tr) > self.track_len:

del tr[0]

new_tracks.append(tr)

cv2.circle(vis, (x, y), 2, (0, 255, 0), -1)

self.tracks = new_tracks

cv2.polylines(vis, [np.int32(tr) for tr in self.tracks], False, (0, 255, 0))

draw_str(vis, (20, 20), 'track count: %d' % len(self.tracks))

以上就是整个光流算法进行点跟踪的处理核心过程。