Difference between revisions of "Example Calibrate Planar Stereo"

From BoofCV
Jump to navigationJump to search
m
m
(19 intermediate revisions by the same user not shown)
Line 1: Line 1:
= Stereo Camera Calibration with Planar Targets =
<center>
<center>
<gallery heights=220 widths=500 >
<gallery heights=220 widths=500 >
Line 10: Line 8:
This example demonstrate how to calibrate a stereo camera system using a high level interface which automatically detects calibration targets in a set of stereo images.  After calibration the intrinsic parameters of each camera is found as well as their extrinsic relationship with each other. Both the square grid and chessboard patterns are supported by this example.  For a full description of the calibration process and instruction on how to do it yourself see the tutorial linked to below.
This example demonstrate how to calibrate a stereo camera system using a high level interface which automatically detects calibration targets in a set of stereo images.  After calibration the intrinsic parameters of each camera is found as well as their extrinsic relationship with each other. Both the square grid and chessboard patterns are supported by this example.  For a full description of the calibration process and instruction on how to do it yourself see the tutorial linked to below.


Example File: [https://github.com/lessthanoptimal/BoofCV/blob/master/examples/src/boofcv/examples/ExampleCalibrateStereoPlanar.java ExampleCalibrateStereoPlanar.java]
Example File: [https://github.com/lessthanoptimal/BoofCV/blob/v0.37/examples/src/main/java/boofcv/examples/calibration/ExampleCalibrateStereo.java ExampleCalibrateStereo.java]


Calibration Tutorial: [[Tutorial_Camera_Calibration|Wikipage]]
Calibration Tutorial: [[Tutorial_Camera_Calibration|Wikipage]]
Line 19: Line 17:
* Intrinsic parameters
* Intrinsic parameters
* Stereo Vision
* Stereo Vision
Relevant Applets:
* [[Applet_Calibrate_Planar_Stereo| Stereo Calibration]]


Related Examples:
Related Examples:
Line 31: Line 26:
<syntaxhighlight lang="java">
<syntaxhighlight lang="java">
/**
/**
  * Example of how to calibrate a single (monocular) camera given a set of observed calibration.
  * Example of how to calibrate a stereo camera system using a planar calibration grid given a set of images.
  * points using the Zhang99 algorithm. Unlike in the other examples, the image processing has
  * Intrinsic camera parameters are estimated for both cameras individually, then extrinsic parameters
  * not already been done. In theory you could add your own more exotic targets by writing
  * for the two cameras relative to each other are found  This example does not rectify the images, which is
  * custom code to detect the target, which is left as an exercise for the readerFor example,
  * required for some algorithms. See {@link boofcv.examples.stereo.ExampleRectifyCalibratedStereo}. Both square grid and chessboard targets
  * have multiple targets visible or calibrate using circles.
  * are demonstrated in this example. See calibration tutorial for a discussion of different target types and how to
* collect good calibration images.
*
* All the image processing and calibration is taken care of inside of {@link CalibrateStereoPlanar}.  The code below
* loads calibration images as inputs, calibrates, and saves results to an XML file.  See in code comments for tuning
* and implementation issues.
  *
  * @see boofcv.examples.stereo.ExampleRectifyCalibratedStereo
* @see CalibrateStereoPlanar
  *
  *
  * @author Peter Abeles
  * @author Peter Abeles
  */
  */
public class ExampleCalibrateMonocularPoints {
public class ExampleCalibrateStereo {
 
// Detects the target and calibration point inside the target
DetectorFiducialCalibration detector;
 
// List of calibration images
List<String> left;
List<String> right;


/**
/**
* Given a description of the calibration target and the observed location of the calibration
* Square grid target taken by a PtGrey Bumblebee camera.
*
* @param targetDesc Describes the target's known physical structure
* @param observations Observations of the target in different images
*/
*/
public static void calibrate( PlanarCalibrationTarget targetDesc ,
public void setupBumblebeeSquare() {
  List<List<Point2D_F64>> observations ) {
// Creates a detector and specifies its physical characteristics
detector = FactoryFiducialCalibration.squareGrid(null,new ConfigGridDimen(4, 3, 30, 30));


// Assume zero skew and model lens distortion with two radial parameters
String directory = UtilIO.pathExample("calibration/stereo/Bumblebee2_Square");
CalibrationPlanarGridZhang99 zhang99 =
new CalibrationPlanarGridZhang99(targetDesc,true,2);


if( !zhang99.process(observations) )
left = UtilIO.listByPrefix(directory, "left", null);
throw new RuntimeException("Calibration failed!");
right = UtilIO.listByPrefix(directory, "right", null);
}


// Get camera parameters and extrinsic target location in each image
/**
Zhang99Parameters found = zhang99.getOptimized();
* Chessboard target taken by a PtGrey Bumblebee camera.
*/
public void setupBumblebeeChess() {
// Creates a detector and specifies its physical characteristics
detector = FactoryFiducialCalibration.chessboardX(null,new ConfigGridDimen(7, 5, 30));


// Convenient function for converting from specialized Zhang99 format to generalized
String directory = UtilIO.pathExample("calibration/stereo/Bumblebee2_Chess");
IntrinsicParameters param = found.convertToIntrinsic();


// print the results to standard out
left = UtilIO.listByPrefix(directory, "left", null);
param.print();
right = UtilIO.listByPrefix(directory, "right", null);
// save to a file using XML
BoofMiscOps.saveXML(param,"intrinsic.xml");
}
}


/**
/**
* Detects calibration points found in several images and returned as a list. Not the focus of this example.
* Process calibration images, compute intrinsic parameters, save to a file
*/
*/
public static List<List<Point2D_F64>> loadObservations() {
public void process() {
// Declare and setup the calibration algorithm
var calibratorAlg = new CalibrateStereoPlanar(detector.getLayout());
calibratorAlg.configure(true, 2, false);
// Uncomment to print more information to stdout
// calibratorAlg.setVerbose(System.out,null);
 
// ensure the lists are in the same order
Collections.sort(left);
Collections.sort(right);


String directory = "../data/evaluation/calibration/stereo/Bumblebee2_Chess";
for( int i = 0; i < left.size(); i++ ) {
List<String> imageNames = BoofMiscOps.directoryList(directory,"left");
BufferedImage l = UtilImageIO.loadImage(left.get(i));
BufferedImage r = UtilImageIO.loadImage(right.get(i));


PlanarCalibrationDetector detector = FactoryPlanarCalibrationTarget.detectorChessboard(3, 4, 6);
GrayF32 imageLeft = ConvertBufferedImage.convertFrom(l,(GrayF32)null);
GrayF32 imageRight = ConvertBufferedImage.convertFrom(r,(GrayF32)null);


List<List<Point2D_F64>> ret = new ArrayList<List<Point2D_F64>>();
CalibrationObservation calibLeft,calibRight;
if( !detector.process(imageLeft)) {
System.out.println("Failed to detect target in "+left.get(i));
continue;
}
calibLeft = detector.getDetectedPoints();
if( !detector.process(imageRight)) {
System.out.println("Failed to detect target in "+right.get(i));
continue;
}
calibRight = detector.getDetectedPoints();


for( String n : imageNames ) {
calibratorAlg.addPair(calibLeft, calibRight);
BufferedImage img = UtilImageIO.loadImage(n);
}
ImageFloat32 input = ConvertBufferedImage.convertFrom(img,(ImageFloat32)null);


if( !detector.process(input) )
// Process and compute calibration parameters
throw new RuntimeException("Detection failed!");
StereoParameters stereoCalib = calibratorAlg.process();


ret.add(detector.getPoints());
// print out information on its accuracy and errors
}
calibratorAlg.printStatistics();
 
// save results to a file and print out
CalibrationIO.save(stereoCalib, "stereo.yaml");
stereoCalib.print();


return ret;
// Note that the stereo baseline translation will be specified in the same units as the calibration grid.
// Which is in millimeters (mm) in this example.
}
}


public static void main( String args[] ) {
public static void main( String[] args ) {
// target description and list of observations
ExampleCalibrateStereo alg = new ExampleCalibrateStereo();
PlanarCalibrationTarget desc = FactoryPlanarCalibrationTarget.gridChess(3, 4, 30);
 
List<List<Point2D_F64>> calibPts = loadObservations();
// Select which set of targets to use
alg.setupBumblebeeChess();
// alg.setupBumblebeeSquare();


// Calibrate the camera
// compute and save results
calibrate(desc,calibPts);
alg.process();
}
}
}
}
</syntaxhighlight>
</syntaxhighlight>

Revision as of 12:45, 21 December 2020

This example demonstrate how to calibrate a stereo camera system using a high level interface which automatically detects calibration targets in a set of stereo images. After calibration the intrinsic parameters of each camera is found as well as their extrinsic relationship with each other. Both the square grid and chessboard patterns are supported by this example. For a full description of the calibration process and instruction on how to do it yourself see the tutorial linked to below.

Example File: ExampleCalibrateStereo.java

Calibration Tutorial: Wikipage

Concepts:

  • Camera calibration
  • Lens distortion
  • Intrinsic parameters
  • Stereo Vision

Related Examples:

Example Code

/**
 * Example of how to calibrate a stereo camera system using a planar calibration grid given a set of images.
 * Intrinsic camera parameters are estimated for both cameras individually, then extrinsic parameters
 * for the two cameras relative to each other are found   This example does not rectify the images, which is
 * required for some algorithms. See {@link boofcv.examples.stereo.ExampleRectifyCalibratedStereo}. Both square grid and chessboard targets
 * are demonstrated in this example. See calibration tutorial for a discussion of different target types and how to
 * collect good calibration images.
 *
 * All the image processing and calibration is taken care of inside of {@link CalibrateStereoPlanar}.  The code below
 * loads calibration images as inputs, calibrates, and saves results to an XML file.  See in code comments for tuning
 * and implementation issues.
 *
 * @see boofcv.examples.stereo.ExampleRectifyCalibratedStereo
 * @see CalibrateStereoPlanar
 *
 * @author Peter Abeles
 */
public class ExampleCalibrateStereo {

	// Detects the target and calibration point inside the target
	DetectorFiducialCalibration detector;

	// List of calibration images
	List<String> left;
	List<String> right;

	/**
	 * Square grid target taken by a PtGrey Bumblebee camera.
	 */
	public void setupBumblebeeSquare() {
		// Creates a detector and specifies its physical characteristics
		detector = FactoryFiducialCalibration.squareGrid(null,new ConfigGridDimen(4, 3, 30, 30));

		String directory = UtilIO.pathExample("calibration/stereo/Bumblebee2_Square");

		left = UtilIO.listByPrefix(directory, "left", null);
		right = UtilIO.listByPrefix(directory, "right", null);
	}

	/**
	 * Chessboard target taken by a PtGrey Bumblebee camera.
	 */
	public void setupBumblebeeChess() {
		// Creates a detector and specifies its physical characteristics
		detector = FactoryFiducialCalibration.chessboardX(null,new ConfigGridDimen(7, 5, 30));

		String directory = UtilIO.pathExample("calibration/stereo/Bumblebee2_Chess");

		left = UtilIO.listByPrefix(directory, "left", null);
		right = UtilIO.listByPrefix(directory, "right", null);
	}

	/**
	 * Process calibration images, compute intrinsic parameters, save to a file
	 */
	public void process() {
		// Declare and setup the calibration algorithm
		var calibratorAlg = new CalibrateStereoPlanar(detector.getLayout());
		calibratorAlg.configure(true, 2, false);
		// Uncomment to print more information to stdout
//		calibratorAlg.setVerbose(System.out,null);

		// ensure the lists are in the same order
		Collections.sort(left);
		Collections.sort(right);

		for( int i = 0; i < left.size(); i++ ) {
			BufferedImage l = UtilImageIO.loadImage(left.get(i));
			BufferedImage r = UtilImageIO.loadImage(right.get(i));

			GrayF32 imageLeft = ConvertBufferedImage.convertFrom(l,(GrayF32)null);
			GrayF32 imageRight = ConvertBufferedImage.convertFrom(r,(GrayF32)null);

			CalibrationObservation calibLeft,calibRight;
			if( !detector.process(imageLeft)) {
				System.out.println("Failed to detect target in "+left.get(i));
				continue;
			}
			calibLeft = detector.getDetectedPoints();
			if( !detector.process(imageRight)) {
				System.out.println("Failed to detect target in "+right.get(i));
				continue;
			}
			calibRight = detector.getDetectedPoints();

			calibratorAlg.addPair(calibLeft, calibRight);
		}

		// Process and compute calibration parameters
		StereoParameters stereoCalib = calibratorAlg.process();

		// print out information on its accuracy and errors
		calibratorAlg.printStatistics();

		// save results to a file and print out
		CalibrationIO.save(stereoCalib, "stereo.yaml");
		stereoCalib.print();

		// Note that the stereo baseline translation will be specified in the same units as the calibration grid.
		// Which is in millimeters (mm) in this example.
	}

	public static void main( String[] args ) {
		ExampleCalibrateStereo alg = new ExampleCalibrateStereo();

		// Select which set of targets to use
		alg.setupBumblebeeChess();
//		alg.setupBumblebeeSquare();

		// compute and save results
		alg.process();
	}
}