Lucas-Kanade Optical Flow
You are given image derivatives for a window of pixels and need to compute the Lucas-Kanade optical flow.
Lucas-Kanade assumes constant flow within a local window, creating an overdetermined system:
Ix1Ix2⋮Iy1Iy2⋮(uv)=−It1It2⋮
Or in matrix form: Av=b where v=(u,v)T
Solve using least squares (normal equations): ATAv=ATb
The 2×2 system ATA can be solved using Cramer's rule or matrix inversion.
Example:
window = [(1, 0, -1), (0, 1, -1), (1, 1, -2)]
(1.0, 1.0)
Building the normal equations:
- A = [[1, 0], b = [-(-1)] = [1] [0, 1], [-(-1)] [1] [1, 1]] [-(-2)] [2]
A^T A = [[1²+0²+1², 1×0+0×1+1×1], = [[2, 1], [0×1+1×0+1×1, 0²+1²+1²]] [1, 2]]
A^T b = [1×1 + 0×1 + 1×2] = [3] [0×1 + 1×1 + 1×2] [3]
Solving [2,1; 1,2] × [u,v]^T = [3,3]:
- det = 2×2 - 1×1 = 3
- u = (2×3 - 1×3) / 3 = 3/3 = 1.0
- v = (2×3 - 1×3) / 3 = 3/3 = 1.0
Result: (1.0, 1.0)
Constraints:
- window: list of (Ix, Iy, It) tuples for each pixel in window
- Return flow (u, v) rounded to 4 decimal places
- If the system is singular (det ≈ 0), return (0.0, 0.0)
Here’s a compact “how to think about it” guide tailored to your coding problem.
1. Background Knowledge
Optical flow describes the apparent 2D motion of image intensity patterns between two frames, usually represented as a vector field (u(x,y),v(x,y)) giving horizontal and vertical motion per pixel. The core assumption is brightness constancy: a point keeps the same intensity as it moves, so I(x,y,t)=I(x+u,y+v,t+1).
By linearizing this assumption for small motions, you get the optical flow constraint equation:
Ixu+Iyv+It=0where Ix,Iy are spatial derivatives and It is the temporal derivative. This is one equation with two unknowns (u,v) per pixel, so it is underdetermined.
Lucas–Kanade resolves this by assuming constant flow inside a small window around the pixel. That means all pixels in the window share the same (u,v), giving many linear equations of the form Ixiu+Iyiv=−Iti. Stacking them yields an overdetermined linear system A\mathbf{v}=b that can be solved in a least-squares sense.
2. Algorithm / General Approach
For a given window:
- Collect image derivatives (Ixi,Iyi,Iti) for each pixel in the window.
- Form the matrix A whose rows are (Ixi,Iyi), and vector b whose entries are −Iti.
- Solve the least squares problem:
which leads to the normal equations:
(ATA)v=ATb- Since ATA is 2×2, directly solve for v=(u,v)T via closed-form formulas (Cramer’s rule or explicit inverse).
Conceptually, your task is: “Given these derivative samples, compute the best-fitting constant motion vector (u,v) over the window.”
3. Step-by-Step Strategy
Assume the problem gives you the derivatives for all pixels in a window, e.g. as arrays Ix, Iy, It or as a list of triplets.
- Accumulate the components of ATA and ATb
Let each sample i in the window have derivatives Ixi,Iyi,Iti.
Build the scalar sums:
- Sxx=\sumiIxi2
- Syy=\sumiIyi2
- Sxy=\sumiIxiIyi
- Sxt=\sumiIxiIti
- Syt=\sumiIyiIti
Then:
- ATA=\begin{pmatrix} S_{xx} & S_{xy} \ S_{xy} & S_{yy} \end{pmatrix}$
- AT\mathbf{b}=−(SxtSyt)
- Solve the 2×2 linear system
You need to solve:
(SxxSxySxySyy)(uv)=−(SxtSyt)Compute the determinant:
Δ=SxxSyy−Sxy2If ∣Δ∣ is sufficiently large (non-degenerate), you can use:
det = S_xx * S_yy - S_xy * S_xy
u = (-S_xt * S_yy + S_xy * S_yt) / det
v = ( S_xx * (-S_yt) - S_xy * (-S_xt)) / det
This is just the analytic solution of the 2×2 system.
- Return the flow vector
Return (u,v) as the optical flow for that window (often assigned to the center pixel).
4. Common Pitfalls
-
Ill-conditioned ATA (aperture problem):
-
If all gradients are in one direction or the region is flat (little texture), Δ is near zero and the system is not reliable.
-
In practice, check ∣Δ∣ against a threshold; if too small, treat the flow as undefined or (0,0).
-
Sign mistakes:
-
Remember that b=−It, so AT\mathbf{b}=−(SxtSyt).
-
A common bug is forgetting the minus sign, which flips motion direction.
-
Overflow / precision:
-
For large windows or many pixels, sums like Sxx can become large; use a suitable numeric type (e.g., float64).
-
Assuming the method handles large motion:
-
Lucas–Kanade in this basic form assumes small motion; large displacements require pyramids or warping, which is beyond this specific coding task.
5. Time & Space Complexity
Let N be the number of pixels in the window.
-
Time complexity (per window):
-
Computing all sums: O(N).
-
Solving the 2×2 system: O(1).
-
Total: O(N) per window.
-
Space complexity (per window):
-
If derivatives are given as input and you only store accumulated sums and the flow vector, you need O(1) extra space.
-
If you store derivatives for all pixels in the window yourself, that is O(N) input storage, but the algorithmic extra space is still O(1).
Use this structure to write clean, incremental code: accumulate the five sums, form the 2×2 system, check the determinant, solve for (u,v), and handle the degenerate case carefully.