2014-05-22 16:23:41 +02:00
|
|
|
|
//*****************************************************************
|
2013-04-09 12:41:27 +02:00
|
|
|
|
// Delphi-OpenCV Demo
|
|
|
|
|
// Copyright (C) 2013 Project Delphi-OpenCV
|
|
|
|
|
// ****************************************************************
|
|
|
|
|
// Contributor:
|
2014-05-22 16:23:41 +02:00
|
|
|
|
// Laentir Valetov
|
2013-04-09 12:41:27 +02:00
|
|
|
|
// email:laex@bk.ru
|
|
|
|
|
// ****************************************************************
|
|
|
|
|
// You may retrieve the latest version of this file at the GitHub,
|
|
|
|
|
// located at git://github.com/Laex/Delphi-OpenCV.git
|
|
|
|
|
// ****************************************************************
|
|
|
|
|
// The contents of this file are used with permission, subject to
|
|
|
|
|
// the Mozilla Public License Version 1.1 (the "License"); you may
|
|
|
|
|
// not use this file except in compliance with the License. You may
|
|
|
|
|
// obtain a copy of the License at
|
|
|
|
|
// http://www.mozilla.org/MPL/MPL-1_1Final.html
|
|
|
|
|
//
|
|
|
|
|
// Software distributed under the License is distributed on an
|
|
|
|
|
// "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
|
|
|
// implied. See the License for the specific language governing
|
|
|
|
|
// rights and limitations under the License.
|
2014-05-22 16:23:41 +02:00
|
|
|
|
//*******************************************************************
|
|
|
|
|
|
2013-04-05 13:36:47 +02:00
|
|
|
|
program cv_CalcOpticalFlowPyrLK;
|
|
|
|
|
|
2013-04-09 12:41:27 +02:00
|
|
|
|
{$APPTYPE CONSOLE}
|
|
|
|
|
{$POINTERMATH ON}
|
|
|
|
|
|
2013-04-05 13:36:47 +02:00
|
|
|
|
{$R *.res}
|
|
|
|
|
|
|
|
|
|
uses
|
|
|
|
|
System.SysUtils,
|
2014-05-22 16:23:41 +02:00
|
|
|
|
ocv.highgui_c,
|
|
|
|
|
ocv.core_c,
|
|
|
|
|
ocv.core.types_c,
|
|
|
|
|
ocv.imgproc_c,
|
|
|
|
|
ocv.imgproc.types_c,
|
|
|
|
|
ocv.tracking_c;
|
2013-04-05 13:36:47 +02:00
|
|
|
|
|
|
|
|
|
const
|
|
|
|
|
MAX_COUNT = 500;
|
|
|
|
|
|
2013-05-21 10:53:30 +02:00
|
|
|
|
var
|
2013-04-05 13:36:47 +02:00
|
|
|
|
image: pIplImage = nil;
|
|
|
|
|
grey: pIplImage = nil;
|
|
|
|
|
prev_grey: pIplImage = nil;
|
|
|
|
|
pyramid: pIplImage = nil;
|
|
|
|
|
prev_pyramid: pIplImage = nil;
|
|
|
|
|
swap_temp: pIplImage;
|
|
|
|
|
win_size: longint = 10;
|
|
|
|
|
corners: pCvPoint2D32f;
|
|
|
|
|
prev_features: pCvPoint2D32f;
|
|
|
|
|
swap_points: pCvPoint2D32f;
|
|
|
|
|
status: array [0 .. MAX_COUNT] of TCVChar;
|
|
|
|
|
count: longint = 0;
|
|
|
|
|
need_to_init: longint = 0;
|
|
|
|
|
night_mode: longint = 0;
|
|
|
|
|
flags: longint = 0;
|
|
|
|
|
add_remove_pt: longint = 0;
|
|
|
|
|
pt: TCvPoint;
|
|
|
|
|
k: longint;
|
|
|
|
|
{ ----------------------- }
|
|
|
|
|
capture: PCvCapture;
|
|
|
|
|
frame: pIplImage;
|
|
|
|
|
|
|
|
|
|
c: Integer;
|
|
|
|
|
|
|
|
|
|
procedure main_cycle();
|
|
|
|
|
var
|
|
|
|
|
cs: TCvSize;
|
|
|
|
|
eig, temp: pIplImage;
|
|
|
|
|
quality, min_distance, dx, dy: double;
|
|
|
|
|
i: Integer;
|
|
|
|
|
begin
|
|
|
|
|
frame := cvQueryFrame(capture);
|
|
|
|
|
if not(assigned(frame)) then
|
|
|
|
|
exit;
|
|
|
|
|
|
|
|
|
|
if not(assigned(image)) then
|
|
|
|
|
begin
|
|
|
|
|
// * allocate all the buffers
|
|
|
|
|
cs.width := frame.width;
|
|
|
|
|
cs.height := frame.height;
|
|
|
|
|
image := cvCreateImage(cs, 8, 3);
|
|
|
|
|
image.Origin := frame.Origin;
|
|
|
|
|
grey := cvCreateImage(cs, 8, 1);
|
|
|
|
|
prev_grey := cvCreateImage(cs, 8, 1);
|
|
|
|
|
pyramid := cvCreateImage(cs, 8, 1);
|
|
|
|
|
prev_pyramid := cvCreateImage(cs, 8, 1);
|
|
|
|
|
flags := 0;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
cvCopy(frame, image);
|
|
|
|
|
cvCvtColor(image, grey, CV_BGR2GRAY);
|
|
|
|
|
|
|
|
|
|
if (night_mode = 1) then
|
|
|
|
|
cvZero(image);
|
|
|
|
|
|
|
|
|
|
if (need_to_init = 1) then
|
|
|
|
|
begin
|
|
|
|
|
// * automatic initialization
|
|
|
|
|
eig := cvCreateImage(cvGetSize(grey), 32, 1);
|
|
|
|
|
temp := cvCreateImage(cvGetSize(grey), 32, 1);
|
|
|
|
|
quality := 0.101;
|
|
|
|
|
min_distance := 10.0;
|
|
|
|
|
|
|
|
|
|
count := MAX_COUNT;
|
|
|
|
|
cvGoodFeaturesToTrack(grey, eig, temp, corners, @count, quality, min_distance, nil, 3, 0, 0.04);
|
|
|
|
|
cvFindCornerSubPix(grey, corners, count, cvsize(win_size, win_size), cvsize(-1, -1),
|
|
|
|
|
cvTermCriteria(CV_TERMCRIT_ITER or CV_TERMCRIT_EPS, 20, 0.03));
|
|
|
|
|
cvReleaseImage(eig);
|
|
|
|
|
cvReleaseImage(temp);
|
|
|
|
|
|
|
|
|
|
add_remove_pt := 0;
|
|
|
|
|
end
|
|
|
|
|
else if (count > 0) then
|
|
|
|
|
begin
|
|
|
|
|
cvCalcOpticalFlowPyrLK(prev_grey, grey, prev_pyramid, pyramid, prev_features, corners, count,
|
|
|
|
|
cvsize(win_size, win_size), 3, @status, nil, cvTermCriteria(CV_TERMCRIT_ITER or CV_TERMCRIT_EPS, 20,
|
|
|
|
|
0.03), flags);
|
|
|
|
|
flags := flags or CV_LKFLOW_PYR_A_READY;
|
|
|
|
|
|
|
|
|
|
k := 0;
|
|
|
|
|
for i := 0 to count - 1 do
|
|
|
|
|
begin
|
|
|
|
|
if (add_remove_pt = 1) then
|
|
|
|
|
begin
|
|
|
|
|
dx := pt.x - corners[i].x;
|
|
|
|
|
dy := pt.y - corners[i].y;
|
|
|
|
|
|
|
|
|
|
if (dx * dx + dy * dy <= 25) then
|
|
|
|
|
begin
|
|
|
|
|
add_remove_pt := 0;
|
|
|
|
|
continue;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
if (status[i] = #0) then
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
corners[k] := corners[i];
|
|
|
|
|
inc(k);
|
|
|
|
|
cvCircle(image, cvPointFrom32f(corners[i]), 3, CV_RGB(0, 255, 0), -1, 8, 0);
|
|
|
|
|
end;
|
|
|
|
|
count := k;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
if ((add_remove_pt = 1) and (count < MAX_COUNT)) then
|
|
|
|
|
begin
|
|
|
|
|
corners[count] := cvPointTo32f(pt);
|
|
|
|
|
inc(count);
|
|
|
|
|
// newpoint -> points[1] + count - 1
|
|
|
|
|
// newpoint := corners[count - 1];
|
|
|
|
|
cvFindCornerSubPix(grey, @corners[count - 1], 1, cvsize(win_size, win_size), cvsize(-1, -1),
|
|
|
|
|
cvTermCriteria(CV_TERMCRIT_ITER or CV_TERMCRIT_EPS, 20, 0.030));
|
|
|
|
|
add_remove_pt := 0;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
CV_SWAP(prev_grey, grey, swap_temp);
|
|
|
|
|
CV_SWAP(prev_pyramid, pyramid, swap_temp);
|
|
|
|
|
CV_SWAP(prev_features, corners, swap_points);
|
|
|
|
|
|
|
|
|
|
need_to_init := 0;
|
|
|
|
|
{ visualize the camera image in the window }
|
|
|
|
|
cvShowImage('LkDemo', image);
|
|
|
|
|
end;
|
|
|
|
|
|
2013-04-18 08:34:16 +02:00
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> c<><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD>
|
2013-04-05 13:36:47 +02:00
|
|
|
|
procedure myMouseCallback(event: Integer; x: Integer; y: Integer; flags: Integer; param: pointer); cdecl;
|
|
|
|
|
begin
|
|
|
|
|
if assigned(image) then
|
|
|
|
|
case event of
|
|
|
|
|
CV_EVENT_MOUSEMOVE:
|
|
|
|
|
;
|
|
|
|
|
CV_EVENT_LBUTTONDOWN:
|
|
|
|
|
begin
|
|
|
|
|
pt := cvPoint(x, y);
|
|
|
|
|
add_remove_pt := 1;
|
|
|
|
|
end;
|
|
|
|
|
CV_EVENT_LBUTTONUP:
|
|
|
|
|
;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
begin
|
|
|
|
|
try
|
|
|
|
|
capture := cvCreateCameraCapture(CV_CAP_ANY);
|
|
|
|
|
Assert(assigned(capture));
|
|
|
|
|
cvNamedWindow('LkDemo', CV_WINDOW_AUTOSIZE);
|
|
|
|
|
cvSetMouseCallback('LkDemo', myMouseCallback);
|
|
|
|
|
|
|
|
|
|
corners := AllocMem(SizeOf(TCvPoint2D32f) * MAX_COUNT);
|
|
|
|
|
prev_features := AllocMem(SizeOf(TCvPoint2D32f) * MAX_COUNT);
|
|
|
|
|
|
|
|
|
|
while true do
|
|
|
|
|
begin
|
|
|
|
|
main_cycle;
|
|
|
|
|
c := cvWaitKey(33);
|
|
|
|
|
if c = 27 then
|
|
|
|
|
Break;
|
|
|
|
|
if c = Ord('r') then
|
|
|
|
|
need_to_init := 1;
|
|
|
|
|
if c = Ord('c') then
|
|
|
|
|
count := 0;
|
|
|
|
|
if c = Ord('n') then
|
|
|
|
|
night_mode := night_mode xor 1;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
cvReleaseCapture(capture);
|
|
|
|
|
cvReleaseImage(image);
|
|
|
|
|
cvDestroyAllWindows;
|
|
|
|
|
|
|
|
|
|
except
|
|
|
|
|
on E: Exception do
|
|
|
|
|
Writeln(E.ClassName, ': ', E.Message);
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
end.
|