Skip to content

Fix more enums carrying stale native values from the OpenCV4->5 migration - #2082

Merged
shimat merged 1 commit into
mainfrom
fix/enum-native-value-drift-sweep
Jul 23, 2026
Merged

Fix more enums carrying stale native values from the OpenCV4->5 migration#2082
shimat merged 1 commit into
mainfrom
fix/enum-native-value-drift-sweep

Conversation

@shimat

@shimat shimat commented Jul 23, 2026

Copy link
Copy Markdown
Owner

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:

FishEyeCalibrationFlags

In OpenCV4, cv::fisheye had its own small-valued flag enum. In OpenCV5 the fisheye namespace no longer defines its own flags — it just aliases the unified cv::CALIB_* flags via using declarations, and those live at completely different bit positions (e.g. CALIB_RECOMPUTE_EXTRINSIC is 1 << 23, not 1 << 1). The managed enum still had the old fisheye-only bit values, so every flag except UseIntrinsicGuess/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.

WMFWeightType

Declared with no explicit values, so the compiler assigned a plain 0..5 sequence. The native cv::ximgproc::WMFWeightType is a bit-flag enum (1, 2, 4, 8, 16, 32). Every member except EXP (0, which happens to alias onto native's default: fallback) invoked the wrong weighting formula in WeightedMedianFilter.

VideoCaptureAPIs cleanup

While cross-checking, also found OPENNI/OPENNI_ASUS/GIGANETIX reference 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

  • Renumber FishEyeCalibrationFlags to match the native CALIB_* aliases.
  • Add explicit bit-flag values to WMFWeightType matching native WMF_*.
  • Remove the three dead VideoCaptureAPIs members.
  • Add a regression test (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 build succeeds
  • dotnet test --filter "FullyQualifiedName~calib3d|FullyQualifiedName~ximgproc|FullyQualifiedName~videoio" — 183 passed, 4 skipped (codec-dependent), 0 failed
  • Verified FishEyeCalibrateWithFixedDistortion actually fails against the pre-fix bit values (temporarily reverted locally) before confirming it passes against the fix

Summary by CodeRabbit

  • Bug Fixes

    • Corrected fisheye calibration flag values so fixed distortion and calibration constraints work as expected.
    • Updated weight-type flags to support proper combination of options.
    • Removed unsupported video capture backend options.
  • Tests

    • Added coverage confirming fixed distortion coefficients remain unchanged during fisheye calibration.

…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.
@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Updated public enum contracts for fisheye calibration, video capture APIs, and WMF weights. Added a regression test verifying fixed fisheye distortion coefficients remain zero.

Changes

Fisheye calibration flags

Layer / File(s) Summary
Fisheye flag bitmasks
src/OpenCvSharp/Modules/calib/Enum/FishEyeCalibrationFlags.cs
Reorders fisheye calibration flags and changes their underlying bitmask values.
Fixed distortion regression test
test/OpenCvSharp.Tests/calib3d/Calib3dTest.cs
Adds calibration coverage combining FixK1FixK4 and asserting zero distortion coefficients.

Video capture API entries

Layer / File(s) Summary
Video capture API enum cleanup
src/OpenCvSharp/Modules/videoio/Enum/VideoCaptureAPIs.cs
Removes OPENNI, OPENNI_ASUS, and GIGANETIX while retaining ANDROID and MSMF.

WMF weight flags

Layer / File(s) Summary
WMF weight flag values
src/OpenCvSharp/Modules/ximgproc/Enum/WMFWeightType.cs
Adds [Flags] and assigns explicit power-of-two values to all weight types.

Estimated code review effort: 3 (Moderate) | ~20 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the enum value updates tied to the OpenCV4-to-5 migration.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/enum-native-value-drift-sweep

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between 5d08d9c and 553e58f.

📒 Files selected for processing (4)
  • src/OpenCvSharp/Modules/calib/Enum/FishEyeCalibrationFlags.cs
  • src/OpenCvSharp/Modules/videoio/Enum/VideoCaptureAPIs.cs
  • src/OpenCvSharp/Modules/ximgproc/Enum/WMFWeightType.cs
  • test/OpenCvSharp.Tests/calib3d/Calib3dTest.cs

Comment on lines 69 to +72
/// <summary>
/// Android - not used
/// </summary>
ANDROID = 1000,
ANDROID = 1000,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ 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' || true

Repository: 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:


🌐 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:


🏁 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' . || true

Repository: 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:


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]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 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 || true

Repository: 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:


🏁 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))
PY

Repository: 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.

Comment on lines +337 to +343
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));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 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.

@shimat
shimat merged commit dac6456 into main Jul 23, 2026
17 of 19 checks passed
@shimat
shimat deleted the fix/enum-native-value-drift-sweep branch July 23, 2026 05:15
@shimat shimat self-assigned this Jul 23, 2026
@shimat shimat added the bug Confirmed defect in OpenCvSharp label Jul 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Confirmed defect in OpenCvSharp

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant