为什么 cv2.calcOpticalFlowFarneback 在简单的合成示例上失败?
Why does cv2.calcOpticalFlowFarneback fail on simple synthetic examples?
cv2.calcOpticalFlowFarneback
似乎在自然图像上工作正常,但如果我在简单的合成示例上尝试它,例如下面的那个,它认为没有流量:
import cv2
import numpy as np
a = np.zeros((10, 10), dtype=np.uint8); a[1:4] = 127; a[2] = 255; a
等于
array([[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[127, 127, 127, 127, 127, 127, 127, 127, 127, 127],
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[127, 127, 127, 127, 127, 127, 127, 127, 127, 127],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=uint8)
b = np.roll(a, 1, 0); b
等于
array([[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[127, 127, 127, 127, 127, 127, 127, 127, 127, 127],
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[127, 127, 127, 127, 127, 127, 127, 127, 127, 127],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=uint8)
流量:
flow = cv2.calcOpticalFlowFarneback(a, b, pyr_scale=0.5, levels=3, winsize=15, iterations=3, poly_n=5, poly_sigma=1.2, flags=0)
本质上是0,因为
np.abs(flow).max()
计算为
1.3305091e-13
我尝试了不同的 winsize
值,结果相似。
为什么会这样?还有其他参数可以更好地发挥作用吗?
(我的 OpenCV 版本是 2.4.8。版本 3 需要添加 None
作为第三个参数,我相信)
我不知道这是否会回答你的问题,但除了 winsize
太大之外,算法很难知道在这样的规则下移动的方向 (left/right)图.
尝试添加一些噪音,例如a[4,4] += 1;
在调用roll之前,你会看到很大的不同。
编辑:添加了我的结果
print(np.abs(flow).max())
无噪音:
winsize 15: 1.33051e-13
winsize 2: 6.00387e-11
噪声 1:
# a[4,4] += 1;
winsize 15: 0.00332422
winsize 2: 1.82871
噪音 2:
# noise = np.round(np.random.random(a.shape) * 2.0).astype(np.int8)
# a = a + noise;
winsize 15: 0.207728
winsize 2: 324.527
原因是等式 19、20、23 和 25 中的 here[1]。
值得注意的是,(抱歉,没有 mathJax
grumble 很难写方程)
I_x[x,y] = (A[x-1, y] - A[x+1, y]) / 2 # Equation 19
这在您的示例中减少为 np.zeros((10,10))
,这会导致后续问题:
G = sum([[I_x**2, I_x * I_y],[I_x * I_y, I_y**2]], axis = (2,3)) # Equation 23
由于 I_x
为零,这意味着 G
的形式为
G = [[0, 0], [0, I_y**2]]
到处都是奇异矩阵。由于需要反转,求解器卡住了。
之后发生的事情很难理解(我无法充分阅读 c
以深入研究 openCV
核心代码),但根据文档似乎跳过了奇异矩阵calcOpticalFlowPyrLK
的 minEigThreshold
参数。这可能意味着您的输出是缓冲区垃圾,或者至少是缓冲区垃圾的某种高斯混合。
这也是为什么@JulioDanielReyes 在添加噪声参数时能够得到响应的原因 - 这添加的 I_x
项足以使 G
非奇异。
参考:
[1] Lucas Kanade 特征跟踪器的金字塔式实现
算法描述,Jean-Yves Bouguet
cv2.calcOpticalFlowFarneback
似乎在自然图像上工作正常,但如果我在简单的合成示例上尝试它,例如下面的那个,它认为没有流量:
import cv2
import numpy as np
a = np.zeros((10, 10), dtype=np.uint8); a[1:4] = 127; a[2] = 255; a
等于
array([[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[127, 127, 127, 127, 127, 127, 127, 127, 127, 127],
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[127, 127, 127, 127, 127, 127, 127, 127, 127, 127],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=uint8)
b = np.roll(a, 1, 0); b
等于
array([[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[127, 127, 127, 127, 127, 127, 127, 127, 127, 127],
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[127, 127, 127, 127, 127, 127, 127, 127, 127, 127],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=uint8)
流量:
flow = cv2.calcOpticalFlowFarneback(a, b, pyr_scale=0.5, levels=3, winsize=15, iterations=3, poly_n=5, poly_sigma=1.2, flags=0)
本质上是0,因为
np.abs(flow).max()
计算为
1.3305091e-13
我尝试了不同的 winsize
值,结果相似。
为什么会这样?还有其他参数可以更好地发挥作用吗?
(我的 OpenCV 版本是 2.4.8。版本 3 需要添加 None
作为第三个参数,我相信)
我不知道这是否会回答你的问题,但除了 winsize
太大之外,算法很难知道在这样的规则下移动的方向 (left/right)图.
尝试添加一些噪音,例如a[4,4] += 1;
在调用roll之前,你会看到很大的不同。
编辑:添加了我的结果
print(np.abs(flow).max())
无噪音:
winsize 15: 1.33051e-13
winsize 2: 6.00387e-11
噪声 1:
# a[4,4] += 1;
winsize 15: 0.00332422
winsize 2: 1.82871
噪音 2:
# noise = np.round(np.random.random(a.shape) * 2.0).astype(np.int8)
# a = a + noise;
winsize 15: 0.207728
winsize 2: 324.527
原因是等式 19、20、23 和 25 中的 here[1]。
值得注意的是,(抱歉,没有 mathJax
grumble 很难写方程)
I_x[x,y] = (A[x-1, y] - A[x+1, y]) / 2 # Equation 19
这在您的示例中减少为 np.zeros((10,10))
,这会导致后续问题:
G = sum([[I_x**2, I_x * I_y],[I_x * I_y, I_y**2]], axis = (2,3)) # Equation 23
由于 I_x
为零,这意味着 G
的形式为
G = [[0, 0], [0, I_y**2]]
到处都是奇异矩阵。由于需要反转,求解器卡住了。
之后发生的事情很难理解(我无法充分阅读 c
以深入研究 openCV
核心代码),但根据文档似乎跳过了奇异矩阵calcOpticalFlowPyrLK
的 minEigThreshold
参数。这可能意味着您的输出是缓冲区垃圾,或者至少是缓冲区垃圾的某种高斯混合。
这也是为什么@JulioDanielReyes 在添加噪声参数时能够得到响应的原因 - 这添加的 I_x
项足以使 G
非奇异。
参考:
[1] Lucas Kanade 特征跟踪器的金字塔式实现 算法描述,Jean-Yves Bouguet