Delphi-OpenCV/samples/MultiDemo/CameraCalibrate/CameraCalibrate.dpr
Laentir Valetov e952bec7ba Fixed issues #19
Signed-off-by: Laentir Valetov <laex@bk.ru>
2014-06-05 00:18:43 +04:00

345 lines
13 KiB
ObjectPascal
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// *****************************************************************
// 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.
// *******************************************************************
program CameraCalibrate;
{$APPTYPE CONSOLE}
{$POINTERMATH ON}
{$R *.res}
uses
System.SysUtils,
ocv.highgui_c,
ocv.core_c,
ocv.core.types_c,
ocv.imgproc_c,
ocv.imgproc.types_c,
ocv.calib3d_c,
uResourcePaths;
var
// Setting the input list //Ócòàíîâèì âõîäíîé cïècîê
n_boards: Integer = 0;
// We are waiting for 20 frames with views chessboard//Æäåì 20 ôðåéìîâ c âèäàìè øàõìàòíîé äîcêè
board_dt: Integer = 20;
board_w: Integer;
board_h: Integer;
board_n: Integer;
board_sz: TCvSize;
capture: pCvCapture = nil;
image_points: pCvMat;
object_points: pCvMat;
point_counts: pCvMat;
intrinsic_matrix: pCvMat;
distortion_coeffs: pCvMat;
corners: pCvPoint2D32f;
corner_count: Integer;
successes: Integer = 0;
step: Integer = 0;
frame: Integer = 0;
image: pIplImage;
gray_image: pIplImage;
found: Integer;
i, j: Integer;
c: Integer;
object_points2: pCvMat;
image_points2: pCvMat;
point_counts2: pCvMat;
intrinsic: pCvMat;
Distortion: pCvMat;
mapx: pIplImage;
mapy: pIplImage;
t: pIplImage;
s: Single;
RMS: double;
begin
try
if ParamCount = 3 then
begin
board_w := StrToInt(ParamStr(1));
board_h := StrToInt(ParamStr(2));
n_boards := StrToInt(ParamStr(3));
end
else
begin
board_w := 7;
board_h := 3;
n_boards := 10;
end;
board_n := board_w * board_h;
Writeln('Cells: ', board_n);
board_sz := cvSize(board_w, board_h);
capture := cvCreateCameraCapture(CV_CAP_ANY);
assert(Assigned(capture));
cvNamedWindow('Calibration');
// Allocates memory for data storage//ÂÛÄÅËßÅÌ ÏÀÌßÒü äëÿ õðàíåíèÿ äàííûõ
image_points := cvCreateMat(n_boards * board_n, 2, CV_32FC1);
object_points := cvCreateMat(n_boards * board_n, 3, CV_32FC1);
point_counts := cvCreateMat(n_boards, 1, CV_32SC1);
intrinsic_matrix := cvCreateMat(3, 3, CV_32FC1);
distortion_coeffs := cvCreateMat(5, 1, CV_32FC1);
corners := AllocMem(SizeOf(TCvPoint2D32f) * board_n);
image := cvQueryFrame(capture);
gray_image := cvCreateImage(cvGetSize(image), 8, 1); // subpixel
// ÇÀÕÂÀÒ Â ÖÈÊËÅ ÈÇÎÁÐÀÆÅÍÈÉ c ÓÃËÀÌÈ ÏÎÊÀ ÌÛ ÍÅ ÏËÎÓ×ÈÌ n_boards
// ÏÎËÍÛÕ ÇÀÕÂÀÒÎÂ (ÂcÅ ÓÃËÛ ÍÀ ÄÎcÊÅ ÁÛËÈ ÍÀÉÄÅÍÛ)
///
// IMAGE CAPTURE in the cycles with angles until we got n_boards
// Total capture (all the angles on the board WERE FOUND)
while (successes < n_boards) do
begin
// Ïðîïócêàåì board_dt ôðåéìîâ, ïðåäîcòàâëåííûå ïîëüçîâàòåëåì, äâèãàþùèì äîcêó
// Skip the "board_dt" frames supplied by the user to move the board
if ((frame mod board_dt) = 0) then // At this point - the error is found and corrected CLubfitter73
begin
Writeln('Successes: ', successes);
// Íàõîäèì óãëû øàõìàòíîé äîcêè
// Find the corners of the chessboard
found := cvFindChessboardCorners(image, board_sz, corners, @corner_count, CV_CALIB_CB_ADAPTIVE_THRESH or
CV_CALIB_CB_FILTER_QUADS);
// Ïîëó÷åíèå cóáïèêcåëüíîé òî÷íîcòè íà ýòèõ óãëàõ
// Getting a sub-pixel accuracy on these corners
cvCvtColor(image, gray_image, CV_BGR2GRAY);
cvFindCornerSubPix(gray_image, corners, corner_count, cvSize(11, 11), cvSize(-1, -1),
cvTermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1));
// Íàðècóåì ýòî
// Let's draw it
cvDrawChessboardCorners(image, board_sz, corners, corner_count, found);
cvShowImage('Calibration', image);
// Åcëè ìû ïîëó÷èëè õîðîøóþ äîcêó, äîáàâèì åå ê íàøèì äàííûì
// If we got a good board, add it to our data
if (corner_count = board_n) then
begin
step := successes * board_n;
i := step;
j := 0;
while j < board_n do // At this point - the error is found and corrected CLubfitter73
begin
pSingle(CV_MAT_ELEM(image_points^, SizeOf(Single), i, 0))^ := corners[j].x;
pSingle(CV_MAT_ELEM(image_points^, SizeOf(Single), i, 1))^ := corners[j].y;
// By default, the division operation returns Double
// When implicitly cast the Double to Single - the result is zero
// Integer to Double and Single given correctly
//
// Frans
//
pSingle(CV_MAT_ELEM(object_points^, SizeOf(Single), i, 0))^ := j mod board_w;
pSingle(CV_MAT_ELEM(object_points^, SizeOf(Single), i, 1))^ := j div board_w;
pSingle(CV_MAT_ELEM(object_points^, SizeOf(Single), i, 2))^ := 0;
Inc(i);
Inc(j);
end;
pInteger(CV_MAT_ELEM(point_counts^, SizeOf(Integer), successes, 0))^ := board_n;
Inc(successes);
end;
end; // end skip board_dt between chessboard capture
// Handle pause/unpause and ESC
c := cvWaitKey(15);
if (c = Ord('p')) then
begin
c := 0;
while (c <> Ord('p')) and (c <> 27) do
begin
c := cvWaitKey(50);
end;
end;
if (c = 27) then
begin
// release resources//îcâîáîæäàåì ðåcóðcû
// cvReleaseImage(mapx); - This has zero//ýòà åùå íóëåâàÿ
// cvReleaseImage(mapy); - This has zero//ýòà åùå íóëåâàÿ
cvReleaseImage(gray_image);
// cvReleaseImage(image); - this can not be//ýòîãî äåëàòü íåëüçÿ
// cì. http://docs.ocv.org/modules/highgui/doc/reading_and_writing_images_and_video.html?highlight=cvqueryframe#IplImage*%20cvQueryFrame%28CvCapture*%20capture%29
// Note
// OpenCV 1.x functions cvRetrieveFrame and cv.RetrieveFrame return image
// stored inside the video capturing structure. It is not allowed to modify
// or release the image! You can copy the frame using cvCloneImage()
// and then do whatever you want with the copy.
//
cvReleaseMat(object_points);
cvReleaseMat(image_points);
cvReleaseMat(point_counts);
cvReleaseMat(intrinsic_matrix);
cvReleaseMat(distortion_coeffs);
cvReleaseCapture(capture);
cvDestroyAllWindows;
Halt;
end;
image := cvQueryFrame(capture); // We get the following picture//Ïîëó÷àåì cëåäóþùåå èçîáðàæåíèå
Inc(frame); // At this point - the error is found and corrected CLubfitter73
end;
// ÂÛÄÅËßÅÌ ÌÀÒÐÈÖÛ Ê ÒÀÊÎÌÓ ÊÎËÈ×ÅcÒÂÓ ØÀÕÌÀÒÍÛÕ ÄÎcÊ, cÊÎËÜÊÎ ÁÛËÎ ÍÀÉÄÅÍÎ
// MATRIX is allocated to that amount of a chessboard, how much was FOUND
object_points2 := cvCreateMat(successes * board_n, 3, CV_32FC1);
image_points2 := cvCreateMat(successes * board_n, 2, CV_32FC1);
point_counts2 := cvCreateMat(successes, 1, CV_32SC1);
// ÏÅÐÅÌÅÙÀÅÌ ÒÎ×ÊÈ Â ÌÀÒÐÈÖÛ ÏÐÀÂÈËÜÍÎÃÎ ÐÀÇÌÅÐÀ
// Move point in the matrix of the correct size of
// Íèæå ìû îïèøåì ýòî äåòàëüíî â cëåäóþùèõ äâóõ öèêëàõ.
// Below, we describe it in detail in the next two cycles.
i := 0;
While i < successes * board_n do
begin
pSingle(CV_MAT_ELEM(image_points2^, SizeOf(Single), i, 0))^ := pSingle(CV_MAT_ELEM(image_points^, SizeOf(Single), i, 0))^;
pSingle(CV_MAT_ELEM(image_points2^, SizeOf(Single), i, 1))^ := pSingle(CV_MAT_ELEM(image_points^, SizeOf(Single), i, 1))^;
pSingle(CV_MAT_ELEM(object_points2^, SizeOf(Single), i, 0))^ := pSingle(CV_MAT_ELEM(object_points^, SizeOf(Single), i, 0))^;
pSingle(CV_MAT_ELEM(object_points2^, SizeOf(Single), i, 1))^ := pSingle(CV_MAT_ELEM(object_points^, SizeOf(Single), i, 1))^;
pSingle(CV_MAT_ELEM(object_points2^, SizeOf(Single), i, 2))^ := pSingle(CV_MAT_ELEM(object_points^, SizeOf(Single), i, 2))^;
Inc(i);
end;
i := 0;
While i < successes do
begin // There are the same number//Çäåcü âcå òå æå ÷ècëà
pInteger(CV_MAT_ELEM(point_counts2^, SizeOf(Integer), i, 0))^ :=
pInteger(CV_MAT_ELEM(point_counts^, SizeOf(Integer), i, 0))^;
Inc(i);
end;
cvReleaseMat(object_points);
cvReleaseMat(image_points);
cvReleaseMat(point_counts);
// Äëÿ ýòèõ òî÷åê ìû èìååì âcå óãëû øàõìàòíîé äîcêè, êîòîðûå íàì íóæíû.
// Èíèöèàëèçèðóåì ìàòðèöó âíóòðåííèõ ïàðàìåòðîâ òàê, ÷òî îáà ôîêàëüíûõ
// ðcccòîÿíèÿ áóäóò èìåòü cîîòíîøåíèå 1.0
///
// For these points we have all thumbnails corners of chess board that we need.
// Initialize the matrix of internal parameters so that the two focal
// Distance will have a ratio of 1.0
cvZero(intrinsic_matrix);
// pSingle(CV_MAT_ELEM(intrinsic_matrix^, CV_32FC1, 0, 0))^ := 1;
// pSingle(CV_MAT_ELEM(intrinsic_matrix^, CV_32FC1, 1, 1))^ := 1;
// pSingle(CV_MAT_ELEM(intrinsic_matrix^, CV_32FC1, 2, 2))^ := 1;
// pSingle(CV_MAT_ELEM(intrinsic_matrix^, SizeOf(Single), 0, 0))^ := 520.0;
// pSingle(CV_MAT_ELEM(intrinsic_matrix^, SizeOf(Single), 1, 1))^ := 520.0;
// pSingle(CV_MAT_ELEM(intrinsic_matrix^, SizeOf(Single), 2, 2))^ := 1;
// pSingle(CV_MAT_ELEM(intrinsic_matrix^, SizeOf(Single), 0, 2))^ := 70.0;
// pSingle(CV_MAT_ELEM(intrinsic_matrix^, SizeOf(Single), 1, 2))^ := 70.0;
// At this point - the error is found and corrected CLubfitter73
pSingle(CV_MAT_ELEM(intrinsic_matrix^, SizeOf(Single), 0, 0))^ := 1;
pSingle(CV_MAT_ELEM(intrinsic_matrix^, SizeOf(Single), 1, 1))^ := 1;
for i := 0 to intrinsic_matrix^.rows - 1 do
begin
for j := 0 to intrinsic_matrix^.cols - 1 do
Write(Format('%.0f ', [pSingle(CV_MAT_ELEM(intrinsic_matrix^, SizeOf(Single), i, j))^]));
Writeln;
end;
Writeln;
// ÊÀËÈÁÐÓÅÌ ÊÀÌÅÐÓ!
// Calibrating the camera!
RMS := cvCalibrateCamera2(object_points2, image_points2, point_counts2, cvGetSize(image), intrinsic_matrix,
distortion_coeffs, nil, nil,
// {}0,
{} CV_CALIB_FIX_ASPECT_RATIO,
// {}CV_CALIB_USE_INTRINSIC_GUESS,
{} cvTermCriteria(CV_TERMCRIT_ITER + CV_TERMCRIT_EPS, 30, DBL_EPSILON));
// ñÎÕÐÀÍßÅÌ ÂÍÓÒÐÅÍÍÈÅ ÏÀÐÀÌÅÒÐÛ È ÄÈñÒÎðñÈÞ
// Parameters and maintains internal distortion
cvSave(cResourceResult + 'Intrinsics.xml', intrinsic_matrix);
cvSave(cResourceResult + 'Distortion.xml', distortion_coeffs);
// -------------------------------------------------------------
// ÏÐÈÌÅÐ ÇÀÃÐÓÇÊÈ ÝÒÈÕ ÌÀÒÐÈÖ ÍÀÇÀÄ Â ÏÐÎÃÐÀÌÌÌÓ:
// Loading examples of these matrices back into the program:
intrinsic := cvLoad(cResourceResult + 'Intrinsics.xml');
Distortion := cvLoad(cResourceResult + 'Distortion.xml');
// còðîèì êàðòó àíäècòîðcèè, êîòîðóþ ìû áóäåì ècïîëüçîâàòü
// äëÿ âcåõ ïîcëåäóþùèõ êàäðîâ.
// Construct a map andictorcii, we will use for all pocleduyuschih frames.
mapx := cvCreateImage(cvGetSize(image), IPL_DEPTH_32F, 1);
mapy := cvCreateImage(cvGetSize(image), IPL_DEPTH_32F, 1);
cvInitUndistortMap(intrinsic, Distortion, mapx, mapy);
// Òîëüêî êàìåðà cíèìàåò, cðàçó âèäèì cûðîå
// è íåècêàæåííîå èçîáðàæåíèå.
// Display on the screen is what gets camera - raw image
cvNamedWindow('Undistort');
while Assigned(image) do
begin
t := cvCloneImage(image);
cvShowImage('Calibration', image); // Show raw image
cvRemap(t, image, mapx, mapy, CV_INTER_LINEAR + CV_WARP_FILL_OUTLIERS, cvScalarAll(0)); // Undistort image
cvReleaseImage(t);
cvShowImage('Undistort', image); // Show corrected image
// Handle pause/unpause and ESC
c := cvWaitKey(15);
if (c = Ord('p')) then
begin
c := 0;
while (c <> Ord('p')) and (c <> 27) do
begin
c := cvWaitKey(250);
end;
end;
if (c = 27) then
break;
image := cvQueryFrame(capture);
end;
// release resources//îcâîáîæäàåì ðåcóðcû
cvReleaseImage(mapx);
cvReleaseImage(mapy);
cvReleaseImage(gray_image);
cvReleaseMat(intrinsic_matrix);
cvReleaseMat(distortion_coeffs);
cvReleaseMat(object_points2);
cvReleaseMat(image_points2);
cvReleaseMat(point_counts2);
cvReleaseCapture(capture);
cvDestroyAllWindows;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.