Delphi-OpenCV/samples/LibDemo/cvExtractSURF/cv_ExtractSURF.dpr

430 lines
14 KiB
ObjectPascal
Raw Normal View History

// *****************************************************************
// Delphi-OpenCV Demo
// Copyright (C) 2013 Project Delphi-OpenCV
// ****************************************************************
// Contributor:
// laentir Valetov
// 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.
// ***************************************************************
// Original file:
// http://blog.vidikon.com/?p=213
// ***************************************************************
program cv_ExtractSURF;
{$APPTYPE CONSOLE}
{$POINTERMATH ON}
{$R *.res}
uses
System.SysUtils,
Winapi.Windows,
opencv.highgui_c,
opencv.core_c,
opencv.core.types_c,
opencv.imgproc_c,
opencv.imgproc.types_c,
opencv.compat,
opencv.calib3d_c,
opencv.nonfree,
uResourcePaths;
// c<><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD>c<EFBFBD><63><EFBFBD>
// comparison of the two features
function compareSURFDescriptors(const d1: PSingle; const d2: PSingle; best: Double; length: Integer): Double;
var
total_cost: Double;
i: Integer;
t0, t1, t2, t3: Double;
begin
total_cost := 0;
assert(length mod 4 = 0);
i := 0;
While i < length - 1 do
begin
t0 := d1[i] - d2[i];
t1 := d1[i + 1] - d2[i + 1];
t2 := d1[i + 2] - d2[i + 2];
t3 := d1[i + 3] - d2[i + 3];
total_cost := total_cost + t0 * t0 + t1 * t1 + t2 * t2 + t3 * t3;
if (total_cost > best) then
break;
i := i + 4;
end;
result := total_cost;
end;
// c<><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD>c<EFBFBD><63> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> c<> <20>c<EFBFBD><63><EFBFBD> <20>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD>c<EFBFBD><63><EFBFBD><EFBFBD> c<><63><EFBFBD><EFBFBD>
// compares one feature of the scene with all the features
function naiveNearestNeighbor(const vec: PSingle; laplacian: Integer; const model_keypoints: pCvSeq;
const model_descriptors: pCvSeq): Integer;
Var
length, i, neighbor: Integer;
d, dist1, dist2: Double;
reader, kreader: TCvSeqReader;
kp: pCvSURFPoint;
mvec: PSingle;
begin
length := model_descriptors.elem_size div sizeof(single);
neighbor := -1;
dist1 := 1E6;
dist2 := 1E6;;
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD>c<EFBFBD><63> c<><63><EFBFBD><EFBFBD>
// The initial feature scenes
cvStartReadSeq(model_keypoints, @kreader, 0);
cvStartReadSeq(model_descriptors, @reader, 0);
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>c<EFBFBD><63> <20>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD>c<EFBFBD><63><EFBFBD> c<><63><EFBFBD><EFBFBD>
// Iterating through all features of the scene
for i := 0 to model_descriptors.total - 1 do
begin
kp := pCvSURFPoint(kreader.ptr);
mvec := PSingle(reader.ptr);
CV_NEXT_SEQ_ELEM(kreader.seq.elem_size, kreader);
CV_NEXT_SEQ_ELEM(reader.seq.elem_size, reader);
// <20><><EFBFBD> <20>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> c<><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD> c<><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>c<EFBFBD> <20><><EFBFBD><EFBFBD>cc<63><63><EFBFBD> <20>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD>c<EFBFBD><63><EFBFBD>
// To accelerate the first compared Laplacian features
if (laplacian <> kp.laplacian) then
continue;
// c<><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD>c<EFBFBD><63><EFBFBD>
// comparison of the features
d := compareSURFDescriptors(vec, mvec, dist2, length);
if (d < dist1) then
begin
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> c<><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD>c<EFBFBD><63><EFBFBD>
// Found a better match features
dist2 := dist1;
dist1 := d;
neighbor := i;
end
else if (d < dist2) then
dist2 := d;
end;
if (dist1 < 0.6 * dist2) then
Exit(neighbor);
result := -1;
end;
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> c<><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
// Function searches for matching pairs
procedure findPairs(const objectKeypoints: pCvSeq; const objectDescriptors: pCvSeq; const imageKeypoints: pCvSeq;
const imageDescriptors: pCvSeq; Var ptpairs: TArray<Integer>);
var
i: Integer;
reader, kreader: TCvSeqReader;
kp: pCvSURFPoint;
descriptor: PSingle;
nearest_neighbor: Integer;
begin
// <20>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD>c<EFBFBD><63> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>cc<63><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// Sets the initial features of object recognition
cvStartReadSeq(objectKeypoints, @kreader);
cvStartReadSeq(objectDescriptors, @reader);
SetLength(ptpairs, 0);
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>c<EFBFBD><63> <20>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// Iterating through all features of the object
for i := 0 to objectDescriptors.total - 1 do
begin
kp := pCvSURFPoint(kreader.ptr);
descriptor := PSingle(reader.ptr);
CV_NEXT_SEQ_ELEM(kreader.seq.elem_size, kreader);
CV_NEXT_SEQ_ELEM(reader.seq.elem_size, reader);
// c<><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD>c<EFBFBD><63> c<> <20>c<EFBFBD><63><EFBFBD> <20>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD>c<EFBFBD><63><EFBFBD><EFBFBD> <20><> c<><63><EFBFBD><EFBFBD>
// comparison of the current features with all the features of the scene
nearest_neighbor := naiveNearestNeighbor(descriptor, kp.laplacian, imageKeypoints, imageDescriptors);
if (nearest_neighbor >= 0) then
begin
// <20><><EFBFBD><EFBFBD><EFBFBD>c<EFBFBD> c<><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD>c<EFBFBD><63><EFBFBD>
// Match the features found
SetLength(ptpairs, length(ptpairs) + 2);
ptpairs[High(ptpairs) - 1] := i;
ptpairs[High(ptpairs)] := nearest_neighbor;
end;
end;
end;
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// Finding rough position of the object
function locatePlanarObject(const objectKeypoints: pCvSeq; const objectDescriptors: pCvSeq; const imageKeypoints: pCvSeq;
const imageDescriptors: pCvSeq; const src_corners: TArray<TCvPoint>; dst_corners: TArray<TCvPoint>): Integer;
var
h: array [0 .. 8] of Double;
_h: TCvMat;
ptpairs: TArray<Integer>;
pt1, pt2: TArray<TCvPoint2D32f>;
_pt1, _pt2: TCvMat;
i, n: Integer;
x, y, _Z, _X, _Y: Double;
begin
_h := cvMat(3, 3, CV_64F, @h);
// <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD>c<EFBFBD><63><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> c<><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>
// We are looking for a pair of features on each image that correspond to each other
findPairs(objectKeypoints, objectDescriptors, imageKeypoints, imageDescriptors, ptpairs);
n := length(ptpairs) div 2;
// <20>c<EFBFBD><63> <20><><EFBFBD> <20><><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// If found little pair, then have to go - object not found
if (n < 4) then
Exit(0);
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
SetLength(pt1, n);
SetLength(pt2, n);
// c<><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// read the coordinates of the "singular" points
for i := 0 to n - 1 do
begin
pt1[i] := pCvSURFPoint(cvGetSeqElem(objectKeypoints, ptpairs[i * 2])).pt;
pt2[i] := pCvSURFPoint(cvGetSeqElem(imageKeypoints, ptpairs[i * 2 + 1])).pt;
end;
// <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> c<><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// Using computed vectors - creating a matrix
_pt1 := cvMat(1, n, CV_32FC2, @pt1[0]);
_pt2 := cvMat(1, n, CV_32FC2, @pt2[0]);
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> c <20><><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
// Find the transformation between the original image and the fact that looking
if (cvFindHomography(@_pt1, @_pt2, @_h, CV_RANSAC, 5) = 0) then
Exit(0);
// <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> (<28> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> _h) <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// Using the values transformation (in the matrix _h) find
// the coordinates of a quadrilateral, indicative of the object
for i := 0 to 3 do
begin
x := src_corners[i].x;
y := src_corners[i].y;
_Z := 1. / (h[6] * x + h[7] * y + h[8]);
_X := (h[0] * x + h[1] * y + h[2]) * _Z;
_Y := (h[3] * x + h[4] * y + h[5]) * _Z;
dst_corners[i] := cvPoint(cvRound(_X), cvRound(_Y));
end;
Exit(1);
end;
Var
object_filename, scene_filename: AnsiString;
storage: pCvMemStorage;
colors: array [0 .. 8] of TCvScalar = (
(
val:
(
0,
0,
255,
0
)
),
(
val:
(
0,
128,
255,
0
)
),
(
val:
(
0,
255,
255,
0
)
),
(
val:
(
0,
255,
0,
0
)
),
(
val:
(
255,
128,
0,
0
)
),
(
val:
(
255,
255,
0,
0
)
),
(
val:
(
255,
0,
0,
0
)
),
(
val:
(
255,
0,
255,
0
)
),
(
val:
(
255,
255,
255,
0
)
)
);
_object, image, object_color: pIplImage;
objectKeypoints, objectDescriptors, imageKeypoints, imageDescriptors: pCvSeq;
i: Integer;
params: TCvSURFParams;
tt: Double;
src_corners, dst_corners: TArray<TCvPoint>;
correspond: pIplImage;
r1, r2: TCvPoint;
ptpairs: TArray<Integer>;
_r1, _r2: pCvSURFPoint;
r: pCvSURFPoint;
center: TCvPoint;
radius: Integer;
begin
try
initModule_nonfree;
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// initialization parameters
object_filename := iif(ParamCount = 2, ParamStr(1), cResourceMedia + 'box.png');
scene_filename := iif(ParamCount = 2, ParamStr(2), cResourceMedia + 'box_in_scene.png');
storage := cvCreateMemStorage(0);
cvNamedWindow('Object', 1);
cvNamedWindow('Object Correspond', 1);
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// Loading Images
_object := cvLoadImage(pcvChar(@object_filename[1]), CV_LOAD_IMAGE_GRAYSCALE);
image := cvLoadImage(pcvChar(@scene_filename[1]), CV_LOAD_IMAGE_GRAYSCALE);
if (not Assigned(_object)) or (not Assigned(image)) then
begin
WriteLn(Format('Can not load %s and/or %s', [object_filename, scene_filename]));
WriteLn('Usage: find_obj [<object_filename> <scene_filename>]');
Halt;
end;
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> c<><63><EFBFBD><EFBFBD><EFBFBD>
// Translation grayscale
object_color := cvCreateImage(cvGetSize(_object), 8, 3);
cvCvtColor(_object, object_color, CV_GRAY2BGR);
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> c<><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> CvSURFParams c <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> 128 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// Initialization of the structure CvSURFParams c size descriptors 128 items
params := CvSURFParams(500, 1);
// <20><>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>
// note the time
tt := cvGetTickCount();
// <20><><EFBFBD><EFBFBD> <20>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD>c<EFBFBD><63> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>cc<63><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// We are looking for particular object recognition
cvExtractSURF(_object, nil, @objectKeypoints, @objectDescriptors, storage, params);
WriteLn(Format('Object Descriptors: %d', [objectDescriptors.total]));
// <20><><EFBFBD><EFBFBD> <20>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD>c<EFBFBD><63> c<><63><EFBFBD><EFBFBD>
// We are looking for particular scenes
cvExtractSURF(image, nil, @imageKeypoints, @imageDescriptors, storage, params);
WriteLn(Format('Image Descriptors: %d', [imageDescriptors.total]));
// c<><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>c<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> (<28> <20><><EFBFBD><EFBFBD> 167 <20><><EFBFBD><EFBFBD><EFBFBD> c<><63><EFBFBD><EFBFBD><EFBFBD>)
// how long it took (I 167 milliseconds)
tt := cvGetTickCount() - tt;
WriteLn(Format('Extraction time = %gms', [tt / (cvGetTickFrequency() * 1000)]));
// <20>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> c<><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>c<EFBFBD> <20>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD>c<EFBFBD><63>
// Set the image borders, within which features will be compared
SetLength(src_corners, 4);
src_corners[0] := cvPoint(0, 0);
src_corners[1] := cvPoint(_object.width, 0);
src_corners[2] := cvPoint(_object.width, _object.height);
src_corners[3] := cvPoint(0, _object.height);
SetLength(dst_corners, 4);
// c<><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> (<28> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> c<><63><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
// <20><><EFBFBD><EFBFBD>c<EFBFBD><63><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD> <20><><EFBFBD><EFBFBD>
// creation of an additional image (it will be a scene and object)
// Run the example and you will understand what I mean
correspond := cvCreateImage(cvSize(image.width, _object.height + image.height), 8, 1);
cvSetImageROI(correspond, cvRect(0, 0, _object.width, _object.height));
cvCopy(_object, correspond);
cvSetImageROI(correspond, cvRect(0, _object.height, correspond.width, correspond.height));
cvCopy(image, correspond);
cvResetImageROI(correspond);
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// Call the function that retrieves the object on the screen
if (locatePlanarObject(objectKeypoints, objectDescriptors, imageKeypoints, imageDescriptors, src_corners, dst_corners) <> 0)
then
begin
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// Draw out the desired quadrangle
for i := 0 to 3 do
begin
r1 := dst_corners[i mod 4];
r2 := dst_corners[(i + 1) mod 4];
cvLine(correspond, cvPoint(r1.x, r1.y + _object.height), cvPoint(r2.x, r2.y + _object.height), colors[8]);
end;
end;
// <20>c<EFBFBD><63> <20> <20><><EFBFBD><EFBFBD> <20><>c<EFBFBD><63> <20><><EFBFBD><EFBFBD>c<EFBFBD><63> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD>, <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>c<EFBFBD> <20><>, <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><>c<EFBFBD><63><EFBFBD><EFBFBD> 23.3.
// c<><63><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>c<EFBFBD> <20>c<EFBFBD> c<><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD>c<EFBFBD><63><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// again finds all the matching pairs of features in both pictures
findPairs(objectKeypoints, objectDescriptors, imageKeypoints, imageDescriptors, ptpairs);
// <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD>c<EFBFBD><63><EFBFBD> <20><> <20><>c<EFBFBD><63><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>c<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// Between pairs of features in the figure are held straight
i := 0;
While i < length(ptpairs) do
begin
_r1 := pCvSURFPoint(cvGetSeqElem(objectKeypoints, ptpairs[i]));
_r2 := pCvSURFPoint(cvGetSeqElem(imageKeypoints, ptpairs[i + 1]));
cvLine(correspond, cvPointFrom32f(_r1.pt), cvPoint(cvRound(_r2.pt.x), cvRound(_r2.pt.y + _object.height)), colors[8]);
i := i + 2;
end;
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><>c<EFBFBD><63><EFBFBD><EFBFBD> 23.4.
cvShowImage('Object Correspond', correspond);
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD>c<EFBFBD><63><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>c<EFBFBD><63><EFBFBD><EFBFBD> (<28><>c. 23.5)
// Highlight features of circles
for i := 0 to objectKeypoints.total - 1 do
begin
r := pCvSURFPoint(cvGetSeqElem(objectKeypoints, i));
center.x := cvRound(r.pt.x);
center.y := cvRound(r.pt.y);
radius := cvRound(r.size * 1.2 / 9 * 2);
cvCircle(object_color, center, radius, colors[0], 1, 8, 0);
end;
cvShowImage('Object', object_color);
cvWaitKey(0);
cvDestroyAllWindows;
except
on E: Exception do
WriteLn(E.ClassName, ': ', E.Message);
end;
end.