Skip to content

Commit 1cc7675

Browse files
authored
Merge branch 'main' into mac_ci
2 parents 5716751 + f25afda commit 1cc7675

393 files changed

Lines changed: 11628 additions & 8830 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.devcontainer/manylinux/Dockerfile

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
FROM quay.io/pypa/manylinux_2_28_x86_64
2+
3+
USER root
4+
5+
# Same tools as CI workflow (manylinux.yml) + GitHub CLI
6+
RUN dnf install -y \
7+
git \
8+
zip \
9+
unzip \
10+
nasm \
11+
yasm \
12+
pkg-config \
13+
ninja-build \
14+
kernel-headers \
15+
perl-IPC-Cmd \
16+
perl-Time-Piece \
17+
gtk3-devel \
18+
&& dnf config-manager --add-repo https://cli.github.com/packages/rpm/gh-cli.repo \
19+
&& dnf install -y gh \
20+
&& dnf clean all
21+
22+
# vcpkg bootstrap (package install is done later via postCreateCommand
23+
# using /work/vcpkg.json from the mounted workspace)
24+
RUN git clone --filter=blob:none --depth=1 https://github.com/microsoft/vcpkg.git /opt/vcpkg \
25+
&& /opt/vcpkg/bootstrap-vcpkg.sh -disableMetrics
26+
27+
# .NET SDK 10 — builds and runs net8.0 targets (SDK cross-targeting)
28+
RUN curl -fsSL https://dot.net/v1/dotnet-install.sh \
29+
| bash -s -- --channel 10.0 --install-dir /usr/local/dotnet
30+
ENV PATH="${PATH}:/usr/local/dotnet"
31+
ENV DOTNET_ROOT=/usr/local/dotnet
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#!/usr/bin/env bash
2+
# build_extern.sh — first-time setup inside the manylinux_2_28 devcontainer.
3+
# Called automatically by postCreateCommand when the container is first created.
4+
# Safe to re-run manually; each step is skipped if its output already exists.
5+
#
6+
# Steps:
7+
# 1. vcpkg install (x64-linux-static)
8+
# 2. Static FFmpeg
9+
# 3. OpenCV (full, static, with contrib)
10+
#
11+
# OpenCvSharpExtern is intentionally NOT built here — run the VS Code task
12+
# "Build OpenCvSharpExtern" (Ctrl+Shift+B) or build_opencvsharpextern.sh manually.
13+
14+
set -euxo pipefail
15+
16+
# ---------------------------------------------------------------------------
17+
# 1. vcpkg packages
18+
# ---------------------------------------------------------------------------
19+
/opt/vcpkg/vcpkg install \
20+
--triplet x64-linux-static \
21+
--overlay-triplets=/work/cmake/triplets \
22+
--x-install-root=/opt/vcpkg-installed
23+
24+
# ---------------------------------------------------------------------------
25+
# 2. Static FFmpeg (skipped if already built)
26+
# ---------------------------------------------------------------------------
27+
bash /work/docker/manylinux/build_static_deps.sh
28+
29+
# ---------------------------------------------------------------------------
30+
# 3. OpenCV (full, static)
31+
# ---------------------------------------------------------------------------
32+
if [[ ! -f /opt/opencv_artifacts/lib64/pkgconfig/opencv4.pc ]] && \
33+
[[ ! -f /opt/opencv_artifacts/lib/pkgconfig/opencv4.pc ]]; then
34+
cmake \
35+
-G Ninja \
36+
-C /work/cmake/opencv_build_options.cmake \
37+
-S /work/opencv \
38+
-B /tmp/opencv-build \
39+
-D OPENCV_EXTRA_MODULES_PATH=/work/opencv_contrib/modules \
40+
-D CMAKE_INSTALL_PREFIX=/opt/opencv_artifacts \
41+
-D CMAKE_TOOLCHAIN_FILE=/opt/vcpkg/scripts/buildsystems/vcpkg.cmake \
42+
-D VCPKG_TARGET_TRIPLET=x64-linux-static \
43+
-D VCPKG_INSTALLED_DIR=/opt/vcpkg-installed \
44+
-D CMAKE_FIND_PACKAGE_PREFER_CONFIG=ON \
45+
-D CMAKE_PREFIX_PATH="/opt/vcpkg-installed/x64-linux-static;/opt/ffmpeg" \
46+
-D BUILD_JPEG=OFF \
47+
-D BUILD_PNG=OFF \
48+
-D BUILD_TIFF=OFF \
49+
-D BUILD_WEBP=OFF \
50+
-D BUILD_ZLIB=ON \
51+
-D WITH_TBB=OFF \
52+
-D WITH_OPENEXR=OFF \
53+
-D WITH_JASPER=OFF
54+
cmake --build /tmp/opencv-build -j4
55+
cmake --install /tmp/opencv-build
56+
rm -rf /tmp/opencv-build
57+
fi
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#!/usr/bin/env bash
2+
# build_opencvsharpextern.sh — configure & build OpenCvSharpExtern inside the
3+
# manylinux_2_28 devcontainer. Run directly or via the VS Code task
4+
# "Build OpenCvSharpExtern" (Ctrl+Shift+B).
5+
#
6+
# Output: /work/src/build/OpenCvSharpExtern/libOpenCvSharpExtern.so
7+
8+
set -euxo pipefail
9+
10+
cmake \
11+
-G Ninja \
12+
-S /work/src \
13+
-B /work/src/build \
14+
-D CMAKE_BUILD_TYPE=Release \
15+
-D CMAKE_TOOLCHAIN_FILE=/opt/vcpkg/scripts/buildsystems/vcpkg.cmake \
16+
-D VCPKG_TARGET_TRIPLET=x64-linux-static \
17+
-D VCPKG_INSTALLED_DIR=/opt/vcpkg-installed \
18+
-D OpenCV_DIR=/opt/opencv_artifacts/lib64/cmake/opencv4 \
19+
-D CMAKE_FIND_PACKAGE_PREFER_CONFIG=ON \
20+
"-D CMAKE_PREFIX_PATH=/opt/opencv_artifacts;/opt/ffmpeg;/opt/vcpkg-installed/x64-linux-static" \
21+
"-D ZLIB_LIBRARY=/opt/vcpkg-installed/x64-linux-static/lib/libz.a" \
22+
"-D ZLIB_INCLUDE_DIR=/opt/vcpkg-installed/x64-linux-static/include" \
23+
"-D CMAKE_SHARED_LINKER_FLAGS=-L/opt/vcpkg-installed/x64-linux-static/lib"
24+
25+
cmake --build /work/src/build -j4
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Dev container that reproduces the manylinux_2_28 CI build environment.
2+
// Workspace is bind-mounted at /work. All build caches live inside the container.
3+
//
4+
// On first container creation, postCreateCommand runs build_extern.sh which does:
5+
// 1. vcpkg install (x64-linux-static)
6+
// 2. Static FFmpeg build
7+
// 3. OpenCV full build -> /opt/opencv_artifacts/
8+
// 4. OpenCvSharpExtern build -> /work/src/build/
9+
//
10+
// To run the OCR test after setup:
11+
// cd /work/test/OpenCvSharp.Tests
12+
// cp /work/src/build/OpenCvSharpExtern/libOpenCvSharpExtern.so .
13+
// LD_LIBRARY_PATH=. dotnet test OpenCvSharp.Tests.csproj -c Release -f net8.0 \
14+
// --filter "FullyQualifiedName~OCRTesseractTest"
15+
{
16+
"name": "manylinux_2_28 (build)",
17+
"build": {
18+
"dockerfile": "Dockerfile"
19+
},
20+
21+
// Mount the workspace at /work — same path as CI (GITHUB_WORKSPACE → /work)
22+
"workspaceMount": "source=${localWorkspaceFolder},target=/work,type=bind,consistency=cached",
23+
"workspaceFolder": "/work",
24+
25+
"remoteUser": "root",
26+
27+
// First-time setup: vcpkg install -> FFmpeg -> OpenCV -> OpenCvSharpExtern
28+
// Safe to re-run manually: bash /work/.devcontainer/manylinux/build_extern.sh
29+
"postCreateCommand": "bash /work/.devcontainer/manylinux/build_extern.sh",
30+
31+
"customizations": {
32+
"vscode": {
33+
"extensions": [
34+
"ms-vscode.cpptools",
35+
"ms-vscode.cmake-tools",
36+
"timonwong.shellcheck"
37+
],
38+
"settings": {
39+
"terminal.integrated.defaultProfile.linux": "bash"
40+
}
41+
}
42+
}
43+
}

.dockerignore

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Exclude everything by default; only allow what the Dockerfile COPYs.
2+
**
3+
4+
# OpenCvSharp managed and native sources
5+
!src/
6+
src/build*/
7+
src/uwpOpenCvSharpExtern/
8+
9+
# cmake option files needed by Dockerfiles
10+
!cmake/opencv_build_options.cmake
11+
!cmake/opencv_build_options_slim.cmake
12+
13+
# Test projects
14+
!test/

.github/copilot-instructions.md

Lines changed: 151 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,32 @@
1-
## File encoding
1+
# Copilot Instructions
2+
3+
## File encoding
24

35
All source files in this repository use **UTF-8 with BOM** (`EF BB BF`).
46

57
When creating or editing files, always save them as UTF-8 with BOM. This applies to `.cs`, `.csproj`, `.yml`, `.md`, `.json`, and all other text files.
68

7-
Do **not** save files as UTF-8 without BOM, ANSI, or Shift-JIS — doing so will corrupt Japanese content and break Visual Studio / MSBuild tooling.
9+
**Exception — Linux tooling files: use UTF-8 without BOM.**
10+
The following file types are processed by Linux tools (Docker, bash, VS Code Dev Containers) that do not tolerate a BOM and must be saved **without** BOM:
11+
- `Dockerfile` and any file named `*.Dockerfile`
12+
- Shell scripts (`.sh`)
13+
- `devcontainer.json` and all files under `.devcontainer/`
14+
15+
Do **not** save files as UTF-8 without BOM, ANSI, or Shift-JIS — doing so will corrupt Japanese content and break Visual Studio / MSBuild tooling (for the files above that require BOM).
16+
17+
### Editing workflow requirement
18+
19+
Maintain correct encoding **during each edit/create step** — do not correct it in a follow-up step.
20+
21+
Do not rely on a final "bulk conversion/check" step at the end of the task.
22+
23+
**Important:** The `create_file` tool does **not** interpret `\uFEFF` in the content string as BOM bytes — it writes the literal six characters `\uFEFF`. Never place `\uFEFF` (or any Unicode escape for U+FEFF) directly in the `content` parameter. Instead, create the file first (BOM-free), then immediately apply the PowerShell conversion command below for files that require BOM.
824

925
### Verification
1026

11-
```powershell
27+
Do not run the verification/conversion commands on every edit by default.
28+
Prevent encoding issues through edit/create operations that preserve UTF-8 BOM.
29+
Run the commands below only when preservation cannot be guaranteed or when troubleshooting is required.
1230
# Check whether a file has UTF-8 BOM
1331
$b = [System.IO.File]::ReadAllBytes("path\to\file")
1432
$b[0] -eq 0xEF -and $b[1] -eq 0xBB -and $b[2] -eq 0xBF # should be True
@@ -17,8 +35,6 @@ $b[0] -eq 0xEF -and $b[1] -eq 0xBB -and $b[2] -eq 0xBF # should be True
1735
$enc = New-Object System.Text.UTF8Encoding $true
1836
$content = [System.IO.File]::ReadAllText("path\to\file", [System.Text.Encoding]::UTF8)
1937
[System.IO.File]::WriteAllText("path\to\file", $content, $enc)
20-
```
21-
2238
## NuGet README sync
2339

2440
When editing the root `README.md`, also update the NuGet-specific README files accordingly.
@@ -38,3 +54,133 @@ The NuGet READMEs are a subset of the top-level README and consist of the follow
3854
- Links (GitHub, Samples, API Docs, Issue Tracker)
3955

4056
Do **not** include CI badges, Docker instructions, build instructions, or donation links in the NuGet READMEs.
57+
58+
## Agent mode — terminal commands
59+
60+
In agent mode, do **not** use display commands that require user input (e.g., `more`, `less` without options). Use non-interactive alternatives instead:
61+
- PowerShell: `Select-Object -First N`, `Out-String`, `Write-Output`
62+
- Git: pass `-P` or `--no-pager`, or pipe to `Out-String`; e.g. `git --no-pager diff`
63+
- Use `cat` for displaying file contents.
64+
65+
## Adding a new OpenCV class wrapper
66+
67+
> **Scope**: This checklist covers `cv::SomeClass : cv::Algorithm` subclasses. OpenCV also has classes that do **not** inherit from `Algorithm` — those may follow different ownership and lifetime patterns (see existing non-Algorithm wrappers such as `BackgroundSubtractor` or classes in `core/` for reference).
68+
69+
Follow this checklist when wrapping a new `cv::SomeClass : cv::Algorithm` class:
70+
71+
### Files to create
72+
73+
| File | Location |
74+
|---|---|
75+
| `<module>_SomeClass.h` | `src/OpenCvSharpExtern/` |
76+
| `SomeClass.cs` | `src/OpenCvSharp/Modules/<module>/` |
77+
| `NativeMethods_<module>_SomeClass.cs` | `src/OpenCvSharp/Internal/PInvoke/NativeMethods/<module>/` |
78+
| `SomeClassTest.cs` | `test/OpenCvSharp.Tests/<module>/` |
79+
| `Enum/SomeEnum.cs` (if needed) | same module folder |
80+
| `VectorOfVecXy.cs` (if needed) | `src/OpenCvSharp/Internal/Vectors/` |
81+
82+
### Files to modify
83+
84+
| File | Change |
85+
|---|---|
86+
| `<module>.cpp` | Add `#include "<module>_SomeClass.h"` |
87+
| `std_vector.h` | Add `#pragma region cv::VecXy` block if new vector type needed |
88+
| `NativeMethods_stdvector.cs` | Add corresponding P/Invoke region if new vector type needed |
89+
| `Cv<Module>.cs` | Add `public static SomeClass CreateSomeClass()` factory method |
90+
91+
### C++ extern pattern (<module>_SomeClass.h)
92+
93+
```cpp
94+
#pragma once
95+
#ifndef NO_CONTRIB
96+
#include "include_opencv.h"
97+
98+
CVAPI(ExceptionStatus) <module>_Ptr_SomeClass_delete(cv::Ptr<cv::<module>::SomeClass> *obj)
99+
{ BEGIN_WRAP delete obj; END_WRAP }
100+
101+
CVAPI(ExceptionStatus) <module>_Ptr_SomeClass_get(
102+
cv::Ptr<cv::<module>::SomeClass> *ptr, cv::<module>::SomeClass **returnValue)
103+
{ BEGIN_WRAP *returnValue = ptr->get(); END_WRAP }
104+
105+
CVAPI(ExceptionStatus) <module>_createSomeClass(
106+
cv::Ptr<cv::<module>::SomeClass> **returnValue)
107+
{
108+
BEGIN_WRAP
109+
const auto ptr = cv::<module>::createSomeClass();
110+
*returnValue = new cv::Ptr<cv::<module>::SomeClass>(ptr);
111+
END_WRAP
112+
}
113+
// ... method bindings ...
114+
#endif // NO_CONTRIB
115+
```
116+
117+
### C# class pattern (SomeClass.cs)
118+
119+
```csharp
120+
public class SomeClass : Algorithm
121+
{
122+
private SomeClass(IntPtr smartPtr, IntPtr rawPtr)
123+
: base(smartPtr, rawPtr, p => NativeMethods.HandleException(
124+
NativeMethods.<module>_Ptr_SomeClass_delete(p))) { }
125+
126+
public static SomeClass Create()
127+
{
128+
NativeMethods.HandleException(NativeMethods.<module>_createSomeClass(out var smartPtr));
129+
NativeMethods.HandleException(NativeMethods.<module>_Ptr_SomeClass_get(smartPtr, out var rawPtr));
130+
return new SomeClass(smartPtr, rawPtr);
131+
}
132+
133+
public virtual void SomeMethod(InputArray src) {
134+
ThrowIfDisposed();
135+
if (src is null) throw new ArgumentNullException(nameof(src));
136+
src.ThrowIfDisposed();
137+
NativeMethods.HandleException(NativeMethods.<module>_SomeClass_someMethod(RawPtr, src.CvPtr));
138+
GC.KeepAlive(this);
139+
GC.KeepAlive(src);
140+
}
141+
142+
// OutputArray methods: call dst.Fix() after the P/Invoke call
143+
// std::vector return methods: use VectorOfXxx, wrap in using, call .ToArray()
144+
}
145+
```
146+
147+
### Params struct pattern (P/Invoke-compatible)
148+
149+
When the C++ class has a `Params` struct with `bool` fields, define a flat C struct with `int` for booleans and convert in `getParams`/`setParams`:
150+
151+
```cpp
152+
// C++ side
153+
struct CvSomeClassParams { int SomeBool; /* other fields */ };
154+
155+
CVAPI(ExceptionStatus) <module>_SomeClass_getParams(obj, CvSomeClassParams* out) {
156+
BEGIN_WRAP out->SomeBool = obj->params.SomeBool ? 1 : 0; END_WRAP }
157+
CVAPI(ExceptionStatus) <module>_SomeClass_setParams(obj, CvSomeClassParams* p) {
158+
BEGIN_WRAP cv::<module>::SomeClass::Params q; q.SomeBool = p->SomeBool != 0; obj->setParams(q); END_WRAP }
159+
```
160+
161+
```csharp
162+
// C# side — [MarshalAs(UnmanagedType.Bool)] makes bool marshal as 4-byte BOOL matching int in C
163+
[StructLayout(LayoutKind.Sequential)]
164+
public struct SomeClassParams {
165+
[MarshalAs(UnmanagedType.Bool)] public bool SomeBool;
166+
// other fields...
167+
}
168+
// P/Invoke: out SomeClassParams / ref SomeClassParams
169+
```
170+
171+
### Namespace access note
172+
173+
From `namespace OpenCvSharp.Internal`, types in `namespace OpenCvSharp` are directly visible (outer scope rule). Types in a sub-namespace such as `namespace OpenCvSharp.XImgProc` are NOT — add an explicit `using` directive in the NativeMethods file when referencing structs defined there.
174+
175+
### std::vector return values
176+
177+
- `std::vector<std::vector<Point>>``VectorOfVectorPoint` (already exists)
178+
- `std::vector<int>``VectorOfInt32` (already exists)
179+
- `std::vector<Vec4f>``VectorOfVec4f` (already exists)
180+
- `std::vector<Vec6d>``VectorOfVec6d` (added in EdgeDrawing PR)
181+
- New vector types: add `#pragma region` in `std_vector.h`, `#region` in `NativeMethods_stdvector.cs`, and create `VectorOfXxx.cs`
182+
183+
### EdgeDrawing as reference implementation
184+
185+
See `src/OpenCvSharpExtern/ximgproc_EdgeDrawing.h`, `src/OpenCvSharp/Modules/ximgproc/EdgeDrawing.cs` for a complete example covering: factory, OutputArray methods, std::vector methods, nested Params struct with bool fields, and VectorOfVec6d.
186+

0 commit comments

Comments
 (0)