无人机光流定位系列——(二)实践

      在本系列blog中的http://blog.csdn.net/andymfc/article/details/53316404文章中,已经对光流定位的原理进行了详细的分析,详细介绍了著名的lucas-kanade光流算法,本期,将带大家一起在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)) 

     以上就是整个光流算法进行点跟踪的处理核心过程,完整代码可以参考

     在dragonboard 410c开发板上搭好鼠标键盘和显示器,我们就可以使用该脚本在上面运行测试了,具体效果如下:

     

     下期blog,将在该代码的基础上,进一步实现如何利用光流法来对运动的目标进行跟踪。

你可能感兴趣的:(DragonBoard,410c,光流,python)