auroraAA 发表于 2024-6-5 14:49:10

基于行空板的opencv lk_homography目标追踪

一、实践目标
本项目在行空板上外接USB摄像头,通过摄像头来检测目标,并进行跟踪。
二、知识目标
学习使用opencv库的lk homography方法来检测目标物并进行跟踪的方法。
三、实践准备
硬件清单:

软件使用:Mind+编程软件x1
四、实践过程
1、硬件搭建 1、将摄像头接入行空板的USB接口。

2、通过USB连接线将行空板连接到计算机。

2、软件编写第一步:打开Mind+,远程连接行空板

第二步:在“行空板的文件”中新建一个名为AI的文件夹,在其中再新建一个名为“基于行空板的opencv lk_homography目标追踪”的文件夹,导入本节课的依赖文件。

第三步:编写程序在上述文件的同级目录下新建一个项目文件,并命名为“main.py”。示例程序:#!/usr/bin/env python

'''
Lucas-Kanade homography tracker
===============================
...
'''

# Python 2/3 compatibility
from __future__ import print_function

import numpy as np
import cv2 as cv

import video
from common import draw_str
from video import presets

# 设置Lucas-Kanade光流法的参数
lk_params = dict( winSize= (19, 19),
                  maxLevel = 2,
                  criteria = (cv.TERM_CRITERIA_EPS | cv.TERM_CRITERIA_COUNT, 10, 0.03))

# 设置寻找好特征点的参数
feature_params = dict( maxCorners = 1000,
                     qualityLevel = 0.01,
                     minDistance = 8,
                     blockSize = 19 )

# 定义跟踪函数,通过比较前后两帧的特征点位置,判断是否为有效的跟踪点
def checkedTrace(img0, img1, p0, back_threshold = 1.0):
    p1, _st, _err = cv.calcOpticalFlowPyrLK(img0, img1, p0, None, **lk_params)
    p0r, _st, _err = cv.calcOpticalFlowPyrLK(img1, img0, p1, None, **lk_params)
    d = abs(p0-p0r).reshape(-1, 2).max(-1)
    status = d < back_threshold
    return p1, status

green = (0, 255, 0)
red = (0, 0, 255)

class App:
    def __init__(self, video_src):
      # 创建视频捕捉对象
      self.cam = self.cam = video.create_capture(video_src, presets['book'])
      self.p0 = None
      self.use_ransac = True
      # 创建一个全屏窗口用于显示
      cv.namedWindow('lk_homography',cv.WND_PROP_FULLSCREEN)    #Set the windows to be full screen.
      cv.setWindowProperty('lk_homography', cv.WND_PROP_FULLSCREEN, cv.WINDOW_FULLSCREEN)    #Set the windows to be full screen.

    def run(self):
      while True:
            # 读取视频帧
            _ret, frame = self.cam.read()
            # 将视频帧转换为灰度图
            frame_gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
            vis = frame.copy()
            if self.p0 is not None:
                # 使用光流法跟踪特征点
                p2, trace_status = checkedTrace(self.gray1, frame_gray, self.p1)

                self.p1 = p2.copy()
                self.p0 = self.p0.copy()
                self.gray1 = frame_gray

                if len(self.p0) < 4:
                  self.p0 = None
                  continue
                # 找到两帧之间的单应性矩阵
                H, status = cv.findHomography(self.p0, self.p1, (0, cv.RANSAC), 10.0)
                h, w = frame.shape[:2]
                overlay = cv.warpPerspective(self.frame0, H, (w, h))
                # 叠加两帧图像
                vis = cv.addWeighted(vis, 0.5, overlay, 0.5, 0.0)

                for (x0, y0), (x1, y1), good in zip(self.p0[:,0], self.p1[:,0], status[:,0]):
                  if good:
                        cv.line(vis, (int(x0), int(y0)), (int(x1), int(y1)), (0, 128, 0))
                  cv.circle(vis, (int(x1), int(y1)), 2, (red, green), -1)
                draw_str(vis, (20, 20), 'track count: %d' % len(self.p1))
                if self.use_ransac:
                  draw_str(vis, (20, 40), 'RANSAC')
            else:
                p = cv.goodFeaturesToTrack(frame_gray, **feature_params)
                if p is not None:
                  for x, y in p[:,0]:
                        cv.circle(vis, (int(x), int(y)), 2, green, -1)
                  draw_str(vis, (20, 20), 'feature count: %d' % len(p))

            cv.imshow('lk_homography', vis)

            ch = cv.waitKey(1)
            if ch == 27:
                break
            if ch == ord('a'):
                self.frame0 = frame.copy()
                self.p0 = cv.goodFeaturesToTrack(frame_gray, **feature_params)
                if self.p0 is not None:
                  self.p1 = self.p0
                  self.gray0 = frame_gray
                  self.gray1 = frame_gray
            if ch == ord('b'):
                self.use_ransac = not self.use_ransac

def main():
    import sys
    try:
      video_src = sys.argv
    except:
      video_src = 0

    # 运行应用程序
    App(video_src).run()
    print('Done')

if __name__ == '__main__':
    print(__doc__)
    main()
    cv.destroyAllWindows()

3、运行调试第一步:运行主程序运行“main.py”程序,将Mind+放入画面中,Mind+随即被检测出并以绿色光点标记,轻轻移动后,依旧在画面中,同时,可以在屏幕上方看到标记特征点的数量。

4、程序解析在上述的“main.py”文件中,我们主要通过opencv库来调用摄像头,获取实时视频流,然后借助计算机视觉中的lk homography算法来实现实时跟踪视频中的特征点,并在视频帧上画出这些特征点的运动轨迹,整体流程如下,
①初始化:程序启动时,会创建一个App类的实例,打开视频源,创建一个全屏窗口用于显示。
②主循环:程序进入一个无限循环,每次循环都会读取一帧视频,然后进行以下处理:如果已经找到了初始特征点(即self.p0不为None),那么程序会使用Lucas-Kanade光流法跟踪这些特征点在当前帧中的位置,然后根据前后两帧特征点的位置找到单应性矩阵,然后用这个矩阵将初始帧映射到当前帧,形成一个叠加图像。如果还没有找到初始特征点,那么程序会在当前帧中寻找好的特征点,并标记出来。
③用户交互:程序会检查用户的键盘输入,如果按下'a'键,那么程序会在当前帧中寻找好的特征点,作为初始特征点;如果按下'b'键,那么程序会切换是否使用RANSAC算法来计算单应性矩阵;如果按下'ESC'键,那么程序会退出。
④结束:当主循环结束时,程序会关闭所有的窗口,然后退出。这个程序的主要目标是跟踪视频中的特征点,并通过找到前后两帧之间的单应性,实现对场景的稳定。这是通过在每一帧中跟踪特征点,然后使用这些特征点来计算单应性矩阵,然后用这个矩阵将初始帧映射到当前帧,形成叠加图像来实现的。

五、知识园地
1. 了解lk homography"Lucas-Kanade" (LK) 和 "Homography" 是两个分别代表不同概念的术语,但在计算机视觉和图像处理中,它们常常被联合使用以实现特定的功能。
Lucas-Kanade (LK):Lucas-Kanade (LK) 是一种光流估计算法。光流是空间运动物体在观察成像平面上的像素变化,它可以描述图像序列中的运动对象的运动。Lucas-Kanade方法是基于对局部像素窗口进行最小二乘拟合的方法。LK算法假设窗口内的所有像素都有相同的运动。在实际应用中,LK算法常常被用来跟踪视频中的特征点。
Homography:Homography 是一个变换,它描述了两个平面之间的映射关系。在计算机视觉中,Homography常常被用于图像配准和透视变换等任务。对于两幅图像,如果我们知道它们之间的特征点对应关系,就可以计算出这两幅图像之间的Homography,然后用这个Homography把一幅图像映射到另一幅图像上。当我们谈论 "LK Homography" 时,通常是指结合使用LK算法和Homography来实现某种功能,比如特征点跟踪和图像配准。具体来说,可以先用LK算法在视频序列中跟踪特征点,然后用这些特征点计算出前后帧之间的Homography,最后用这个Homography实现图像的配准或叠加。

页: [1]
查看完整版本: 基于行空板的opencv lk_homography目标追踪