使用Python和OpenCV中的calcOpticalFlowFarneback函数提取稠密光流并进行映射(warp)

介绍

OpenCV中自带两个提取光流的函数:
cv2.calcOpticalFlowPyrLK()
cv2.calcOpticalFlowFarneback()
其中calcOpticalFlowPyrLK函数是提取稀疏光流的函数,而本文主要关注calcOpticalFlowFarneback函数,并将它应用在一个真实的问题中
具体的原理介绍可以参考知乎博客光流估计——从传统方法到深度学习

真实问题是:
给定两张图像,一张是带形变矫正的图像(unwraped_img.png),一张是参照图像(reference_img.png)。目的是提取这两张图像之间的光流,并利用提取的光流对带形变矫正的图像进行矫正,得到矫正过后的图像(warped_img.png),矫正过后的图像更可能与参考图像对齐,即没有形变误差。

calcOpticalFlowFarneback

为了本文的完整,这里搬抄了知乎博客cv2.calcOpticalFlowFarneback函数,来对calcOpticalFlowFarneback函数进行简单的介绍

调用方式

flow = cv2.calcOpticalFlowFarneback(prevImg,
									nextImg,
									None,
									pyr_scale,
									levels,
									winsize,
									iterations,
									poly_n,
									poly_sigma,
									flags)

参数解释

要注意第三个参数None,这是根据OpenCV版本决定的,有的需要这个参数,有的不需要这个参数,这需要根据报的错来判断
比如我的版本:Python=3.8.8,OpenCV=4.5.5
如果不带None这个参数,就会报一下错误:

Traceback (most recent call last):
  File ".\singleImage.py", line 15, in <module>
    flows = cv2.calcOpticalFlowFarneback(reference_img, unwraped_img,
cv2.error: OpenCV(4.5.5) :-1: error: (-5:Bad argument) in function 'calcOpticalFlowFarneback'
> Overload resolution failed:
>  - calcOpticalFlowFarneback() missing required argument 'flow' (pos 3)
>  - calcOpticalFlowFarneback() missing required argument 'flow' (pos 3)

根据报错的信息我们可以发现,这个参数其实就是flow参数,如果版本需要这个参数传入None就可以解决
CSDN博客OpenCV Python calcOpticalFlowFarneback也提出了这个问题

其他参数解释

prevImg:前一帧8-bit单通道图像,或者是参考图像
nextImg:当前帧图像,与前一帧保持同样的格式、尺寸,即期望与参考图像一致的待矫正图像
pyr_scale:金字塔上下两层之间的尺度关系,该参数一般设置为pyrScale=0.5,表示图像金字塔上一层是下一层的2倍降采样
levels:图像金字塔的层数
winsize:均值窗口大小,winsize越大,算法对图像噪声越鲁棒,并且能提升对快速运动目标的检测效果,但也会引起运动区域模糊。个人经验:相较于其他参数,这是一个更加重要的参数,如果设置得不合理将极大地影响提取的光流正确性,建议从小到大多调调这个参数
iterations:算法在图像金字塔每层的迭代次数
poly_n:用于在每个像素点处计算多项式展开的相邻像素点的个数。poly_n越大,图像的近似逼近越光滑,算法鲁棒性更好,也会带来更多的运动区域模糊。通常,poly_n=5 or 7
poly_sigma:标准差,poly_n=5时,poly_sigma = 1.1;poly_n=7时,poly_sigma = 1.5
flags:有两种选择:1)cv2.OPTFLOW_USE_INITIAL_FLOW,使用输入流量作为初始流量近似。2)cv2.OPTFLOW_FARNEBACK_GAUSSIAN,使用高斯过滤器,而不是相同尺寸的盒形滤波器。通常,这种选择比箱形过滤器提供z更准确的流量,但代价是速度较低。通常,一个高斯窗口的winsize应该设置为一个更大的值,以达到相同的鲁棒性水平。

完整代码

注意:flow_to_image函数可以从CSDN博客python 可视化光流中获取
image_warp函数可以从CSDN博客一文搞懂光流 光流的生成,可视化以及映射(warp)

import cv2
import numpy as np
from PIL import Image

from utils.flow_show import flow_to_image
from utils.image_warp_numpy import image_warp

unwraped_img = np.asarray(Image.open('./unwraped_img.png'))
reference_img = np.asarray(Image.open('./reference_img.png'))

####### estimate flows #######
# 注意第三个参数None
# 这个参数得根据OpenCV的版本来确定是否使用
# 我这里使用的是4.5.5版本
flows = cv2.calcOpticalFlowFarneback(reference_img,
									unwraped_img,
									None,
                                    pyr_scale=0.5,
                                    levels=3,
                                    winsize=55,
                                    iterations=3,
                                    poly_n=7,  # 5, 7
                                    poly_sigma=1.5,  # 1.1, 1.5
                                    flags=cv2.OPTFLOW_FARNEBACK_GAUSSIAN)

# show flows
flow_img = flow_to_image(flows)
cv2.imwrite('./flows.png', flow_img)

# warp image
warped_img = image_warp(unwraped_img, flows)
cv2.imwrite('./warped_img.png', warped_img)

代码输入

unwraped_img.png

reference_img.png

代码输出

flows.png

warped_img.png

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
社会演员多的头像社会演员多普通用户
上一篇 2022年5月19日
下一篇 2022年5月19日

相关推荐