解释下上篇遗留问题,为什么会用到光流法,因为模型要在手机甚至眼镜端上运行,这就要求速度,和用户体验感,我用sift一次对比的时间大概在200ms,人眼1s差不多在12帧,所以光用sift是达不到1秒12帧的,但是光流一整个流程下来只要35ms,加上数据传输30ms,加起来65ms,能达到一秒十五帧。因此使用sift结合光流的方法。

光流法 opencv里面有七八种方法,这里我使用了LK光流法,网上对于lk光流介绍的有很多文章,我就这放一篇我最推荐的文章(懒人就直接看下面代码吧):Opencv Python版学习笔记(五)光流跟踪 Lucas-Kanade(LK)算法,里面有python版本的Lk光流代码,本人亲测可用,但是这些代码仅限于跑跑demo,而且这个代码在逻辑顺序上(代码中的序号1,2)有点问题(当然是我这么想的,可能作者本身有其他的意思,我这就按照我的想法更改过来了),sift+光流的方法,是在这个代码的基础上去改进的:


#encoding:utf-8
'''
Lucas-Kanade tracker
====================
Lucas-Kanade sparse optical flow demo. Uses goodFeaturesToTrack
for track initialization and back-tracking for match verification
between frames.
Usage
-----
lk_track.py [<video_source>]
Keys
----
ESC - exit
'''import numpy as np
import cv2
#from common import anorm2, draw_str
from time import clocklk_params = dict( winSize  = (15, 15), maxLevel = 2, criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))    feature_params = dict( maxCorners = 500, qualityLevel = 0.3,minDistance = 7,blockSize = 7 )class App:def __init__(self, video_src):#构造方法,初始化一些参数和视频路径self.track_len = 10self.detect_interval = 5self.tracks = []self.cam = cv2.VideoCapture(video_src)self.frame_idx = 0def run(self):#光流运行方法while True:ret, frame = self.cam.read()#读取视频帧if ret == True:frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)#转化为灰度虚图像vis = frame.copy()#原来的代码这个是是下一个的if下面 这里标为序号2if self.frame_idx % self.detect_interval == 0:#每5帧检测一次特征点mask = np.zeros_like(frame_gray)#初始化和视频大小相同的图像mask[:] = 255#将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)])#将检测到的角点放在待跟踪序列中#原来的代码这个是在上一个的if前面 这里标为序号1if len(self.tracks) > 0:#检测到角点后进行光流跟踪img0, img1 = self.prev_gray, frame_grayp0 = 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#判断d内的值是否小于1,大于1跟踪被认为是错误的跟踪点new_tracks = []for tr, (x, y), good_flag in zip(self.tracks, p1.reshape(-1, 2), good):#将跟踪正确的点列入成功跟踪点if not good_flag:continuetr.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_trackscv2.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))self.frame_idx += 1self.prev_gray = frame_graycv2.imshow('lk_track', vis)ch = 0xFF & cv2.waitKey(1)if ch == 27:breakdef main():import systry: video_src = sys.argv[1]except: video_src = "E:\Megamind.avi"print __doc__App(video_src).run()cv2.destroyAllWindows()             if __name__ == '__main__':main()

函数原型:corners = cv2.goodFeaturesToTrack(image, maxCorners, qualityLevel, minDistance[, corners[, mask[, blockSize[, useHarrisDetector[, k]]]]])

参数说明:image 输入的单通道图像,可以为8-bit或32-bit

maxCorners 最大的角点数,如果检测出的角点多余最大角点数,将取出最强最大角点数个角点

qualityLevel 最小可接受的角点质量

minDistance 角点间的最小欧几里得距离(也就是两个角点间不能太近)

corners 输出的检测到的角点

mask 需要检测角点的区域,mask标记区域是我自己写的,不过百度上也有很多方法。

blocksize 计算离散卷积块的大小(没用到)

useHarrisDetector 是否使用Harris角点(没用到,用到可能会更准确些?)

具体改进的思路和方法我会用文字和代码段的形式说明,整体代码因为保密原因,所以就不全贴了。

通过上段代码我们可以知道,光流法是用cv2.goodFeaturesToTrack方法去计算有哪些可以跟踪的点,并且这些点都是good点,为了方便与sift结合,将cv2.goodFeaturesToTrack检测特征点和cv2.calcOpticalFlowPyrLK跟踪两个if分别写了下面两个函数,sift走完后会触发检测特征点的初始化操作,并记录状态(flag):

 def goodFeaturesToTrack(self, grayimg,h,w):mask = self.creatMask(grayimg, self.four_points, h,w)#mask 是我根据前面所写的四个像素点创建的区域,跟着看过来的都知道是哪四个点,h,w 是grayimg的宽高self.corners = cv2.goodFeaturesToTrack(grayimg,self.max_corners,self.quality_level, self.min_distance, mask=mask)self.preimg = copy.deepcopy(grayimg)#grayimg是做为sift识别的图以及要作为下一帧光流的初始化的图self.track_status.clear()return 0

当sift走完并触发了检测特征点的状态后,下一帧的图片传入,和上一帧的图片做光流跟踪(grayimg已经深拷贝了) ,此时就会调用到下面的方法进行跟踪并返会下一帧的点

 def calcOpticalFlowPyrLK(self, grayimg, **kwargs):""":param grayimg::param kwargs::return: list of dict"""result = []if self.corners is None or self.preimg.shape != grayimg.shape:return []#self.corners 就是检测的特征点中的self.corners# 跟踪点next_corners, status, err = cv2.calcOpticalFlowPyrLK(self.preimg, grayimg, self.corners, None)#next_corners就是光流跟踪后的特征点goodcnt = list(status).count(1)if goodcnt < 6:#判断good点的个数是否达标return []return next_corners

在Python函数原型为:def calcOpticalFlowPyrLK(prevImg, nextImg, prevPts, nextPts, status=None, err=None, winSize=None, maxLevel=None, flags=None)

参数说明:prevImage 前一帧8-bit图像

nextImage 当前帧8-bit图像

prevPts 待跟踪的特征点向量

nextPts 输出跟踪特征点向量

status 特征点是否找到,找到的状态为1,未找到的状态为0

err 输出错误向量,(不太理解用途...)

winSize 搜索窗口的大小

maxLevel 最大的金字塔层数

flags 可选标识:OPTFLOW_USE_INITIAL_FLOW   OPTFLOW_LK_GET_MIN_EIGENVALS

做sift与光流结合不难,难的是如何将sift与光流同步,这只是个小项目,我的做法是,第一帧或者当跟踪不上的时候使用sift方法去识别。如果有其他好的方法,希望大佬能不吝赐教。

不出意外,到这里应该知道怎么去求解经过LK光流之后的旋转角度了,这里就写给不大清楚的朋友们了,我们已经得到初始帧的特征点(跟踪点)self.corners和下一帧跟踪到的点next_corners,看过我前面博客的朋友应该都知道了,应该要求什么了,没错,求单应性矩阵,具体可以看看我前面的文章,我就不再赘述了。直接上代码:

M, h_status = cv2.findHomography(self.corners, next_corners, cv2.RANSAC, 4)

就这么简单的一行代码,再去看我的第三篇文章,pnp求解就可以求出角度了。

后续会自己写一个简易版本的sift+lk+pnp,不过得看时间了。

sitf+LK+pnp 识别、跟踪图片,并求三维旋转角度(一) -----特征匹配

sitf+LK+pnp 识别、跟踪图片,并求三维旋转角度(二) -----单应性矩阵分解,求解角度

sitf+LK+pnp 识别、跟踪图片,并求三维旋转角度(三) -----pnp 相机位姿求解

sitf+LK+pnp 识别、跟踪图片,并求三维旋转角度(四) -----LK光流跟踪相关推荐

  1. 二维码/条码识别、身份证识别、银行卡识别、车牌识别、图片文字识别、黄图识别、驾驶证(驾照)识别

    Scanner 项目地址:shouzhong/Scanner 简介: 二维码/条码识别.身份证识别.银行卡识别.车牌识别.图片文字识别.黄图识别.驾驶证(驾照)识别 更多:作者   提 Bug 标签: ...

  2. 移动端浏览器AR扫描识别指定图片

    官网:https://www.easyar.cn/ 本次学习的是在移动端浏览器识别指定图片 目录 效果 第一步:下载文件 第二步:找到要用的文件 第三步:获取webAR Token 第四步:修改代码( ...

  3. 利用python进行识别相似图片(二)

    前言 和网上各种首先你要有一个女朋友的系列一样,想进行人脸判断,首先要有脸, 只要能靠确定人脸的位置,那么进行两张人脸是否相似的操作便迎刃而解了. 所以本篇文章着重讲述如何利用openCV定位人脸. ...

  4. java主界面设置背景图片_java 窗体设置背景图片问题?(附上登陆界面代码,我想加个背景图片,求大神帮忙改改)...

    java 窗体设置背景图片问题?(附上登陆界面代码,我想加个背景图片,求大神帮忙改改) 关注:223  答案:4  mip版 解决时间 2021-01-26 22:09 提问者非莪莫属 2021-01 ...

  5. 【python爬虫】easyocr识别gif图片文字

    使用easyocr直接识别gif格式的图片会报错,如下所示: 图片地址:https://code.nongji360.com/images/u/0o2o.gif import easyocr read ...

  6. Java 扫描识别条形码图片

    1.条形码扫描识别的实现方法及步骤 本文以Java代码示例介绍如何来扫描和识别条形码图片.这里使用免费的条码工具Free Spire.Barcode for Java,调用BarcodeScanner ...

  7. Tools_@截屏工具@OCR识别工具@图片文字翻译工具长截屏,普通截屏套件推荐(by QQ)@鼠标键盘动作录制

    文章目录 Tools_@截屏工具@OCR识别工具@图片文字翻译工具长截屏,普通截屏套件推荐(QQ自带) 全局录屏/长截屏: OCR 优点 不足 quicker动作 鼠键录制工具

  8. HTML img标签识别base64图片格式

    img标签识别base64图片格式 红色框框为需要带上的格式,有这个格式img标签才能对base64进行解码,后面白色框框为base64编码 还有一些其他格式为: data:,文本数据 data:te ...

  9. 图像 - 识别出图片里的数字和字母

    本文给大家分享的是C#识别出图片里的数字和字母的代码,主要是识别以前公司的软件注册码截图里的数字和字母,功能很简单,也存在很大的局限性,这里仅仅是分享,小伙伴们参考下. 一个图片识别小工具,原先主要是 ...

最新文章

  1. 九、OLTP 性能调整与优化--结语
  2. 江行智能CTO樊小毅:AI+边缘计算驱动能源产业变革 | 量子位·视点分享回顾
  3. C语言指定编译对齐方式
  4. liunx常用命令0
  5. Day24-Ajax文件上传
  6. embed 标签怎么嵌入pdf_联合Aspect-Sentiment主题嵌入的弱监督的情感分析(2020年10)
  7. 《必玩》!学习大师们的游戏设计经验,激发你的游戏创造力!
  8. 帆软连接kingbase8
  9. ShenYu 网关源码学习(1)- 简单介绍、编译和测试
  10. js如何区分单击与双击(如何避免双击的时候触发单击事件)
  11. 转载,gini系数代码对应的公式
  12. 微服务下的几个难点问题及常见的解决方案
  13. Android注解@TargetApi和@RequiresApi什么意思?
  14. 人工智能--技术发展史
  15. 【硬创邦】跟hoowa学做智能路由(十三):网络音箱之Android篇
  16. 三种安装httpd的方法
  17. 解决 sublimeLinter-php 的配置问题
  18. 工具收集 - 搜索工具
  19. 记忆法——《认知天性》
  20. java毕业设计开题报告SSM实现的在线商城系统|电商购物系统

热门文章

  1. 【C++学习】 第一课1——最初的最初
  2. 【offerMe--面经必备】---交通、微众银行面经分享(包含答案)
  3. Jason和xml两者的区别
  4. K8S中的pod自动扩容与缩容
  5. SolidWorks添加焊件库的方法
  6. 【003】判断闰年,统计闰年个数
  7. 怎样解决电信网通南北互通问题?
  8. 蓝桥试题 算法训练 区间k大数查询 JAVA
  9. Cobalt Strike使用教程一
  10. [已解决]win11家庭版安装软件提示,系统策略禁止安装此设备。请与系统管理员联系