|
| 1 | +//! Port of code from the tutorial at: https://docs.opencv.org/4.x/dc/dbb/tutorial_py_calibration.html |
| 2 | +
|
| 3 | +use std::error::Error; |
| 4 | +use std::fs; |
| 5 | + |
| 6 | +use opencv::core::{no_array, Point2f, Point3f, Size, TermCriteria, TermCriteria_EPS, TermCriteria_MAX_ITER, Vector}; |
| 7 | +use opencv::prelude::*; |
| 8 | +use opencv::{calib3d, highgui, imgcodecs, imgproc}; |
| 9 | + |
| 10 | +fn main() -> Result<(), Box<dyn Error>> { |
| 11 | + // termination criteria |
| 12 | + let criteria = TermCriteria { |
| 13 | + typ: TermCriteria_EPS + TermCriteria_MAX_ITER, |
| 14 | + max_count: 30, |
| 15 | + epsilon: 0.001, |
| 16 | + }; |
| 17 | + |
| 18 | + // prepare object points, like (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0) |
| 19 | + let objp_len = 6 * 7; |
| 20 | + let objp = Vector::from_iter((0..objp_len).map(|i| Point3f::new((i % 7) as f32, (i / 7) as f32, 0.))); |
| 21 | + |
| 22 | + let images = fs::read_dir(".")? |
| 23 | + .into_iter() |
| 24 | + .flatten() |
| 25 | + .filter(|entry| entry.path().extension().map_or(false, |ext| ext == "jpg")); |
| 26 | + |
| 27 | + for image in images { |
| 28 | + // Arrays to store object points and image points from all the images. |
| 29 | + let mut objpoints = Vector::<Vector<Point3f>>::new(); // 3d point in real world space |
| 30 | + let mut imgpoints = Vector::<Vector<Point2f>>::new(); // 2d points in image plane. |
| 31 | + |
| 32 | + let mut img = imgcodecs::imread_def(image.path().to_string_lossy().as_ref())?; |
| 33 | + let mut gray = Mat::default(); |
| 34 | + imgproc::cvt_color_def(&img, &mut gray, imgproc::COLOR_BGR2GRAY)?; |
| 35 | + |
| 36 | + let mut corners = Vector::<Point2f>::default(); |
| 37 | + let ret = calib3d::find_chessboard_corners_def(&gray, Size::new(7, 6), &mut corners)?; |
| 38 | + if ret { |
| 39 | + objpoints.push(objp.clone()); |
| 40 | + |
| 41 | + imgproc::corner_sub_pix(&gray, &mut corners, Size::new(11, 11), Size::new(-1, -1), criteria)?; |
| 42 | + |
| 43 | + // Draw and display the corners |
| 44 | + calib3d::draw_chessboard_corners(&mut img, Size::new(7, 6), &corners, ret)?; |
| 45 | + highgui::imshow("Source", &img)?; |
| 46 | + |
| 47 | + imgpoints.push(corners); |
| 48 | + |
| 49 | + // Calibration |
| 50 | + let mut mtx = Mat::default(); |
| 51 | + let mut dist = Mat::default(); |
| 52 | + let mut rvecs = Vector::<Mat>::new(); |
| 53 | + let mut tvecs = Vector::<Mat>::new(); |
| 54 | + calib3d::calibrate_camera_def( |
| 55 | + &objpoints, |
| 56 | + &imgpoints, |
| 57 | + gray.size()?, |
| 58 | + &mut mtx, |
| 59 | + &mut dist, |
| 60 | + &mut rvecs, |
| 61 | + &mut tvecs, |
| 62 | + )?; |
| 63 | + |
| 64 | + // Using cv.undistort() |
| 65 | + let mut dst_undistort = Mat::default(); |
| 66 | + calib3d::undistort_def(&img, &mut dst_undistort, &mtx, &dist)?; |
| 67 | + highgui::imshow("Result using undistort", &dst_undistort)?; |
| 68 | + |
| 69 | + // Using remapping |
| 70 | + let mut mapx = Mat::default(); |
| 71 | + let mut mapy = Mat::default(); |
| 72 | + calib3d::init_undistort_rectify_map( |
| 73 | + &mtx, |
| 74 | + &dist, |
| 75 | + &no_array(), |
| 76 | + &no_array(), |
| 77 | + img.size()?, |
| 78 | + f32::opencv_type(), |
| 79 | + &mut mapx, |
| 80 | + &mut mapy, |
| 81 | + )?; |
| 82 | + let mut dst_remap = Mat::default(); |
| 83 | + imgproc::remap_def(&img, &mut dst_remap, &mapx, &mapy, imgproc::INTER_LINEAR)?; |
| 84 | + highgui::imshow("Result using remap", &dst_undistort)?; |
| 85 | + |
| 86 | + highgui::wait_key_def()?; |
| 87 | + } |
| 88 | + } |
| 89 | + highgui::destroy_all_windows()?; |
| 90 | + Ok(()) |
| 91 | +} |
0 commit comments