Delphi for realizing Lucas-kanade optical flow calculation

Source: Internet
Author: User
Tags cos min sin

Geo.cra[at]gmail[dot]com
}
Unit opticalflowlk;

Interface

Uses
Math, Windows, sysutils, variants, Classes, Graphics, Unitypes, Colorconv;

Type

TOPTICALFLOWLK = Class
Private
Imageold, Imagenew:ttriplelongintarray;
Imagegray, DX, dy, dxy:tdoublelongintarray;
Eigenvalues:tdoubleextendedarray;
Wbpoint:tdoublebooleanarray;
Height, Width, L, Radiox, Radioy:longint;
Procedure Cornerdetect (Swidth, Sheight:longint; quality:extended);
Procedure Makepyramid (var Images:ttriplelongintarray; Swidth, Sheight, Sl:longint);
Public
Frame:tbitmap;
Features:tsinglepointinfoarray;
Featurecount, Supportcount:longint;
Speed, radio:extended;
Procedure Init (Swidth, Sheight, Sl:longint);
Procedure Initfeatures (FRAMES:TBITMAP);
Procedure Calopticalflowlk (FRAMES:TBITMAP);
destructor Destroy; Override
End

Implementation

Procedure Topticalflowlk.cornerdetect (Swidth, Sheight:longint; quality:extended);
Var
I, J, Fi, Fj:longint;
A, B, C, Sum, minaccept, maxeigenvalue:extended;
Begin
Featurecount: = 0;
{
The following methods are introduced by good Feature to track
J. Shi and C. Tomasi "Good Features to Track", CVPR 94
}
For I: = 1 to SWidth-2 do
for J: = 1 to SHeight-2 do begin
Dx[i, j]: = Imagegray[i-1, j-1] + 2 * imagegray[i-1, J] + imagegray[i-1, j + 1]
-(imagegray[i + 1, j-1] + 2 * imagegray[i + 1, j] + Imagegray[i + 1, j + 1]);
Dy[i, j]: = Imagegray[i-1, J + 1] + 2 * imagegray[i, J + 1] + Imagegray[i + 1, j + 1]
-(Imagegray[i-1, j-1] + 2 * imagegray[i, j-1] + imagegray[i + 1, j-1]);
Dxy[i, j]: = Imagegray[i + 1, j-1] + imagegray[i-1, j + 1]
-(Imagegray[i-1, j-1] + imagegray[i + 1, j + 1]);
End
{To obtain DX, Dy, Dxy of Sobel operator
Dx:
|1 0-1|
0-2|
|1 0-1|
Dy:
|-1-2 -1|
| 0 0 0|
| 1 2 1|
Dxy
|-1 0 1|
| 0 0 0|
| 1 0-1|}
Maxeigenvalue: = 0;
For I: = 2 to SWidth-3 do
for j: = 2 to sHeight-3 do begin
A: = 0; B: = 0; c: = 0;
for fi: = I-1 to i + 1 do
For FJ: = J-1 to J + 1 do begin
A: = A + SQR (Dx[fi, FJ]);
B: = B + Dxy[fi, FJ];
c: = C + sqr (Dy[fi, FJ]);
End
A: = A/2; c: = C/2;
Eigenvalues[i, j]: = (A + c-sqrt (a-c) * (A-C) + b * b));
If Eigenvalues[i, J] > Maxeigenvalue then maxeigenvalue: = Eigenvalues[i, j];
End
{Fetch matrix
|∑dx*dx∑dxy|
m=| |
|∑dxy∑dy*dy|
The eigenvalues
Λ=∑DX*DX +∑dy*dy-((∑dx*dx+∑dy*dy) ^2-4* (∑dx*dx *∑dy*dy-∑dxy *∑DXY)) ^1/2}
Minaccept: = Maxeigenvalue * Quality;
{Set minimum allowable threshold}

For I: = 8 to SWidth-9 do
For J: = 8 to SHeight-9 do
If Eigenvalues[i, J] > Minaccept THEN BEGIN
Wbpoint[i, j]: = true;
INC (Featurecount);
End Else
Wbpoint[i, j]: = false;

For I: = 8 to SWidth-9 do
For J: = 8 to SHeight-9 do
If Wbpoint[i, j] then BEGIN
Sum: = Eigenvalues[i, j];
for fi: = i-8 to i + 8 do begin
For FJ: = j-8 to J + 8 do
If Sqr (fi-i) + SQR (fj-j) <=
if (Eigenvalues[fi, FJ] >= sum) and ((fi <> i) or (FJ <> J)) and (Wbpoint[fi, FJ]) THEN BEGIN
Wbpoint[i, j]: = false;
Dec (Featurecount);
Break
End
If not Wbpoint[i, j] then break;
End
End
{Suppressing false corners with non-maximized suppression}

SetLength (Features, Featurecount); Fi: = 0;
For I: = 8 to SWidth-9 do
For J: = 8 to SHeight-9 do
If Wbpoint[i, j] then BEGIN
FEATURES[FI]. info.x: = i;
FEATURES[FI]. INFO.Y: = j;
FEATURES[FI]. Index: = 0;
Inc. (FI);
End
{Output final point sequence}
End

Procedure Topticalflowlk.init (Swidth, Sheight, Sl:longint);
Begin
Width: = Swidth; Height: = Sheight; L: = SL;
SetLength (Imageold, Width, Height, L);
SetLength (Imagenew, Width, Height, L);
Frame: = tbitmap.create;
Frame.width: = Width; Frame.height: = Height;
Frame.pixelformat: = Pf24bit;
SetLength (Imagegray, Width, Height);
SetLength (eigenvalues, Width, Height);
SetLength (DX, Width, Height);
SetLength (Dy, Width, Height);
SetLength (DXY, Width, Height);
SetLength (Wbpoint, Width, Height);
Featurecount: = 0;
End

Procedure Topticalflowlk.makepyramid (var Images:ttriplelongintarray; Swidth, Sheight, Sl:longint);
Var
I, J, K, II, JJ, Nwidth, nheight, Owidth, Oheight:longint;
Begin
{Generate pyramid image}
Owidth: = Swidth; Oheight: = Sheight;
For k: = 1 to SL-1 do begin
Nwidth: = (owidth + 1) shr 1; Nheight: = (oheight + 1) shr 1;
For I: = 1 to NWidth-2 do begin
II: = i SHL 1;
for J: = 1 to NHeight-2 do begin
JJ: = j SHL 1;
Images[i, J, K]: = (Images[ii, JJ, K-1] SHL 2 +
Images[ii-1, JJ, K-1] SHL 1 + images[ii + 1, JJ, K-1] SHL 1 + images[ii, jj-1, k-1] SHL 1 + images[ii, JJ + 1, K -1] SHL 1 +
Images[ii-1, Jj-1, k-1] + images[ii + 1, jj-1, k-1] + images[ii-1, JJ + 1, k-1] + images[ii + 1, JJ + 1, K- 1] SHR 4;
{Gauss principle, SHL right shift, SHR left shift}
End
End
For I: = 1 to NWidth-2 do begin
II: = i SHL 1;
Images[i, 0, K]: = (images[ii, 0, k-1] SHL 2 +
Images[ii-1, 0, k-1] SHL 1 + images[ii + 1, 0, k-1] SHL 1 + images[ii, 0, k-1] SHL 1 + images[ii, 1, k-1] SHL 1 +
Images[ii-1, 0, k-1] + images[ii + 1, 0, k-1] + images[ii-1, 1, k-1] + images[ii + 1, 1, k-1]) SHR 4;
Images[i, NHeight-1, K]: = (images[ii, oHeight-1, K-1] SHL 2 +
Images[ii-1, OHeight-1, k-1] SHL 1 + images[ii + 1, oHeight-1, k-1] SHL 1 + images[ii, oHeight-2, k-1] SHL 1 + Images[ii, oHeight-1, k-1] SHL 1 +
Images[ii-1, OHeight-2, k-1] + images[ii + 1, oHeight-2, k-1] + images[ii-1, oHeight-1, k-1] + images[ii + 1, OHeight-1, K-1]) SHR 4;
End
{processing the bottom of}
for J: = 1 to NHeight-2 do begin
JJ: = j SHL 1;
Images[0, J, K]: = (images[0, JJ, K-1] SHL 2 +
Images[0, JJ, K-1] SHL 1 + images[1, JJ, K-1] SHL 1 + images[0, jj-1, k-1] SHL 1 + images[0, JJ + 1, k-1] SHL 1 +
Images[0, Jj-1, k-1] + images[1, jj-1, k-1] + images[0, JJ + 1, k-1] + images[1, JJ + 1, k-1] SHR 4;
Images[nwidth-1, J, K]: = (images[owidth-1, JJ, K-1] SHL 2 +
Images[owidth-2, JJ, K-1] SHL 1 + images[owidth-1, JJ, K-1] SHL 1 + images[owidth-1, jj-1, k-1] SHL 1 + imag Es[owidth-1, JJ + 1, k-1] SHL 1 +
Images[owidth-2, Jj-1, k-1] + images[owidth-1, jj-1, k-1] + images[owidth-2, JJ + 1, k-1] + images[owidth -1, JJ + 1, k-1] SHR 4;
End
{Processing left and right sides}
Images[0, 0, K]: = (images[0, 0, k-1] SHL 2 +
Images[0, 0, k-1] SHL 1 + images[1, 0, k-1] SHL 1 + images[0, 0, k-1] SHL 1 + images[0, 1, k-1] SHL 1 +
Images[0, 0, k-1] + images[1, 0, k-1] + images[0, 1, k-1] + images[1, 1, k-1]) SHR 4;
{process left Upper point}
Images[0, NHeight-1, K]: = (images[0, oHeight-1, K-1] SHL 2 +
Images[0, OHeight-1, k-1] SHL 1 + images[1, oHeight-1, k-1] SHL 1 + images[0, oHeight-2, k-1] SHL 1 + images[0 , OHeight-1, k-1] SHL 1 +
Images[0, OHeight-2, k-1] + images[1, oHeight-2, k-1] + images[0, oHeight-1, k-1] + images[1, oHeight-1, K- 1] SHR 4;
{process left lower point}
Images[nwidth-1, 0, K]: = (images[owidth-1, 0, k-1] SHL 2 +
Images[owidth-2, OHeight-1, k-1] SHL 1 + images[owidth-1, oHeight-1, k-1] SHL 1 + images[owidth-1, Oheight- 1, K-1] SHL 1 + images[owidth-1, oHeight-1, k-1] SHL 1 +
Images[owidth-2, OHeight-1, k-1] + images[owidth-1, oHeight-1, k-1] + images[owidth-2, oHeight-1, k-1] + Images[owidth-1, OHeight-1, K-1]) SHR 4;
{Handling the top right point}
Images[nwidth-1, NHeight-1, K]: = (images[owidth-1, oHeight-1, K-1] SHL 2 +
Images[owidth-2, OHeight-1, k-1] SHL 1 + images[owidth-1, oHeight-1, k-1] SHL 1 + images[owidth-1, Oheight- 2, K-1] SHL 1 + images[owidth-1, oHeight-1, k-1] SHL 1 +
Images[owidth-2, OHeight-2, k-1] + images[owidth-1, oHeight-2, k-1] + images[owidth-2, oHeight-1, k-1] + Images[owidth-1, OHeight-1, K-1]) SHR 4;
{Handle lower-right point}
End
End

Procedure Topticalflowlk.initfeatures (FRAMES:TBITMAP);
Var
I, J:longint;
Line:prgbtriple;
Begin
Setstretchbltmode (Frame.Canvas.Handle, Stretch_halftone);
StretchBlt (Frame.Canvas.Handle, 0, 0, Width, Height, Frames.Canvas.Handle, 0, 0, frames.width, Frames.height, srccopy);
For I: = 0 to Height-1 do begin
Line: = Frame.scanline[i];
For J: = 0 to Width-1 do begin
Imageold[j, I, 0]: = (Line^.rgbtblue * one + line^.rgbtgreen * + line^.rgbtred *) div 100;
Imagegray[j, I]: = imageold[j, I, 0];
INC (line);
End
End
{Initializing the first layer of the pyramid image imageold[x,y,0]}
Makepyramid (Imageold, Width, Height, L);
{Generate pyramid image}
Cornerdetect (Width, Height, 0.01);
{Strong Corner detection}
End

Procedure Topticalflowlk.calopticalflowlk (FRAMES:TBITMAP);
Var
I, J, Fi, FJ, K, LL, M, DX, DY, GX, GY, PX, PY, KX, KY, ed, EDC, Nwidth, Nheight:longint;
NX, NY, VX, VY, A, B, C, D, E, F, ik:extended;
Ix, Iy:tdoubleextendedarray;
Line:prgbtriple;
Change:boolean;
Begin
Setstretchbltmode (Frame.Canvas.Handle, Stretch_halftone);
StretchBlt (Frame.Canvas.Handle, 0, 0, Width, Height, Frames.Canvas.Handle, 0, 0, frames.width, Frames.height, srccopy);
For I: = 0 to Height-1 do begin
Line: = Frame.scanline[i];
For J: = 0 to Width-1 do begin
Imagenew[j, I, 0]: = (Line^.rgbtblue * one + line^.rgbtgreen * + line^.rgbtred *) div 100;
INC (line);
End
End
{Initializing the first layer of the pyramid image imagenew[x,y,0]}
Makepyramid (Imagenew, Width, Height, L);
{Generate pyramid image}
SetLength (Ix, 15, 15); SetLength (Iy, 15, 15);
{Request Differential image temp Array}
For M: = 0 to FeatureCount-1 do begin
{See algorithm details:
Jean-yves Bouguet "Pyramidal implementation of the Lucas Kanade Feature Tracker Description of the Algorithm"}
GX: = 0; GY: = 0;
for ll: = L-1 downto 0 DO begin
PX: = Features[m]. info.x SHR ll;
PY: = Features[m]. Info.y SHR ll;
{u-point corresponding to the current pyramid image: U[l]:=u/2^l}
Nwidth: = Width shr ll; Nheight: = Height shr ll;
A: = 0; B: = 0; C: = 0;
For I: = Max (px-7, 1) to min (px + 7, nWidth-2) do
for j: = Max (py-7, 1) to min (py + 7, nHeight-2) DO begin
Fi: = i-px + 7; FJ: = j-py + 7;
Ix[fi, FJ]: = (imageold[i + 1, J, LL]-Imageold[i-1, J, LL])/2;
Iy[fi, FJ]: = (Imageold[i, j + 1, ll]-Imageold[i, J-1, LL])/2;
A: = A + Ix[fi, FJ] * ix[fi, FJ]; B: = B + Ix[fi, FJ] * iy[fi, FJ];
c: = C + Iy[fi, FJ] * iy[fi, FJ];
End
{Calculate the 2-order matrix G:
| IX (x,y) *ix (x,y) IX (x,y) *iy (x,y) |
∑| Ix (x,y) *iy (x,y) Iy (x,y) *iy (x,y) |}
D: = A * C-b * B;
VX: = 0; VY: = 0; DX: = 0; DY: = 0;
If ABS (D) > 1E-8 THEN BEGIN
For k: = 1 do begin
E: = 0; F: = 0;
For I: = Max (px-7, 1) to min (px + 7, nWidth-2) do
for j: = Max (py-7, 1) to min (py + 7, nHeight-2) DO begin
Fi: = i-px + 7; FJ: = j-py + 7;
KX: = i + GX + dx; KY: = j + gy + dy;
If KX < 0 then KX: = 0; If KX > NWidth-1 then KX: = NWidth-1;
If KY < 0 then KY: = 0; If KY > nHeight-1 then KY: = nHeight-1;
Ik: = Imageold[i, J, LL]-Imagenew[kx, KY, LL];
E: = e + Ik * ix[fi, FJ];
F: = f + Ik * iy[fi, FJ];
End
{Calculate 2x1 order matrix B:
| Ik (x,y) *ix (x,y) |
∑| Ik (x,y) *iy (x,y) |}
NX: = (C * e-b * F)/D;
NY: = (B * e-a * F)/(d);
{Calculate Η=g^-1*b}
VX: = VX + NX; VY: = Vy + ny;
DX: = TRUNC (VX); DY: = Trunc (VY);
{Get relative motion vector D}
End
End
GX: = (GX + dx) SHL 1; GY: = (gy + dy) SHL 1;
{Get the next layer of the predictive motion vector g}
End
GX: = GX Div 2; GY: = Gy div 2;
PX: = px + GX; PY: = py + gy;
FEATURES[M]. info.x: = px;
FEATURES[M]. INFO.Y: = py;
FEATURES[M]. Vector.x: = GX;
FEATURES[M]. VECTOR.Y: = Gy;
Then features[m] if (px > Width-1) or (px < 0) or (py > Height-1) or (py < 0). Index: = 1;
{Loss of Feature point processing}
End

For k: = 0 to L-1 do begin
Nwidth: = Width shr k; Nheight: = Height shr k;
For I: = 0 to NWidth-1 do
For J: = 0 to NHeight-1 do
Imageold[i, J, K]: = Imagenew[i, J, K];
End
{Copy J to i}
Repeat
Change: = false;
For I: = 0 to FeatureCount-1 do begin
If Features[i]. Index = 1 Then
For J: = i + 1-FeatureCount-1 do begin
Features[j-1]: = Features[j];
Change: = true;
End
If change then a break;
End
If change then Dec (Featurecount);
Until not change;

SetLength (Features, Featurecount);
{Remove missing feature points}
Speed: = 0; Radio: = 0; Radiox: = 0; Radioy: = 0;
If featurecount > 0 THEN BEGIN
Supportcount: = 0;
For I: = 0 to FeatureCount-1 do
if (features[i). Vector.x <> 0) and (Features[i]. VECTOR.Y <> 0) THEN BEGIN
Radiox: = Radiox + features[i]. vector.x;
Radioy: = Radioy + features[i]. VECTOR.Y;
Speed: = Speed + sqrt (SQR (features[i). vector.x) + SQR (Features[i]. VECTOR.Y));
INC (Supportcount);
End
If supportcount > 0 THEN BEGIN
Speed: = Speed/supportcount; *0.0352778;
Radio: = ArcTan2 (Radioy, Radiox);
End
End
{Calculate average speed and overall orientation}
Frame.Canvas.Pen.Style: = Pssolid;
Frame.Canvas.Pen.Width: = 1;
Frame.Canvas.Pen.Color: = Cllime;
Frame.Canvas.Brush.Style: = Bsclear;
For I: = 0 to FeatureCount-1 do
Frame.Canvas.Ellipse (Features[i]. Info.x-4, Features[i]. Info.y-4, Features[i]. Info.x + 4, features[i]. INFO.Y + 4);
{Identifying feature points with green circles}
Frame.Canvas.Pen.Color: = Clyellow;
For I: = 0 to FeatureCount-1 do begin
Frame.Canvas.MoveTo (Features[i]. Info.x-features[i]. Vector.x, Features[i]. Info.y-features[i]. VECTOR.Y);
Frame.Canvas.LineTo (Features[i]. Info.x, Features[i]. INFO.Y);
End
{The motion vector is represented by a yellow line}
if (Supportcount > 0) and (Speed > 3) THEN BEGIN
Frame.Canvas.Pen.Style: = Pssolid;
Frame.Canvas.Pen.Width: = 6;
Frame.Canvas.Pen.Color: = Clwhite;
Frame.Canvas.Ellipse (width div 2-100, height div 2-100, Width div 2 +, height div 2 + 100);
Frame.Canvas.MoveTo (Width Div 2, Height Div 2);
Frame.Canvas.Pen.Color: = Clblue;
Frame.Canvas.LineTo (Width Div 2 + trunc (* * Cos (Radio)), Height Div 2 + trunc (* Sin (Radio)));
Frame.Canvas.Pen.Style: = Psclear;
Frame.Canvas.Brush.Style: = Bssolid;
Frame.Canvas.Brush.Color: = clred;
Frame.Canvas.Ellipse (Width div 2 + trunc (* * Cos (Radio))-8, Height Div 2 + trunc (* Sin (Radio))-8, Width Div 2 + tr UNC (* Cos (Radio)) + 8, Height Div 2 + trunc (Radio) + 8);
End
End

destructor Topticalflowlk.destroy;
Begin
SetLength (imageold, 0);
SetLength (imagenew, 0);
SetLength (Imagegray, 0);
SetLength (eigenvalues, 0);
SetLength (DX, 0);
SetLength (dy, 0);
SetLength (DXY, 0);
SetLength (wbpoint, 0);
inherited;
End

End.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.