0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

基于opencv对高空拍摄视频消抖处理

新机器视觉 来源:AI算法与图像处理 作者:AI算法与图像处理 2021-03-20 10:29 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

一、问题背景

无人机在拍摄视频时,由于风向等影响因素,不可避免会出现位移和旋转,导致拍摄出的画面存在平移和旋转的帧间变换, 即“抖动” 抖动会改变目标物体 (车辆、行人) 的坐标,给后续的检测、跟踪任务引入额外误差,造成数据集不可用。

原效果

目标效果

理想的无抖动视频中,对应于真实世界同一位置的背景点在不同帧中的坐标应保持一致,从而使车辆、行人等目标物体的坐标变化只由物体本身的运动导致,而不包含相机的运动 抖动可以由不同帧中对应背景点的坐标变换来描述

二、量化指标

抖动可以用相邻帧之间的 x 方向平移像素 dx,y 方向平移像素 dy,旋转角度 da,缩放比例 s 来描述,分别绘制出 4 个折线图,根据折线图的走势可以判断抖动的程度 理想的无抖动视频中,dx、dy、da 几乎始终为 0,s 几乎始终为 1。

三、技术思路

我们最终实现,将视频的所有帧都对齐到第一帧,以达到视频消抖问题,实现逻辑如下图所示。

97fc0916-88ef-11eb-8b86-12bb97331649.png

(1)首先对视频进行抽第一帧与最后一帧,为什么抽取两帧?这样做的主要目的是,我们在做帧对齐时,使用帧中静态物的关键点做对齐,如果特征点来源于动态物上,那么对齐后就会产生形变,我们选取第一帧与最后一帧,提取特征点,留下交集部分,则可以得到静态特征点我们这里称为特征模板,然后将特征模板应用到每一帧上,这样可以做有效对齐。

(2)常用特征点检测器:

SIFT: 04 年提出,广泛应用于各种跟踪和识别算法,表现能力强,但计算复杂度高。

SURF: 06 年提出,是 SIFT 的演进版本,保持强表现能力的同时大大减少了计算量。

BRISK: BRIEF 的演进版本,压缩了特征的表示,提高了匹配速度。ORB: 以速度著称,是 SURF 的演进版本,多用于实时应用。

GFTT: 最早提出的 Harris 角点的改进版本,经常合称为 Harris-Shi-Tomasi 角点。

SimpleBlob: 使用 blob 的概念来抽取图像中的特征点,相对于角点的一种创新。FAST: 相比其他方法特征点数量最多,但也容易得到距离过近的点,需要经过 NMS。

Star: 最初用于视觉测距,后来也成为一种通用的特征点检测方法。

我们这里使用的是SURF特征点检测器

第一帧特特征点提取

最后一帧特征点提取

(3)在上图中,我们发现所提取的特征点中部分来自于车身,由于车是运动的,所以我们不能使用,我们用第一帧与最后一帧做静态特帧点匹配,生成静态特征模板,在下图中,我们发现只有所有的特征点只选取在静态物上

静态特征点模板

(4)静态特征模板匹配 ,我们这里使用Flann算法,匹配结果如下

特征匹配

(5)使用匹配成功的两组特征点,估计两帧之间的透视变换 (Perspective Transformation)。估计矩阵 H,其中 (x_i, y_i) 和 (x_i^′, y_i^′) 分别是两帧的特征点。

第一帧

最后一帧对齐到第一帧

四、实现代码

代码基于python实现,如下所示

import cv2import timeimport numpy as npimport os class Stable: # 处理视频文件路径 __video_path = None # surf 特征提取 __surf = { # surf算法 'surf': None, # 提取的特征点 'kp': None, # 描述符 'des': None, # 过滤后的特征模板 'template_kp': None } # capture __capture = { # 捕捉器 'cap': None, # 视频大小 'size': None, # 视频总帧 'frame_count': None, # 视频帧率 'fps': None, 'video': None } # 配置 __config = { # 要保留的最佳特征的数量 'key_point_count': 5000, # Flann特征匹配 'index_params': dict(algorithm=0, trees=5), 'search_params': dict(checks=50), 'ratio': 0.5, 'frame_count': 9999 } # 当前处理帧数 __current_frame = 0 # 需要处理帧数 __handle_count = 0 # 处理时间 __handle_timer = { 'init': 0, 'handle': 0, 'read': 0, 'key': 0, 'matrix': 0, 'flann': 0, 'perspective': 0, 'write': 0, 'other': 0, } # 帧队列 __frame_queue = None # 需要写入的帧队列 __write_frame_queue = None # 特征提取列表 __surf_list = [] def __init__(self): pass # 初始化capture def __init_capture(self): self.__capture['cap'] = cv2.VideoCapture(self.__video_path) self.__capture['size'] = (int(self.__capture['cap'].get(cv2.CAP_PROP_FRAME_WIDTH)), int(self.__capture['cap'].get(cv2.CAP_PROP_FRAME_HEIGHT))) self.__capture['fps'] = self.__capture['cap'].get(cv2.CAP_PROP_FPS) self.__capture['video'] = cv2.VideoWriter(self.__video_path.replace('.', '_stable.'), cv2.VideoWriter_fourcc(*"mp4v"), self.__capture['fps'], self.__capture['size']) self.__capture['frame_count'] = int(self.__capture['cap'].get(cv2.CAP_PROP_FRAME_COUNT)) self.__handle_count = min(self.__config['frame_count'], self.__capture['frame_count']) # 初始化surf def __init_surf(self): st = time.time() self.__capture['cap'].set(cv2.CAP_PROP_POS_FRAMES, 0) state, first_frame = self.__capture['cap'].read() self.__capture['cap'].set(cv2.CAP_PROP_POS_FRAMES, self.__capture['frame_count'] - 20) state, last_frame = self.__capture['cap'].read() self.__surf['surf'] = cv2.xfeatures2d.SURF_create(self.__config['key_point_count'], 1, 1, 1, 1) # nfeatures:默认为0,要保留的最佳特征的数量。特征按其分数排名(在SIFT算法中按局部对比度排序) # nOctaveLayers:默认为3,金字塔每组(Octave)有多少层。3是D. Lowe纸中使用的值。 # contrastThreshold:默认为0.04,对比度阈值,用于滤除半均匀(低对比度)区域中的弱特征。阈值越大,检测器产生的特征越少。 # edgeThreshold:默认为10,用来过滤边缘特征的阈值。注意,它的意思与contrastThreshold不同,edgeThreshold越大,滤出的特征越少(保留更多特征)。 # sigma:默认为1.6,高斯金字塔中的σ。如果使用带有软镜头的弱相机拍摄图像,则可能需要减少数量。 self.__surf['kp'], self.__surf['des'] = self.__surf['surf'].detectAndCompute(first_frame, None) kp, des = self.__surf['surf'].detectAndCompute(last_frame, None) # 快速临近匹配 flann = cv2.FlannBasedMatcher(self.__config['index_params'], self.__config['search_params']) matches = flann.knnMatch(self.__surf['des'], des, k=2) good_match = [] for m, n in matches: if m.distance < self.__config['ratio'] * n.distance: good_match.append(m) self.__surf['template_kp'] = [] for f in good_match: self.__surf['template_kp'].append(self.__surf['kp'][f.queryIdx]) self.__capture['cap'].set(cv2.CAP_PROP_POS_FRAMES, 0) self.__handle_timer['init'] = int((time.time() - st) * 1000) print("[INFO] init time:{}ms".format(self.__handle_timer['init'])) # 初始化 队列 def __init_data(self): pass # 初始化 def __init(self): self.__init_capture() self.__init_surf() self.__init_data() # 处理 def __process(self): self.__current_frame = 1 while True: if self.__current_frame > self.__handle_count: break start_time = time.time() # 抽帧 success, frame = self.__capture['cap'].read() self.__handle_timer['read'] = int((time.time() - start_time) * 1000) if not success: return # 计算 frame = self.detect_compute(frame) # 写帧 st = time.time() self.__capture['video'].write(frame) self.__handle_timer['write'] = int((time.time() - st) * 1000) self.__handle_timer['handle'] = int((time.time() - start_time) * 1000) self.__current_frame += 1 self.print_handle_time() # 视频稳像 def stable(self, path): self.__video_path = path self.__init() self.__process() # 打印耗时 def print_handle_time(self): print( "[INFO] handle frame:{}/{} time:{}ms(read:{}ms key:{}ms flann:{}ms matrix:{}ms perspective:{}ms write:{}ms)". format(self.__current_frame, self.__handle_count, self.__handle_timer['handle'], self.__handle_timer['read'], self.__handle_timer['key'], self.__handle_timer['flann'], self.__handle_timer['matrix'], self.__handle_timer['perspective'], self.__handle_timer['write'])) # 特征点提取 def detect_compute(self, frame): frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # 计算特征点 st = time.time() kp, des = self.__surf['surf'].detectAndCompute(frame_gray, None) self.__handle_timer['key'] = int((time.time() - st) * 1000) # 快速临近匹配 st = time.time() flann = cv2.FlannBasedMatcher(self.__config['index_params'], self.__config['search_params']) matches = flann.knnMatch(self.__surf['des'], des, k=2) self.__handle_timer['flann'] = int((time.time() - st) * 1000) # 计算单应性矩阵 st = time.time() good_match = [] for m, n in matches: if m.distance < self.__config['ratio'] * n.distance: good_match.append(m) p1, p2 = [], [] for f in good_match: # 存在与模板特征点中 if self.__surf['kp'][f.queryIdx] in self.__surf['template_kp']: p1.append(self.__surf['kp'][f.queryIdx].pt) p2.append(kp[f.trainIdx].pt) H, _ = cv2.findHomography(np.float32(p2), np.float32(p1), cv2.RHO) self.__handle_timer['matrix'] = int((time.time() - st) * 1000) # 透视变换 st = time.time() output_frame = cv2.warpPerspective(frame, H, self.__capture['size'], borderMode=cv2.BORDER_REPLICATE) self.__handle_timer['perspective'] = int((time.time() - st) * 1000) return output_frame s = Stable() s.stable('video/test10.mov')

五、效果展示

我们消抖后的视频道路完全没有晃动,但是在边界有马赛克一样的东西,那是因为图片对齐后后出现黑边,我们采用边缘点重复来弥补黑边。

消抖前

消抖后

六、效率优化

目前的处理效率(原视频尺寸3840*2160),我们可以看出主要时间是花费在特征点(key)提取上。
可以采用异步处理+GPU提高计算效率

ae4ac39c-88ef-11eb-8b86-12bb97331649.png

处理效率

七、存在问题

目前存在的问题 还不能完全消除视频中的所有抖动

(1)尤其是对于原来的抖动比较剧烈的视频,目前只能去除大部分明显抖动;

(2)由于画面旋转造成的边缘画面缺失,目前采取了复制边缘点 (replicate) 的操作,是否会对数据集的使用造成影响还需要进行实验。

改进思路

(1)对于抖动问题,计划通过调整关键点检测器参数、尽可能过滤掉运动物体的特征点、调整特征点匹配参数来解决;

(2)对于边缘画面缺失问题,可以使用基于 CNN 的图像修复算法,尽可能让缺失的边缘表现得更自然 后续进一步增加运动平滑等算法,实现对整体运动的进一步平滑。

责任编辑:lq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 检测器
    +关注

    关注

    1

    文章

    951

    浏览量

    50180
  • gpu
    gpu
    +关注

    关注

    28

    文章

    5329

    浏览量

    136227
  • OpenCV
    +关注

    关注

    33

    文章

    652

    浏览量

    45185

原文标题:基于opencv对高空拍摄视频消抖处理

文章出处:【微信号:vision263com,微信公众号:新机器视觉】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    RK3576 单板机高清视频图像处理开发实战手册(三)

    工业相机采集、OpenCV 边缘检测等实战案例,支持 4K@60fps 高性能处理。创龙科技通过标准化流程与工程化案例,帮助用户高效完成嵌入式视频与视觉应用开发。
    的头像 发表于 04-29 09:49 301次阅读
    RK3576 单板机高清<b class='flag-5'>视频</b>图像<b class='flag-5'>处理</b>开发实战手册(三)

    RK3576 单板机高清视频图像处理开发实战手册(二)

    工业相机采集、OpenCV 边缘检测等实战案例,支持 4K@60fps 高性能处理。创龙科技通过标准化流程与工程化案例,帮助用户高效完成嵌入式视频与视觉应用开发。
    的头像 发表于 04-28 10:33 162次阅读
    RK3576 单板机高清<b class='flag-5'>视频</b>图像<b class='flag-5'>处理</b>开发实战手册(二)

    RK3576 单板机高清视频图像处理开发实战手册(一)

    工业相机采集、OpenCV 边缘检测等实战案例,支持 4K@60fps 高性能处理。创龙科技通过标准化流程与工程化案例,帮助用户高效完成嵌入式视频与视觉应用开发。
    的头像 发表于 04-27 09:36 177次阅读
    RK3576 单板机高清<b class='flag-5'>视频</b>图像<b class='flag-5'>处理</b>开发实战手册(一)

    音关键词搜索视频的接口文档

    一、接口基本信息 接口名称 :视频搜索(关键词) 接口版本 :v2 HTTP 方法 :GET 接口地址 : plaintext   https://open.douyin.com
    的头像 发表于 04-14 13:40 508次阅读

    音关键词搜索,视频详情api

    Scope: aweme.dy.video_search_v2 需申请「 视频垂搜 」权限音开放平台 请求头 http   access-token: {你的client_token
    的头像 发表于 04-13 17:16 1699次阅读

    深入解析MC14490:六通道接触器的卓越性能与应用

    深入解析MC14490:六通道接触器的卓越性能与应用 在电子设计领域,接触抖动是一个常见且令人头疼的问题,尤其是在涉及机械触点的系统中。ON Semiconductor的MC14490六通道接触
    的头像 发表于 04-11 13:40 182次阅读

    MAX16054:具备和±15kV ESD保护的开关控制器

    MAXIM推出的推钮式开关控制器,它集成了单开关器和内置锁存器,能够有效处理机械开关带来的噪声问题,同时具备强大的ESD保护能力,适用于多种电子设备。 文件下载: MAX16054AZT+T.pdf 产品概述 基本功能 MA
    的头像 发表于 03-13 17:20 759次阅读

    如何通过HDMI(LT8912)显示OS08A20摄像机拍摄视频呢?

    您能告诉我如何通过HDMI(LT8912)显示OS08A20相机拍摄视频吗? ■ Environment Board: i.MX95 Verdin Camera: OS08A20 HDMI
    发表于 03-10 08:20

    MAX16054:高性能带和 ±15kV ESD 保护的开关控制器

    MAX16054:高性能带和 ±15kV ESD 保护的开关控制器 在电子产品设计中,开关控制器是常见且关键的组件。但如何处理开关抖动以及静电防护,是工程师们常常面临的难题。今天,我们就来详细
    的头像 发表于 02-09 17:30 458次阅读

    没有专利的opencv-python 版本

    视频处理 视频读取/写入、帧提取、运动检测(背景差分) 绘图功能 画直线/矩形/圆、添加文字、标注关键点 关键总结: 对 Python 3.13 来说,最优选择是安装 opencv
    发表于 12-13 12:37

    晶台KLH11LX系列丨施密特触发器光耦在按键中的应用

    在电子系统中,机械按键因机械结构特性,在按下或释放时会产生5-10ms的抖动信号,可能导致电路误判。施密特触发器光耦凭借其独特的迟滞特性,成为硬件的核心器件,而晶台推出的KLH11LX系列
    的头像 发表于 12-06 09:04 700次阅读
    晶台KLH11LX系列丨施密特触发器光耦在按键<b class='flag-5'>消</b><b class='flag-5'>抖</b>中的应用

    硬件方案元件参数的计算方法

    硬件是通过电路设计消除机械开关(如按键、继电器等)在闭合或断开时产生的抖动信号。以下是常见硬件方案及其元件参数计算方法: 1. RC滤波
    发表于 11-19 06:31

    索尼FCB-EV9520L——超级图像防助力无人机稳定拍摄

    ,影响最终效果。这时,图像防技术就显得尤为关键。索尼FCB-EV9520L凭借其超级图像防功能,为无人机拍摄提供了可靠的解决方案。 传统的无人机拍摄,往往因为飞行中的各种因素导致画
    的头像 发表于 10-20 15:23 459次阅读

    【开发实例】基于GM-3568JHF开发板安装OpenCV并使用视频目标跟踪 ( CamShift)

    在计算机视觉领域,视频目标跟踪是一个非常重要的任务。视频目标跟踪广泛应用于监控、自动驾驶、人机交互等多个领域。OpenCV提供了多种目标跟踪算法,其中MeanShift和CamShift是两种经典且
    的头像 发表于 09-02 08:04 1049次阅读
    【开发实例】基于GM-3568JHF开发板安装<b class='flag-5'>OpenCV</b>并使用<b class='flag-5'>视频</b>目标跟踪 ( CamShift)

    揭秘视频详情API:电商行业的制胜法宝与实时数据获取的奥秘

    随着社交媒体的普及和电商行业的快速发展,音等短视频平台已经成为电商企业获取用户、推广产品和了解市场趋势的重要渠道。获取[视频详情API]对于电商行业来说具有重要意义,它可以帮助企
    的头像 发表于 08-14 15:47 918次阅读
    揭秘<b class='flag-5'>抖</b>音<b class='flag-5'>视频</b>详情API:电商行业的制胜法宝与实时数据获取的奥秘