Fix more enums carrying stale native values from the OpenCV4->5 migration - #2082
Conversation
…tion Auditing for the same class of bug as #2080 (SolvePnPMethod) turned up two more live cases where a managed enum's numeric values no longer match their native OpenCV5 counterpart: - FishEyeCalibrationFlags: cv::fisheye lost its own flag enum in OpenCV5 and now aliases the unified CALIB_* flags, whose bit positions are unrelated to the old fisheye-only values. Every flag except UseIntrinsicGuess/FixIntrinsic (which happened to keep the same bit) was silently setting the wrong native bits. - WMFWeightType: declared as a plain 0..5 sequence, but the native enum is bit flags (1,2,4,8,16,32). Every value except EXP called the wrong weighting formula in WeightedMedianFilter. Also removes VideoCaptureAPIs.OPENNI/OPENNI_ASUS/GIGANETIX, whose native backend IDs (CAP_OPENNI/CAP_OPENNI_ASUS/CAP_GIGANETIX) no longer exist in OpenCV5 at all (OpenNI was superseded by OpenNI2, Giganetix support was dropped) - VideoCapture.Open() with these would silently fail to find a backend.
📝 WalkthroughWalkthroughUpdated public enum contracts for fisheye calibration, video capture APIs, and WMF weights. Added a regression test verifying fixed fisheye distortion coefficients remain zero. ChangesFisheye calibration flags
Video capture API entries
WMF weight flags
Estimated code review effort: 3 (Moderate) | ~20 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/OpenCvSharp/Modules/videoio/Enum/VideoCaptureAPIs.cs`:
- Around line 69-72: Preserve the legacy public members OPENNI, OPENNI_ASUS, and
GIGANETIX in the VideoCaptureAPIs enum. Restore them with their historical
numeric values and mark them obsolete if the backends are unsupported, retaining
source compatibility without changing existing constants.
In `@src/OpenCvSharp/Modules/ximgproc/Enum/WMFWeightType.cs`:
- Line 7: Remove the [Flags] attribute from the WMFWeightType enum so it
represents only the individual native WMF_EXP, WMF_COS, and related values;
leave the enum members and their underlying values unchanged.
In `@test/OpenCvSharp.Tests/calib3d/Calib3dTest.cs`:
- Around line 337-343: Harden the fish-eye calibration test around
Cv2.FishEye.Calibrate by asserting each public FishEyeCalibrationFlags value
individually, then require distCoeffValues.Length == 4 before checking its
contents. Replace the aggregate Assert.All-only validation with explicit
assertions for all four coefficient positions and their expected zero values.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: ad6e7a95-8400-47cc-ac58-294b49ff3678
📒 Files selected for processing (4)
src/OpenCvSharp/Modules/calib/Enum/FishEyeCalibrationFlags.cssrc/OpenCvSharp/Modules/videoio/Enum/VideoCaptureAPIs.cssrc/OpenCvSharp/Modules/ximgproc/Enum/WMFWeightType.cstest/OpenCvSharp.Tests/calib3d/Calib3dTest.cs
| /// <summary> | ||
| /// Android - not used | ||
| /// </summary> | ||
| ANDROID = 1000, | ||
| ANDROID = 1000, |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== locate file =="
fd -a 'VideoCaptureAPIs.cs' . || true
echo "== file excerpt =="
file="$(fd 'VideoCaptureAPIs.cs' . | head -n1)"
if [ -n "${file:-}" ]; then
wc -l "$file"
cat -n "$file" | sed -n '1,140p'
fi
echo "== search enum references =="
rg -n "VideoCaptureAPIs|OPENNI|OPENNI_ASUS|GIGANETIX|Android API|VideoCapture\\(" src tests test tests? 2>/dev/null | head -n 200 || true
echo "== git status/diff context =="
git status --short
git diff --stat
echo "-- changed names in enum/context if any --"
git diff -- src/OpenCvSharp/Modules/videoio/Enum/VideoCaptureAPIs.cs | sed -n '1,220p' || trueRepository: shimat/opencvsharp
Length of output: 20008
🌐 Web query:
OpenCV videoio::capture API VideoCaptureAPIs OPENNI OPENNI_ASUS GIGANETIX
💡 Result:
In the OpenCV Video I/O library (videoio), VideoCaptureAPIs defines the backend engines used for capturing video [1][2]. The specific identifiers you mentioned correspond to the following legacy and specialized camera interfaces: - CAP_OPENNI: Used for the OpenNI framework, primarily for original Kinect sensors [2][3]. - CAP_OPENNI_ASUS: Used for the OpenNI framework specifically supporting Asus Xtion devices [1][2]. - CAP_GIGANETIX: Used for the Smartek Giganetix GigEVisionSDK [2][4]. These flags are part of the cv::VideoCaptureAPIs enumeration, which allows developers to specify the desired backend when initializing a cv::VideoCapture object [1][5]. Over time, many of these specialized backends have been superseded by more modern or broader support frameworks (such as OpenNI2, which includes identifiers like CAP_OPENNI2, CAP_OPENNI2_ASUS, and CAP_OPENNI2_ASTRA for newer depth-sensing hardware) [2][5]. For implementation, these are passed to the cv::VideoCapture constructor or the open method to force the use of a particular backend driver [6][7]. If not specified, OpenCV attempts to auto-detect the appropriate backend [8][6].
Citations:
- 1: https://docs.opencv.org/ref/master/d4/d15/group__videoio__flags__base.html
- 2: https://docs.opencv.org/4.5.1/d4/d15/group__videoio__flags__base.html
- 3: https://shimat.github.io/opencvsharp_docs/html/d402af6c-df03-76c7-1fa2-0873b613a9ae.htm
- 4: https://docs.opencv.org/4.5.0/d4/d15/group%5F%5Fvideoio%5F%5Fflags%5F%5Fbase.html
- 5: https://github.com/opencv/opencv/blob/91c78f50/modules/videoio/include/opencv2/videoio.hpp
- 6: https://itn-web.it.liu.se/~karlu20/work/Gramods-docs/classgramods_1_1gmTrack_1_1OpenCvVideoCapture.html
- 7: https://github.com/RandomPrototypes/RPMixedRealityCapture
- 8: https://github.com/shimat/opencvsharp/blob/main/src/OpenCvSharp/Modules/videoio/Enum/VideoCaptureAPIs.cs
🌐 Web query:
shimat opencvsharp Git history "VideoCaptureAPIs.cs" "GIGANETIX" "OPENNI_ASUS" "OPENNI"
💡 Result:
In OpenCvSharp, the VideoCaptureAPIs enumeration is used to specify the preferred video capture backend, matching the structure and values defined in the native OpenCV library [1][2][3]. The specific members mentioned are defined as follows: OPENNI: 900 (OpenNI support for Kinect) [1][4] OPENNI_ASUS: 910 (OpenNI support for Asus Xtion sensors) [1][4] GIGANETIX: 1300 (Smartek Giganetix GigEVisionSDK) [1][4] The VideoCaptureAPIs enumeration is the current standard for defining capture backends in OpenCvSharp 4.x and later, replacing older naming conventions like CaptureDevice [5]. These values are direct mappings to the corresponding CAP_* flags in the native OpenCV videoio module [1][2][3]. The library uses these values to allow developers to enforce specific reader implementations when initializing a VideoCapture object [6][7].
Citations:
- 1: https://github.com/shimat/opencvsharp/blob/main/src/OpenCvSharp/Modules/videoio/Enum/VideoCaptureAPIs.cs
- 2: https://github.com/opencv/opencv/blob/91c78f50/modules/videoio/include/opencv2/videoio.hpp
- 3: https://docs.opencv.org/4.5.1/d4/d15/group__videoio__flags__base.html
- 4: https://shimat.github.io/opencvsharp_docs/html/d402af6c-df03-76c7-1fa2-0873b613a9ae.htm
- 5: Can not find Enum CaptureDevice #876
- 6: https://shimat.github.io/opencvsharp_docs/html/6eb72986-ae37-fdb0-eb16-3cf0ca81a2dd.htm
- 7: https://github.com/shimat/opencvsharp/blob/main/src/OpenCvSharp/Modules/videoio/VideoCapture.cs
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== exact references to removed names in tracked files =="
rg -n '\b(OPENNI\b|OPENNI_ASUS\b|GIGANETIX\b)\b' --glob '*.cs' --glob '*.cpp' --glob '*.h' . || true
echo "== current main videoio enum tail/list relevant area if available =="
main_file="src/OpenCvSharp/Modules/videoio/Enum/VideoCaptureAPIs.cs"
if [ -f "$main_file" ]; then
sed -n '1,260p' "$main_file" | cat -n
fi
echo "== repo references outside src =="
rg -n 'VideoCaptureAPIs' --glob '*.md' --glob '*.txt' --glob '*.csproj' --glob '*.sln' . || trueRepository: shimat/opencvsharp
Length of output: 5304
🌐 Web query:
"VideoCaptureAPIs" "GIGANETIX" "1300" "OpenCV"; "VideoCaptureAPIs" "OPENNI" "900"; "VideoCaptureAPIs" "OPENNI_ASUS" "910"
💡 Result:
In OpenCV, VideoCaptureAPIs are enumerations used to specify or identify the video I/O backend used by the cv::VideoCapture class to capture video from cameras, video files, or image sequences [1][2]. These identifiers allow developers to select a specific backend at runtime to interface with different hardware or libraries [3]. The specific identifiers requested correspond to the following legacy and specialized backends: - CAP_OPENNI = 900: This backend provides support for OpenNI-compatible depth sensors, such as the original Microsoft Kinect [4][1]. - CAP_OPENNI_ASUS = 910: This backend is specifically for OpenNI-compatible devices such as the Asus Xtion [4][1]. - CAP_GIGANETIX = 1300: This backend provides an interface for the Smartek Giganetix GigEVision SDK [4][1]. These constants are part of the cv::VideoCaptureAPIs enum, which includes a wide range of backends such as FFMPEG (1900), GStreamer (1800), and various hardware-specific interfaces [1][5]. While these constants remain in the API for compatibility, OpenCV has moved toward a more flexible plugin-based architecture for loading backends at runtime [3]. Developers can use the cv::videoio_registry namespace to check which backends are available and supported in their specific build of OpenCV [3].
Citations:
- 1: https://docs.opencv.org/4.5.3/d4/d15/group__videoio__flags__base.html
- 2: https://docs.opencv.org/4.x/d8/dfe/classcv_1_1VideoCapture.html
- 3: https://docs.opencv.org/4.5.1/d0/da7/videoio_overview.html
- 4: https://codebrowser.dev/opencv/opencv/modules/videoio/include/opencv2/videoio/legacy/constants_c.h.html
- 5: https://github.com/opencv/opencv/blob/91c78f50/modules/videoio/include/opencv2/videoio.hpp
Preserve the legacy videoio backend constants.
OPENNI, OPENNI_ASUS, and GIGANETIX are still part of OpenCV’s VideoCaptureAPIs; removing them drops public enum members from opencvsharp and breaks source compatibility for callers using those APIs. Keep the values as aliases/obsolete members, or document this as an intentional major/API-covenant breaking change.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/OpenCvSharp/Modules/videoio/Enum/VideoCaptureAPIs.cs` around lines 69 -
72, Preserve the legacy public members OPENNI, OPENNI_ASUS, and GIGANETIX in the
VideoCaptureAPIs enum. Restore them with their historical numeric values and
mark them obsolete if the backends are unsupported, retaining source
compatibility without changing existing constants.
| /// <summary> | ||
| /// Specifies weight types of weighted median filter. | ||
| /// </summary> | ||
| [Flags] |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== locate WMFWeightType.cs =="
fd -a 'WMFWeightType\.cs$' . || true
echo "== file contents =="
while IFS= read -r f; do
echo "--- $f"
cat -n "$f"
done < <(fd 'WMFWeightType\.cs$' .)
echo "== ximgproc WMF WeightType references in repo =="
rg -n "WMFWeightType|WeightType|weighted_median_filter|WeightedMedianFilter" src/OpenCvSharp || trueRepository: shimat/opencvsharp
Length of output: 333
🌐 Web query:
OpenCV ximgproc WeightedMedianFilter WMFWeightType weightType switch EXP COS
💡 Result:
In the OpenCV ximgproc module, the WMFWeightType enumeration defines the method used to calculate weights for the weightedMedianFilter function [1][2]. The weightType parameter determines how the filter handles the relationship between the joint image pixels [2][3]. The two types you mentioned correspond to the following weight calculation formulas: WMF_EXP: Uses an exponential decay function [4][2]. Formula: exp(-|I1-I2|^2 / (2 * sigma^2)) [4][2] WMF_COS: Uses a cosine-based similarity metric [4][2]. Formula: dot(I1, I2) / (|I1| * |I2|) [4][2] The full WMFWeightType enumeration includes: - WMF_EXP (Value: 1) [1][2] - WMF_IV1 (Value: 2): (|I1-I2| + sigma)^-1 [4][2] - WMF_IV2 (Value: 4): (|I1-I2|^2 + sigma^2)^-1 [4][2] - WMF_COS (Value: 8): dot(I1, I2) / (|I1| * |I2|) [4][2] - WMF_JAC (Value: 16): (min(r1,r2)+min(g1,g2)+min(b1,b2)) / (max(r1,r2)+max(g1,g2)+max(b1,b2)) [4][2] - WMF_OFF (Value: 32): Unweighted [4][2] Note that while some documentation or wrappers may assign specific integer values (e.g., 0, 1, 2, 3), the official C++ header typically defines them as bitwise flags (1, 1<<1, 1<<2, etc.) [1][2]. Always refer to your specific language wrapper if you are using Java, Python, or C# to confirm the exact integer mappings [5][4][2].
Citations:
- 1: https://docs.opencv.org/3.4/df/de9/weighted__median__filter_8hpp.html
- 2: https://docs.opencv.org/4.x/d9/d29/namespacecv_1_1ximgproc.html
- 3: https://docs.opencv.org/3.4/d9/d29/namespacecv_1_1ximgproc.html
- 4: https://shimat.github.io/opencvsharp/api/OpenCvSharp.XImgProc.WMFWeightType.html
- 5: https://docs.opencv.org/4.x/javadoc/org/opencv/ximgproc/Ximgproc.html
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== file contents =="
cat -n src/OpenCvSharp/Modules/ximgproc/Enum/WMFWeightType.cs
echo "== ximgproc WMF WeightType references in repo =="
rg -n "WMFWeightType|WeightType|WMF_EXP|WMF_COS|WMF_IV[12]|WMF_JAC|WMF_OFF|weighted_median_filter|WeightedMedianFilter" src/OpenCvSharp || true
echo "== opencvcontrib source availability check =="
if command -v curl >/dev/null 2>&1; then
echo "--- native enum definition ---"
curl -fsSL 'https://raw.githubusercontent.com/opencv/opencv_contrib/4.x/modules/ximgproc/include/opencv2/ximgproc/weighted_median_filter.hpp' \
| rg -n "enum .*Weight|WMF" || true
echo "--- native implementation switch candidates ---"
curl -fsSL 'https://raw.githubusercontent.com/opencv/opencv_contrib/4.x/modules/ximgproc/src/weighted_median_filter.cpp' \
| rg -n "weightType|WMF_EXP|WMF_COS|case |default" || true
fi
echo "== parser-ish behavioral probe for C# enum values/Flags and OpenCV doc enum flags =="
python3 - <<'PY'
from pathlib import Path
import re
p = Path('src/OpencVSharp/Modules/ximgproc/Enum/WMFWeightType.cs')
text = p.read_text() if p.exists() else None
print("has_flags:", bool(text and re.search(r'\[Flags\]\s*]', text, re.S)))
for name in ["EXP", "COS", "IV1", "IV2", "JAC", "OFF"]:
m = re.search(rf'WMF_{name}\s*=\s*(\d+)\b', text or '')
print(f"WMF_{name}:", m.group(1) if m else None, "mask-like:", 1 <= int(m.group(1)) <= 32 and ((int(m.group(1)) & (int(m.group(1))-1)) == 0 if m else None))
PYRepository: shimat/opencvsharp
Length of output: 4508
Remove [Flags] from WMFWeightType.
OpenCV defines these values as distinct int constants, and its implementation switches on exact WMF_EXP, WMF_COS, etc. Combinations like EXP | COS do not select both weights; they hit the default branch and fall back to EXP, so this enum should expose only the individual native values.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/OpenCvSharp/Modules/ximgproc/Enum/WMFWeightType.cs` at line 7, Remove the
[Flags] attribute from the WMFWeightType enum so it represents only the
individual native WMF_EXP, WMF_COS, and related values; leave the enum members
and their underlying values unchanged.
| Cv2.FishEye.Calibrate([objectPoints], [imagePoints], image.Size(), cameraMatrix, | ||
| distCoeffs, out _, out _, | ||
| FishEyeCalibrationFlags.FixK1 | FishEyeCalibrationFlags.FixK2 | | ||
| FishEyeCalibrationFlags.FixK3 | FishEyeCalibrationFlags.FixK4); | ||
|
|
||
| var distCoeffValues = distCoeffs.ToArray(); | ||
| Assert.All(distCoeffValues, d => Assert.Equal(0.0, d, 10)); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Assert each public flag value and the four-coefficient output.
OR-ing all flags cannot detect an individual mapping swap, and Assert.All passes for an empty array. Assert each numeric contract and Length == 4 before validating the coefficients.
Proposed test hardening
+ Assert.Equal(0x00020, (int)FishEyeCalibrationFlags.FixK1);
+ Assert.Equal(0x00040, (int)FishEyeCalibrationFlags.FixK2);
+ Assert.Equal(0x00080, (int)FishEyeCalibrationFlags.FixK3);
+ Assert.Equal(0x00800, (int)FishEyeCalibrationFlags.FixK4);
+
Cv2.FishEye.Calibrate([objectPoints], [imagePoints], image.Size(), cameraMatrix,
distCoeffs, out _, out _,
FishEyeCalibrationFlags.FixK1 | FishEyeCalibrationFlags.FixK2 |
FishEyeCalibrationFlags.FixK3 | FishEyeCalibrationFlags.FixK4);
var distCoeffValues = distCoeffs.ToArray();
+ Assert.Equal(4, distCoeffValues.Length);
Assert.All(distCoeffValues, d => Assert.Equal(0.0, d, 10));🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@test/OpenCvSharp.Tests/calib3d/Calib3dTest.cs` around lines 337 - 343, Harden
the fish-eye calibration test around Cv2.FishEye.Calibrate by asserting each
public FishEyeCalibrationFlags value individually, then require
distCoeffValues.Length == 4 before checking its contents. Replace the aggregate
Assert.All-only validation with explicit assertions for all four coefficient
positions and their expected zero values.
Description
Following up on #2081 (SolvePnPMethod), I audited the rest of the managed enums for the same class of bug — numeric values that were left over from OpenCV4 while the corresponding native OpenCV5 enum got renumbered, added members, or dropped members. Two more live, high-impact cases turned up:
FishEyeCalibrationFlagsIn OpenCV4,
cv::fisheyehad its own small-valued flag enum. In OpenCV5 thefisheyenamespace no longer defines its own flags — it just aliases the unifiedcv::CALIB_*flags viausingdeclarations, and those live at completely different bit positions (e.g.CALIB_RECOMPUTE_EXTRINSICis1 << 23, not1 << 1). The managed enum still had the old fisheye-only bit values, so every flag exceptUseIntrinsicGuess/FixIntrinsic(which happened to keep the same bit) silently set the wrong native bits, or collided with unrelated flags. Any fisheye calibration using more than the default flags was affected.WMFWeightTypeDeclared with no explicit values, so the compiler assigned a plain
0..5sequence. The nativecv::ximgproc::WMFWeightTypeis a bit-flag enum (1, 2, 4, 8, 16, 32). Every member exceptEXP(0, which happens to alias onto native'sdefault:fallback) invoked the wrong weighting formula inWeightedMedianFilter.VideoCaptureAPIscleanupWhile cross-checking, also found
OPENNI/OPENNI_ASUS/GIGANETIXreference native backend IDs (CAP_OPENNI/CAP_OPENNI_ASUS/CAP_GIGANETIX) that no longer exist in OpenCV5 at all — OpenNI was superseded by OpenNI2, and Giganetix support was dropped. Not a value-drift bug (nothing else shifted), but a dead/misleading member:VideoCapture.Open()with these silently fails to find a backend rather than throwing. Removed since OpenCvSharp5 doesn't guarantee source compatibility with the 4.x API.Changes
FishEyeCalibrationFlagsto match the nativeCALIB_*aliases.WMFWeightTypematching nativeWMF_*.VideoCaptureAPIsmembers.FishEyeCalibrateWithFixedDistortion) that fixes k1-k4 during fisheye calibration and asserts the resulting distortion coefficients are exactly 0 — this fails against the old bit values and passes against the fix.Test plan
dotnet buildsucceedsdotnet test --filter "FullyQualifiedName~calib3d|FullyQualifiedName~ximgproc|FullyQualifiedName~videoio"— 183 passed, 4 skipped (codec-dependent), 0 failedFishEyeCalibrateWithFixedDistortionactually fails against the pre-fix bit values (temporarily reverted locally) before confirming it passes against the fixSummary by CodeRabbit
Bug Fixes
Tests