Skip to content

Commit

Permalink
Implement scaling (WIP)
Browse files Browse the repository at this point in the history
  • Loading branch information
hyazinthh committed Sep 10, 2024
1 parent b0230f2 commit 30e08b9
Show file tree
Hide file tree
Showing 15 changed files with 527 additions and 69 deletions.
12 changes: 9 additions & 3 deletions paket.dependencies
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ group Test
storage: none
source https://api.nuget.org/v3/index.json

nuget NUnit ~> 3.14.0
nuget NUnit3TestAdapter ~> 4.5.0
nuget Microsoft.NET.Test.Sdk ~> 17.9.0
nuget FSharp.Core ~> 8.0.0

nuget Aardvark.PixImage.ImageSharp ~> 2.0.1

nuget NUnit ~> 3.14.0
nuget NUnit3TestAdapter ~> 4.5.0
nuget Microsoft.NET.Test.Sdk ~> 17.9.0

nuget BenchmarkDotNet ~> 0.14.0
277 changes: 267 additions & 10 deletions paket.lock

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,22 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<GenerateProgramFile>false</GenerateProgramFile>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<OutputPath>..\..\bin\Debug</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<OutputPath>..\..\bin\Release</OutputPath>
</PropertyGroup>
<ItemGroup>
<Compile Include="Benchmarks\ImageBench.fs" />
<Compile Include="Tests\ClusteringTests.fs" />
<Compile Include="Tests\FittingTests.fs" />
<Compile Include="Tests\ImageTests.fs" />
<Compile Include="Program.fs" />
<None Include="paket.references" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Aardvark.OpenCV\Aardvark.OpenCV.csproj" />
</ItemGroup>
Expand Down
35 changes: 35 additions & 0 deletions src/Aardvark.OpenCV.Tests/Benchmarks/ImageBench.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
namespace Aardvark.OpenCV.Benchmarks

open Aardvark.Base
open Aardvark.OpenCV
open BenchmarkDotNet.Attributes

module ``Image Processing Benchmarks`` =

type Scaling() =

[<DefaultValue; Params(128, 1024, 2048, 4096)>]
val mutable Size : int

[<DefaultValue; Params(ImageInterpolation.Linear, ImageInterpolation.Cubic, ImageInterpolation.Lanczos)>]
val mutable Interpolation : ImageInterpolation

let mutable image = null

let scaleFactor = V2d(0.234, 0.894)

[<GlobalSetup>]
member x.Setup() =
Aardvark.Init()
let rnd = RandomSystem 0
image <- new PixImage<float32>(Col.Format.RGBA, x.Size, x.Size)
image.Volume.SetByIndex(ignore >> rnd.UniformFloat) |> ignore

[<Benchmark(Description = "Aardvark (Tensors)", Baseline = true)>]
member x.AardvarkTensors() =
let volume = image.Volume.Scaled(scaleFactor, x.Interpolation)
PixImage<float32>(image.Format, volume)

[<Benchmark>]
member x.OpenCV() =
TensorExtensions.ScaledOpenCV(image, scaleFactor, x.Interpolation)

Check failure on line 35 in src/Aardvark.OpenCV.Tests/Benchmarks/ImageBench.fs

View workflow job for this annotation

GitHub Actions / build

The type 'TensorExtensions' does not define the field, constructor or member 'ScaledOpenCV'. Maybe you want one of the following:� Scaled� Scale� ScaledAboutCentroid

Check failure on line 35 in src/Aardvark.OpenCV.Tests/Benchmarks/ImageBench.fs

View workflow job for this annotation

GitHub Actions / build

The type 'TensorExtensions' does not define the field, constructor or member 'ScaledOpenCV'. Maybe you want one of the following:� Scaled� Scale� ScaledAboutCentroid

Check failure on line 35 in src/Aardvark.OpenCV.Tests/Benchmarks/ImageBench.fs

View workflow job for this annotation

GitHub Actions / build

The type 'TensorExtensions' does not define the field, constructor or member 'ScaledOpenCV'. Maybe you want one of the following:� Scaled� Scale� ScaledAboutCentroid

Check failure on line 35 in src/Aardvark.OpenCV.Tests/Benchmarks/ImageBench.fs

View workflow job for this annotation

GitHub Actions / build

The type 'TensorExtensions' does not define the field, constructor or member 'ScaledOpenCV'. Maybe you want one of the following:� Scaled� Scale� ScaledAboutCentroid

Check failure on line 35 in src/Aardvark.OpenCV.Tests/Benchmarks/ImageBench.fs

View workflow job for this annotation

GitHub Actions / build

The type 'TensorExtensions' does not define the field, constructor or member 'ScaledOpenCV'. Maybe you want one of the following:� Scaled� Scale� ScaledAboutCentroid

Check failure on line 35 in src/Aardvark.OpenCV.Tests/Benchmarks/ImageBench.fs

View workflow job for this annotation

GitHub Actions / build

The type 'TensorExtensions' does not define the field, constructor or member 'ScaledOpenCV'. Maybe you want one of the following:� Scaled� Scale� ScaledAboutCentroid
25 changes: 0 additions & 25 deletions src/Aardvark.OpenCV.Tests/ClusteringTests.cs

This file was deleted.

25 changes: 0 additions & 25 deletions src/Aardvark.OpenCV.Tests/FittingTests.cs

This file was deleted.

20 changes: 20 additions & 0 deletions src/Aardvark.OpenCV.Tests/Program.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
namespace Aardvark.OpenCV.Benchmarks

open System.Reflection
open BenchmarkDotNet.Running;
open BenchmarkDotNet.Configs
open BenchmarkDotNet.Jobs
open BenchmarkDotNet.Toolchains

module Program =

[<EntryPoint>]
let main argv =

let cfg =
let job = Job.ShortRun.WithToolchain(InProcess.Emit.InProcessEmitToolchain.Instance)
ManualConfig.Create(DefaultConfig.Instance).WithOptions(ConfigOptions.DisableOptimizationsValidator).AddJob(job)

BenchmarkSwitcher.FromAssembly(Assembly.GetExecutingAssembly()).Run(argv, cfg) |> ignore

0
38 changes: 38 additions & 0 deletions src/Aardvark.OpenCV.Tests/TensorExtensionsBench.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using Aardvark.Base;
using BenchmarkDotNet.Attributes;

namespace Aardvark.OpenCV.Tests
{
public class Scaling
{
[Params(128, 1024, 2048, 4096)]
public int Size;

[Params(ImageInterpolation.Linear, ImageInterpolation.Cubic)]
public ImageInterpolation Interpolation;

private PixImage<float> _image;

private readonly V2d _scaleFactor = new (0.234, 0.894);

[GlobalSetup]
public void Init()
{
Aardvark.Base.Aardvark.Init();
var rnd = new RandomSystem(0);
_image = new PixImage<float>(Col.Format.RGBA, new V2i(Size, Size));
_image.Volume.SetByIndex((_) => rnd.UniformFloat());
}

[Benchmark(Description = "Aardvark (Tensors)", Baseline = true)]
public PixImage<float> AardvarkTensors()
{
var volume = Aardvark.Base.TensorExtensions.Scaled(_image.Volume, _scaleFactor, Interpolation);
return new PixImage<float>(_image.Format, volume);
}

[Benchmark]
public PixImage<float> OpenCV()
=> TensorExtensions.ScaledOpenCV(_image, _scaleFactor, Interpolation);
}
}
25 changes: 25 additions & 0 deletions src/Aardvark.OpenCV.Tests/Tests/ClusteringTests.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
namespace Aardvark.OpenCV.Tests

open Aardvark.Base
open Aardvark.OpenCV
open NUnit.Framework

module ``Clustering Tests`` =

let private vec value =
Vector<float32> [| value; value; value |]

[<SetUp>]
let init() =
Aardvark.Init()

[<Test>]
let ``K-means``() =
let data = [| vec -1.2f; vec -1.3f; vec -1.4f; vec 2.3f; vec 2.4f |]

let mutable clusters = Array.empty
let mutable centers = Array.empty
OpenCVKMeansClustering.ClusterKMeans(data, 2, 1, false, &clusters, &centers);

Assert.AreEqual([| 0; 0; 0; 1; 1 |], clusters);

17 changes: 17 additions & 0 deletions src/Aardvark.OpenCV.Tests/Tests/FittingTests.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace Aardvark.OpenCV.Tests

open Aardvark.Base
open Aardvark.OpenCV
open NUnit.Framework

module ``Fitting Tests`` =

[<SetUp>]
let init() =
Aardvark.Init()

[<Test>]
let ``Plane3d least squares``() =
let data = [| V3d(1.0, 2.0, -1.0); V3d(5.0, 4.0, -1.0); V3d(23.0, 100.0, -1.0) |]
let plane = data.FitPlane3dLeastSquares();
Assert.AreEqual(Plane3d(V3d.ZAxis, -1), plane);
25 changes: 25 additions & 0 deletions src/Aardvark.OpenCV.Tests/Tests/ImageTests.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
namespace Aardvark.OpenCV.Tests

open Aardvark.Base
open Aardvark.OpenCV
open NUnit.Framework

module ``Image Processing Tests`` =

[<SetUp>]
let init() =
Aardvark.Init()

[<Test>]
let ``Scaling`` () =
let rnd = RandomSystem()

let pi = PixImage<uint8>(Col.Format.RGBA, 512, 567)
pi.Volume.SetByIndex(ignore >> rnd.UniformInt >> uint8) |> ignore

let scaleFactor = V2d(0.134, 0.234)
let result = pi.ScaledOpenCV(scaleFactor, ImageInterpolation.Cubic)
let expected = pi.Scaled(scaleFactor, ImageInterpolation.Cubic)
let psnr = PixImage.peakSignalToNoiseRatio result expected

Assert.Greater(psnr, 20.0)
8 changes: 7 additions & 1 deletion src/Aardvark.OpenCV.Tests/paket.references
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
group Test

FSharp.Core

Aardvark.PixImage.ImageSharp

NUnit
NUnit3TestAdapter
Microsoft.NET.Test.Sdk
Microsoft.NET.Test.Sdk

BenchmarkDotNet
10 changes: 5 additions & 5 deletions src/Aardvark.OpenCV.sln
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ VisualStudioVersion = 17.10.35027.167
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Aardvark.OpenCV", "Aardvark.OpenCV\Aardvark.OpenCV.csproj", "{BC1776B2-A92F-4056-B779-80ABD9C8963C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Aardvark.OpenCV.Tests", "Aardvark.OpenCV.Tests\Aardvark.OpenCV.Tests.csproj", "{BC131623-6EAC-4C1F-B407-644E19298651}"
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Aardvark.OpenCV.Tests", "Aardvark.OpenCV.Tests\Aardvark.OpenCV.Tests.fsproj", "{431C5E75-DA70-44DC-BD61-8727C8BF5719}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand All @@ -17,10 +17,10 @@ Global
{BC1776B2-A92F-4056-B779-80ABD9C8963C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BC1776B2-A92F-4056-B779-80ABD9C8963C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BC1776B2-A92F-4056-B779-80ABD9C8963C}.Release|Any CPU.Build.0 = Release|Any CPU
{BC131623-6EAC-4C1F-B407-644E19298651}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BC131623-6EAC-4C1F-B407-644E19298651}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BC131623-6EAC-4C1F-B407-644E19298651}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BC131623-6EAC-4C1F-B407-644E19298651}.Release|Any CPU.Build.0 = Release|Any CPU
{431C5E75-DA70-44DC-BD61-8727C8BF5719}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{431C5E75-DA70-44DC-BD61-8727C8BF5719}.Debug|Any CPU.Build.0 = Debug|Any CPU
{431C5E75-DA70-44DC-BD61-8727C8BF5719}.Release|Any CPU.ActiveCfg = Release|Any CPU
{431C5E75-DA70-44DC-BD61-8727C8BF5719}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
1 change: 1 addition & 0 deletions src/Aardvark.OpenCV/Aardvark.OpenCV.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>9.0</LangVersion>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>1701;1702;1705;1591</NoWarn>
</PropertyGroup>
Expand Down
69 changes: 69 additions & 0 deletions src/Aardvark.OpenCV/ImageProcessing.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using Aardvark.Base;
using OpenCvSharp;
using CvMat = OpenCvSharp.Mat;

namespace Aardvark.OpenCV
{
public static class ImageProcessing
{
[OnAardvarkInit]
public static void Init()
{
}

private static readonly Dictionary<Type, Func<int, MatType>> matTypes = new()
{
{ typeof(byte), MatType.CV_8UC },
{ typeof(sbyte), MatType.CV_8SC },
{ typeof(short), MatType.CV_16UC },
{ typeof(ushort), MatType.CV_16SC },
{ typeof(int), MatType.CV_32SC },
{ typeof(float), MatType.CV_32FC },
{ typeof(double), MatType.CV_64FC },
};

private static MatType ToMatType(this Type type, int channels)
{
if (matTypes.TryGetValue(type, out var toMatType)) return toMatType(channels);
else throw new NotSupportedException($"Channel type {type} is not supported.");
}

private static readonly Dictionary<ImageInterpolation, InterpolationFlags> interpolationFlags = new()
{
{ ImageInterpolation.Near, InterpolationFlags.Nearest },
{ ImageInterpolation.Linear, InterpolationFlags.Linear },
{ ImageInterpolation.Cubic, InterpolationFlags.Cubic },
{ ImageInterpolation.Lanczos, InterpolationFlags.Lanczos4 },
};

private static InterpolationFlags ToInterpolationFlags(this ImageInterpolation interpolation)
{
if (interpolationFlags.TryGetValue(interpolation, out InterpolationFlags flags)) return flags;
else throw new NotSupportedException($"Interpolation {interpolation} is not supported.");
}

public static Volume<T> ScaledOpenCV<T>(this Volume<T> src, V2d scaleFactor, ImageInterpolation interpolation)
{
if (!src.HasImageLayout())
{
throw new ArgumentException($"Volume must be in image layout (Origin = {src.Origin}, First = {src.First}, Delta = {src.Delta}).");
}

var dstSize = new V3l((V2l)(V2d.Half + scaleFactor * (V2d)src.Size.XY), src.Size.Z);
var dst = dstSize.CreateImageVolume<T>();

var matType = typeof(T).ToMatType((int)src.SZ);

var mSrc = CvMat.FromPixelData((int)src.SY, (int)src.SX, matType, src.Array);
var mDst = CvMat.FromPixelData((int)dst.SY, (int)dst.SX, matType, dst.Array);
Cv2.Resize(mSrc, mDst, new Size((int)dst.SX, (int)dst.SY), interpolation: interpolation.ToInterpolationFlags());

return dst;
}

public static PixImage<T> ScaledOpenCV<T>(this PixImage<T> src, V2d scaleFactor, ImageInterpolation interpolation)
=> new (src.Format, src.Volume.ScaledOpenCV(scaleFactor, interpolation));
}
}

0 comments on commit 30e08b9

Please sign in to comment.