Originally I have a image with a perfect circle grid, denoted as A
I add some lens distortion and perspective transformation to it, and it becomes B.
In camera calibration, A would be my destination image, and B would be my source image.
Let's say I have all the circle center coordinates in both images, stored in stdPts and disPts.
//25 center pts in A
vector<Point2f> stdPts;
for (int i = 0; i <= 4; ++i) {
for (int j = 0; j <= 4; ++j) {
stdPts[i * 5 + j].x = 250 + i * 500;
stdPts[i * 5 + j].y = 200 + j * 400;
}
}
//25 center pts in B
vector<Point2f> disPts = FindCircleCenter();
I want to generate an image C that is as close as A, from input: B, stdPts and disPts.
I tried to use the intrinsic and extrinsic generated by cv::calibrateCamera. Here is my code:
//prepare object_points and image_points
vector<vector<Point3f>> object_points;
vector<vector<Point2f>> image_points;
object_points.push_back(stdPts);
image_points.push_back(disPts);
//prepare distCoeffs rvecs tvecs
Mat distCoeffs = Mat::zeros(5, 1, CV_64F);
vector<Mat> rvecs;
vector<Mat> tvecs;
//prepare camera matrix
Mat intrinsic = Mat::eye(3, 3, CV_64F);
//solve calibration
calibrateCamera(object_points, image_points, Size(2500,2000), intrinsic, distCoeffs, rvecs, tvecs);
//apply undistortion
string inputName = "../B.jpg";
Mat imgB = imread(imgName);
cvtColor(imgB, imgB, CV_BGR2GRAY)
Mat tempImgC;
undistort(imgB, tempImgC, intrinsic, distCoeffs);
//apply perspective transform
double transData[] = { 0, 0, tvecs[0].at<double>(0), 0, 0,,tvecs[0].at<double>(1), 0, 0, tvecs[0].at<double>(2) };
Mat translate3x3(3, 3, CV_64F, transData);
Mat rotation3x3;
Rodrigues(rvecs[0], rotation3x3);
Mat transRot3x3(3, 3, CV_64F);
rotation3x3.col(0).copyTo(transRot3x3.col(0));
rotation3x3.col(1).copyTo(transRot3x3.col(1));
translate3x3.col(2).copyTo(transRot3x3.col(2));
Mat imgC;
Mat matPerspective = intrinsic*transRot3x3;
warpPerspective(tempImgC, imgC, matPerspective, Size(2500, 2000));
//write
string outputName = "../C.jpg";
imwrite(outputName, imgC); // A JPG FILE IS BEING SAVED
And here is the result image C,which looks like a scaled-up version of A.
So I tried to experiment with the scale a little bit. The code is changed to
// apply distortion
Mat scale = Mat::eye(3, 3, CV_64F);
intrinsic.copyTo(scale);
scale.at<double>(0,0) /= 1.3;
scale.at<double>(1,1) /= 1.3;
undistort(imgB, tempImgC, intrinsic, distCoeffs,scale);
//apply perspective transform
Mat newIntrinsic;
intrinsic.copyTo(newIntrinsic);
newIntrinsic.at<double>(0,0) /= 1.1;
newIntrinsic.at<double>(1,1) /= 1.1;
Mat matPerspective = newIntrinsic*transRot3x3;
warpPerspective(tempImgC, imgC, matPerspective, Size(2500, 2000));
And the result looks better, denoted as C'
So could someone help me explain what is going on with the scale, and calculate the right scale to match the grid size in C to the one in A? Thanks.