feat: 切换后端至PaddleOCR-NCNN,切换工程为CMake

1.项目后端整体迁移至PaddleOCR-NCNN算法,已通过基本的兼容性测试
2.工程改为使用CMake组织,后续为了更好地兼容第三方库,不再提供QMake工程
3.重整权利声明文件,重整代码工程,确保最小化侵权风险

Log: 切换后端至PaddleOCR-NCNN,切换工程为CMake
Change-Id: I4d5d2c5d37505a4a24b389b1a4c5d12f17bfa38c
This commit is contained in:
wangzhengyang
2022-05-10 09:54:44 +08:00
parent ecdd171c6f
commit 718c41634f
10018 changed files with 3593797 additions and 186748 deletions

View File

@ -0,0 +1,185 @@
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/calib3d.hpp>
using namespace std;
using namespace cv;
namespace
{
enum Pattern { CHESSBOARD, CIRCLES_GRID, ASYMMETRIC_CIRCLES_GRID };
void calcChessboardCorners(Size boardSize, float squareSize, vector<Point3f>& corners, Pattern patternType = CHESSBOARD)
{
corners.resize(0);
switch (patternType) {
case CHESSBOARD:
case CIRCLES_GRID:
for( int i = 0; i < boardSize.height; i++ )
for( int j = 0; j < boardSize.width; j++ )
corners.push_back(Point3f(float(j*squareSize),
float(i*squareSize), 0));
break;
case ASYMMETRIC_CIRCLES_GRID:
for( int i = 0; i < boardSize.height; i++ )
for( int j = 0; j < boardSize.width; j++ )
corners.push_back(Point3f(float((2*j + i % 2)*squareSize),
float(i*squareSize), 0));
break;
default:
CV_Error(Error::StsBadArg, "Unknown pattern type\n");
}
}
Mat computeHomography(const Mat &R_1to2, const Mat &tvec_1to2, const double d_inv, const Mat &normal)
{
Mat homography = R_1to2 + d_inv * tvec_1to2*normal.t();
return homography;
}
void computeC2MC1(const Mat &R1, const Mat &tvec1, const Mat &R2, const Mat &tvec2,
Mat &R_1to2, Mat &tvec_1to2)
{
//c2Mc1 = c2Mo * oMc1 = c2Mo * c1Mo.inv()
R_1to2 = R2 * R1.t();
tvec_1to2 = R2 * (-R1.t()*tvec1) + tvec2;
}
void decomposeHomography(const string &img1Path, const string &img2Path, const Size &patternSize,
const float squareSize, const string &intrinsicsPath)
{
Mat img1 = imread( samples::findFile( img1Path) );
Mat img2 = imread( samples::findFile( img2Path) );
vector<Point2f> corners1, corners2;
bool found1 = findChessboardCorners(img1, patternSize, corners1);
bool found2 = findChessboardCorners(img2, patternSize, corners2);
if (!found1 || !found2)
{
cout << "Error, cannot find the chessboard corners in both images." << endl;
return;
}
//! [compute-poses]
vector<Point3f> objectPoints;
calcChessboardCorners(patternSize, squareSize, objectPoints);
FileStorage fs( samples::findFile( intrinsicsPath ), FileStorage::READ);
Mat cameraMatrix, distCoeffs;
fs["camera_matrix"] >> cameraMatrix;
fs["distortion_coefficients"] >> distCoeffs;
Mat rvec1, tvec1;
solvePnP(objectPoints, corners1, cameraMatrix, distCoeffs, rvec1, tvec1);
Mat rvec2, tvec2;
solvePnP(objectPoints, corners2, cameraMatrix, distCoeffs, rvec2, tvec2);
//! [compute-poses]
//! [compute-camera-displacement]
Mat R1, R2;
Rodrigues(rvec1, R1);
Rodrigues(rvec2, R2);
Mat R_1to2, t_1to2;
computeC2MC1(R1, tvec1, R2, tvec2, R_1to2, t_1to2);
Mat rvec_1to2;
Rodrigues(R_1to2, rvec_1to2);
//! [compute-camera-displacement]
//! [compute-plane-normal-at-camera-pose-1]
Mat normal = (Mat_<double>(3,1) << 0, 0, 1);
Mat normal1 = R1*normal;
//! [compute-plane-normal-at-camera-pose-1]
//! [compute-plane-distance-to-the-camera-frame-1]
Mat origin(3, 1, CV_64F, Scalar(0));
Mat origin1 = R1*origin + tvec1;
double d_inv1 = 1.0 / normal1.dot(origin1);
//! [compute-plane-distance-to-the-camera-frame-1]
//! [compute-homography-from-camera-displacement]
Mat homography_euclidean = computeHomography(R_1to2, t_1to2, d_inv1, normal1);
Mat homography = cameraMatrix * homography_euclidean * cameraMatrix.inv();
homography /= homography.at<double>(2,2);
homography_euclidean /= homography_euclidean.at<double>(2,2);
//! [compute-homography-from-camera-displacement]
//! [decompose-homography-from-camera-displacement]
vector<Mat> Rs_decomp, ts_decomp, normals_decomp;
int solutions = decomposeHomographyMat(homography, cameraMatrix, Rs_decomp, ts_decomp, normals_decomp);
cout << "Decompose homography matrix computed from the camera displacement:" << endl << endl;
for (int i = 0; i < solutions; i++)
{
double factor_d1 = 1.0 / d_inv1;
Mat rvec_decomp;
Rodrigues(Rs_decomp[i], rvec_decomp);
cout << "Solution " << i << ":" << endl;
cout << "rvec from homography decomposition: " << rvec_decomp.t() << endl;
cout << "rvec from camera displacement: " << rvec_1to2.t() << endl;
cout << "tvec from homography decomposition: " << ts_decomp[i].t() << " and scaled by d: " << factor_d1 * ts_decomp[i].t() << endl;
cout << "tvec from camera displacement: " << t_1to2.t() << endl;
cout << "plane normal from homography decomposition: " << normals_decomp[i].t() << endl;
cout << "plane normal at camera 1 pose: " << normal1.t() << endl << endl;
}
//! [decompose-homography-from-camera-displacement]
//! [estimate homography]
Mat H = findHomography(corners1, corners2);
//! [estimate homography]
//! [decompose-homography-estimated-by-findHomography]
solutions = decomposeHomographyMat(H, cameraMatrix, Rs_decomp, ts_decomp, normals_decomp);
cout << "Decompose homography matrix estimated by findHomography():" << endl << endl;
for (int i = 0; i < solutions; i++)
{
double factor_d1 = 1.0 / d_inv1;
Mat rvec_decomp;
Rodrigues(Rs_decomp[i], rvec_decomp);
cout << "Solution " << i << ":" << endl;
cout << "rvec from homography decomposition: " << rvec_decomp.t() << endl;
cout << "rvec from camera displacement: " << rvec_1to2.t() << endl;
cout << "tvec from homography decomposition: " << ts_decomp[i].t() << " and scaled by d: " << factor_d1 * ts_decomp[i].t() << endl;
cout << "tvec from camera displacement: " << t_1to2.t() << endl;
cout << "plane normal from homography decomposition: " << normals_decomp[i].t() << endl;
cout << "plane normal at camera 1 pose: " << normal1.t() << endl << endl;
}
//! [decompose-homography-estimated-by-findHomography]
}
const char* params
= "{ help h | | print usage }"
"{ image1 | left02.jpg | path to the source chessboard image }"
"{ image2 | left01.jpg | path to the desired chessboard image }"
"{ intrinsics | left_intrinsics.yml | path to camera intrinsics }"
"{ width bw | 9 | chessboard width }"
"{ height bh | 6 | chessboard height }"
"{ square_size | 0.025 | chessboard square size }";
}
int main(int argc, char *argv[])
{
CommandLineParser parser(argc, argv, params);
if ( parser.has("help") )
{
parser.about( "Code for homography tutorial.\n"
"Example 4: decompose the homography matrix.\n" );
parser.printMessage();
return 0;
}
Size patternSize(parser.get<int>("width"), parser.get<int>("height"));
float squareSize = (float) parser.get<double>("square_size");
decomposeHomography(parser.get<String>("image1"),
parser.get<String>("image2"),
patternSize, squareSize,
parser.get<String>("intrinsics"));
return 0;
}

View File

@ -0,0 +1,201 @@
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/calib3d.hpp>
using namespace std;
using namespace cv;
namespace
{
enum Pattern { CHESSBOARD, CIRCLES_GRID, ASYMMETRIC_CIRCLES_GRID };
void calcChessboardCorners(Size boardSize, float squareSize, vector<Point3f>& corners, Pattern patternType = CHESSBOARD)
{
corners.resize(0);
switch (patternType)
{
case CHESSBOARD:
case CIRCLES_GRID:
for( int i = 0; i < boardSize.height; i++ )
for( int j = 0; j < boardSize.width; j++ )
corners.push_back(Point3f(float(j*squareSize),
float(i*squareSize), 0));
break;
case ASYMMETRIC_CIRCLES_GRID:
for( int i = 0; i < boardSize.height; i++ )
for( int j = 0; j < boardSize.width; j++ )
corners.push_back(Point3f(float((2*j + i % 2)*squareSize),
float(i*squareSize), 0));
break;
default:
CV_Error(Error::StsBadArg, "Unknown pattern type\n");
}
}
//! [compute-homography]
Mat computeHomography(const Mat &R_1to2, const Mat &tvec_1to2, const double d_inv, const Mat &normal)
{
Mat homography = R_1to2 + d_inv * tvec_1to2*normal.t();
return homography;
}
//! [compute-homography]
Mat computeHomography(const Mat &R1, const Mat &tvec1, const Mat &R2, const Mat &tvec2,
const double d_inv, const Mat &normal)
{
Mat homography = R2 * R1.t() + d_inv * (-R2 * R1.t() * tvec1 + tvec2) * normal.t();
return homography;
}
//! [compute-c2Mc1]
void computeC2MC1(const Mat &R1, const Mat &tvec1, const Mat &R2, const Mat &tvec2,
Mat &R_1to2, Mat &tvec_1to2)
{
//c2Mc1 = c2Mo * oMc1 = c2Mo * c1Mo.inv()
R_1to2 = R2 * R1.t();
tvec_1to2 = R2 * (-R1.t()*tvec1) + tvec2;
}
//! [compute-c2Mc1]
void homographyFromCameraDisplacement(const string &img1Path, const string &img2Path, const Size &patternSize,
const float squareSize, const string &intrinsicsPath)
{
Mat img1 = imread( samples::findFile( img1Path ) );
Mat img2 = imread( samples::findFile( img2Path ) );
//! [compute-poses]
vector<Point2f> corners1, corners2;
bool found1 = findChessboardCorners(img1, patternSize, corners1);
bool found2 = findChessboardCorners(img2, patternSize, corners2);
if (!found1 || !found2)
{
cout << "Error, cannot find the chessboard corners in both images." << endl;
return;
}
vector<Point3f> objectPoints;
calcChessboardCorners(patternSize, squareSize, objectPoints);
FileStorage fs( samples::findFile( intrinsicsPath ), FileStorage::READ);
Mat cameraMatrix, distCoeffs;
fs["camera_matrix"] >> cameraMatrix;
fs["distortion_coefficients"] >> distCoeffs;
Mat rvec1, tvec1;
solvePnP(objectPoints, corners1, cameraMatrix, distCoeffs, rvec1, tvec1);
Mat rvec2, tvec2;
solvePnP(objectPoints, corners2, cameraMatrix, distCoeffs, rvec2, tvec2);
//! [compute-poses]
Mat img1_copy_pose = img1.clone(), img2_copy_pose = img2.clone();
Mat img_draw_poses;
drawFrameAxes(img1_copy_pose, cameraMatrix, distCoeffs, rvec1, tvec1, 2*squareSize);
drawFrameAxes(img2_copy_pose, cameraMatrix, distCoeffs, rvec2, tvec2, 2*squareSize);
hconcat(img1_copy_pose, img2_copy_pose, img_draw_poses);
imshow("Chessboard poses", img_draw_poses);
//! [compute-camera-displacement]
Mat R1, R2;
Rodrigues(rvec1, R1);
Rodrigues(rvec2, R2);
Mat R_1to2, t_1to2;
computeC2MC1(R1, tvec1, R2, tvec2, R_1to2, t_1to2);
Mat rvec_1to2;
Rodrigues(R_1to2, rvec_1to2);
//! [compute-camera-displacement]
//! [compute-plane-normal-at-camera-pose-1]
Mat normal = (Mat_<double>(3,1) << 0, 0, 1);
Mat normal1 = R1*normal;
//! [compute-plane-normal-at-camera-pose-1]
//! [compute-plane-distance-to-the-camera-frame-1]
Mat origin(3, 1, CV_64F, Scalar(0));
Mat origin1 = R1*origin + tvec1;
double d_inv1 = 1.0 / normal1.dot(origin1);
//! [compute-plane-distance-to-the-camera-frame-1]
//! [compute-homography-from-camera-displacement]
Mat homography_euclidean = computeHomography(R_1to2, t_1to2, d_inv1, normal1);
Mat homography = cameraMatrix * homography_euclidean * cameraMatrix.inv();
homography /= homography.at<double>(2,2);
homography_euclidean /= homography_euclidean.at<double>(2,2);
//! [compute-homography-from-camera-displacement]
//Same but using absolute camera poses instead of camera displacement, just for check
Mat homography_euclidean2 = computeHomography(R1, tvec1, R2, tvec2, d_inv1, normal1);
Mat homography2 = cameraMatrix * homography_euclidean2 * cameraMatrix.inv();
homography_euclidean2 /= homography_euclidean2.at<double>(2,2);
homography2 /= homography2.at<double>(2,2);
cout << "\nEuclidean Homography:\n" << homography_euclidean << endl;
cout << "Euclidean Homography 2:\n" << homography_euclidean2 << endl << endl;
//! [estimate-homography]
Mat H = findHomography(corners1, corners2);
cout << "\nfindHomography H:\n" << H << endl;
//! [estimate-homography]
cout << "homography from camera displacement:\n" << homography << endl;
cout << "homography from absolute camera poses:\n" << homography2 << endl << endl;
//! [warp-chessboard]
Mat img1_warp;
warpPerspective(img1, img1_warp, H, img1.size());
//! [warp-chessboard]
Mat img1_warp_custom;
warpPerspective(img1, img1_warp_custom, homography, img1.size());
imshow("Warped image using homography computed from camera displacement", img1_warp_custom);
Mat img_draw_compare;
hconcat(img1_warp, img1_warp_custom, img_draw_compare);
imshow("Warped images comparison", img_draw_compare);
Mat img1_warp_custom2;
warpPerspective(img1, img1_warp_custom2, homography2, img1.size());
imshow("Warped image using homography computed from absolute camera poses", img1_warp_custom2);
waitKey();
}
const char* params
= "{ help h | | print usage }"
"{ image1 | left02.jpg | path to the source chessboard image }"
"{ image2 | left01.jpg | path to the desired chessboard image }"
"{ intrinsics | left_intrinsics.yml | path to camera intrinsics }"
"{ width bw | 9 | chessboard width }"
"{ height bh | 6 | chessboard height }"
"{ square_size | 0.025 | chessboard square size }";
}
int main(int argc, char *argv[])
{
CommandLineParser parser(argc, argv, params);
if (parser.has("help"))
{
parser.about("Code for homography tutorial.\n"
"Example 3: homography from the camera displacement.\n");
parser.printMessage();
return 0;
}
Size patternSize(parser.get<int>("width"), parser.get<int>("height"));
float squareSize = (float) parser.get<double>("square_size");
homographyFromCameraDisplacement(parser.get<String>("image1"),
parser.get<String>("image2"),
patternSize, squareSize,
parser.get<String>("intrinsics"));
return 0;
}

View File

@ -0,0 +1,90 @@
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
using namespace std;
using namespace cv;
namespace
{
void basicPanoramaStitching(const string &img1Path, const string &img2Path)
{
Mat img1 = imread( samples::findFile( img1Path ) );
Mat img2 = imread( samples::findFile( img2Path ) );
//! [camera-pose-from-Blender-at-location-1]
Mat c1Mo = (Mat_<double>(4,4) << 0.9659258723258972, 0.2588190734386444, 0.0, 1.5529145002365112,
0.08852133899927139, -0.3303661346435547, -0.9396926164627075, -0.10281121730804443,
-0.24321036040782928, 0.9076734185218811, -0.342020183801651, 6.130080699920654,
0, 0, 0, 1);
//! [camera-pose-from-Blender-at-location-1]
//! [camera-pose-from-Blender-at-location-2]
Mat c2Mo = (Mat_<double>(4,4) << 0.9659258723258972, -0.2588190734386444, 0.0, -1.5529145002365112,
-0.08852133899927139, -0.3303661346435547, -0.9396926164627075, -0.10281121730804443,
0.24321036040782928, 0.9076734185218811, -0.342020183801651, 6.130080699920654,
0, 0, 0, 1);
//! [camera-pose-from-Blender-at-location-2]
//! [camera-intrinsics-from-Blender]
Mat cameraMatrix = (Mat_<double>(3,3) << 700.0, 0.0, 320.0,
0.0, 700.0, 240.0,
0, 0, 1);
//! [camera-intrinsics-from-Blender]
//! [extract-rotation]
Mat R1 = c1Mo(Range(0,3), Range(0,3));
Mat R2 = c2Mo(Range(0,3), Range(0,3));
//! [extract-rotation]
//! [compute-rotation-displacement]
//c1Mo * oMc2
Mat R_2to1 = R1*R2.t();
//! [compute-rotation-displacement]
//! [compute-homography]
Mat H = cameraMatrix * R_2to1 * cameraMatrix.inv();
H /= H.at<double>(2,2);
cout << "H:\n" << H << endl;
//! [compute-homography]
//! [stitch]
Mat img_stitch;
warpPerspective(img2, img_stitch, H, Size(img2.cols*2, img2.rows));
Mat half = img_stitch(Rect(0, 0, img1.cols, img1.rows));
img1.copyTo(half);
//! [stitch]
Mat img_compare;
Mat img_space = Mat::zeros(Size(50, img1.rows), CV_8UC3);
hconcat(img1, img_space, img_compare);
hconcat(img_compare, img2, img_compare);
imshow("Compare images", img_compare);
imshow("Panorama stitching", img_stitch);
waitKey();
}
const char* params
= "{ help h | | print usage }"
"{ image1 | Blender_Suzanne1.jpg | path to the first Blender image }"
"{ image2 | Blender_Suzanne2.jpg | path to the second Blender image }";
}
int main(int argc, char *argv[])
{
CommandLineParser parser(argc, argv, params);
if (parser.has("help"))
{
parser.about( "Code for homography tutorial.\n"
"Example 5: basic panorama stitching from a rotating camera.\n" );
parser.printMessage();
return 0;
}
basicPanoramaStitching(parser.get<String>("image1"), parser.get<String>("image2"));
return 0;
}

View File

@ -0,0 +1,96 @@
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/calib3d.hpp>
#include <opencv2/highgui.hpp>
using namespace std;
using namespace cv;
namespace
{
enum Pattern { CHESSBOARD, CIRCLES_GRID, ASYMMETRIC_CIRCLES_GRID };
Scalar randomColor( RNG& rng )
{
int icolor = (unsigned int) rng;
return Scalar( icolor & 255, (icolor >> 8) & 255, (icolor >> 16) & 255 );
}
void perspectiveCorrection(const string &img1Path, const string &img2Path, const Size &patternSize, RNG &rng)
{
Mat img1 = imread( samples::findFile(img1Path) );
Mat img2 = imread( samples::findFile(img2Path) );
//! [find-corners]
vector<Point2f> corners1, corners2;
bool found1 = findChessboardCorners(img1, patternSize, corners1);
bool found2 = findChessboardCorners(img2, patternSize, corners2);
//! [find-corners]
if (!found1 || !found2)
{
cout << "Error, cannot find the chessboard corners in both images." << endl;
return;
}
//! [estimate-homography]
Mat H = findHomography(corners1, corners2);
cout << "H:\n" << H << endl;
//! [estimate-homography]
//! [warp-chessboard]
Mat img1_warp;
warpPerspective(img1, img1_warp, H, img1.size());
//! [warp-chessboard]
Mat img_draw_warp;
hconcat(img2, img1_warp, img_draw_warp);
imshow("Desired chessboard view / Warped source chessboard view", img_draw_warp);
//! [compute-transformed-corners]
Mat img_draw_matches;
hconcat(img1, img2, img_draw_matches);
for (size_t i = 0; i < corners1.size(); i++)
{
Mat pt1 = (Mat_<double>(3,1) << corners1[i].x, corners1[i].y, 1);
Mat pt2 = H * pt1;
pt2 /= pt2.at<double>(2);
Point end( (int) (img1.cols + pt2.at<double>(0)), (int) pt2.at<double>(1) );
line(img_draw_matches, corners1[i], end, randomColor(rng), 2);
}
imshow("Draw matches", img_draw_matches);
waitKey();
//! [compute-transformed-corners]
}
const char* params
= "{ help h | | print usage }"
"{ image1 | left02.jpg | path to the source chessboard image }"
"{ image2 | left01.jpg | path to the desired chessboard image }"
"{ width bw | 9 | chessboard width }"
"{ height bh | 6 | chessboard height }";
}
int main(int argc, char *argv[])
{
cv::RNG rng( 0xFFFFFFFF );
CommandLineParser parser(argc, argv, params);
if (parser.has("help"))
{
parser.about("Code for homography tutorial.\n"
"Example 2: perspective correction.\n");
parser.printMessage();
return 0;
}
Size patternSize(parser.get<int>("width"), parser.get<int>("height"));
perspectiveCorrection(parser.get<String>("image1"),
parser.get<String>("image2"),
patternSize, rng);
return 0;
}

View File

@ -0,0 +1,155 @@
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/calib3d.hpp>
#include <opencv2/highgui.hpp>
using namespace std;
using namespace cv;
namespace
{
enum Pattern { CHESSBOARD, CIRCLES_GRID, ASYMMETRIC_CIRCLES_GRID };
void calcChessboardCorners(Size boardSize, float squareSize, vector<Point3f>& corners, Pattern patternType = CHESSBOARD)
{
corners.resize(0);
switch (patternType)
{
case CHESSBOARD:
case CIRCLES_GRID:
//! [compute-chessboard-object-points]
for( int i = 0; i < boardSize.height; i++ )
for( int j = 0; j < boardSize.width; j++ )
corners.push_back(Point3f(float(j*squareSize),
float(i*squareSize), 0));
//! [compute-chessboard-object-points]
break;
case ASYMMETRIC_CIRCLES_GRID:
for( int i = 0; i < boardSize.height; i++ )
for( int j = 0; j < boardSize.width; j++ )
corners.push_back(Point3f(float((2*j + i % 2)*squareSize),
float(i*squareSize), 0));
break;
default:
CV_Error(Error::StsBadArg, "Unknown pattern type\n");
}
}
void poseEstimationFromCoplanarPoints(const string &imgPath, const string &intrinsicsPath, const Size &patternSize,
const float squareSize)
{
Mat img = imread( samples::findFile( imgPath) );
Mat img_corners = img.clone(), img_pose = img.clone();
//! [find-chessboard-corners]
vector<Point2f> corners;
bool found = findChessboardCorners(img, patternSize, corners);
//! [find-chessboard-corners]
if (!found)
{
cout << "Cannot find chessboard corners." << endl;
return;
}
drawChessboardCorners(img_corners, patternSize, corners, found);
imshow("Chessboard corners detection", img_corners);
//! [compute-object-points]
vector<Point3f> objectPoints;
calcChessboardCorners(patternSize, squareSize, objectPoints);
vector<Point2f> objectPointsPlanar;
for (size_t i = 0; i < objectPoints.size(); i++)
{
objectPointsPlanar.push_back(Point2f(objectPoints[i].x, objectPoints[i].y));
}
//! [compute-object-points]
//! [load-intrinsics]
FileStorage fs( samples::findFile( intrinsicsPath ), FileStorage::READ);
Mat cameraMatrix, distCoeffs;
fs["camera_matrix"] >> cameraMatrix;
fs["distortion_coefficients"] >> distCoeffs;
//! [load-intrinsics]
//! [compute-image-points]
vector<Point2f> imagePoints;
undistortPoints(corners, imagePoints, cameraMatrix, distCoeffs);
//! [compute-image-points]
//! [estimate-homography]
Mat H = findHomography(objectPointsPlanar, imagePoints);
cout << "H:\n" << H << endl;
//! [estimate-homography]
//! [pose-from-homography]
// Normalization to ensure that ||c1|| = 1
double norm = sqrt(H.at<double>(0,0)*H.at<double>(0,0) +
H.at<double>(1,0)*H.at<double>(1,0) +
H.at<double>(2,0)*H.at<double>(2,0));
H /= norm;
Mat c1 = H.col(0);
Mat c2 = H.col(1);
Mat c3 = c1.cross(c2);
Mat tvec = H.col(2);
Mat R(3, 3, CV_64F);
for (int i = 0; i < 3; i++)
{
R.at<double>(i,0) = c1.at<double>(i,0);
R.at<double>(i,1) = c2.at<double>(i,0);
R.at<double>(i,2) = c3.at<double>(i,0);
}
//! [pose-from-homography]
//! [polar-decomposition-of-the-rotation-matrix]
cout << "R (before polar decomposition):\n" << R << "\ndet(R): " << determinant(R) << endl;
Mat W, U, Vt;
SVDecomp(R, W, U, Vt);
R = U*Vt;
cout << "R (after polar decomposition):\n" << R << "\ndet(R): " << determinant(R) << endl;
//! [polar-decomposition-of-the-rotation-matrix]
//! [display-pose]
Mat rvec;
Rodrigues(R, rvec);
drawFrameAxes(img_pose, cameraMatrix, distCoeffs, rvec, tvec, 2*squareSize);
imshow("Pose from coplanar points", img_pose);
waitKey();
//! [display-pose]
}
const char* params
= "{ help h | | print usage }"
"{ image | left04.jpg | path to a chessboard image }"
"{ intrinsics | left_intrinsics.yml | path to camera intrinsics }"
"{ width bw | 9 | chessboard width }"
"{ height bh | 6 | chessboard height }"
"{ square_size | 0.025 | chessboard square size }";
}
int main(int argc, char *argv[])
{
CommandLineParser parser(argc, argv, params);
if (parser.has("help"))
{
parser.about("Code for homography tutorial.\n"
"Example 1: pose from homography with coplanar points.\n");
parser.printMessage();
return 0;
}
Size patternSize(parser.get<int>("width"), parser.get<int>("height"));
float squareSize = (float) parser.get<double>("square_size");
poseEstimationFromCoplanarPoints(parser.get<String>("image"),
parser.get<String>("intrinsics"),
patternSize, squareSize);
return 0;
}