diff --git a/ci/script.sh b/ci/script.sh index 264018c0..84602b0f 100755 --- a/ci/script.sh +++ b/ci/script.sh @@ -73,7 +73,7 @@ fi # remove tests and examples that require the latest OpenCV version so that they don't fail due to missing modules if [[ "${OPENCV_VERSION:-}" != "4.10.0" ]]; then rm -vf tests/*_only_latest_opencv.rs - rm -vf examples/dnn_face_detect.rs examples/text_detection.rs + rm -vf examples/dnn_face_detect.rs examples/text_detection.rs examples/camera_calibration.rs fi echo "=== Current directory: $(pwd)" diff --git a/examples/camera_calibration.rs b/examples/camera_calibration.rs new file mode 100644 index 00000000..a1b59bb8 --- /dev/null +++ b/examples/camera_calibration.rs @@ -0,0 +1,91 @@ +//! Port of code from the tutorial at: https://docs.opencv.org/4.x/dc/dbb/tutorial_py_calibration.html + +use std::error::Error; +use std::fs; + +use opencv::core::{no_array, Point2f, Point3f, Size, TermCriteria, TermCriteria_EPS, TermCriteria_MAX_ITER, Vector}; +use opencv::prelude::*; +use opencv::{calib3d, highgui, imgcodecs, imgproc}; + +fn main() -> Result<(), Box> { + // termination criteria + let criteria = TermCriteria { + typ: TermCriteria_EPS + TermCriteria_MAX_ITER, + max_count: 30, + epsilon: 0.001, + }; + + // prepare object points, like (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0) + let objp_len = 6 * 7; + let objp = Vector::from_iter((0..objp_len).map(|i| Point3f::new((i % 7) as f32, (i / 7) as f32, 0.))); + + let images = fs::read_dir(".")? + .into_iter() + .flatten() + .filter(|entry| entry.path().extension().map_or(false, |ext| ext == "jpg")); + + for image in images { + // Arrays to store object points and image points from all the images. + let mut objpoints = Vector::>::new(); // 3d point in real world space + let mut imgpoints = Vector::>::new(); // 2d points in image plane. + + let mut img = imgcodecs::imread_def(image.path().to_string_lossy().as_ref())?; + let mut gray = Mat::default(); + imgproc::cvt_color_def(&img, &mut gray, imgproc::COLOR_BGR2GRAY)?; + + let mut corners = Vector::::default(); + let ret = calib3d::find_chessboard_corners_def(&gray, Size::new(7, 6), &mut corners)?; + if ret { + objpoints.push(objp.clone()); + + imgproc::corner_sub_pix(&gray, &mut corners, Size::new(11, 11), Size::new(-1, -1), criteria)?; + + // Draw and display the corners + calib3d::draw_chessboard_corners(&mut img, Size::new(7, 6), &corners, ret)?; + highgui::imshow("Source", &img)?; + + imgpoints.push(corners); + + // Calibration + let mut mtx = Mat::default(); + let mut dist = Mat::default(); + let mut rvecs = Vector::::new(); + let mut tvecs = Vector::::new(); + calib3d::calibrate_camera_def( + &objpoints, + &imgpoints, + gray.size()?, + &mut mtx, + &mut dist, + &mut rvecs, + &mut tvecs, + )?; + + // Using cv.undistort() + let mut dst_undistort = Mat::default(); + calib3d::undistort_def(&img, &mut dst_undistort, &mtx, &dist)?; + highgui::imshow("Result using undistort", &dst_undistort)?; + + // Using remapping + let mut mapx = Mat::default(); + let mut mapy = Mat::default(); + calib3d::init_undistort_rectify_map( + &mtx, + &dist, + &no_array(), + &no_array(), + img.size()?, + f32::opencv_type(), + &mut mapx, + &mut mapy, + )?; + let mut dst_remap = Mat::default(); + imgproc::remap_def(&img, &mut dst_remap, &mapx, &mapy, imgproc::INTER_LINEAR)?; + highgui::imshow("Result using remap", &dst_undistort)?; + + highgui::wait_key_def()?; + } + } + highgui::destroy_all_windows()?; + Ok(()) +}