MVTB currently defensively pins opencv-python<5.0.0 / opencv-contrib-python<5.0.0 in
pyproject.toml. This isn't just "prepare for a future release" — it already broke CI for
real once: on 2026-07-29, conda-forge's unpinned opencv conda package started resolving to
5.0.0, and CI failed across the whole matrix (every OS × Python version). Confirmed causes at
the time: cv2.BRISK_create relocation, cv2.aruco.estimatePoseSingleMarkers removal, and
"MSER indexing return shape changed" (this last one is disputed — see below). That incident
was patched reactively by pinning conda's opencv<5 to match pyproject.toml's existing
pip-level pin, but the underlying problem (CI's conda/micromamba path and the pip-installable
package path can silently diverge — see the separate conda/micromamba tech-debt issue) was
never fixed, so the same failure mode can recur the moment that pin is forgotten or another
conda-forge quirk resurfaces.
Every finding below was verified empirically (not just read off OpenCV's own migration guide):
opencv-contrib-python==5.0.0.93 installed in a throwaway venv, diffed function-by-function
against a real 4.13.0 install.
Confirmed technical findings
Feature detector relocation — BRISK_create, AKAZE_create, KAZE_create moved from
cv2 to cv2.xfeatures2d in OpenCV 5 (fully functional there in the standard
opencv-contrib-python wheel, verified via real detectAndCompute() calls). SIFT, ORB
stay in main cv2 in both versions, unaffected. Affects
src/machinevisiontoolbox/ImagePointFeatures.py's detector-factory dict.
Singleton middle-dimension removal ("1D array semantics" change) — functions wrapping
std::vector<T> now produce true (N, M) arrays instead of the old (N, 1, M) convention.
Not universal — verified case by case, do not apply a blanket fix everywhere.
Confirmed affected (hard crashes on v5 today):
src/machinevisiontoolbox/ImageLineFeatures.py:160 — lines[:, 0, :] after
cv2.HoughLinesP; v4 output (N,1,4), v5 output (N,4) → IndexError.
src/machinevisiontoolbox/ImageFiducials.py:145-149 — id[0] on the ids array from
ArucoDetector.detectMarkers(); v4 shape (N,1), v5 shape flat (N,) → IndexError.
src/machinevisiontoolbox/Camera.py:2230,2236 — findChessboardCorners/cornerSubPix
shape changes (49,1,2) → (49,2); may not currently break functionally (no
shape-dependent indexing downstream) but should be normalized defensively.
Confirmed not affected (verified empirically, no fix needed): findContours,
approxPolyDP, convexHull, HoughLines, projectPoints, minAreaRect, fitEllipse,
minEnclosingCircle, boxPoints, solvePnP, Rodrigues, findHomography (+ mask),
decomposeHomographyMat, findEssentialMat/recoverPose, findFundamentalMat, MSER
detectRegions output (verified identical (M,2) in both versions).
Discrepancy to resolve, not silently drop: the historical CI incident's third confirmed
cause, "MSER indexing return shape changed," doesn't match this empirical finding. Either the
original CI failure was actually about something else MSER-adjacent, or it's already been
independently fixed/was a red herring — re-check before assuming MSER needs no work.
Hard removal, no relocation — cv2.aruco.estimatePoseSingleMarkers (used in
ImageFiducials.py:142-146) is completely gone in OpenCV 5, not moved. Needs a real
reimplementation via cv2.solvePnP(..., flags=cv2.SOLVEPNP_IPPE_SQUARE) per marker (OpenCV's
own documented replacement for planar square markers) — this replacement works unchanged on
OpenCV 4 too, so no version branching needed.
Lower-priority, verify not necessarily fix:
- Numeric drift in
warpAffine/warpPerspective/remap (revised interpolation, expected
benign) — audit tests for exact-equality assertions on warped pixel data.
cv2.VideoCapture.get() returns -1 instead of 0 for unsupported properties on v5 — check
Sources.py for == 0 comparisons that should be <= 0 or in (0, -1).
FONT_HERSHEY_* renders via a different embedded font on v5 — affects any exact pixel-diff
test on annotated/labelled images.
Plan
- Remove conda/micromamba from
ci.yml first (see the separate tech-debt issue) — this closes
the two-disconnected-sourcing-paths gap that let the original incident happen, and makes the
dual-version test matrix in step 4 trivial (plain pip version pins, no conda solver).
- Cut a fresh branch off
main for the actual compat fixes rather than reviving the stalled,
untested opencv5 branch.
- Apply the fixes above, each with a loud inline comment and its own regression test, verified
against both a real OpenCV 4.13 and a real OpenCV 5.0.0 environment.
- Relax
pyproject.toml's opencv pin to a range supporting both (e.g. >=4.5,<6.0.0), add an
OpenCV-version axis to the CI matrix (pinning specific tested versions, not an open range),
keep the empirical probe scripts used to verify all of this as a checked-in, reusable dev
tool, and track opencv-python/opencv-contrib-python in Dependabot (without auto-merge).
Verification
Full test suite run under both a real OpenCV 4.13 and a real OpenCV 5.0.0 environment before
considering this done, and confirm the new CI matrix actually catches a deliberately
reintroduced version of one of these bugs before trusting it as a safety net.
MVTB currently defensively pins
opencv-python<5.0.0/opencv-contrib-python<5.0.0inpyproject.toml. This isn't just "prepare for a future release" — it already broke CI forreal once: on 2026-07-29, conda-forge's unpinned
opencvconda package started resolving to5.0.0, and CI failed across the whole matrix (every OS × Python version). Confirmed causes at
the time:
cv2.BRISK_createrelocation,cv2.aruco.estimatePoseSingleMarkersremoval, and"MSER indexing return shape changed" (this last one is disputed — see below). That incident
was patched reactively by pinning conda's
opencv<5to matchpyproject.toml's existingpip-level pin, but the underlying problem (CI's conda/micromamba path and the pip-installable
package path can silently diverge — see the separate conda/micromamba tech-debt issue) was
never fixed, so the same failure mode can recur the moment that pin is forgotten or another
conda-forge quirk resurfaces.
Every finding below was verified empirically (not just read off OpenCV's own migration guide):
opencv-contrib-python==5.0.0.93installed in a throwaway venv, diffed function-by-functionagainst a real 4.13.0 install.
Confirmed technical findings
Feature detector relocation —
BRISK_create,AKAZE_create,KAZE_createmoved fromcv2tocv2.xfeatures2din OpenCV 5 (fully functional there in the standardopencv-contrib-pythonwheel, verified via realdetectAndCompute()calls).SIFT,ORBstay in main
cv2in both versions, unaffected. Affectssrc/machinevisiontoolbox/ImagePointFeatures.py's detector-factory dict.Singleton middle-dimension removal ("1D array semantics" change) — functions wrapping
std::vector<T>now produce true(N, M)arrays instead of the old(N, 1, M)convention.Not universal — verified case by case, do not apply a blanket fix everywhere.
Confirmed affected (hard crashes on v5 today):
src/machinevisiontoolbox/ImageLineFeatures.py:160—lines[:, 0, :]aftercv2.HoughLinesP; v4 output(N,1,4), v5 output(N,4)→IndexError.src/machinevisiontoolbox/ImageFiducials.py:145-149—id[0]on theidsarray fromArucoDetector.detectMarkers(); v4 shape(N,1), v5 shape flat(N,)→IndexError.src/machinevisiontoolbox/Camera.py:2230,2236—findChessboardCorners/cornerSubPixshape changes
(49,1,2)→(49,2); may not currently break functionally (noshape-dependent indexing downstream) but should be normalized defensively.
Confirmed not affected (verified empirically, no fix needed):
findContours,approxPolyDP,convexHull,HoughLines,projectPoints,minAreaRect,fitEllipse,minEnclosingCircle,boxPoints,solvePnP,Rodrigues,findHomography(+ mask),decomposeHomographyMat,findEssentialMat/recoverPose,findFundamentalMat, MSERdetectRegionsoutput (verified identical(M,2)in both versions).Discrepancy to resolve, not silently drop: the historical CI incident's third confirmed
cause, "MSER indexing return shape changed," doesn't match this empirical finding. Either the
original CI failure was actually about something else MSER-adjacent, or it's already been
independently fixed/was a red herring — re-check before assuming MSER needs no work.
Hard removal, no relocation —
cv2.aruco.estimatePoseSingleMarkers(used inImageFiducials.py:142-146) is completely gone in OpenCV 5, not moved. Needs a realreimplementation via
cv2.solvePnP(..., flags=cv2.SOLVEPNP_IPPE_SQUARE)per marker (OpenCV'sown documented replacement for planar square markers) — this replacement works unchanged on
OpenCV 4 too, so no version branching needed.
Lower-priority, verify not necessarily fix:
warpAffine/warpPerspective/remap(revised interpolation, expectedbenign) — audit tests for exact-equality assertions on warped pixel data.
cv2.VideoCapture.get()returns-1instead of0for unsupported properties on v5 — checkSources.pyfor== 0comparisons that should be<= 0orin (0, -1).FONT_HERSHEY_*renders via a different embedded font on v5 — affects any exact pixel-difftest on annotated/labelled images.
Plan
ci.ymlfirst (see the separate tech-debt issue) — this closesthe two-disconnected-sourcing-paths gap that let the original incident happen, and makes the
dual-version test matrix in step 4 trivial (plain pip version pins, no conda solver).
mainfor the actual compat fixes rather than reviving the stalled,untested
opencv5branch.against both a real OpenCV 4.13 and a real OpenCV 5.0.0 environment.
pyproject.toml's opencv pin to a range supporting both (e.g.>=4.5,<6.0.0), add anOpenCV-version axis to the CI matrix (pinning specific tested versions, not an open range),
keep the empirical probe scripts used to verify all of this as a checked-in, reusable dev
tool, and track
opencv-python/opencv-contrib-pythonin Dependabot (without auto-merge).Verification
Full test suite run under both a real OpenCV 4.13 and a real OpenCV 5.0.0 environment before
considering this done, and confirm the new CI matrix actually catches a deliberately
reintroduced version of one of these bugs before trusting it as a safety net.