Skip to content

OpenCV 5 migration (5.x integration branch) - #1920

Merged
shimat merged 296 commits into
mainfrom
5.x
Jul 2, 2026
Merged

shimat merged 296 commits into
mainfrom
5.x

Conversation

@shimat

@shimat shimat commented Jun 23, 2026

Copy link
Copy Markdown
Owner

Overview

This is the long-running integration branch for migrating OpenCvSharp to OpenCV 5.0.0.

🚧 Draft / work in progress. This branch is an ongoing effort to bring the full OpenCvSharp stack up to OpenCV 5. It is updated continuously via a series of stacked PRs, and more implementation is still to come. This PR is intentionally kept as a draft to track the overall migration; the description below is kept up to date as new PRs land.

The goal is a complete OpenCV 5 follow-up: a new OpenCvSharp5 NuGet package family built against OpenCV 5.0.0, with the native OpenCvSharpExtern layer and the managed API fully ported to OpenCV 5's restructured modules and behavior changes.

High-level change summary

Compared to main, this branch currently touches ~341 files (+19,470 / −8,510). The major themes:

1. Packaging & toolchain foundation

  • New OpenCvSharp5 NuGet package family (renamed from OpenCvSharp4), version basis bumped to OpenCV 5.0.0.
  • Managed target frameworks narrowed to .NET 8+ (dropped netstandard2.0/2.1 and net48), removing dead conditional compilation.
  • OpenCvSharpExtern now builds as C++20.
  • Extensions restructured: dedicated GdipExtensions package, helpers moved into core.
  • New OpenCV 5.0.0 Docker images (full + slim), and READMEs / 4→5 migration docs updated.

2. Native port (OpenCvSharpExtern)

  • opencv / opencv_contrib submodules bumped to 5.0.0.
  • Full extern compile port against OpenCV 5: calib3d/stereo header relocations, legacy Cv* types, aruco includes, BOW guards.
  • CI across all workflows (Windows / Linux / macOS / wasm / arm64) updated to build OpenCV 5, with broken vendored MLAS paths disabled where needed.

3. Module restructuring (following OpenCV 5)

  • features2dfeatures (contrib detectors relocated to xfeatures2d).
  • calib3d split into geometry / calib / stereo and relocated into objdetect / imgproc.
  • New ptcloud module wrapper: Volume, Odometry, RgbdNormals, depth free functions, OdometryFrame.

4. Behavior-change fixes

  • Adjustments for OpenCV 5 type encoding, 1-D Mat handling, dims<=2 asserts, and other behavior changes surfaced by the test suite.
  • Cross-platform test tolerance/parameter fixes (ImgHash, SuperpixelSEEDS), including a win-arm64 crash investigation.

5. New high-level DNN API

  • High-level Model API: Classification / Detection / Segmentation / Keypoints models.
  • High-level text models: TextRecognitionModel, TextDetectionModel (EAST / DB).
  • TFLite reader, blobFromImageWithParams, imagesFromBlob, and batched / soft NMS.
  • Net introspection: params, layer types, KV cache, getAvailable*, model format.

6. Full OpenCV 5 API coverage (#1924)

A sweep of the remaining OpenCV 5 additions/changes against the wiki and source diff, landed as a series of focused PRs (see below): DNN engine selection, the new features deep-learning detectors, geometry/calib additions and multi-view calibration, ptcloud mesh I/O, the built-in TrueType text renderer, core MatShape, and assorted enum/parameter gaps. Two internal/non-CPU APIs were intentionally skipped (documented in #1924).

Merged PRs so far

OpenCV 5 migration work

OpenCV 5 API coverage (#1924 — complete)

Intentionally skipped (internal / non-CPU; not exposed by OpenCV's own bindings): Net.forwardAsync + AsyncArray, Net.getMainGraph + Graph.

Dependency / CI maintenance (merged in from main)


This description will be expanded as additional stacked PRs are merged into 5.x.

shimat and others added 23 commits June 22, 2026 13:26
After merging the #1910 CI fixes, restore the ITestOutputHelper field the new
depth tests use, and drop RgbdNormals.apply() from the smoke test — like the
Volume/Odometry pipelines it can hard-crash (native segfault) on synthetic input
on some platforms (Windows arm64). Keep RgbdNormals construction + property
getters, and the stateless depth free-function calls (DepthTo3d/RescaleDepth/
RegisterDepth/WarpFrame/FindPlanes) which use valid inputs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
OpenCV 5: rename features2d→features, split calib3d, add ptcloud wrapper
The depth.hpp algorithm calls (RgbdNormals create/apply, depthTo3d, rescaleDepth,
registerDepth, warpFrame, findPlanes, Odometry.getNormalsComputer) hard-crash the
test process (native access violation, exit 0xC0000005 — not a catchable
exception) on Windows arm64, where OpenCV 5's new ptcloud module is unstable.
The bindings are fully exercised on x64 and linux, so guard these tests with
ArchitectureSpecificFact(Arm64) to skip them on arm64 only. Construction and
property smoke tests continue to run on all platforms.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…arm64 crash

Temporary: the Assert.Skip/attribute guards did not identify the culprit. Emit
unbuffered markers to the process raw stderr before/after each native ptcloud
call so the arm64 CI log reveals exactly which call segfaults (the last
"-before" with no "-after"). To be reverted once the offending call is known.
…tderr was swallowed)

xunit v3 (Microsoft.Testing.Platform) runs tests in a child process whose raw
stderr is not forwarded, so the previous stderr markers never reached the CI log.
Instead write each before/after marker to PTCLOUD_MARKER_FILE (AppendAllText
closes the handle, so it survives the subsequent hard crash) and add an
always()-run step to the Windows arm64 job that prints the file. The last
"-before" without an "-after" identifies the crashing native call.
…iagnostics

Investigation result: the Windows arm64 test-process crash (0xC0000005) is
INTERMITTENT — a diagnostic run logged every ptcloud native call completing and
the job passed, while earlier runs crashed at varying points. The C++ and
P/Invoke bindings for the ptcloud depth API were audited and are memory-safe
(only InputArray/OutputArray + scalars, standard clone() for the smart pointer),
so this is upstream instability in OpenCV 5's new ptcloud module on arm64, not a
wrapper bug.

Mitigate by skipping the algorithm-executing ptcloud tests on arm64 with a
runtime Assert.Skip guard (the ArchitectureSpecificFact attribute's discovery-time
Skip was not honored by xunit v3). Construction/property smoke tests still run on
all platforms; full algorithm coverage runs on x64 and linux. Removes the
temporary stderr/file marker diagnostics and the windows.yml dump step.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ng test

The win-arm64 process crash is intermittent and not caused by #1911's ptcloud
algorithm tests (they were skipped yet the host still crashed). Run the arm64
Test step with `dotnet test --blame-crash --blame-crash-dump-type full` so the
Sequence_*.xml records the test(s) executing when the host died, and upload the
crash dump as an artifact for offline stack analysis. Temporary; to be reverted
once the culprit is identified.
…e flaky crash

The single --blame-crash run passed (the crash is intermittent, ~50-80%/run).
Build once, then run the suite up to 6 times under --blame-crash, stopping at the
first crash so the Sequence_*.xml + full dump capture the culprit.
The arm64 crash investigation concluded it is an intermittent, instrumentation-
masked native heisenbug across the OpenCV 5 line (not caused by #1911's ptcloud
wrapper, which is clean, and not the algorithm tests, which crashed even when
skipped). Revert all the temporary diagnostics so this PR is clean for merge:
- PtCloudTest: drop the arm64 Assert.Skip guard and marker scaffolding; all
  construction/property/smoke tests run on every platform.
- windows.yml: restore the original arm64 Test step (no --blame-crash loop or
  dump-upload steps).

The win-arm64 instability is tracked and root-caused separately.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ptcloud: wrap RgbdNormals, depth free functions, and Odometry.getNormalsComputer
…h*height

Root cause of the intermittent win-arm64 test-process crash (exit 0xC0000005),
found by crash-dump analysis (DOTNET_DbgEnableMiniDump + SOS): the faulting
thread was inside cv::ximgproc::SuperpixelSEEDS::iterate(), reached from
SuperpixelTest.SeedsSimple.

The tests passed num_superpixels = image.Width * image.Height (one superpixel per
pixel). In OpenCV's seeds.cpp initialize(), that drives num_superpixels_w/h to
W/H, which collapses the level pyramid to seeds_nr_levels == 1
(seeds_top_level == 0, seeds_current_level == -1). SEEDS is a hierarchical,
multi-level algorithm (the OpenCV sample uses ~400 superpixels / 4 levels); this
degenerate single-level configuration produces edge-case memory access that
survives on x64 but intermittently faults on arm64.

Use a sane num_superpixels (400) so the normal multi-level configuration is
exercised on all platforms. Not an OpenCvSharp binding bug; OpenCV could also
guard against the degenerate level count (candidate upstream report).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…tation/Keypoints)

The OpenCvSharp5 DNN wrapper only covered the minimal "read + Net.Forward"
path; the OpenCV 5 high-level Model API (input preprocessing + predict helpers)
was missing. Add the high-priority core classes.

- Model (base): SetInputSize/Mean/Scale/Crop/SwapRB/Params, SetOutputNames,
  Predict, SetPreferableBackend/Target, EnableWinograd. Constructible from a
  file path or from a Net.
- ClassificationModel: Classify, SetEnableSoftmaxPostProcessing
- DetectionModel: Detect, SetNmsAcrossClasses
- SegmentationModel: Segment
- KeypointsModel: Estimate

Implementation notes:
- Each derived type is destroyed via its own delete; base methods upcast the
  derived pointer to Model* and are shared (safe under single inheritance, no
  pointer adjustment needed).
- setInputScale takes cv::Scalar in OpenCV 5 (changed from double); handled.
- Native dnn_Model.h is included from dnn.cpp and registered in the vcxproj
  and .filters.

The native layer needs a full OpenCV 5 build to verify, so it is validated in
CI. The managed library and test project build locally with 0 errors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The first version of ModelTest only constructed models from an empty Net and
called setters, which never exercised the actual inference path. Replace those
with end-to-end tests that reuse the MNIST TensorFlow model and digit images
already committed in the repo (also used by TensorflowTest), so they run in CI
without any download:

- ClassificationModel.Classify recognizes MNIST digits 5 and 9
- Model.Predict returns a probability blob whose argmax is the correct digit

Verified locally against a freshly built OpenCvSharpExtern (OpenCV 5.0.0): all
8 ModelTest cases pass, and the full dnn suite stays green (22 passed / 3
explicit-skipped).

This surfaced a real requirement that the lifecycle-only tests had missed: the
high-level Model API requires an explicit input size (unlike blobFromImage,
which defaults to the frame size). The tests now set it via SetInputParams.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add high-level dnn Model API (Model + Classification/Detection/Segmentation/Keypoints)
…ST/DB)

Follow-up to the dnn Model API work (#1917). Adds the remaining high-level
text models from OpenCV 5's dnn module.

- TextRecognitionModel: SetDecodeType/GetDecodeType,
  SetDecodeOptsCTCPrefixBeamSearch, SetVocabulary/GetVocabulary, Recognize.
- TextDetectionModel (abstract base): Detect (quadrangles + confidences) and
  DetectTextRectangles (RotatedRects + confidences), shared by EAST and DB.
- TextDetectionModelEAST: SetConfidenceThreshold/Get, SetNMSThreshold/Get.
- TextDetectionModelDB: SetBinaryThreshold/Get, SetPolygonThreshold/Get,
  SetUnclipRatio/Get, SetMaxCandidates/Get.

All classes can be built from a file path or from a Net, and inherit the base
Model preprocessing setters. As with the Model API, the base TextDetectionModel
methods upcast the derived pointer (single inheritance, no pointer adjustment).

Native dnn_TextModel.h is included from dnn.cpp and registered in the vcxproj
and .filters.

Verified locally against a freshly built OpenCvSharpExtern (OpenCV 5.0.0):
- The 3 lifecycle tests pass (constructors, setters/getters, vocabulary and
  decode-type round-trips for all three model types).
- The EAST end-to-end test (temporarily un-skipped) downloads the EAST model
  and detects text rectangles on abbey_road.jpg with confidences above the
  threshold; it ships as [ExplicitTheory] like the existing EAST test.
- Full dnn suite stays green (25 passed / 4 explicit-skipped).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add high-level dnn text Model API (TextRecognition + TextDetection EAST/DB)
…ed/soft NMS

Priority group B of the dnn coverage work (follows the Model API in #1917/#1918).
Adds the OpenCV 5 preprocessing / post-processing helpers that were missing.

- readNetFromTFLite: CvDnn.ReadNetFromTFLite and Net.ReadNetFromTFLite
  (file path, byte[], ReadOnlySpan<byte>, Stream) mirroring the ONNX readers.
- blobFromImageWithParams / blobFromImagesWithParams via a new Image2BlobParams
  class (ScaleFactor, Size, Mean, SwapRB, Depth, DataLayout, PaddingMode,
  BorderValue), enabling letterbox/center-crop preprocessing.
- imagesFromBlob: CvDnn.ImagesFromBlob to unpack a 4D blob back into images.
- NMSBoxesBatched (Rect and Rect2d) and softNMSBoxes (Rect).
- New enums DataLayout, ImagePaddingMode, SoftNMSMethod.

Note: in OpenCV 5 the DataLayout enum moved from cv::dnn to the cv namespace
(core/mat.hpp); the native wrapper uses cv::DataLayout accordingly.

Verified locally against a freshly built OpenCvSharpExtern (OpenCV 5.0.0); the
6 BlobAndNmsTest cases pass and the full dnn suite stays green:
- blobFromImageWithParams produces the same blob as blobFromImage for matching
  params, and LETTERBOX yields the requested NCHW shape.
- imagesFromBlob round-trips blobFromImages.
- NMSBoxesBatched returns the expected kept indices; softNMSBoxes returns
  indices with matching updated scores.
- readNetFromTFLite on an invalid buffer raises OpenCVException (entry point
  wired), rather than a P/Invoke failure.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add dnn TFLite reader, blobFromImageWithParams, imagesFromBlob, batched/soft NMS
@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 175ed37b-2da5-4680-938d-a402824f1693

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 5.x

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.

shimat and others added 6 commits June 23, 2026 23:06
…e*, model format

Priority group C/D of the dnn coverage work (follows #1917/#1918/#1919). Wraps the
genuinely useful and C#-friendly Net introspection / utility members and skips the
ones that only make sense in C++.

Net:
- SetInputShape(name, shape)
- GetParam / SetParam (by layer id and by layer name)
- GetLayerTypes, GetLayersCount
- GetModelFormat (+ new ModelFormat enum)
- EnableWinograd, DumpToPbtxt, PrintPerfProfile
- EnableKVCache / DisableKVCache / ResetKVCache (transformer/LLM KV cache control)

CvDnn (free functions):
- GetAvailableTargets(Backend), GetAvailableBackends(), EnableModelDiagnostics(bool)

Deliberately NOT wrapped (documented in docs/opencv5/dnn-coverage.md):
- getFLOPS / getLayersShapes / getLayerShapes / getMemoryConsumption — awkward in 5.0
  (MatShape is now a struct, plus netInputTypes and nested vector<vector<MatShape>>);
  low value, can be added later.
- Layer class, getLayer/addLayer/registerOutput/getLayerInputs — these exist mainly for
  authoring custom layers, which requires subclassing cv::dnn::Layer in C++ and is not
  practical via P/Invoke (per-forward managed callbacks + blob marshaling).
- forwardAsync/AsyncArray — async-backend only, low value.

Notes:
- MatShape moved from std::vector<int> alias to a real cv::MatShape struct in OpenCV 5;
  SetInputShape constructs it from an int range natively.

Verified locally against a freshly built OpenCvSharpExtern (OpenCV 5.0.0): 9
NetIntrospectionTest cases pass, full dnn suite green (31 passed / 3 explicit-skipped).
GetModelFormat returns TF for a TF model; GetLayerTypes/GetLayersCount,
GetAvailableTargets/Backends return real values. GetParam/SetParam, SetInputShape and
DumpToPbtxt are verified via their error path (the committed TF models do not expose
layer blobs, and DumpToPbtxt needs allocated output blobs), confirming the entry points
are wired rather than failing in the P/Invoke layer.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…pection

# Conflicts:
#	src/OpenCvSharp/Internal/PInvoke/NativeMethods/dnn/NativeMethods_dnn.cs
#	src/OpenCvSharpExtern/dnn.h
Add dnn Net introspection: params, layer types, KV cache, getAvailable*, model format
OpenCV 5 lets readNet* pick an inference engine via an `int engine`
parameter (EngineType: Classic/New/Auto/Ort). Expose it through the
native bridge and the managed Net / CvDnn read APIs, defaulting to Auto.

Also re-sync the Backend and Target enums with OpenCV 5: add Backend
WEBNN/TIMVX/CANN (Halide removed but its value 1 kept as a gap so the
remaining values stay correct) and Target NPU/CPU_FP16.

Refs #1924.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add DNN engine selection (EngineType) and sync Backend/Target enums
…dex, AffineFeature

Wraps the new and previously-unwrapped classes from the OpenCV 5 features
module (formerly features2d):

- ALIKED, DISK: deep-learning local feature detectors/descriptors (Feature2D,
  ONNX via dnn). Both expose Create (file path) and CreateFromMemory (buffer).
- LightGlueMatcher: attention-based descriptor matcher (DescriptorMatcher) with
  SetPairInfo/ClearPairInfo.
- ANNIndex: Annoy-based approximate nearest neighbor index (modern FLANN
  alternative) with add/build/knnSearch/save/load and ANNIndexDistance enum.
- AffineFeature: affine-invariant wrapper over a backend Feature2D (ASIFT).

DNN-dependent classes are guarded with HAVE_OPENCV_DNN in the native bridge.
Model-path string entry points use the Windows/NotWindows marshaling split.

Tests: AffineFeature and ANNIndex are exercised end-to-end; DISK/ALIKED/
LightGlue verify entry-point wiring (missing model -> OpenCVException) since
their ONNX models are not committed. Full Features suite green (51 passed).

Refs #1924.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
shimat and others added 23 commits July 2, 2026 21:43
…/Randn/RandShuffle/Kmeans) to InputArrayRef/OutputArrayRef (issue #1976 step 5, part 9)

Completes the #region core.hpp block in Cv2_core.cs. Fixes the
Mat_CvMethods.cs Randu/Randn instance wrappers.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…Zero/Mean/Sqrt/PCAComputeVar overload/Format) to InputArrayRef/OutputArrayRef (issue #1976 step 5, part 10)

Completes the InputArrayRef/OutputArrayRef/InputOutputArrayRef conversion
of Cv2_core.cs - these were missed by earlier batches (out of file order or
in a second overload). Fixes the Mat.Mean(InputArray?) instance wrapper.

Verified: zero remaining InputArray/OutputArray/InputOutputArray parameter
declarations in Cv2_core.cs (only native extern function names containing
those substrings remain, e.g. core_meanStdDev_OutputArray).

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…Dot) to InputArrayRef/OutputArrayRef (issue #1976 step 5, part 11)

Mul() captures the InputArrayRef's proxy/source by value before handing
off to MatExpr.FromExpr's deferred delegate, since ref structs cannot be
captured by a closure.
These wrapped Cv2 static methods as Mat instance methods purely for
chainable call syntax (e.g. mat.GaussianBlur(...).CvtColor(...)). The
duplication doubled the maintenance surface of every Cv2 static method,
and intermediate Mats produced mid-chain cannot be captured with `using`,
so they leaked into non-deterministic GC-driven native cleanup -- the
same class of problem InputArray/OutputArray ref-structification and the
MatExpr lazy-tree rework were addressing elsewhere. Call sites now use
Cv2.Xxx(...) directly.

This is a breaking change for OpenCvSharp5.
…to InputArrayRef/OutputArrayRef (issue #1976 step 5, part 12)
…f/InputOutputArrayRef (issue #1976 step 5, part 13)

Completes the "core残り" batch alongside Mat.cs/UMat.cs (parts 11-12).
…/OutputArrayRef/InputOutputArrayRef (issue #1976 step 5, part 14)

Scripted the mechanical parts of this conversion (signature retyping,
null-check/ThrowIfDisposed/ThrowIfNotReady/Fix() removal, ToXProxy()->
.Proxy, GC.KeepAlive(x)->GC.KeepAlive(x.Source)) since Cv2_imgproc.cs is
the largest Cv2 static file; manually fixed the handful of cases the
script couldn't infer:
- CreateHanningWindow's dst is purely an output (native signature takes
  OutputArray, not InputOutputArray) despite the old class-based API
  exposing it as InputOutputArray via inheritance -- InputOutputArrayRef
  has no such inheritance, so the param is now OutputArrayRef.
- Moments' InputArray constructor/helper migrated alongside its only
  caller (Cv2.Moments).
- Call sites passing literal `null` for now non-nullable *Ref parameters
  (CalcHist mask, MorphologyEx element, EMD cost) updated to `default`.
- ImgProcTest.Rectangle's InputOutputArray.Create(...) smoke coverage
  swapped for InputOutputArrayRef.Create(...).
…ef/InputOutputArrayRef (issue #1976 step 5, part 15)

Scripted via migrate_step5.py (same tool used for Cv2_imgproc.cs). Only
manual fixup needed: the two convenience Rodrigues(double[]/double[,])
overloads built explicit old-class InputArray.Create(...)/
OutputArray.Create(...) wrappers around their Mats before delegating to
Rodrigues(InputArrayRef, OutputArrayRef, OutputArrayRef) -- simplified to
pass the Mats directly, since Mat converts implicitly to the *Ref types.
…InputOutputArrayRef (issue #1976 step 5, part 16)

Scripted via migrate_step5.py; no manual fixups needed this time.
…InputOutputArrayRef (issue #1976 step 5, part 17)

Scripted via migrate_step5.py; fixed one null-literal call site
(FindTransformECC's inputMask) to use default.
…ef/InputOutputArrayRef (issue #1976 step 5, part 18)

Scripted via migrate_step5.py; no manual fixups needed.
…InputOutputArrayRef (issue #1976 step 5, part 19)

Scripted via migrate_step5.py; no manual fixups needed. Completes the
Cv2 static-file batch that followed the ArrayProxy ABI migration's
module order (core/imgproc/geometry/calib/video/objdetect/stereo).
…tputArrayRef/InputOutputArrayRef (issue #1976 step 5, part 20)

Covers every remaining class-based InputArray/OutputArray/
InputOutputArray consumer in src/OpenCvSharp/Modules and the nested
Cv2.<Sub> facades (Aruco/Dnn/OptFlow/Detail/Text/XImgProc/XPhoto/Shape),
completing issue #1976 Step 5's type migration across the whole library.

Scripted via a generalized migrate_step5_v2.py that extends the Cv2
static-file script to instance methods and constructors (any access
modifier, not just `public static`), since these files are mostly
classes with instance members rather than Cv2 facade statics. Fixed two
script bugs found along the way:
- Missing \b word boundaries let e.g. "sum" match inside "sqsum".
- The block-vs-expression-body scan treated any "=>" as an expression-
  bodied method terminator, including lambdas inside a constructor's
  `: base(..., x => ...)` initializer -- now tracks paren depth so only
  top-level terminators count.

Manual fixups beyond the script:
- FaceDetectorYN.Detect: replaced explicit `new InputArray(image)`/
  `new OutputArray(faces)` wrapping with direct Mat-to-*Ref conversion
  (no owning wrapper needed anymore).
- CharucoDetector: the cameraMatrix/distCoeffs "both null or both
  non-null" validation used `is null`, which doesn't apply to non-
  nullable ref structs -- rewritten to check Proxy.Kind against
  ArrayProxyKind.None.
- A handful of leftover `if(x is null)` checks (no space after `if`,
  which the removal regex didn't match) caused CS0037 "null to non-
  nullable value type" -- removed.
- XML doc <see cref="..."/> references to old signatures updated to
  match the new *Ref parameter types.
…ssue #1976 step 5, part 20 follow-up)

- Null-literal arguments for now non-nullable *Ref parameters (mask/
  element/etc.) changed to `default` across several test files.
- Removed BarcodeDetectorTest.DetectAndDecode_NullImage_ThrowsArgumentNullException
  and WeChatQRCodeTest.DetectAndDecode_NullInput_ThrowsArgumentNullException:
  both asserted an ArgumentNullException from passing `null!` for an
  InputArrayRef parameter, which the type system now rejects at compile
  time instead -- the runtime check the test covered no longer exists.
…sue #1976 step 5, final cleanup part 1)

All call sites were migrated to the *Ref ref structs in prior commits;
this removes the now-dead classes. InOutArrayKind (and the KIND_SHIFT/
KIND_MASK constants that backed it) is deleted alongside InputArray:
it only existed to support InputArray.Kind(), one of the ~25
introspection methods (GetMat/Empty/Type/IsMat/etc.) that turned out to
have zero callers and zero tests when the *Ref types were designed, and
so was never ported.

Zero build fallout confirms every caller had already moved to
InputArrayRef/OutputArrayRef/InputOutputArrayRef.
… cleanup part 2)

TransposeRef/AddRef/CompleteSymmRef were the original proof-of-concept
for the ref-struct design and call the exact same native functions as
the now-migrated Cv2.Transpose/Add/CompleteSymm, making them pure
duplicates. Rewired InputArrayRefTest.cs to exercise the same
allocation-free and Create(...) factory behavior through the real,
permanent Cv2 methods instead of the deleted PoC ones, so the
zero-allocation regression coverage isn't lost.
…l names (issue #1976 step 5, final cleanup part 3)

Mechanical rename now that the class-based InputArray/OutputArray/
InputOutputArray are gone and the names are free:
  InputArrayRef       -> InputArray
  OutputArrayRef      -> OutputArray
  InputOutputArrayRef -> InputOutputArray

Single-pass whole-word regex per name (no placeholder/2-pass needed,
unlike the earlier MatExprNode->MatExpr rename, since these three names
don't overlap as substrings of each other and the target names weren't
already in use). Renamed the defining file InputArrayRef.cs ->
InputArray.cs and the test file/class InputArrayRefTest(.cs) ->
InputArrayTest.

Also dropped the ArrayProxyKind.RawInputArray/RawOutputArray/
RawInputOutputArray migration-scaffold enum values and rewrote the
file-header comment in InputArray.cs: both were explicitly documented
as "removed once the type flip is complete", which it now is. Nothing
in the codebase ever constructed a proxy with those Kind values anymore
(they existed solely so externs could wrap a class-based
InputArray/OutputArray/InputOutputArray handle during the incremental
ArrayProxy ABI migration).

This completes issue #1976 step 5: InputArray/OutputArray/
InputOutputArray are now ref structs everywhere, matching their
original class-based public API names.
…aining-5x

Migration: remaining modules to the ArrayProxy ABI (by-pointer) + tests
…anup-5x

Migration: InputArray/OutputArray/InputOutputArray to allocation-free ref structs (issue #1976 step 4 & 5)
…b is net8.0-only

src/OpenCvSharp/ targets net8.0 exclusively (netstandard2.0/2.1/net4x were
already dropped), so a net4x consumer can never reference it. WindowsLibraryLoader's
dll/{arch} folder probing existed only for that unreachable net4x scenario, and its
default no-op path (no AdditionalPaths) already made it a pure pass-through for
every real net8.0 consumer.

The one working escape hatch (WindowsLibraryLoader.Instance.AdditionalPaths, undocumented)
is fully subsumed by calling System.Runtime.InteropServices.NativeLibrary.Load or
NativeLibrary.SetDllImportResolver directly from consumer code, so no OpenCvSharp-side
API is needed for it either.

Native library resolution is now handled entirely by the .NET runtime's default
probing via the runtimes/{rid}/native/ layout. Drops the now-pointless net4x
dll/{arch} copy wiring from the runtime NuGet packages (.props/.targets) as well.
- "net8.0 only" could be misread as excluding newer runtimes (net9.0,
  net10.0, ...) that can also reference a net8.0 assembly; reword as
  "net8.0 or above".
- release-process.md's ffmpeg DLL rename step still pointed at the
  already-renamed OpenCvSharp4.runtime.win.props (deleted in the prior
  commit) instead of the current OpenCvSharp5.runtime.win.csproj.
…oader-5x

Remove WindowsLibraryLoader/Win32Api: unreachable now that the managed lib is net8.0-only
# Conflicts:
#	.github/workflows/macos.yml
#	.github/workflows/publish_nuget.yml
#	README.md
#	cmake/triplets/arm64-osx-static.cmake
#	cmake/triplets/x64-osx-static.cmake
#	nuget/OpenCvSharp4.runtime.osx.10.15-x64.csproj
#	nuget/OpenCvSharp4.runtime.osx.x64.csproj
#	nuget/OpenCvSharp5.runtime.osx.x64.csproj
#	nuget/OpenCvSharp5.runtime.win.csproj
#	nuget/README.runtime.md
#	test/OpenCvSharp.Tests/xphoto/XPhotoTest.cs
@shimat
shimat marked this pull request as ready for review July 2, 2026 13:26
shimat and others added 3 commits July 2, 2026 23:04
…e check

Replaces a raw Proxy.Kind comparison with a named property for readability.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… tool

Allows publishing packages to nuget.org with the -beta suffix kept, for a
real pre-release publish (e.g. the first release of a new package line)
instead of always promoting straight to a final version. The beta-stripping
logic (package file rename + in-place .nuspec version edit) is now inlined
in the workflow instead of a separate OpenCvSharp.NupkgBetaRemover console
tool, which is removed.
Migrated every project in opencvsharp_samples from OpenCvSharp4 to a locally
packed OpenCvSharp5 beta to validate the upcoming package before release.
Captures what broke and why: Mat's fluent Cv2-wrapper instance methods were
removed entirely (large blast radius), InputArray/OutputArray ref-structs
need `default` instead of `null`, MatExpr is no longer IDisposable,
OutputArray.Create(List<T>) is gone, namespace moves in features/xfeatures2d,
ArucoDetector's instance-based DetectMarkers, a ReadNetFromOnnx/ReadNetFromONNX
casing mismatch, and confirmation that Cv2.Dnn.ReadNet has no working
Caffe/Darknet fallback (throws at runtime). Marked as an unedited dump for a
future pass, not yet reconciled with the rest of the document's structure.
@shimat
shimat merged commit b73ec96 into main Jul 2, 2026
15 of 16 checks passed
@shimat
shimat deleted the 5.x branch July 2, 2026 14:43
@shimat shimat added the enhancement New feature or improvement to OpenCvSharp label Jul 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or improvement to OpenCvSharp

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant