中国民用航空局(CAAC)
无人机驾驶员及教员培训

飞行讲堂

当前位置: 首页 > 飞行讲堂

recommended
热门推荐

应用大讲堂|无人机光流定位系列

发布时间:2017-07-28 14:36 浏览:

一、原理剖析

  这次参加深圳的高交会,在qualcomm展区看到了多款mini无人机,大家稍微细心一点就可以发现这些无人机都使用了一种叫光流定位的技术,很多人可能都还不明白光流定位是个什么东西,是如何进行定位的,今天就带大家一起来了解一下光流定位的原理。

  在无人机上光流定位通常是借助于无人机底部的一个摄像头采集图像数据,然后采用光流算法计算两帧图像的位移,进而实现对无人机的定位,这种定位手段配合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))

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

联系我们

地址:成都市锦江区锦华路三段88号汇融国际C座15层

电话:13350061060(刘老师)

邮箱:market2@cdszw-uas.com

{13350061060

*24小时招生​热线,欢迎您的来电!联系人:刘老师

版权所有:成都三足乌无人机科技有限公司 Copyright © 2014-2019,All rights reserved 蜀ICP备18003228号-1

三足乌宣传片