[英]Why does the output contain only 2 values but not the displacement for the entire image?
我已經在這里停留了一段時間。 我無法理解使用Lucas Kanade方法計算沿x軸和y軸的位移矢量時我做錯了什么。
我按照上面的Wikipedia鏈接中的說明實施了它。 這是我所做的:
import cv2
import numpy as np
img_a = cv2.imread("./images/1.png",0)
img_b = cv2.imread("./images/2.png",0)
# Calculate gradient along x and y axis
ix = cv2.Sobel(img_a, cv2.CV_64F, 1, 0, ksize = 3, scale = 1.0/3.0)
iy = cv2.Sobel(img_a, cv2.CV_64F, 0, 1, ksize = 3, scale = 1.0/3.0)
# Calculate temporal difference between the 2 images
it = img_b - img_a
ix = ix.flatten()
iy = iy.flatten()
it = -it.flatten()
A = np.vstack((ix, iy)).T
atai = np.linalg.inv(np.dot(A.T,A))
atb = np.dot(A.T, it)
v = np.dot(np.dot(np.linalg.inv(np.dot(A.T,A)),A.T),it)
print(v)
這段代碼可以正常運行,但是會打印2個值的數組! 我曾期望v
矩陣的大小與圖像的大小相同。 為什么會這樣? 我做錯了什么?
PS:我知道有一些直接可用於OpenCV的方法,但是我想自己寫這個簡單的算法(也在上面共享的Wikipedia鏈接中給出)。
為了正確計算盧卡斯-坎納德(Lucas-Kanade)光流估計,您需要使用每個像素的鄰域信息,而不是整個圖像的像素,求解兩個方程組。
這是配方(符號指的是Wikipedia頁面上使用的符號):
使用任何方法(Sobel可以,我更喜歡高斯導數)計算第一張圖像(OP中的ix
, iy
)的圖像梯度( A )。
ix = cv2.Sobel(img_a, cv2.CV_64F, 1, 0, ksize = 3, scale = 1.0/3.0) iy = cv2.Sobel(img_a, cv2.CV_64F, 0, 1, ksize = 3, scale = 1.0/3.0)
計算結構張量( A T WA ): Axx = ix * ix
, Axy = ix * iy
, Ayy = iy * iy
。 這三個圖像中的每一個都必須使用高斯濾鏡進行平滑處理(這是開窗)。 例如,
Axx = cv2.GaussianBlur(ix * ix, (0,0), 5) Axy = cv2.GaussianBlur(ix * iy, (0,0), 5) Ayy = cv2.GaussianBlur(iy * iy, (0,0), 5)
這三個圖像共同形成結構張量,該結構張量是每個像素處的2x2對稱矩陣。 對於(i,j)
處的像素,矩陣為:
| Axx(i,j) Axy(i,j) | | Axy(i,j) Ayy(i,j) |
通過減去兩個圖像(在OP中為it
)來計算時間梯度( b )。
it = img_b - img_a
計算A T Wb : Abx = ix * it
, Aby = iy * it
,並使用與上述相同的高斯濾波器對這兩個圖像進行平滑處理。
Abx = cv2.GaussianBlur(ix * it, (0,0), 5) Aby = cv2.GaussianBlur(iy * it, (0,0), 5)
計算A T WA (對稱正定矩陣)的逆並乘以A T Wb 。 注意,該逆是每個像素處的2x2矩陣,而不是整個圖像。 您可以將其寫為對圖像Axx
, Axy
, Ayy
, Abx
和Aby
一組簡單算術運算。
矩陣A T WA的逆矩陣為:
| Ayy -Axy | | -Axy Axx | / ( Axx*Ayy - Axy*Axy )
所以你可以寫解決方案為
norm = Axx*Ayy - Axy*Axy vx = ( Ayy * Abx - Axy * Aby ) / norm vy = ( Axx * Aby - Axy * Abx ) / norm
如果圖像是自然的,它將至少有一點點噪點,並且norm
不會為零。 但是對於人工圖像, norm
可以為零,這意味着您不能將其除以零。 只需向其添加一個小值即可避免除以零錯誤: norm += 1e-6
。
選擇高斯濾波器的大小是在精度和允許的運動速度之間的折衷:較大的濾波器將產生較不精確的結果,但將在圖像之間的較大偏移下起作用。
通常,僅在矩陣A T WA的兩個特征值足夠大的情況下評估vx
和vy
(如果至少一個小,則結果不准確或可能錯誤)。
使用PyDIP (公開:我是作者),這非常容易,因為它支持在每個像素處都有矩陣的圖像。 您可以按照以下步驟進行操作:
import PyDIP as dip
img_a = dip.ImageRead("./images/1.png")
img_b = dip.ImageRead("./images/2.png")
A = dip.Gradient(img_a, [1.0])
b = img_b - img_a
ATA = dip.Gauss(A * dip.Transpose(A), [5.0])
ATb = dip.Gauss(A * b, [5.0])
v = dip.Inverse(ATA) * ATb
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.