Difference between revisions of "Example Calibrate Planar Stereo"

From BoofCV
Jump to navigationJump to search
(Updated for v0.8)
m
Line 31: Line 31:
<syntaxhighlight lang="java">
<syntaxhighlight lang="java">
/**
/**
  * Example of how to calibrate a stereo camera system using a planar calibration grid given a set of images.
  * Example of how to calibrate a single (monocular) camera given a set of observed calibration.
  * Intrinsic camera parameters are estimated for both cameras individually, then extrinsic parameters
  * points using the Zhang99 algorithm. Unlike in the other examples, the image processing has
  * for the two cameras relative to each other are found  This example does not rectify the images, which is
  * not already been done. In theory you could add your own more exotic targets by writing
  * required for some algorithms. See {@link ExampleRectifyCalibratedStereo}. Both square grid and chessboard targets
  * custom code to detect the target, which is left as an exercise for the readerFor example,
  * are demonstrated in this example. See calibration tutorial for a discussion of different target types and how to
  * have multiple targets visible or calibrate using circles.
* 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 fileSee in code comments for tuning
  * and implementation issues.
*
* @see ExampleRectifyCalibratedStereo
* @see CalibrateStereoPlanar
  *
  *
  * @author Peter Abeles
  * @author Peter Abeles
  */
  */
public class ExampleCalibrateStereoPlanar {
public class ExampleCalibrateMonocularPoints {


// Detects the target and calibration point inside the target
/**
PlanarCalibrationDetector detector;
* Given a description of the calibration target and the observed location of the calibration
 
*
// Description of the target's physical dimension
* @param targetDesc Describes the target's known physical structure
PlanarCalibrationTarget target;
* @param observations Observations of the target in different images
 
*/
// List of calibration images
public static void calibrate( PlanarCalibrationTarget targetDesc ,
List<String> left;
  List<List<Point2D_F64>> observations ) {
List<String> right;


// Many 3D operations assumed a right handed coordinate system with +Z pointing out of the image.
// Assume zero skew and model lens distortion with two radial parameters
// If the image coordinate system is left handed then the y-axis needs to be flipped to meet
CalibrationPlanarGridZhang99 zhang99 =
// that requirement.  Most of the time this is false.
new CalibrationPlanarGridZhang99(targetDesc,true,2);
boolean flipY;


/**
if( !zhang99.process(observations) )
* Square grid target taken by a PtGrey Bumblebee camera.
throw new RuntimeException("Calibration failed!");
*/
public void setupBumblebeeSquare() {
// Use the wrapper below for square grid targets.
detector = FactoryPlanarCalibrationTarget.detectorSquareGrid(3,4);
// Target physical description
target = FactoryPlanarCalibrationTarget.gridSquare(3, 4, 30,30);


String directory = "../data/evaluation/calibration/stereo/Bumblebee2_Square";
// Get camera parameters and extrinsic target location in each image
Zhang99Parameters found = zhang99.getOptimized();


left = BoofMiscOps.directoryList(directory, "left");
// Convenient function for converting from specialized Zhang99 format to generalized
right = BoofMiscOps.directoryList(directory, "right");
IntrinsicParameters param = found.convertToIntrinsic();


flipY = false;
// print the results to standard out
param.print();
// save to a file using XML
BoofMiscOps.saveXML(param,"intrinsic.xml");
}
}


/**
/**
* Chessboard target taken by a PtGrey Bumblebee camera.
* Detects calibration points found in several images and returned as a list. Not the focus of this example.
*/
*/
public void setupBumblebeeChess() {
public static List<List<Point2D_F64>> loadObservations() {
// Use the wrapper below for chessboard targets.  The last parameter adjusts the size of the corner detection
// region.  TUNE THIS PARAMETER FOR OPTIMAL ACCURACY!
detector = FactoryPlanarCalibrationTarget.detectorChessboard(3, 4, 6);
// Target physical description
target = FactoryPlanarCalibrationTarget.gridChess(3, 4, 30);


String directory = "../data/evaluation/calibration/stereo/Bumblebee2_Chess";
String directory = "../data/evaluation/calibration/stereo/Bumblebee2_Chess";
List<String> imageNames = BoofMiscOps.directoryList(directory,"left");


left = BoofMiscOps.directoryList(directory, "left");
PlanarCalibrationDetector detector = FactoryPlanarCalibrationTarget.detectorChessboard(3, 4, 6);
right = BoofMiscOps.directoryList(directory, "right");


flipY = false;
List<List<Point2D_F64>> ret = new ArrayList<List<Point2D_F64>>();
}
 
/**
* Process calibration images, compute intrinsic parameters, save to a file
*/
public void process() {
// Declare and setup the calibration algorithm
CalibrateStereoPlanar calibratorAlg = new CalibrateStereoPlanar(detector, flipY);
calibratorAlg.configure(target, true, 2);


// ensure the lists are in the same order
for( String n : imageNames ) {
Collections.sort(left);
BufferedImage img = UtilImageIO.loadImage(n);
Collections.sort(right);
ImageFloat32 input = ConvertBufferedImage.convertFrom(img,(ImageFloat32)null);


for( int i = 0; i < left.size(); i++ ) {
if( !detector.process(input) )
BufferedImage l = UtilImageIO.loadImage(left.get(i));
throw new RuntimeException("Detection failed!");
BufferedImage r = UtilImageIO.loadImage(right.get(i));


ImageFloat32 imageLeft = ConvertBufferedImage.convertFrom(l,(ImageFloat32)null);
ret.add(detector.getPoints());
ImageFloat32 imageRight = ConvertBufferedImage.convertFrom(r,(ImageFloat32)null);
 
calibratorAlg.addPair(imageLeft, imageRight);
}
}


// Process and compute calibration parameters
return ret;
StereoParameters stereoCalib = calibratorAlg.process();
 
// save results to a file and print out
BoofMiscOps.saveXML(stereoCalib, "stereo.xml");
stereoCalib.print();
}
}


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


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

Revision as of 15:45, 6 November 2012

Stereo Camera Calibration with Planar Targets

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: ExampleCalibrateStereoPlanar.java

Calibration Tutorial: Wikipage

Concepts:

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

Relevant Applets:

Related Examples:

Example Code

/**
 * Example of how to calibrate a single (monocular) camera given a set of observed calibration.
 * points using the Zhang99 algorithm.  Unlike in the other examples, the image processing has
 * not already been done.  In theory you could add your own more exotic targets by writing
 * custom code to detect the target, which is left as an exercise for the reader.  For example,
 * have multiple targets visible or calibrate using circles.
 *
 * @author Peter Abeles
 */
public class ExampleCalibrateMonocularPoints {

	/**
	 * Given a description of the calibration target and the observed location of the calibration
	 *
	 * @param targetDesc Describes the target's known physical structure
	 * @param observations Observations of the target in different images
	 */
	public static void calibrate( PlanarCalibrationTarget targetDesc ,
								  List<List<Point2D_F64>> observations ) {

		// Assume zero skew and model lens distortion with two radial parameters
		CalibrationPlanarGridZhang99 zhang99 =
				new CalibrationPlanarGridZhang99(targetDesc,true,2);

		if( !zhang99.process(observations) )
			throw new RuntimeException("Calibration failed!");

		// Get camera parameters and extrinsic target location in each image
		Zhang99Parameters found = zhang99.getOptimized();

		// Convenient function for converting from specialized Zhang99 format to generalized
		IntrinsicParameters param = found.convertToIntrinsic();

		// print the results to standard out
		param.print();
		// 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.
	 */
	public static List<List<Point2D_F64>> loadObservations() {

		String directory = "../data/evaluation/calibration/stereo/Bumblebee2_Chess";
		List<String> imageNames = BoofMiscOps.directoryList(directory,"left");

		PlanarCalibrationDetector detector = FactoryPlanarCalibrationTarget.detectorChessboard(3, 4, 6);

		List<List<Point2D_F64>> ret = new ArrayList<List<Point2D_F64>>();

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

			if( !detector.process(input) )
				throw new RuntimeException("Detection failed!");

			ret.add(detector.getPoints());
		}

		return ret;
	}

	public static void main( String args[] ) {
		// target description and list of observations
		PlanarCalibrationTarget desc = FactoryPlanarCalibrationTarget.gridChess(3, 4, 30);
		List<List<Point2D_F64>> calibPts = loadObservations();

		// Calibrate the camera
		calibrate(desc,calibPts);
	}
}