Skip to content

Commit 0231680

Browse files
shimatclaude
andcommitted
Clone non-continuous per-view Mats before reshaping in fisheye calibrate
CodeRabbit review comment on PR #2004: the toRow() workaround called cv::Mat::reshape(0, 1) directly on any Nx1 per-view Mat, but reshape() requires a continuous Mat to change the row count. An ROI/submat view passed as one of the per-view point Mats would throw "The matrix is not continuous, thus its number of rows can not be changed". Clone non-continuous Mats before reshaping. Added a regression test that builds each per-view points Mat as column 0 of a wider Mat (a non-continuous view) to reproduce this. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
1 parent 8de20a4 commit 0231680

2 files changed

Lines changed: 53 additions & 2 deletions

File tree

src/OpenCvSharpExtern/calib_fisheye.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,14 @@ CVAPI(ExceptionStatus) calib_fisheye_calibrate(
138138
// points Mat). Since OpenCV 5 changed `Mat(vector<T>)` to build a 1xN mat instead of
139139
// OpenCV 4's Nx1, a column-shaped (Nx1) per-view Mat now mismatches and throws
140140
// StsUnmatchedSizes. Row-shaped (1xN) input sidesteps the bug, so reshape any Nx1 views
141-
// to 1xN before calling into OpenCV (reshape is a metadata-only view for continuous mats).
142-
const auto toRow = [](const cv::Mat &m) { return m.rows > m.cols ? m.reshape(0, 1) : m; };
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+
};
143149

144150
std::vector<cv::Mat> objectPointsRow(objectPoints->size());
145151
for (size_t i = 0; i < objectPoints->size(); i++)

test/OpenCvSharp.Tests/calib3d/Calib3dTest.cs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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)