Skip to content

ccalib: fix misleading assertion when no calibration views survive - #4196

Open
SomSamantray wants to merge 2 commits into
opencv:5.xfrom
SomSamantray:fix/omnidir-calibrate-empty-views
Open

ccalib: fix misleading assertion when no calibration views survive#4196
SomSamantray wants to merge 2 commits into
opencv:5.xfrom
SomSamantray:fix/omnidir-calibrate-empty-views

Conversation

@SomSamantray

Copy link
Copy Markdown

cv2.omnidir.calibrate failed with a confusing assertion that looked like a type bug even when the input arrays had the correct type, shape, and were non-empty:

CV_Assert(!objectPoints.empty() && objectPoints.type() == CV_64FC3)

The actual cause has nothing to do with types. omnidir::calibrate() filters out any calibration view whose initial-pose reprojection error exceeds an internal threshold; if every view fails that filter (e.g. the object/image point correspondences don't come from a real calibration target), the point vectors end up empty and the code still proceeds into computeJacobian(), tripping the assertion above on its emptiness half only — the type half was never actually false.

This PR replaces that misleading assertion with two explicit, actionable errors:

  • omnidir::calibrate() now reports "no calibration views survived initial pose estimation" when every view is rejected.
  • omnidir::stereoCalibrate() has an independent failure mode not covered by the first fix: two per-camera views can each individually survive filtering, yet their surviving-view sets can fail to intersect. That path used to crash even earlier, via Mat::copyTo() on a fixed-size OutputArray::getMat() temporary that refuses to "reallocate" an empty array even to the same size. Both issues are fixed together — the intersection-empty case is now a clear "no calibration views are valid for both cameras" error.

modules/ccalib had no test suite at all before this change; this PR adds its first one, covering the error path for both functions plus a synthetic-projection-based happy-path regression test proving valid calibration is unaffected.

Fixes opencv/opencv#28462

Validation

Built and ran the new test suite locally (opencv_test_ccalib, scoped build of core, imgproc, geometry, calib, objdetect, features, xfeatures2d, highgui, imgcodecs, ccalib, ts): all 4 tests pass, including the happy-path tests that confirm valid single-camera and stereo calibration are unaffected.

Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

  • I agree to contribute to the project under Apache 2 License.
  • To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
  • The PR is proposed to the proper branch
  • There is a reference to the original bug report and related work
  • There is accuracy test, performance test and test data in opencv_extra repository, if applicable
    Patch to opencv_extra has the same branch name.
  • The feature is well documented and sample code can be built with the project CMake

…nidir calibration has no valid views

cv::omnidir::calibrate() and cv::omnidir::stereoCalibrate() both filter
input views by initial-pose reprojection error before optimization. When
every view is rejected (e.g. mismatched/uncorrelated object-image point
correspondences, as reported in opencv/opencv#28462), the code proceeded
into computeJacobian()/computeJacobianStereo() with empty point vectors,
tripping CV_Assert(!objectPoints.empty() && objectPoints.type() ==
CV_64FC3). Since only the emptiness half of that assertion was actually
false, the error message misleadingly pointed at a type mismatch that
did not exist.

Add explicit CV_Error guards at the point where each function discovers
zero surviving views, with messages that name the actual cause (no
views survived initialization, or no views were valid for both cameras)
instead of the confusing low-level assertion. For stereoCalibrate(), the
guard lives in internal::initializeStereoCalibration() rather than
stereoCalibrate() itself, since the intersection-empty case previously
also crashed one level earlier via Mat::copyTo() on a fixed-size
temporary from OutputArray::getMat() -- fixed here too by copying into
the OutputArray directly instead of through getMat().

Also adds modules/ccalib's first test suite (it had none), covering the
error path for both functions plus a synthetic-projection-based
happy-path regression test for calibrate().
- Add TEST(CV_OmnidirStereoCalibrate, succeeds_with_valid_overlapping_views)
  to cover the normal working stereo case, per the testing reviewer's finding
  that only the error path was exercised for stereoCalibrate().
- Fix the last remaining instance of the old _idx.copyTo(idx.getMat())
  pattern in cv::omnidir::calibrate()'s idx output block, matching the two
  other call sites already fixed, per the reliability reviewer's residual
  risk note.
- Seed the two RNG-based error-path tests explicitly instead of drawing from
  the shared cv::theRNG() singleton, so they're reproducible independent of
  run order or other tests' RNG draws.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

cv2.omnidir.calibrate Assertion Failure

1 participant