簡體   English   中英

為什么輸出只包含2個值,而不包含整個圖像的位移?

[英]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頁面上使用的符號):

  1. 使用任何方法(Sobel可以,我更喜歡高斯導數)計算第一張圖像(OP中的ixiy )的圖像梯度( 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) 
  2. 計算結構張量( A T WA ): Axx = ix * ixAxy = ix * iyAyy = 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) | 
  3. 通過減去兩個圖像(在OP中為it )來計算時間梯度( b )。

     it = img_b - img_a 
  4. 計算A T WbAbx = ix * itAby = iy * it ,並使用與上述相同的高斯濾波器對這兩個圖像進行平滑處理。

     Abx = cv2.GaussianBlur(ix * it, (0,0), 5) Aby = cv2.GaussianBlur(iy * it, (0,0), 5) 
  5. 計算A T WA (對稱正定矩陣)的逆並乘以A T Wb 注意,該逆是每個像素處的2x2矩陣,而不是整個圖像。 您可以將其寫為對圖像AxxAxyAyyAbxAby一組簡單算術運算。

    矩陣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的兩個特征值足夠大的情況下評估vxvy (如果至少一個小,則結果不准確或可能錯誤)。


使用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM