Skip to content

Commit 1a3c48c

Browse files
authored
Merge pull request #2004 from shimat/fix/fisheye-calibrate-1906
Fix cv::fisheye::calibrate throwing on OpenCV 5
2 parents c9fc176 + 0231680 commit 1a3c48c

2 files changed

Lines changed: 70 additions & 2 deletions

File tree

src/OpenCvSharpExtern/calib_fisheye.h

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,31 @@ CVAPI(ExceptionStatus) calib_fisheye_calibrate(
131131
double *returnValue)
132132
{
133133
return cvTry([&] {
134+
// Work around an OpenCV 5 upstream regression: cv::fisheye::calibrate's internal
135+
// ComputeJacobians/EstimateUncertainties helpers (modules/calib/src/fisheye.cpp) subtract
136+
// a `cv::Mat(std::vector<Point2d>)` from the per-view points Mat without transposing it
137+
// (their orientation check tests channels() == 1, which is never true for a 2-channel
138+
// points Mat). Since OpenCV 5 changed `Mat(vector<T>)` to build a 1xN mat instead of
139+
// OpenCV 4's Nx1, a column-shaped (Nx1) per-view Mat now mismatches and throws
140+
// StsUnmatchedSizes. Row-shaped (1xN) input sidesteps the bug, so reshape any Nx1 views
141+
// to 1xN before calling into OpenCV. reshape() requires a continuous Mat, which an
142+
// ROI/submat view is not, so clone those before reshaping.
143+
const auto toRow = [](const cv::Mat &m) {
144+
if (m.rows <= m.cols)
145+
return m;
146+
const cv::Mat continuous = m.isContinuous() ? m : m.clone();
147+
return continuous.reshape(0, 1);
148+
};
149+
150+
std::vector<cv::Mat> objectPointsRow(objectPoints->size());
151+
for (size_t i = 0; i < objectPoints->size(); i++)
152+
objectPointsRow[i] = toRow((*objectPoints)[i]);
153+
std::vector<cv::Mat> imagePointsRow(imagePoints->size());
154+
for (size_t i = 0; i < imagePoints->size(); i++)
155+
imagePointsRow[i] = toRow((*imagePoints)[i]);
156+
134157
*returnValue = cv::fisheye::calibrate(
135-
*objectPoints, *imagePoints, cpp(imageSize),
158+
objectPointsRow, imagePointsRow, cpp(imageSize),
136159
IoProxy(*K), IoProxy(*D), *rvecs, *tvecs, flags, cpp(criteria));
137160
});
138161
}

test/OpenCvSharp.Tests/calib3d/Calib3dTest.cs

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ public void CalibrateCameraByMat()
228228
Assert.Contains(distCoeffValues, d => Math.Abs(d) > 1e-20);
229229
}
230230

231-
[Fact(Skip = "OpenCV 5: fisheye::calibrate throws an internal size-mismatch error. See https://github.com/shimat/opencvsharp/issues/1906")]
231+
[Fact]
232232
public void FishEyeCalibrate()
233233
{
234234
var patternSize = new Size(10, 7);
@@ -255,6 +255,51 @@ public void FishEyeCalibrate()
255255
Assert.NotEmpty(translationVectors);
256256
}
257257

258+
[Fact]
259+
public void FishEyeCalibrateWithNonContinuousPoints()
260+
{
261+
var patternSize = new Size(10, 7);
262+
263+
using var image = LoadImage("calibration/00.jpg");
264+
using var corners = new Mat<Point2f>();
265+
Cv2.FindChessboardCorners(image, patternSize, corners);
266+
267+
var objectPointsArray = Create3DChessboardCorners(patternSize, 1.0f).ToArray();
268+
var imagePointsArray = corners.ToArray();
269+
270+
// Build each per-view points Mat as column 0 of a wider (Nx2) Mat, so it is a
271+
// non-continuous view. Regression test for the toRow() workaround in
272+
// calib_fisheye_calibrate, which used to call reshape() on such a Mat directly
273+
// (reshape requires a continuous Mat).
274+
using var objectPointsWide = new Mat(objectPointsArray.Length, 2, MatType.CV_32FC3);
275+
using var imagePointsWide = new Mat(imagePointsArray.Length, 2, MatType.CV_32FC2);
276+
for (var i = 0; i < objectPointsArray.Length; i++)
277+
{
278+
objectPointsWide.Set(i, 0, objectPointsArray[i]);
279+
objectPointsWide.Set(i, 1, objectPointsArray[i]);
280+
}
281+
for (var i = 0; i < imagePointsArray.Length; i++)
282+
{
283+
imagePointsWide.Set(i, 0, imagePointsArray[i]);
284+
imagePointsWide.Set(i, 1, imagePointsArray[i]);
285+
}
286+
287+
using var objectPoints = objectPointsWide.Col(0);
288+
using var imagePoints = imagePointsWide.Col(0);
289+
Assert.False(objectPoints.IsContinuous());
290+
Assert.False(imagePoints.IsContinuous());
291+
292+
using var cameraMatrix = Mat.EyeMat(3, 3, MatType.CV_64FC1);
293+
using var distCoeffs = new Mat<double>();
294+
295+
var rms = Cv2.FishEye.Calibrate([objectPoints], [imagePoints], image.Size(), cameraMatrix,
296+
distCoeffs, out var rotationVectors, out var translationVectors);
297+
298+
Assert.True(rms > 8, $"rms = {rms}");
299+
Assert.NotEmpty(rotationVectors);
300+
Assert.NotEmpty(translationVectors);
301+
}
302+
258303
/// <summary>
259304
/// https://stackoverflow.com/questions/25244603/opencvs-projectpoints-function
260305
/// </summary>

0 commit comments

Comments
 (0)