Skip to content

Commit 3dbd4fb

Browse files
committed
docs: add raw findings from OpenCvSharp5 samples migration testing
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.
1 parent d969515 commit 3dbd4fb

1 file changed

Lines changed: 165 additions & 0 deletions

File tree

docs/migration-4-to-5.md

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,171 @@ Caffe model support was dropped; these constructors now take ONNX model paths:
9797
| `new BarcodeDetector(superResolutionPrototxtPath, superResolutionCaffeModelPath)` | `new BarcodeDetector(superResolutionModelPath = "")` |
9898
| `new WeChatQRCode(detectorPrototxt, detectorCaffe, srPrototxt, srCaffe)` | `new WeChatQRCode(detectorModelPath = "", superResolutionModelPath = "")` |
9999

100+
## 3b. Additional findings from real-world migration testing (raw notes, needs editing pass)
101+
102+
The following was found by taking the `opencvsharp_samples` repo and actually
103+
migrating every sample project from OpenCvSharp4 to a locally-built
104+
OpenCvSharp5 beta package. Not yet cross-checked against other modules or
105+
polished into the rest of this document — treat as a raw findings dump for a
106+
future editing pass.
107+
108+
### `Cv2.Dnn.ReadNet(model, config)` is NOT a working fallback for Caffe/Darknet
109+
110+
The "Removed APIs" table above says to use ONNX for Caffe/Darknet models, but
111+
it's worth being explicit: the generic dispatcher `Cv2.Dnn.ReadNet(model,
112+
config)` (`cv::dnn::readNet` in `opencv/modules/dnn/src/dnn_read.cpp`)
113+
still *detects* `.caffemodel`/`.prototxt`/`.weights`/`.cfg` extensions, but on
114+
match it unconditionally throws:
115+
116+
```
117+
cv::Exception: Caffe importer has been removed. Please use ONNX-converted models or use an older OpenCV version.
118+
```
119+
120+
(same for Darknet). So there is no code-level workaround at all for
121+
Caffe/Darknet models in OpenCvSharp5 — model conversion to ONNX is mandatory,
122+
not just recommended. (The `opencvsharp_samples` samples that loaded
123+
`.caffemodel` files — `CaffeSample`, `FaceDetectionDNN`, `HandPose`, `Pose`
124+
were deleted outright rather than "fixed", since there is nothing to fix them
125+
to without a different model file.)
126+
127+
### Minor: `ReadNetFromOnnx` casing is inconsistent between `Cv2.Dnn` and `Net`
128+
129+
`Cv2.Dnn.ReadNetFromOnnx` (lowercase `nnx`) forwards to `Net.ReadNetFromONNX`
130+
(uppercase `ONNX`). Pick one casing convention; right now the facade and the
131+
underlying type disagree with each other, and this migration doc's own
132+
"Removed APIs" table used the `ONNX` casing (inherited from the `Net` side) —
133+
worth double-checking every mention once one casing is chosen.
134+
135+
### `OutputArray.Create(List<T>)` (write-back into a `List<T>`) was removed
136+
137+
This is a genuine removed API, missing from the "Removed APIs" table above.
138+
OpenCvSharp4 let you pass a `List<T>` as an output sink, e.g.:
139+
140+
```csharp
141+
var output = new List<byte>();
142+
Cv2.Threshold(InputArray.Create(input), OutputArray.Create(output), T, Max, ThresholdTypes.Binary);
143+
```
144+
145+
`OutputArray.Create(List<T>)` no longer exists. Use a `Mat` as the output and
146+
pull the array back out with `Mat.GetArray<T>(out T[])`:
147+
148+
```csharp
149+
using var output = new Mat();
150+
Cv2.Threshold(InputArray.Create(input), output, T, Max, ThresholdTypes.Binary);
151+
output.GetArray(out byte[] outputArr);
152+
```
153+
154+
This was removed as "dead scaffolding" (issue #1976 step 4), but real sample
155+
code in `opencvsharp_samples` (`NormalArrayOperations`, `SolveEquation`) was
156+
using it, so "dead" was inaccurate — flag this if the same reasoning gets
157+
applied to other APIs going forward.
158+
159+
### `null` no longer works for optional `InputArray`/`OutputArray`/`InputOutputArray` parameters — use `default`
160+
161+
`InputArray` / `OutputArray` / `InputOutputArray` are now `readonly ref
162+
struct`s (see the InputArray/OutputArray ref-struct redesign, issue #1976),
163+
so they can't be `null`. Any call site that used to pass a literal `null` for
164+
an optional mask/array parameter (e.g. `Feature2D.DetectAndCompute(image,
165+
null, out keypoints, descriptors)`, `Cv2.CalcHist(..., null, ...)`,
166+
`Cv2.Dilate(src, dst, null)`) now needs `default` instead:
167+
168+
```csharp
169+
sift.DetectAndCompute(gray, default, out var keypoints, descriptors); // was: null
170+
```
171+
172+
This is the same convention already used in `test/OpenCvSharp.Tests` (e.g.
173+
`FlannBasedMatcherTest.cs`, `ORBTest.cs`), so it's at least consistent — but
174+
it isn't mentioned anywhere in this migration doc yet, and the compiler error
175+
you get (`CS0037: cannot convert null to 'InputArray' because it's a
176+
non-nullable value type`) doesn't point at `default` as the fix.
177+
178+
### `Mat`'s fluent Cv2-wrapper instance methods were removed entirely (huge blast radius)
179+
180+
`Mat_CvMethods.cs` — the file of `Mat` instance methods that wrapped `Cv2`
181+
static methods purely for chainable call syntax (`mat.Circle(...)`,
182+
`mat.Line(...)`, `mat.Rectangle(...)`, `mat.PutText(...)`,
183+
`mat.Polylines(...)`, `mat.CvtColor(...)`, `mat.Threshold(...)`,
184+
`mat.Resize(...)`, `mat.SaveImage(...)`, `mat.HoughCircles(...)`,
185+
`mat.MinEnclosingCircle(...)`, and many more — over 2300 lines) — was deleted
186+
outright (commit `446c36b8`, "Remove Mat_CvMethods.cs fluent Cv2 wrappers
187+
(Mat instance methods)"). Rationale from the commit message: the duplication
188+
doubled the maintenance surface of every `Cv2` method, and intermediate
189+
`Mat`s produced mid-chain couldn't be captured with `using`, leaking into
190+
non-deterministic GC-driven native cleanup.
191+
192+
This is an intentional, deliberate, already-decided breaking change — not a
193+
bug — but its real-world impact is large: migrating the ~20 files in
194+
`opencvsharp_samples` that used this fluent style touched **every single
195+
non-GUI sample that draws or converts a `Mat`**. The compile error gives zero
196+
indication of what changed (`CS1061: 'Mat' does not contain a definition for
197+
'Circle'`), so anyone hitting this needs to already know the fluent API was
198+
removed. This deserves prominent, explicit coverage in the migration guide —
199+
probably its own top-level section — since it's likely the single most common
200+
break for existing OpenCvSharp4 code, more so than any of the renames above.
201+
202+
Migration pattern is mechanical: `mat.Xxx(args)``Cv2.Xxx(mat, args)`
203+
(insert the `Mat` as the first argument). Two subtleties found in practice:
204+
205+
- Methods that used to *return a new Mat* (`var gray = src.CvtColor(code);`,
206+
`var t = src.Threshold(...)`) need an explicit destination `Mat` created
207+
first: `using var gray = new Mat(); Cv2.CvtColor(src, gray, code);`.
208+
- `Mat.Resize(...)` collides with an unrelated, still-existing instance
209+
method: `Mat.Resize(int sz)` / `Mat.Resize(int sz, Scalar s)` (std::vector
210+
-style row-count resize, present since OpenCvSharp4). Callers who meant
211+
"image resize" and got a "wrong number of arguments" error rather than a
212+
"no such method" error should be pointed at `Cv2.Resize(src, dst, size,
213+
fx, fy, interpolation)` explicitly, since overload resolution won't say
214+
"did you mean Cv2.Resize" for them.
215+
216+
### `MatExpr` is no longer `IDisposable` — drop `using` on it
217+
218+
Consistent with the `MatExpr` lazy-tree rework: `Mat.Zeros(...)`, `Mat.Eye(...)`,
219+
`mat.T()`, and Mat arithmetic operators (`+`, `*`, `-0.5`, ...) now return a
220+
`MatExpr` that is a lightweight managed value, not a disposable native
221+
handle. Code that did `using var x = Mat.Zeros(...);` or `using var t = a *
222+
b;` now fails with `CS1674: 'MatExpr': type used in a using statement must be
223+
implicitly convertible to 'System.IDisposable'`. Fix is to just drop the
224+
`using`/`using var` (`var x = Mat.Zeros(...);`). If the declared type is
225+
explicitly `Mat` rather than `var` (e.g. `using (Mat img = Mat.Zeros(...))`),
226+
it still compiles and still needs disposal, because `MatExpr` has an
227+
implicit conversion to `Mat` that materializes it.
228+
229+
### Namespace churn in `features`/`xfeatures2d` beyond what's listed above
230+
231+
Found while migrating `SiftSurfSample`, `BRISKSample`, `KAZESample*`:
232+
233+
- `SIFT` moved out of `OpenCvSharp.Features2D` and now lives directly in
234+
`OpenCvSharp` (the `OpenCvSharp.Features2D` namespace no longer exists at
235+
all).
236+
- `BRISK`, `KAZE`, `AKAZE` moved the *other* direction: from `OpenCvSharp`
237+
into `OpenCvSharp.XFeatures2D`.
238+
- `SURF` was already in `OpenCvSharp.XFeatures2D` in OpenCvSharp4, unchanged.
239+
240+
Worth a full sweep of every `features`/`xfeatures2d` type's namespace before
241+
finalizing this doc, since the above was only what surfaced through the
242+
samples actually exercised.
243+
244+
### Aruco: `DetectMarkers` is a structural change, not just a `CvAruco``Cv2.Aruco` rename
245+
246+
Beyond the `CvAruco.Xxx``Cv2.Aruco.Xxx` facade rename already documented
247+
above, `DetectMarkers` itself moved from being a static one-shot call to an
248+
instance method on `ArucoDetector` (constructed once from a `Dictionary` +
249+
`DetectorParameters` + `RefineParameters`, then reused):
250+
251+
```csharp
252+
// OpenCvSharp4
253+
CvAruco.DetectMarkers(image, dictionary, out corners, out ids, detectorParameters, out rejected);
254+
255+
// OpenCvSharp5
256+
using var dictionary = Cv2.Aruco.GetPredefinedDictionary(PredefinedDictionaryType.Dict4X4_1000);
257+
using var detector = new ArucoDetector(dictionary, detectorParameters, new RefineParameters());
258+
detector.DetectMarkers(image, out corners, out ids, out rejected);
259+
```
260+
261+
This mirrors the OpenCV 5 C++ API shape (`cv::aruco::ArucoDetector`), so it's
262+
expected/upstream-driven, but it's a bigger call-site change than the simple
263+
prefix swap the existing table above implies.
264+
100265
## 4. OpenCV 5 API changes surfaced through the wrapper
101266

102267
OpenCV 5 reorganizes modules and changes some APIs. The managed surface follows

0 commit comments

Comments
 (0)