Created
November 2, 2020 06:24
-
-
Save robosina/b5129a64982876084a672553d22d5f86 to your computer and use it in GitHub Desktop.
camera calibration in opencv
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
int main(int argc, char* argv[]) { | |
int n_boards = 0; // Will be set by input list | |
float image_sf = 0.5f; | |
float delay = 1.f; | |
int board_w = 0; | |
int board_h = 0; | |
if(argc < 4 || argc > 6) { | |
cout << "\nERROR: Wrong number of input parameters"; | |
help( argv ); | |
return -1; | |
} | |
board_w = atoi( argv[1] ); | |
board_h = atoi( argv[2] ); | |
n_boards = atoi( argv[3] ); | |
if( argc > 4 ) delay = atof( argv[4] ); | |
if( argc > 5 ) image_sf = atof( argv[5] ); | |
int board_n = board_w * board_h; | |
cv::Size board_sz = cv::Size( board_w, board_h ); | |
cv::VideoCapture capture(0); | |
capture.set(cv::CAP_PROP_FRAME_WIDTH,640); | |
capture.set(cv::CAP_PROP_FRAME_HEIGHT,480); | |
if( !capture.isOpened() ) { | |
cout << "\nCouldn't open the camera\n"; | |
help( argv ); | |
return -1; | |
} | |
// ALLOCATE STORAGE | |
// | |
vector< vector<cv::Point2f> > image_points; | |
vector< vector<cv::Point3f> > object_points; | |
// Capture corner views: loop until we've got n_boards successful | |
// captures (all corners on the board are found). | |
// | |
double last_captured_timestamp = 0; | |
cv::Size image_size; | |
while( image_points.size() < (size_t)n_boards ) { | |
cv::Mat image0, image; | |
capture >> image0; | |
image_size = image0.size(); | |
cv::resize(image0, image, cv::Size(), image_sf, image_sf, cv::INTER_LINEAR ); | |
// Find the board | |
// | |
vector<cv::Point2f> corners; | |
bool found = cv::findChessboardCorners( image, board_sz, corners ); | |
// Draw it | |
// | |
drawChessboardCorners( image, board_sz, corners, found ); | |
// If we got a good board, add it to our data | |
// | |
double timestamp = (double)clock()/CLOCKS_PER_SEC; | |
if( found && timestamp - last_captured_timestamp > 1 ) { | |
last_captured_timestamp = timestamp; | |
image ^= cv::Scalar::all(255); | |
cv::Mat mcorners(corners); // do not copy the data | |
mcorners *= (1./image_sf); // scale the corner coordinates | |
image_points.push_back(corners); | |
object_points.push_back(vector<cv::Point3f>()); | |
vector<cv::Point3f>& opts = object_points.back(); | |
opts.resize(board_n); | |
for( int j=0; j<board_n; j++ ) { | |
opts[j] = cv::Point3f((float)(j/board_w), (float)(j%board_w), 0.f); | |
} | |
cout << "Collected our " << (int)image_points.size() << | |
" of " << n_boards << " needed chessboard images\n" << endl; | |
} | |
cv::imshow( "Calibration", image ); //show in color if we did collect the image | |
if((cv::waitKey(30) & 255) == 27) | |
return -1; | |
} | |
// END COLLECTION WHILE LOOP. | |
cv::destroyWindow( "Calibration" ); | |
cout << "\n\n*** CALIBRATING THE CAMERA...\n" << endl; | |
// CALIBRATE THE CAMERA! | |
// | |
cv::Mat intrinsic_matrix, distortion_coeffs; | |
double err = cv::calibrateCamera( | |
object_points, | |
image_points, | |
image_size, | |
intrinsic_matrix, | |
distortion_coeffs, | |
cv::noArray(), | |
cv::noArray(), | |
cv::CALIB_ZERO_TANGENT_DIST | cv::CALIB_FIX_PRINCIPAL_POINT | |
); | |
// SAVE THE INTRINSICS AND DISTORTIONS | |
cout << " *** DONE!\n\nReprojection error is " << err << | |
"\nStoring Intrinsics.xml and Distortions.xml files\n\n"; | |
cv::FileStorage fs( "intrinsics.xml", cv::FileStorage::WRITE ); | |
fs << "image_width" << image_size.width << "image_height" << image_size.height | |
<<"camera_matrix" << intrinsic_matrix << "distortion_coefficients" | |
<< distortion_coeffs; | |
fs.release(); | |
// EXAMPLE OF LOADING THESE MATRICES BACK IN: | |
fs.open( "intrinsics.xml", cv::FileStorage::READ ); | |
cout << "\nimage width: " << (int)fs["image_width"]; | |
cout << "\nimage height: " << (int)fs["image_height"]; | |
cv::Mat intrinsic_matrix_loaded, distortion_coeffs_loaded; | |
fs["camera_matrix"] >> intrinsic_matrix_loaded; | |
fs["distortion_coefficients"] >> distortion_coeffs_loaded; | |
cout << "\nintrinsic matrix:" << intrinsic_matrix_loaded; | |
cout << "\ndistortion coefficients: " << distortion_coeffs_loaded << endl; | |
// Build the undistort map which we will use for all | |
// subsequent frames. | |
// | |
cv::Mat map1, map2; | |
cv::initUndistortRectifyMap( | |
intrinsic_matrix_loaded, | |
distortion_coeffs_loaded, | |
cv::Mat(), | |
intrinsic_matrix_loaded, | |
image_size, | |
CV_16SC2, | |
map1, | |
map2 | |
); | |
// Just run the camera to the screen, now showing the raw and | |
// the undistorted image. | |
// | |
for(;;) { | |
cv::Mat image, image0; | |
capture >> image0; | |
if( image0.empty() ) break; | |
cv::remap( | |
image0, | |
image, | |
map1, | |
map2, | |
cv::INTER_LINEAR, | |
cv::BORDER_CONSTANT, | |
cv::Scalar() | |
); | |
cv::imshow("Undistorted", image); | |
if((cv::waitKey(30) & 255) == 27) break; | |
} | |
return 0; | |
// cv::findHomography() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment