Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
## File encoding
# Copilot Instructions

## File encoding

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

Expand All @@ -25,8 +27,6 @@ Do not rely on a final "bulk conversion/check" step at the end of the task.
Do not run the verification/conversion commands on every edit by default.
Prevent encoding issues through edit/create operations that preserve UTF-8 BOM.
Run the commands below only when preservation cannot be guaranteed or when troubleshooting is required.

```powershell
# Check whether a file has UTF-8 BOM
$b = [System.IO.File]::ReadAllBytes("path\to\file")
$b[0] -eq 0xEF -and $b[1] -eq 0xBB -and $b[2] -eq 0xBF # should be True
Expand All @@ -35,8 +35,6 @@ $b[0] -eq 0xEF -and $b[1] -eq 0xBB -and $b[2] -eq 0xBF # should be True
$enc = New-Object System.Text.UTF8Encoding $true
$content = [System.IO.File]::ReadAllText("path\to\file", [System.Text.Encoding]::UTF8)
[System.IO.File]::WriteAllText("path\to\file", $content, $enc)
```

## NuGet README sync

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

Do **not** include CI badges, Docker instructions, build instructions, or donation links in the NuGet READMEs.

## Agent mode — terminal commands

In agent mode, do **not** use display commands that require user input (e.g., `more`, `less` without options). Use non-interactive alternatives instead:
- PowerShell: `Select-Object -First N`, `Out-String`, `Write-Output`
- Git: pass `-P` or `--no-pager`, or pipe to `Out-String`; e.g. `git --no-pager diff`
- Use `cat` for displaying file contents.
21 changes: 16 additions & 5 deletions build_opencv_windows.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ param(

$ErrorActionPreference = "Stop"
$RepoRoot = $PSScriptRoot
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8

function Require-Command($name) {
if (-not (Get-Command $name -ErrorAction SilentlyContinue)) {
Expand Down Expand Up @@ -63,20 +64,22 @@ $vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.e
if (-not (Test-Path $vswhere)) {
throw "vswhere.exe not found at '$vswhere'. Install Visual Studio or Build Tools first."
}
$vsInfo = & $vswhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -format json 2>$null | ConvertFrom-Json
if (-not $vsInfo) {
$vsInstallVersion = & $vswhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationVersion 2>$null
$vsDisplayName = & $vswhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property displayName 2>$null
$vsInstallPath = & $vswhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath 2>$null
if (-not $vsInstallVersion) {
throw "No Visual Studio installation with C++ tools found. Install 'Desktop development with C++' workload."
}
$vsMajor = [int]($vsInfo.installationVersion.Split('.')[0])
$vsMajor = [int]($vsInstallVersion.Split('.')[0])
$generatorMap = @{
17 = "Visual Studio 17 2022"
18 = "Visual Studio 18 2026"
}
$vsGenerator = $generatorMap[$vsMajor]
if (-not $vsGenerator) {
throw "Unsupported Visual Studio major version: $vsMajor (from '$($vsInfo.installationVersion)'). Visual Studio 2022 or 2026 is required."
throw "Unsupported Visual Studio major version: $vsMajor (from '$vsInstallVersion'). Visual Studio 2022 or 2026 is required."
}
Write-Host "Using generator: $vsGenerator ($($vsInfo.displayName))"
Write-Host "Using generator: $vsGenerator ($vsDisplayName)"

# ---------------------------------------------------------------------------
# Configure
Expand Down Expand Up @@ -109,11 +112,18 @@ $vcpkgInstalledDir = "$RepoRoot/vcpkg_installed"
Write-Host "Using vcpkg toolchain: $vcpkgToolchain"

Write-Host "Configuring OpenCV $OpenCvVersion ..."
# Remove stale CMakeCache.txt so generator/compiler settings are never overridden by a previous run.
$cmakeCache = "$buildDir/CMakeCache.txt"
if (Test-Path $cmakeCache) {
Write-Host "Removing stale CMakeCache.txt ..."
Remove-Item $cmakeCache -Force
}
cmake `
-C "$RepoRoot/cmake/opencv_build_options.cmake" `
-S "$RepoRoot/opencv" `
-B "$buildDir" `
-G "$vsGenerator" -A x64 `
-D "CMAKE_GENERATOR_INSTANCE=$vsInstallPath" `
-D "CMAKE_TOOLCHAIN_FILE=$vcpkgToolchain" `
-D "VCPKG_TARGET_TRIPLET=x64-windows-static" `
-D "VCPKG_INSTALLED_DIR=$vcpkgInstalledDir" `
Expand All @@ -133,6 +143,7 @@ Write-Host "Done. OpenCV installed to: $installDir"
Write-Host ""
Write-Host "Next step — configure and build OpenCvSharpExtern:"
Write-Host " cmake -S src -B src\build -G `"$vsGenerator`" -A x64 ``"
Write-Host " -D `"CMAKE_GENERATOR_INSTANCE=$vsInstallPath`" ``"
Write-Host " -D `"CMAKE_PREFIX_PATH=`$PWD\opencv_artifacts`" ``"
Write-Host " -D CMAKE_TOOLCHAIN_FILE=`"$vcpkgToolchain`" ``"
Write-Host " -D VCPKG_TARGET_TRIPLET=x64-windows-static ``"
Expand Down
3 changes: 2 additions & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ cmake_minimum_required(VERSION 3.15)

project(OpenCvSharpExtern)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

#set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")

Expand Down
4 changes: 2 additions & 2 deletions src/OpenCvSharp.Extensions/OpenCvSharp.Extensions.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,12 @@

<ItemGroup>
<PackageReference Include="System.Drawing.Common">
<Version>10.0.3</Version>
<Version>10.0.5</Version>
</PackageReference>
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="10.0.103" PrivateAssets="All" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="10.0.201" PrivateAssets="All" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
<UseWPF>true</UseWPF>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Drawing.Common" Version="10.0.3" />
<PackageReference Include="System.Drawing.Common" Version="10.0.5" />
</ItemGroup>

<ItemGroup>
Expand Down
10 changes: 4 additions & 6 deletions src/OpenCvSharp/Cv2/Cv2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,8 @@ public static partial class Cv2
/// <summary>
/// 引数がnullの時はIntPtr.Zeroに変換する
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
internal static IntPtr ToPtr(ICvPtrHolder? obj)
{
return obj?.CvPtr ?? IntPtr.Zero;
}
internal static IntPtr ToPtr(CvObject? obj) => obj?.CvPtr ?? IntPtr.Zero;

/// <inheritdoc cref="ToPtr(CvObject?)"/>
internal static IntPtr ToPtr(CvPtrObject? obj) => obj?.RawPtr ?? IntPtr.Zero;
}
2 changes: 1 addition & 1 deletion src/OpenCvSharp/Cv2/Cv2_calib3d.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.CodeAnalysis;
using OpenCvSharp.Internal;
using OpenCvSharp.Internal.Util;
using OpenCvSharp.Internal.Vectors;
Expand Down
4 changes: 2 additions & 2 deletions src/OpenCvSharp/Cv2/Cv2_core.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.CodeAnalysis;
using OpenCvSharp.Internal;
using OpenCvSharp.Internal.Vectors;

Expand Down Expand Up @@ -3509,7 +3509,7 @@ public static IntPtr FastMalloc(long bufSize)
/// <param name="ptr"></param>
public static void FastFree(IntPtr ptr)
{
NativeMethods.core_fastFree(ptr);
NativeMethods.core_fastFree(CvPtr);
}
*/

Expand Down
2 changes: 1 addition & 1 deletion src/OpenCvSharp/Cv2/Cv2_highgui.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using OpenCvSharp.Internal;
using OpenCvSharp.Internal;
using OpenCvSharp.Internal.Vectors;

// ReSharper disable UnusedMember.Global
Expand Down
2 changes: 1 addition & 1 deletion src/OpenCvSharp/Cv2/Cv2_imgproc.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.CodeAnalysis;
using OpenCvSharp.Internal;
using OpenCvSharp.Internal.Util;
using OpenCvSharp.Internal.Vectors;
Expand Down
2 changes: 1 addition & 1 deletion src/OpenCvSharp/Cv2/Cv2_photo.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using OpenCvSharp.Internal;
using OpenCvSharp.Internal;

namespace OpenCvSharp;

Expand Down
96 changes: 88 additions & 8 deletions src/OpenCvSharp/Fundamentals/CvObject.cs
Original file line number Diff line number Diff line change
@@ -1,34 +1,114 @@
using System.Diagnostics.CodeAnalysis;
#pragma warning disable CA2216

using System.Runtime.InteropServices;

namespace OpenCvSharp;

/// <summary>
/// A class which has a pointer of OpenCV structure
/// DisposableObject + ICvPtrHolder
/// </summary>
[SuppressMessage("Design", "CA1051: Do not declare visible instance fields")]
public abstract class CvObject : ICvPtrHolder
public abstract class CvObject : DisposableObject
{
/// <summary>
/// Data pointer
/// The SafeHandle that wraps (and optionally owns) the native pointer.
/// This is the single source of truth for the native handle value.
/// </summary>
protected IntPtr ptr;
private OpenCvSafeHandle? safeHandle;

/// <summary>
/// Native data pointer, derived from <see cref="safeHandle"/>.
/// Returns <see cref="IntPtr.Zero"/> when no SafeHandle has been set.
/// </summary>
protected IntPtr ptr => safeHandle?.DangerousGetHandle() ?? IntPtr.Zero;

/// <summary>
/// Default constructor
/// </summary>
protected CvObject()
: this(true)
{
}

/// <summary>
///
/// Constructor (backward compatibility).
/// Wraps the pointer in a non-owning SafeHandle.
/// Derived classes that own the native resource should call
/// <see cref="SetSafeHandle"/> to replace it with an owning handle.
/// </summary>
/// <param name="ptr"></param>
protected CvObject(IntPtr ptr)
: this(ptr, true)
{
}

/// <summary>
/// Constructor
/// </summary>
/// <param name="isEnabledDispose"></param>
protected CvObject(bool isEnabledDispose)
: base(isEnabledDispose)
{
this.ptr = ptr;
}

/// <summary>
/// Constructor (backward compatibility).
/// Wraps the pointer in a non-owning SafeHandle so that the
/// <see cref="ptr"/> property returns the correct value.
/// </summary>
/// <param name="ptr"></param>
/// <param name="isEnabledDispose"></param>
protected CvObject(IntPtr ptr, bool isEnabledDispose)
: base(isEnabledDispose)
{
if (ptr != IntPtr.Zero)
safeHandle = new OpenCvPtrSafeHandle(ptr, ownsHandle: false, releaseAction: null);
}

/// <summary>
/// Constructor that accepts an <see cref="OpenCvSafeHandle"/>.
/// The SafeHandle owns the native resource and will release it on disposal.
/// </summary>
/// <param name="safeHandle">The safe handle wrapping the native pointer.</param>
protected CvObject(OpenCvSafeHandle safeHandle)
: base(true)
{
this.safeHandle = safeHandle ?? throw new ArgumentNullException(nameof(safeHandle));
}

/// <summary>
/// Sets or replaces the internal SafeHandle.
/// The <see cref="ptr"/> property will reflect the new handle's value.
/// </summary>
/// <param name="handle">The safe handle wrapping the native pointer.</param>
protected void SetSafeHandle(OpenCvSafeHandle handle)
{
var old = safeHandle;
safeHandle = handle ?? throw new ArgumentNullException(nameof(handle));

// If we're replacing an existing SafeHandle (e.g. derived class overrides base),
// invalidate the old one so its finalizer won't call the wrong delete function.
if (old is not null && !ReferenceEquals(old, handle))
{
old.SetHandleAsInvalid();
}
}

/// <summary>
/// releases unmanaged resources
/// </summary>

/// <summary>
/// Releases managed resources, including the SafeHandle if present.
/// </summary>
protected override void DisposeManaged()
{
if (safeHandle is { IsInvalid: false, IsClosed: false })
{
safeHandle.Dispose();
}
base.DisposeManaged();
}

/// <summary>
/// Native pointer of OpenCV structure
/// </summary>
Expand Down
75 changes: 75 additions & 0 deletions src/OpenCvSharp/Fundamentals/CvPtrObject.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
namespace OpenCvSharp;

/// <summary>
/// Base class for OpenCV Algorithm-hierarchy objects.
/// Stores both the smart pointer (cv::Ptr&lt;T&gt;*) for lifetime management
/// and the raw T* for P/Invoke calls, so that <see cref="RawPtr"/> always
/// returns the raw pointer without ambiguity.
/// </summary>
public abstract class CvPtrObject : DisposableObject
{
private OpenCvSafeHandle? lifecycleHandle;
private readonly IntPtr rawPtr;

/// <summary>
/// Factory-pattern constructor.
/// <paramref name="smartPtr"/> is a cv::Ptr&lt;T&gt;* that owns the object lifetime;
/// <paramref name="rawPtr"/> is the T* extracted from it for P/Invoke.
/// </summary>
protected CvPtrObject(IntPtr smartPtr, IntPtr rawPtr, Action<IntPtr> releaseSmartPtr)
{
this.rawPtr = rawPtr;
lifecycleHandle = new OpenCvPtrSafeHandle(
smartPtr, ownsHandle: true,
releaseAction: _ => releaseSmartPtr(smartPtr));
}

/// <summary>
/// Direct-allocation constructor.
/// <paramref name="rawPtr"/> is a T* that is released directly by <paramref name="releaseRawPtr"/>.
/// </summary>
protected CvPtrObject(IntPtr rawPtr, Action<IntPtr> releaseRawPtr)
{
this.rawPtr = rawPtr;
lifecycleHandle = new OpenCvPtrSafeHandle(
rawPtr, ownsHandle: true,
releaseAction: _ => releaseRawPtr(rawPtr));
}

/// <summary>
/// Returns the raw T* for use in P/Invoke calls.
/// </summary>
public IntPtr RawPtr
{
get
{
ThrowIfDisposed();
return rawPtr;
}
}

/// <summary>

Check warning on line 51 in src/OpenCvSharp/Fundamentals/CvPtrObject.cs

View workflow job for this annotation

GitHub Actions / build

XML comment is not placed on a valid language element

Check warning on line 51 in src/OpenCvSharp/Fundamentals/CvPtrObject.cs

View workflow job for this annotation

GitHub Actions / build

XML comment is not placed on a valid language element

Check warning on line 51 in src/OpenCvSharp/Fundamentals/CvPtrObject.cs

View workflow job for this annotation

GitHub Actions / build

XML comment is not placed on a valid language element

Check warning on line 51 in src/OpenCvSharp/Fundamentals/CvPtrObject.cs

View workflow job for this annotation

GitHub Actions / build

XML comment is not placed on a valid language element

Check warning on line 51 in src/OpenCvSharp/Fundamentals/CvPtrObject.cs

View workflow job for this annotation

GitHub Actions / build

XML comment is not placed on a valid language element

Check warning on line 51 in src/OpenCvSharp/Fundamentals/CvPtrObject.cs

View workflow job for this annotation

GitHub Actions / build

XML comment is not placed on a valid language element

Check warning on line 51 in src/OpenCvSharp/Fundamentals/CvPtrObject.cs

View workflow job for this annotation

GitHub Actions / test

XML comment is not placed on a valid language element

Check warning on line 51 in src/OpenCvSharp/Fundamentals/CvPtrObject.cs

View workflow job for this annotation

GitHub Actions / test

XML comment is not placed on a valid language element
/// Alias for <see cref="RawPtr"/>. Kept for source compatibility with existing subclass code.
/// </summary>
//public IntPtr CvPtr => RawPtr;

/// <summary>
/// Returns the cv::Ptr&lt;T&gt;* smart pointer for P/Invoke calls that require it
/// (e.g. functions that take ownership of the pointer).
/// </summary>
internal IntPtr SmartPtr
{
get
{
ThrowIfDisposed();
return lifecycleHandle?.DangerousGetHandle() ?? IntPtr.Zero;
}
}

/// <inheritdoc />
protected override void DisposeManaged()
{
lifecycleHandle?.Dispose();
lifecycleHandle = null;
}
}
Loading
Loading