@ -34,7 +34,8 @@ public:
void write ( FileStorage & fs ) const //Write serialization for this class
{
fs < < " { " < < " BoardSize_Width " < < boardSize . width
fs < < " { "
< < " BoardSize_Width " < < boardSize . width
< < " BoardSize_Height " < < boardSize . height
< < " Square_Size " < < squareSize
< < " Calibrate_Pattern " < < patternToUse
@ -43,8 +44,8 @@ public:
< < " Calibrate_AssumeZeroTangentialDistortion " < < calibZeroTangentDist
< < " Calibrate_FixPrincipalPointAtTheCenter " < < calibFixPrincipalPoint
< < " Write_DetectedFeaturePoints " < < b writePoints
< < " Write_extrinsicParameters " < < b writeExtrinsics
< < " Write_DetectedFeaturePoints " < < writePoints
< < " Write_extrinsicParameters " < < writeExtrinsics
< < " Write_outputFileName " < < outputFileName
< < " Show_UndistortedImage " < < showUndistorsed
@ -62,8 +63,8 @@ public:
node [ " Square_Size " ] > > squareSize ;
node [ " Calibrate_NrOfFrameToUse " ] > > nrFrames ;
node [ " Calibrate_FixAspectRatio " ] > > aspectRatio ;
node [ " Write_DetectedFeaturePoints " ] > > b writePoints;
node [ " Write_extrinsicParameters " ] > > b writeExtrinsics;
node [ " Write_DetectedFeaturePoints " ] > > writePoints ;
node [ " Write_extrinsicParameters " ] > > writeExtrinsics ;
node [ " Write_outputFileName " ] > > outputFileName ;
node [ " Calibrate_AssumeZeroTangentialDistortion " ] > > calibZeroTangentDist ;
node [ " Calibrate_FixPrincipalPointAtTheCenter " ] > > calibFixPrincipalPoint ;
@ -71,9 +72,9 @@ public:
node [ " Show_UndistortedImage " ] > > showUndistorsed ;
node [ " Input " ] > > input ;
node [ " Input_Delay " ] > > delay ;
interpr ate( ) ;
valid ate( ) ;
}
void interpr ate( )
void valid ate( )
{
goodInput = true ;
if ( boardSize . width < = 0 | | boardSize . height < = 0 )
@ -105,10 +106,10 @@ public:
else
{
if ( readStringList ( input , imageList ) )
{
inputType = IMAGE_LIST ;
nrFrames = ( nrFrames < ( int ) imageList . size ( ) ) ? nrFrames : ( int ) imageList . size ( ) ;
}
{
inputType = IMAGE_LIST ;
nrFrames = ( nrFrames < ( int ) imageList . size ( ) ) ? nrFrames : ( int ) imageList . size ( ) ;
}
else
inputType = VIDEO_FILE ;
}
@ -121,7 +122,7 @@ public:
}
if ( inputType = = INVALID )
{
cerr < < " Inexistent inpu t: " < < input ;
cerr < < " Input does not exis t: " < < input ;
goodInput = false ;
}
@ -136,10 +137,10 @@ public:
if ( ! patternToUse . compare ( " CIRCLES_GRID " ) ) calibrationPattern = CIRCLES_GRID ;
if ( ! patternToUse . compare ( " ASYMMETRIC_CIRCLES_GRID " ) ) calibrationPattern = ASYMMETRIC_CIRCLES_GRID ;
if ( calibrationPattern = = NOT_EXISTING )
{
cerr < < " Inexistent camera calibration mode : " < < patternToUse < < endl ;
goodInput = false ;
}
{
cerr < < " Camera calibration mode does not exist : " < < patternToUse < < endl ;
goodInput = false ;
}
atImageList = 0 ;
}
@ -152,7 +153,7 @@ public:
inputCapture > > view0 ;
view0 . copyTo ( result ) ;
}
else if ( atImageList < ( int ) imageList . size ( ) )
else if ( atImageList < imageList . size ( ) )
result = imread ( imageList [ atImageList + + ] , IMREAD_COLOR ) ;
return result ;
@ -173,26 +174,24 @@ public:
return true ;
}
public :
Size boardSize ; // The size of the board -> Number of items by width and height
Pattern calibrationPattern ; // One of the Chessboard, circles, or asymmetric circle pattern
float squareSize ; // The size of a square in your defined unit (point, millimeter,etc).
int nrFrames ; // The number of frames to use from the input for calibration
float aspectRatio ; // The aspect ratio
int delay ; // In case of a video input
bool bwritePoints ; // Write detected feature points
bool bwriteExtrinsics ; // Write extrinsic parameters
bool calibZeroTangentDist ; // Assume zero tangential distortion
bool calibFixPrincipalPoint ; // Fix the principal point at the center
bool flipVertical ; // Flip the captured images around the horizontal axis
string outputFileName ; // The name of the file where to write
bool showUndistorsed ; // Show undistorted images after calibration
string input ; // The input ->
Size boardSize ; // The size of the board -> Number of items by width and height
Pattern calibrationPattern ; // One of the Chessboard, circles, or asymmetric circle pattern
float squareSize ; // The size of a square in your defined unit (point, millimeter,etc).
int nrFrames ; // The number of frames to use from the input for calibration
float aspectRatio ; // The aspect ratio
int delay ; // In case of a video input
bool writePoints ; // Write detected feature points
bool writeExtrinsics ; // Write extrinsic parameters
bool calibZeroTangentDist ; // Assume zero tangential distortion
bool calibFixPrincipalPoint ; // Fix the principal point at the center
bool flipVertical ; // Flip the captured images around the horizontal axis
string outputFileName ; // The name of the file where to write
bool showUndistorsed ; // Show undistorted images after calibration
string input ; // The input ->
int cameraID ;
vector < string > imageList ;
in t atImageList ;
size_ t atImageList ;
VideoCapture inputCapture ;
InputType inputType ;
bool goodInput ;
@ -204,7 +203,7 @@ private:
} ;
static void read ( const FileNode & node , Settings & x , const Settings & default_value = Settings ( ) )
static inline void read ( const FileNode & node , Settings & x , const Settings & default_value = Settings ( ) )
{
if ( node . empty ( ) )
x = default_value ;
@ -212,6 +211,11 @@ static void read(const FileNode& node, Settings& x, const Settings& default_valu
x . read ( node ) ;
}
static inline void write ( FileStorage & fs , const String & , const Settings & s )
{
s . write ( fs ) ;
}
enum { DETECTION = 0 , CAPTURING = 1 , CALIBRATED = 2 } ;
bool runCalibrationAndSave ( Settings & s , Size imageSize , Mat & cameraMatrix , Mat & distCoeffs ,
@ -220,6 +224,8 @@ bool runCalibrationAndSave(Settings& s, Size imageSize, Mat& cameraMatrix, Mat&
int main ( int argc , char * argv [ ] )
{
help ( ) ;
//! [file_read]
Settings s ;
const string inputSettingsFile = argc > 1 ? argv [ 1 ] : " default.xml " ;
FileStorage fs ( inputSettingsFile , FileStorage : : READ ) ; // Read the settings
@ -230,6 +236,10 @@ int main(int argc, char* argv[])
}
fs [ " Settings " ] > > s ;
fs . release ( ) ; // close Settings file
//! [file_read]
//FileStorage fout("settings.yml", FileStorage::WRITE); // write config as YAML
//fout << "Settings" << s;
if ( ! s . goodInput )
{
@ -245,32 +255,35 @@ int main(int argc, char* argv[])
const Scalar RED ( 0 , 0 , 255 ) , GREEN ( 0 , 255 , 0 ) ;
const char ESC_KEY = 27 ;
for ( int i = 0 ; ; + + i )
//! [get_input]
for ( ; ; )
{
Mat view ;
bool blinkOutput = false ;
Mat view ;
bool blinkOutput = false ;
view = s . nextImage ( ) ;
view = s . nextImage ( ) ;
//----- If no more image, or got enough, then stop calibration and show result -------------
if ( mode = = CAPTURING & & imagePoints . size ( ) > = ( unsigned ) s . nrFrames )
{
//----- If no more image, or got enough, then stop calibration and show result -------------
if ( mode = = CAPTURING & & imagePoints . size ( ) > = ( size_t ) s . nrFrames )
{
if ( runCalibrationAndSave ( s , imageSize , cameraMatrix , distCoeffs , imagePoints ) )
mode = CALIBRATED ;
else
mode = DETECTION ;
}
if ( view . empty ( ) ) // If no more images then run calibration, save and stop loop.
{
if ( imagePoints . size ( ) > 0 )
}
if ( view . empty ( ) ) // If there are no more images stop the loop
{
// if calibration threshold was not reached yet, calibrate now
if ( mode ! = CALIBRATED & & ! imagePoints . empty ( ) )
runCalibrationAndSave ( s , imageSize , cameraMatrix , distCoeffs , imagePoints ) ;
break ;
}
}
//! [get_input]
imageSize = view . size ( ) ; // Format input image.
if ( s . flipVertical ) flip ( view , view , 0 ) ;
//! [find_pattern]
vector < Point2f > pointBuf ;
bool found ;
@ -290,7 +303,8 @@ int main(int argc, char* argv[])
found = false ;
break ;
}
//! [find_pattern]
//! [pattern_found]
if ( found ) // If done with success,
{
// improve the found corners' coordinate accuracy for chessboard
@ -313,8 +327,9 @@ int main(int argc, char* argv[])
// Draw the corners.
drawChessboardCorners ( view , s . boardSize , Mat ( pointBuf ) , found ) ;
}
//! [pattern_found]
//----------------------------- Output Text ------------------------------------------------
//! [output_text]
string msg = ( mode = = CAPTURING ) ? " 100/100 " :
mode = = CALIBRATED ? " Calibrated " : " Press 'g' to start " ;
int baseLine = 0 ;
@ -333,15 +348,17 @@ int main(int argc, char* argv[])
if ( blinkOutput )
bitwise_not ( view , view ) ;
//! [output_text]
//------------------------- Video capture output undistorted ------------------------------
//! [output_undistorted]
if ( mode = = CALIBRATED & & s . showUndistorsed )
{
Mat temp = view . clone ( ) ;
undistort ( temp , view , cameraMatrix , distCoeffs ) ;
}
//! [output_undistorted]
//------------------------------ Show image and check for input commands -------------------
//! [await_input]
imshow ( " Image View " , view ) ;
char key = ( char ) waitKey ( s . inputCapture . isOpened ( ) ? 50 : s . delay ) ;
@ -356,9 +373,11 @@ int main(int argc, char* argv[])
mode = CAPTURING ;
imagePoints . clear ( ) ;
}
//! [await_input]
}
// -----------------------Show the undistorted image for the image list ------------------------
//! [show_results]
if ( s . inputType = = Settings : : IMAGE_LIST & & s . showUndistorsed )
{
Mat view , rview , map1 , map2 ;
@ -366,7 +385,7 @@ int main(int argc, char* argv[])
getOptimalNewCameraMatrix ( cameraMatrix , distCoeffs , imageSize , 1 , imageSize , 0 ) ,
imageSize , CV_16SC2 , map1 , map2 ) ;
for ( in t i = 0 ; i < ( int ) s . imageList . size ( ) ; i + + )
for ( size_ t i = 0 ; i < s . imageList . size ( ) ; i + + )
{
view = imread ( s . imageList [ i ] , 1 ) ;
if ( view . empty ( ) )
@ -378,11 +397,12 @@ int main(int argc, char* argv[])
break ;
}
}
//! [show_results]
return 0 ;
}
//! [compute_errors]
static double computeReprojectionErrors ( const vector < vector < Point3f > > & objectPoints ,
const vector < vector < Point2f > > & imagePoints ,
const vector < Mat > & rvecs , const vector < Mat > & tvecs ,
@ -390,17 +410,16 @@ static double computeReprojectionErrors( const vector<vector<Point3f> >& objectP
vector < float > & perViewErrors )
{
vector < Point2f > imagePoints2 ;
int i , totalPoints = 0 ;
size_t totalPoints = 0 ;
double totalErr = 0 , err ;
perViewErrors . resize ( objectPoints . size ( ) ) ;
for ( i = 0 ; i < ( int ) objectPoints . size ( ) ; + + i )
for ( size_t i = 0 ; i < objectPoints . size ( ) ; + + i )
{
projectPoints ( Mat ( objectPoints [ i ] ) , rvecs [ i ] , tvecs [ i ] , cameraMatrix ,
distCoeffs , imagePoints2 ) ;
err = norm ( Mat ( imagePoints [ i ] ) , Mat ( imagePoints2 ) , NORM_L2 ) ;
projectPoints ( objectPoints [ i ] , rvecs [ i ] , tvecs [ i ] , cameraMatrix , distCoeffs , imagePoints2 ) ;
err = norm ( imagePoints [ i ] , imagePoints2 , NORM_L2 ) ;
in t n = ( int ) objectPoints [ i ] . size ( ) ;
size_ t n = objectPoints [ i ] . size ( ) ;
perViewErrors [ i ] = ( float ) std : : sqrt ( err * err / n ) ;
totalErr + = err * err ;
totalPoints + = n ;
@ -408,7 +427,8 @@ static double computeReprojectionErrors( const vector<vector<Point3f> >& objectP
return std : : sqrt ( totalErr / totalPoints ) ;
}
//! [compute_errors]
//! [board_corners]
static void calcBoardCornerPositions ( Size boardSize , float squareSize , vector < Point3f > & corners ,
Settings : : Pattern patternType /*= Settings::CHESSBOARD*/ )
{
@ -420,28 +440,28 @@ static void calcBoardCornerPositions(Size boardSize, float squareSize, vector<Po
case Settings : : 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 ) ) ;
corners . push_back ( Point3f ( j * squareSize , i * squareSize , 0 ) ) ;
break ;
case Settings : : 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 ) ) ;
corners . push_back ( Point3f ( ( 2 * j + i % 2 ) * squareSize , i * squareSize , 0 ) ) ;
break ;
default :
break ;
}
}
//! [board_corners]
static bool runCalibration ( Settings & s , Size & imageSize , Mat & cameraMatrix , Mat & distCoeffs ,
vector < vector < Point2f > > imagePoints , vector < Mat > & rvecs , vector < Mat > & tvecs ,
vector < float > & reprojErrs , double & totalAvgErr )
{
//! [fixed_aspect]
cameraMatrix = Mat : : eye ( 3 , 3 , CV_64F ) ;
if ( s . flag & CALIB_FIX_ASPECT_RATIO )
cameraMatrix . at < double > ( 0 , 0 ) = 1.0 ;
cameraMatrix . at < double > ( 0 , 0 ) = s . aspectRatio ;
//! [fixed_aspect]
distCoeffs = Mat : : zeros ( 8 , 1 , CV_64F ) ;
vector < vector < Point3f > > objectPoints ( 1 ) ;
@ -475,49 +495,48 @@ static void saveCameraParams( Settings& s, Size& imageSize, Mat& cameraMatrix, M
time ( & tm ) ;
struct tm * t2 = localtime ( & tm ) ;
char buf [ 1024 ] ;
strftime ( buf , sizeof ( buf ) - 1 , " %c " , t2 ) ;
strftime ( buf , sizeof ( buf ) , " %c " , t2 ) ;
fs < < " calibration_T ime " < < buf ;
fs < < " calibration_t ime " < < buf ;
if ( ! rvecs . empty ( ) | | ! reprojErrs . empty ( ) )
fs < < " nrOfF rames " < < ( int ) std : : max ( rvecs . size ( ) , reprojErrs . size ( ) ) ;
fs < < " image_W idth " < < imageSize . width ;
fs < < " image_H eight " < < imageSize . height ;
fs < < " board_W idth " < < s . boardSize . width ;
fs < < " board_H eight " < < s . boardSize . height ;
fs < < " square_S ize " < < s . squareSize ;
fs < < " nr_of_f rames " < < ( int ) std : : max ( rvecs . size ( ) , reprojErrs . size ( ) ) ;
fs < < " image_w idth " < < imageSize . width ;
fs < < " image_h eight " < < imageSize . height ;
fs < < " board_w idth " < < s . boardSize . width ;
fs < < " board_h eight " < < s . boardSize . height ;
fs < < " square_s ize " < < s . squareSize ;
if ( s . flag & CALIB_FIX_ASPECT_RATIO )
fs < < " FixAspectR atio" < < s . aspectRatio ;
fs < < " fix_aspect_r atio" < < s . aspectRatio ;
if ( s . flag )
if ( s . flag )
{
sprintf ( buf , " flags: %s%s%s%s " ,
s . flag & CALIB_USE_INTRINSIC_GUESS ? " +use_intrinsic_guess " : " " ,
s . flag & CALIB_FIX_ASPECT_RATIO ? " +fix_aspectRatio " : " " ,
s . flag & CALIB_FIX_PRINCIPAL_POINT ? " +fix_principal_point " : " " ,
s . flag & CALIB_ZERO_TANGENT_DIST ? " +zero_tangent_dist " : " " ) ;
//cvWriteComment( *fs, buf, 0 );
sprintf ( buf , " flags: %s%s%s%s " ,
s . flag & CALIB_USE_INTRINSIC_GUESS ? " +use_intrinsic_guess " : " " ,
s . flag & CALIB_FIX_ASPECT_RATIO ? " +fix_aspect_ratio " : " " ,
s . flag & CALIB_FIX_PRINCIPAL_POINT ? " +fix_principal_point " : " " ,
s . flag & CALIB_ZERO_TANGENT_DIST ? " +zero_tangent_dist " : " " ) ;
cvWriteComment ( * fs , buf , 0 ) ;
}
fs < < " flagValue " < < s . flag ;
fs < < " flags " < < s . flag ;
fs < < " Camera_M atrix" < < cameraMatrix ;
fs < < " Distortion_C oefficients" < < distCoeffs ;
fs < < " camera_m atrix" < < cameraMatrix ;
fs < < " distortion_c oefficients" < < distCoeffs ;
fs < < " Avg_Reprojection_E rror" < < totalAvgErr ;
if ( ! reprojErrs . empty ( ) )
fs < < " Per_View_Reprojection_E rrors" < < Mat ( reprojErrs ) ;
fs < < " avg_reprojection_e rror" < < totalAvgErr ;
if ( s . writeExtrinsics & & ! reprojErrs . empty ( ) )
fs < < " per_view_reprojection_e rrors" < < Mat ( reprojErrs ) ;
if ( ! rvecs . empty ( ) & & ! tvecs . empty ( ) )
if ( s . writeExtrinsics & & ! rvecs . empty ( ) & & ! tvecs . empty ( ) )
{
CV_Assert ( rvecs [ 0 ] . type ( ) = = tvecs [ 0 ] . type ( ) ) ;
Mat bigmat ( ( int ) rvecs . size ( ) , 6 , rvecs [ 0 ] . type ( ) ) ;
for ( in t i = 0 ; i < ( int ) rvecs . size ( ) ; i + + )
for ( size_ t i = 0 ; i < rvecs . size ( ) ; i + + )
{
Mat r = bigmat ( Range ( i , i + 1 ) , Range ( 0 , 3 ) ) ;
Mat t = bigmat ( Range ( i , i + 1 ) , Range ( 3 , 6 ) ) ;
Mat r = bigmat ( Range ( int ( i ) , int ( i + 1 ) ) , Range ( 0 , 3 ) ) ;
Mat t = bigmat ( Range ( int ( i ) , int ( i + 1 ) ) , Range ( 3 , 6 ) ) ;
CV_Assert ( rvecs [ i ] . rows = = 3 & & rvecs [ i ] . cols = = 1 ) ;
CV_Assert ( tvecs [ i ] . rows = = 3 & & tvecs [ i ] . cols = = 1 ) ;
@ -526,35 +545,38 @@ static void saveCameraParams( Settings& s, Size& imageSize, Mat& cameraMatrix, M
t = tvecs [ i ] . t ( ) ;
}
//cvWriteComment( *fs, "a set of 6-tuples (rotation vector + translation vector) for each view", 0 );
fs < < " Extrinsic_P arameters" < < bigmat ;
fs < < " extrinsic_p arameters" < < bigmat ;
}
if ( ! imagePoints . empty ( ) )
if ( s . writePoints & & ! imagePoints . empty ( ) )
{
Mat imagePtMat ( ( int ) imagePoints . size ( ) , ( int ) imagePoints [ 0 ] . size ( ) , CV_32FC2 ) ;
for ( in t i = 0 ; i < ( int ) imagePoints . size ( ) ; i + + )
for ( size_ t i = 0 ; i < imagePoints . size ( ) ; i + + )
{
Mat r = imagePtMat . row ( i ) . reshape ( 2 , imagePtMat . cols ) ;
Mat r = imagePtMat . row ( int ( i ) ) . reshape ( 2 , imagePtMat . cols ) ;
Mat imgpti ( imagePoints [ i ] ) ;
imgpti . copyTo ( r ) ;
}
fs < < " I mage_points" < < imagePtMat ;
fs < < " i mage_points" < < imagePtMat ;
}
}
bool runCalibrationAndSave ( Settings & s , Size imageSize , Mat & cameraMatrix , Mat & distCoeffs , vector < vector < Point2f > > imagePoints )
//! [run_and_save]
bool runCalibrationAndSave ( Settings & s , Size imageSize , Mat & cameraMatrix , Mat & distCoeffs ,
vector < vector < Point2f > > imagePoints )
{
vector < Mat > rvecs , tvecs ;
vector < float > reprojErrs ;
double totalAvgErr = 0 ;
bool ok = runCalibration ( s , imageSize , cameraMatrix , distCoeffs , imagePoints , rvecs , tvecs ,
reprojErrs , totalAvgErr ) ;
bool ok = runCalibration ( s , imageSize , cameraMatrix , distCoeffs , imagePoints , rvecs , tvecs , reprojErr s ,
totalAvgErr ) ;
cout < < ( ok ? " Calibration succeeded " : " Calibration failed " )
< < " . avg re projection error = " < < totalAvgErr ;
< < " . avg re projection error = " < < totalAvgErr < < endl ;
if ( ok )
saveCameraParams ( s , imageSize , cameraMatrix , distCoeffs , rvecs , tvecs , reprojErrs ,
imagePoints , totalAvgErr ) ;
if ( ok )
saveCameraParams ( s , imageSize , cameraMatrix , distCoeffs , rvecs , tvecs , reprojErrs , imagePoint s ,
totalAvgErr ) ;
return ok ;
}
//! [run_and_save]