Skip to content

Commit 13ee04e

Browse files
committed
084~086
1 parent 9eee6f9 commit 13ee04e

17 files changed

+748
-2
lines changed

Diff for: README.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -121,4 +121,7 @@ code_079 | [Video Analysis-Background/Foreground Extraction](python/code_079/ope
121121
code_080 | [Video Analysis–Background Subtraction and ROI Extraction of the Foreground](python/code_080) | ✔️
122122
code_081 | [Corner Detection-Harris](python/code_081) | ✔️
123123
code_082 | [Corner Detection-Shi-Tomas](python/code_082) | ✏️
124-
code_083 | [Corner Detection-Sub-Pixel ](python/code_083) | ✔️
124+
code_083 | [Corner Detection-Sub-Pixel ](python/code_083) | ✔️
125+
code_084 | [Video Analysis-KLT Optical Flow-1](python/code_084) | ✏️
126+
code_085 | [Video Analysis-KLT Optical Flow-2](python/code_085) | ✏️
127+
code_086 | [Video Analysis-Dense Optical Flow](python/code_086) | ✏️

Diff for: README_CN.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -120,4 +120,7 @@ code_079 | [视频分析-背景/前景 提取](python/code_079/opencv_079.py)
120120
code_080 | [视频分析–背景消除与前景ROI提取](python/code_080) | ✔️
121121
code_081 | [角点检测-Harris角点检测](python/code_081) | ✔️
122122
code_082 | [角点检测-Shi-Tomas角点检测](python/code_082) | ✏️
123-
code_083 | [角点检测-亚像素角点检测](python/code_083) | ✔️
123+
code_083 | [角点检测-亚像素角点检测](python/code_083) | ✔️
124+
code_084 | [视频分析-KLT光流跟踪算法-1](python/code_084) | ✏️
125+
code_085 | [视频分析-KLT光流跟踪算法-2](python/code_085) | ✏️
126+
code_086 | [视频分析-稠密光流分析](python/code_086) | ✏️

Diff for: python/code_084/README.md

+158
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
# 视频光流检测
2+
✏️ ⛳️👍
3+
4+
## 概述
5+
6+
✔️ 光流是由对象或相机的移动引起的两个连续帧之间的图像对象的明显运动的模式.它是2D矢量场,其中每个矢量是位移矢量,表示从第一帧到第二帧的点的移动。
7+
8+
如下图所示,是一个球在连续的5帧图像中的运动,箭头显示其位移矢量.
9+
10+
![光流](https://segmentfault.com/img/bVbel9k?w=538&h=238)
11+
12+
**光流有很多应用场景如下:**
13+
14+
- 运动恢复结构
15+
- 视频压缩
16+
- 视频防抖动等
17+
18+
**光流法的工作原理基于如下假设:**
19+
20+
- 连续的两帧图像之间,**目标像素灰度值不变**
21+
- 相邻的像素之间有**相似的运动**
22+
23+
**数学原理**
24+
25+
✔️ 第一帧的像素$I(x,y,t)$,表示在 t 时刻的像素值,那么经过$d_t$时间后,像素在下一帧移动的距离为$(d_x,d_y)$。基于像素相同,亮度不变,可得:
26+
```math
27+
I(x, y, t)=I\left(x+d_{x}, y+d_{y}, t+d_{t}\right)
28+
```
29+
假设移动很小,使用泰勒公式得:
30+
```math
31+
I(x+\Delta x, y+\Delta y, t+\Delta t)=I(x, y, t)+\frac{\partial I}{\partial x} \Delta x+\frac{\partial I}{\partial y} \Delta y+\frac{\partial I}{\partial t} \Delta t + \varepsilon
32+
```
33+
34+
其中$\varepsilon$为无穷小,由第一个假设得:
35+
```math
36+
\frac{\partial I}{\partial x} \Delta x+\frac{\partial I}{\partial y} \Delta y+\frac{\partial I}{\partial t} \Delta t=0
37+
38+
<==>
39+
40+
\frac{\partial I}{\partial x} \frac{\Delta x}{\Delta t}+\frac{\partial I}{\partial y} \frac{\Delta y}{\Delta t}+\frac{\partial I}{\partial t} \frac{\Delta t}{\Delta t}=0
41+
```
42+
设 $\frac{\partial I}{\partial x}=f_{x} , \frac{\partial I}{\partial y}=f_{y} , \frac{\partial I}{\partial t}=f_{t}$,$\frac{\Delta x}{\Delta t}=u ; \frac{\Delta y}{\Delta t}=v$,则有得到光流方程为:
43+
```math
44+
f_{x} u+f_{y} v+f_{t}=0
45+
```
46+
其中,$f_x$和$f_y$分别是图像梯度,$f_t$是图像沿着时间的梯度。
47+
48+
![3.png](https://i.loli.net/2019/06/19/5d0a03cc7d14051499.png)
49+
50+
✔️ 为了求解未知的$u, v$,采用Lucas-Kanada 方法解决,这个算法最早是有Bruce D. Lucas and Takeo Kanade两位作者提出来的,所以又被称为KLT。
51+
52+
KLT算法工作有三个假设前提条件:
53+
- 亮度恒定
54+
- 短距离移动
55+
- 空间一致性
56+
57+
## 函数
58+
59+
✔️ Opencv中使用`cv2.calcOpticalFlowPyrLK()`函数计算一个稀疏特征集的光流,使用金字塔中的迭代 Lucas-Kanade 方法。
60+
```python
61+
nextPts,status,err = cv2.calcOpticalFlowPyrLK(prevImg, #上一帧图片
62+
nextImg, #当前帧图片
63+
prevPts, #上一帧找到的特征点向量
64+
nextPts #与返回值中的nextPtrs相同
65+
[, status[, err[, winSize
66+
[, maxLevel[, criteria
67+
[, flags[, minEigThreshold]]]]]]])
68+
```
69+
>输入值:
70+
71+
- prevImg--> 上一帧图片;
72+
- nextImg--> 当前帧图片;
73+
- prevPts--> 上一帧找到的特征点向量;
74+
- nextPts--> 与返回值中的nextPtrs相同;
75+
- status--> 与返回的status相同;
76+
- err--> 与返回的err相同;
77+
- winSize--> 在计算局部连续运动的窗口尺寸(在图像金字塔中),default=Size(21, 21);
78+
- maxLevel--> 图像金字塔层数,0表示不使用金字塔, default=3;
79+
- criteria--> 寻找光流迭代终止的条件;
80+
- flags--> 有两个宏,表示两种计算方法,分别是OPTFLOW_USE_INITIAL_FLOW表示使用估计值作为寻找到的初始光流,OPTFLOW_LK_GET_MIN_EIGENVALS表示使用最小特征值作为误差测量,default=0;
81+
- minEigThreshold--> 该算法计算光流方程的2×2规范化矩阵的最小特征值,除以窗口中的像素数; 如果此值小于minEigThreshold,则会过滤掉相应的功能并且不会处理该光流,因此它允许删除坏点并获得性能提升, default=1e-4.
82+
83+
>返回值:
84+
85+
- nextPtrs--> 输出一个二维点的向量,这个向量可以是用来作为光流算法的输入特征点,也是光流算法在当前帧找到特征点的新位置(浮点数);
86+
- status--> 标志,在当前帧当中发现的特征点标志status==1,否则为0;
87+
- err--> 向量中的每个特征对应的错误率.
88+
89+
**实现原理:**
90+
- 在第一帧图像中检测Shi-Tomasi角点,
91+
- 使用LK算法来迭代的跟踪这些特征点。迭代的方式就是不断向cv2.calcOpticalFlowPyrLK()中传入上一帧图片的特征点以及当前帧的图片。
92+
- 函数会返回当前帧的点,这些点带有状态1或者0,如果在当前帧找到了上一帧中的点,那么这个点的状态就是1,否则就是0。
93+
94+
**实现流程:**
95+
96+
- 加载视频。
97+
- 调用`cv2.GoodFeaturesToTrack` 函数寻找兴趣点(关键点)。
98+
- 调用`cv2.CalcOpticalFlowPyrLK` 函数计算出两帧图像中兴趣点的移动情况。
99+
- 删除未移动的兴趣点。
100+
- 在两次移动的点之间绘制一条线段。
101+
102+
## 示例代码
103+
104+
**1. 删除静止点的光流分析:**
105+
106+
[Python code](../code_085/opencv_085_flow.py)
107+
108+
<img src=http://libai.91iot.net/lufax-read-palm/9jDmeoBxbh8g8lFq6HUCUvVgWtX5w3g1 height=400>
109+
110+
**2. 反向检测的光流分析:**
111+
[Python code](../code_085/opencv_085.py)
112+
113+
<img src=http://libai.91iot.net/lufax-read-palm/uzeMGAcukDD2EsQBclmMRuGa5AYPuQfD height=400 >
114+
115+
# 稠密光流
116+
117+
## 概述
118+
✔️ Lucas-Kanade方法计算稀疏特征集的光流,OpenCV提供了另一种算法来查找密集的光流,它计算帧中所有点的光流。它基于Gunner Farneback于2003年的《Two-Frame Motion Estimation Based on Polynomial Expansion》。
119+
120+
## 函数
121+
✔️ 我们可以通过Opencv的函数`cv2.calcOpticalFlowFarneback`寻找稠密光流,我们得到的一个两个通道的向量(u,v)。得到的该向量的大小和方向。用不同的颜色编码来使其可视化。
122+
123+
✔️ 方向与Hue值相关,大小与Value值相关。
124+
125+
```bash
126+
flow=cv.calcOpticalFlowFarneback(
127+
prev,
128+
next, flow,
129+
pyr_scale, levels, winsize,
130+
iterations, poly_n, poly_sigma, flags)
131+
```
132+
133+
>输入
134+
- prev--> 前一帧图片
135+
- next--> 下一帧图片,格式与prev相同
136+
- flow--> 与返回值相同,得到一个CV_32FC2格式的光流图
137+
- pyr_scale--> 构建图像金字塔尺度
138+
- levels--> 图像金字塔层数
139+
- winsize--> 窗口尺寸,值越大探测高速运动的物体越容易,但是越模糊,同时对噪声的容错性越强
140+
- iterations--> 对每层金字塔的迭代次数
141+
- poly_n--> 每个像素中找到多项式展开的邻域像素的大小。n越大越光滑,也越稳定
142+
- poly_sigma--> 高斯标准差,用来平滑倒数,n越大,sigma应该适当增加
143+
- flags--> 光流的方式,有OPTFLOW_USE_INITIAL_FLOW 和OPTFLOW_FARNEBACK_GAUSSIAN 两种
144+
-
145+
> 输出
146+
- 一个两通道的光流向量,实际上是每个点的像素位移值
147+
148+
## 示例代码
149+
[Python code](../code_086/opencv_086.py)
150+
151+
![opticalfb](../code_086/opticalfb.png)
152+
![opticalhsv](../code_086/opticalhsv.png)
153+
# 参考
154+
👍👍👍- [机器视觉 OpenCV—python目标跟踪(光流)](https://blog.csdn.net/wsp_1138886114/article/details/84400392)
155+
156+
👍👍👍- [opencv python 光流法](https://segmentfault.com/a/1190000015777243)
157+
158+
👍👍👍- [OpenCV Tutorial 官网](https://docs.opencv.org/4.0.0-alpha/d6/d00/tutorial_py_root.html)

Diff for: python/code_084/__pycache__/common.cpython-36.pyc

8.36 KB
Binary file not shown.
3.61 KB
Binary file not shown.

Diff for: python/code_084/__pycache__/video.cpython-36.pyc

1.21 KB
Binary file not shown.

Diff for: python/code_084/opencv_084.py

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import numpy as np
2+
import cv2 as cv
3+
cap = cv.VideoCapture('vtest.avi')
4+
5+
# 角点检测参数
6+
feature_params = dict(maxCorners=100, qualityLevel=0.01, minDistance=10, blockSize=3)
7+
8+
# KLT光流参数
9+
lk_params = dict(winSize=(31, 31), maxLevel=3, criteria=(cv.TERM_CRITERIA_EPS | cv.TERM_CRITERIA_COUNT, 30, 0.01))
10+
11+
# 随机颜色
12+
color = np.random.randint(0,255,(100,3)) #shape(100,3)
13+
14+
# 读取第一帧
15+
ret, old_frame = cap.read()
16+
old_gray = cv.cvtColor(old_frame, cv.COLOR_BGR2GRAY)
17+
p0 = cv.goodFeaturesToTrack(old_gray, mask=None, **feature_params)
18+
19+
# for pt in p0:
20+
# print(pt)
21+
# b = np.random.random_integers(0, 256)
22+
# g = np.random.random_integers(0, 256)
23+
# r = np.random.random_integers(0, 256)
24+
# x = np.int32(pt[0][0])
25+
# y = np.int32(pt[0][1])
26+
# cv.circle(old_frame, (x, y), 5, (int(b), int(g), int(r)), 2)
27+
# cv.imshow('s',old_frame)
28+
# cv.waitKey(0)
29+
30+
# 光流跟踪
31+
while True:
32+
ret, frame = cap.read()
33+
if ret is False:
34+
break
35+
frame_gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
36+
# 计算光流
37+
p1, st, err = cv.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params)
38+
# 根据状态选择
39+
good_new = p1[st == 1]
40+
good_old = p0[st == 1]
41+
42+
# 绘制跟踪线
43+
for i, (new, old) in enumerate(zip(good_new,good_old)):
44+
a,b = new.ravel()
45+
c,d = old.ravel()
46+
frame = cv.line(frame, (a,b),(c,d), color[i].tolist(), 2)
47+
frame = cv.circle(frame,(a,b),5,color[i].tolist(),-1)
48+
cv.imshow('frame',frame)
49+
k = cv.waitKey(30) & 0xff
50+
if k == 27:
51+
break
52+
53+
# 更新
54+
old_gray = frame_gray.copy()
55+
p0 = good_new.reshape(-1, 1, 2)
56+
57+
cv.destroyAllWindows()
58+
cap.release()

Diff for: python/code_084/vtest.avi

7.75 MB
Binary file not shown.

Diff for: python/code_085/README.md

+158
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
# 视频光流检测
2+
✏️ ⛳️👍
3+
4+
## 概述
5+
6+
✔️ 光流是由对象或相机的移动引起的两个连续帧之间的图像对象的明显运动的模式.它是2D矢量场,其中每个矢量是位移矢量,表示从第一帧到第二帧的点的移动。
7+
8+
如下图所示,是一个球在连续的5帧图像中的运动,箭头显示其位移矢量.
9+
10+
![光流](https://segmentfault.com/img/bVbel9k?w=538&h=238)
11+
12+
**光流有很多应用场景如下:**
13+
14+
- 运动恢复结构
15+
- 视频压缩
16+
- 视频防抖动等
17+
18+
**光流法的工作原理基于如下假设:**
19+
20+
- 连续的两帧图像之间,**目标像素灰度值不变**
21+
- 相邻的像素之间有**相似的运动**
22+
23+
**数学原理**
24+
25+
✔️ 第一帧的像素$I(x,y,t)$,表示在 t 时刻的像素值,那么经过$d_t$时间后,像素在下一帧移动的距离为$(d_x,d_y)$。基于像素相同,亮度不变,可得:
26+
```math
27+
I(x, y, t)=I\left(x+d_{x}, y+d_{y}, t+d_{t}\right)
28+
```
29+
假设移动很小,使用泰勒公式得:
30+
```math
31+
I(x+\Delta x, y+\Delta y, t+\Delta t)=I(x, y, t)+\frac{\partial I}{\partial x} \Delta x+\frac{\partial I}{\partial y} \Delta y+\frac{\partial I}{\partial t} \Delta t + \varepsilon
32+
```
33+
34+
其中$\varepsilon$为无穷小,由第一个假设得:
35+
```math
36+
\frac{\partial I}{\partial x} \Delta x+\frac{\partial I}{\partial y} \Delta y+\frac{\partial I}{\partial t} \Delta t=0
37+
38+
<==>
39+
40+
\frac{\partial I}{\partial x} \frac{\Delta x}{\Delta t}+\frac{\partial I}{\partial y} \frac{\Delta y}{\Delta t}+\frac{\partial I}{\partial t} \frac{\Delta t}{\Delta t}=0
41+
```
42+
设 $\frac{\partial I}{\partial x}=f_{x} , \frac{\partial I}{\partial y}=f_{y} , \frac{\partial I}{\partial t}=f_{t}$,$\frac{\Delta x}{\Delta t}=u ; \frac{\Delta y}{\Delta t}=v$,则有得到光流方程为:
43+
```math
44+
f_{x} u+f_{y} v+f_{t}=0
45+
```
46+
其中,$f_x$和$f_y$分别是图像梯度,$f_t$是图像沿着时间的梯度。
47+
48+
![3.png](https://i.loli.net/2019/06/19/5d0a03cc7d14051499.png)
49+
50+
✔️ 为了求解未知的$u, v$,采用Lucas-Kanada 方法解决,这个算法最早是有Bruce D. Lucas and Takeo Kanade两位作者提出来的,所以又被称为KLT。
51+
52+
KLT算法工作有三个假设前提条件:
53+
- 亮度恒定
54+
- 短距离移动
55+
- 空间一致性
56+
57+
## 函数
58+
59+
✔️ Opencv中使用`cv2.calcOpticalFlowPyrLK()`函数计算一个稀疏特征集的光流,使用金字塔中的迭代 Lucas-Kanade 方法。
60+
```python
61+
nextPts,status,err = cv2.calcOpticalFlowPyrLK(prevImg, #上一帧图片
62+
nextImg, #当前帧图片
63+
prevPts, #上一帧找到的特征点向量
64+
nextPts #与返回值中的nextPtrs相同
65+
[, status[, err[, winSize
66+
[, maxLevel[, criteria
67+
[, flags[, minEigThreshold]]]]]]])
68+
```
69+
>输入值:
70+
71+
- prevImg--> 上一帧图片;
72+
- nextImg--> 当前帧图片;
73+
- prevPts--> 上一帧找到的特征点向量;
74+
- nextPts--> 与返回值中的nextPtrs相同;
75+
- status--> 与返回的status相同;
76+
- err--> 与返回的err相同;
77+
- winSize--> 在计算局部连续运动的窗口尺寸(在图像金字塔中),default=Size(21, 21);
78+
- maxLevel--> 图像金字塔层数,0表示不使用金字塔, default=3;
79+
- criteria--> 寻找光流迭代终止的条件;
80+
- flags--> 有两个宏,表示两种计算方法,分别是OPTFLOW_USE_INITIAL_FLOW表示使用估计值作为寻找到的初始光流,OPTFLOW_LK_GET_MIN_EIGENVALS表示使用最小特征值作为误差测量,default=0;
81+
- minEigThreshold--> 该算法计算光流方程的2×2规范化矩阵的最小特征值,除以窗口中的像素数; 如果此值小于minEigThreshold,则会过滤掉相应的功能并且不会处理该光流,因此它允许删除坏点并获得性能提升, default=1e-4.
82+
83+
>返回值:
84+
85+
- nextPtrs--> 输出一个二维点的向量,这个向量可以是用来作为光流算法的输入特征点,也是光流算法在当前帧找到特征点的新位置(浮点数);
86+
- status--> 标志,在当前帧当中发现的特征点标志status==1,否则为0;
87+
- err--> 向量中的每个特征对应的错误率.
88+
89+
**实现原理:**
90+
- 在第一帧图像中检测Shi-Tomasi角点,
91+
- 使用LK算法来迭代的跟踪这些特征点。迭代的方式就是不断向cv2.calcOpticalFlowPyrLK()中传入上一帧图片的特征点以及当前帧的图片。
92+
- 函数会返回当前帧的点,这些点带有状态1或者0,如果在当前帧找到了上一帧中的点,那么这个点的状态就是1,否则就是0。
93+
94+
**实现流程:**
95+
96+
- 加载视频。
97+
- 调用`cv2.GoodFeaturesToTrack` 函数寻找兴趣点(关键点)。
98+
- 调用`cv2.CalcOpticalFlowPyrLK` 函数计算出两帧图像中兴趣点的移动情况。
99+
- 删除未移动的兴趣点。
100+
- 在两次移动的点之间绘制一条线段。
101+
102+
## 示例代码
103+
104+
**1. 删除静止点的光流分析:**
105+
106+
[Python code](../code_085/opencv_085_flow.py)
107+
108+
<img src=http://libai.91iot.net/lufax-read-palm/9jDmeoBxbh8g8lFq6HUCUvVgWtX5w3g1 height=400>
109+
110+
**2. 反向检测的光流分析:**
111+
[Python code](../code_085/opencv_085.py)
112+
113+
<img src=http://libai.91iot.net/lufax-read-palm/uzeMGAcukDD2EsQBclmMRuGa5AYPuQfD height=400 >
114+
115+
# 稠密光流
116+
117+
## 概述
118+
✔️ Lucas-Kanade方法计算稀疏特征集的光流,OpenCV提供了另一种算法来查找密集的光流,它计算帧中所有点的光流。它基于Gunner Farneback于2003年的《Two-Frame Motion Estimation Based on Polynomial Expansion》。
119+
120+
## 函数
121+
✔️ 我们可以通过Opencv的函数`cv2.calcOpticalFlowFarneback`寻找稠密光流,我们得到的一个两个通道的向量(u,v)。得到的该向量的大小和方向。用不同的颜色编码来使其可视化。
122+
123+
✔️ 方向与Hue值相关,大小与Value值相关。
124+
125+
```bash
126+
flow=cv.calcOpticalFlowFarneback(
127+
prev,
128+
next, flow,
129+
pyr_scale, levels, winsize,
130+
iterations, poly_n, poly_sigma, flags)
131+
```
132+
133+
>输入
134+
- prev--> 前一帧图片
135+
- next--> 下一帧图片,格式与prev相同
136+
- flow--> 与返回值相同,得到一个CV_32FC2格式的光流图
137+
- pyr_scale--> 构建图像金字塔尺度
138+
- levels--> 图像金字塔层数
139+
- winsize--> 窗口尺寸,值越大探测高速运动的物体越容易,但是越模糊,同时对噪声的容错性越强
140+
- iterations--> 对每层金字塔的迭代次数
141+
- poly_n--> 每个像素中找到多项式展开的邻域像素的大小。n越大越光滑,也越稳定
142+
- poly_sigma--> 高斯标准差,用来平滑倒数,n越大,sigma应该适当增加
143+
- flags--> 光流的方式,有OPTFLOW_USE_INITIAL_FLOW 和OPTFLOW_FARNEBACK_GAUSSIAN 两种
144+
-
145+
> 输出
146+
- 一个两通道的光流向量,实际上是每个点的像素位移值
147+
148+
## 示例代码
149+
[Python code](../code_086/opencv_086.py)
150+
151+
![opticalfb](../code_086/opticalfb.png)
152+
![opticalhsv](../code_086/opticalhsv.png)
153+
# 参考
154+
👍👍👍- [机器视觉 OpenCV—python目标跟踪(光流)](https://blog.csdn.net/wsp_1138886114/article/details/84400392)
155+
156+
👍👍👍- [opencv python 光流法](https://segmentfault.com/a/1190000015777243)
157+
158+
👍👍👍- [OpenCV Tutorial 官网](https://docs.opencv.org/4.0.0-alpha/d6/d00/tutorial_py_root.html)

Diff for: python/code_085/flow.jpg

160 KB
Loading

0 commit comments

Comments
 (0)