diff --git a/.gitignore b/.gitignore index e9c85891..45668ccb 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ *.userprefs # Build results +[Bb]uild/ [Dd]ebugPublic/ [Rr]eleases/ [Ii]nt/ diff --git a/.gitmodules b/.gitmodules index 19ffb64f..7ada222b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "Samples/RustSqueezenet/winrt-rs"] path = Samples/RustSqueezenet/winrt-rs url = https://github.com/microsoft/winrt-rs.git +[submodule "external/opencv"] + path = external/opencv + url = https://github.com/opencv/opencv.git diff --git a/Samples/WinMLSamplesGallery/WinMLSamplesGallery (Package)/WinMLSamplesGallery (Package).wapproj b/Samples/WinMLSamplesGallery/WinMLSamplesGallery (Package)/WinMLSamplesGallery (Package).wapproj index a9a6028d..5258aa4e 100644 --- a/Samples/WinMLSamplesGallery/WinMLSamplesGallery (Package)/WinMLSamplesGallery (Package).wapproj +++ b/Samples/WinMLSamplesGallery/WinMLSamplesGallery (Package)/WinMLSamplesGallery (Package).wapproj @@ -128,7 +128,7 @@ - + diff --git a/Samples/WinMLSamplesGallery/WinMLSamplesGallery/SampleMetadata/SampleMetadata.cs b/Samples/WinMLSamplesGallery/WinMLSamplesGallery/SampleMetadata/SampleMetadata.cs index 23e043c7..e88c3038 100644 --- a/Samples/WinMLSamplesGallery/WinMLSamplesGallery/SampleMetadata/SampleMetadata.cs +++ b/Samples/WinMLSamplesGallery/WinMLSamplesGallery/SampleMetadata/SampleMetadata.cs @@ -39,6 +39,17 @@ namespace WinMLSamplesGallery for (int i = 0; i < metadataJsonArray.Count; i++) { JsonObject currentSampleMetadata = metadataJsonArray[i].GetObject(); + + bool shouldHideSample = false; +#if !USE_OPENCV + shouldHideSample |= currentSampleMetadata["Tag"].GetString() == "OpenCVInterop"; +#endif + + if (shouldHideSample) + { + continue; + } + allSampleMetadata.Add(new SampleMetadata { Title = currentSampleMetadata["Title"].GetString(), diff --git a/Samples/WinMLSamplesGallery/WinMLSamplesGallery/Samples/OpenCVInterop/README.md b/Samples/WinMLSamplesGallery/WinMLSamplesGallery/Samples/OpenCVInterop/README.md index 8d730934..c5eab40f 100644 --- a/Samples/WinMLSamplesGallery/WinMLSamplesGallery/Samples/OpenCVInterop/README.md +++ b/Samples/WinMLSamplesGallery/WinMLSamplesGallery/Samples/OpenCVInterop/README.md @@ -22,7 +22,22 @@ Windows ML will be used to resize and tensorize the image into NCHW format, as w - [OpenCV LICENSE](../../../../../external/opencv/4.5.4/LICENSE) ## Getting Started -- Check out the [source](https://github.com/microsoft/Windows-Machine-Learning/blob/91e493d699df80a633654929418f41bab136ae1d/Samples/WinMLSamplesGallery/WinMLSamplesGalleryNative/OpenCVImage.cpp#L21) +In order to build this sample, OpenCV will need to be built and linked into the WinML Samples Gallery. The OpenCV project is included as a submodule, and will need to be synced and built for your Platform Architecture and Configuration before it will appear in the Windows ML Samples Gallery. To do so follow these instructions: +- Launch a Visual Studio Developer Command Prompt. +- Navigate to root. +- Sync submodules with `git submodule update --init --recursive` +- Launch Powershell with `powershell` +- Build the OpenCV project with + + `.\external\tools\BuildOpenCV.ps1 -Architecture -Configuration ` + + For example: + + `.\external\tools\BuildOpenCV.ps1 -Architecture x64 -Configuration Debug` +- Launch the `WinMLSamplesGallery.sln` and build with the same **Architecture** and **Configuration** to see the sample appear. + + +You can check out the source [here](https://github.com/microsoft/Windows-Machine-Learning/blob/91e493d699df80a633654929418f41bab136ae1d/Samples/WinMLSamplesGallery/WinMLSamplesGalleryNative/OpenCVImage.cpp#L21). ## Feedback Please file an issue [here](https://github.com/microsoft/Windows-Machine-Learning/issues/new) if you encounter any issues with this sample. diff --git a/Samples/WinMLSamplesGallery/WinMLSamplesGallery/WinMLSamplesGallery.csproj b/Samples/WinMLSamplesGallery/WinMLSamplesGallery/WinMLSamplesGallery.csproj index 1e80d083..e575e226 100644 --- a/Samples/WinMLSamplesGallery/WinMLSamplesGallery/WinMLSamplesGallery.csproj +++ b/Samples/WinMLSamplesGallery/WinMLSamplesGallery/WinMLSamplesGallery.csproj @@ -9,7 +9,13 @@ win10-x86;win10-x64;win10-arm64 true false + opencv_world454d.lib + opencv_world454.lib + $(SolutionDir)..\..\build\external\opencv\cmake_config\$(Platform)\lib\$(Configuration)\$(OpenCVLib) + False + True $(DefineConstants);USE_LARGE_MODELS + $(DefineConstants);USE_OPENCV true diff --git a/Samples/WinMLSamplesGallery/WinMLSamplesGalleryNative/OpenCVImage.cpp b/Samples/WinMLSamplesGallery/WinMLSamplesGalleryNative/OpenCVImage.cpp index 1b874ff6..3fb01fcc 100644 --- a/Samples/WinMLSamplesGallery/WinMLSamplesGalleryNative/OpenCVImage.cpp +++ b/Samples/WinMLSamplesGallery/WinMLSamplesGalleryNative/OpenCVImage.cpp @@ -7,9 +7,7 @@ #include "winrt/Microsoft.AI.MachineLearning.h" #include "WeakBuffer.h" - #include - #include namespace wrl = ::Microsoft::WRL; @@ -20,31 +18,44 @@ namespace winrt::WinMLSamplesGalleryNative::implementation { OpenCVImage::OpenCVImage(winrt::hstring path) { +#ifdef USE_OPENCV image_ = cv::imread(winrt::to_string(path), cv::IMREAD_COLOR); +#endif } +#ifdef USE_OPENCV OpenCVImage::OpenCVImage(cv::Mat&& image) : image_(std::move(image)) { } +#endif winrt::Windows::Storage::Streams::IBuffer OpenCVImage::AsWeakBuffer() { +#ifdef USE_OPENCV auto cz_buffer = image_.ptr(); auto size = image_.total()* image_.elemSize(); winrt::com_ptr ptr; wrl::MakeAndInitialize>(ptr.put(), cz_buffer, cz_buffer + size); return ptr.as(); +#else + return nullptr; +#endif } winrt::Microsoft::AI::MachineLearning::ITensor OpenCVImage::AsTensor() { +#ifdef USE_OPENCV auto buffer = AsWeakBuffer(); return winrt::Microsoft::AI::MachineLearning::TensorUInt8Bit::CreateFromBuffer( std::vector{ 1, image_.rows, image_.cols, 3 }, buffer); +#else + return nullptr; +#endif } winrt::Windows::Graphics::Imaging::SoftwareBitmap OpenCVImage::AsSoftwareBitmap() { +#ifdef USE_OPENCV cv::Mat bgra_image; cv::cvtColor(image_, bgra_image, cv::COLOR_RGB2RGBA); @@ -55,11 +66,16 @@ namespace winrt::WinMLSamplesGalleryNative::implementation winrt::Windows::Graphics::Imaging::SoftwareBitmap::CreateCopyFromBuffer( bgra_buffer, winrt::Windows::Graphics::Imaging::BitmapPixelFormat::Bgra8, image_.cols, image_.rows); return software_bitmap; +#else + return nullptr; +#endif } void OpenCVImage::Close() { +#ifdef USE_OPENCV image_.deallocate(); +#endif } winrt::WinMLSamplesGalleryNative::OpenCVImage OpenCVImage::CreateFromPath(hstring const& path) { @@ -67,6 +83,7 @@ namespace winrt::WinMLSamplesGalleryNative::implementation } winrt::WinMLSamplesGalleryNative::OpenCVImage OpenCVImage::AddSaltAndPepperNoise(winrt::WinMLSamplesGalleryNative::OpenCVImage image) { +#ifdef USE_OPENCV auto& image_mat = image.as().get()->image_; cv::Mat saltpepper_noise = cv::Mat::zeros(image_mat.rows, image_mat.cols, CV_8U); randu(saltpepper_noise, 0, 255); @@ -79,12 +96,19 @@ namespace winrt::WinMLSamplesGalleryNative::implementation saltpepper_img.setTo(0, black); return winrt::make(std::move(saltpepper_img)); +#else + return nullptr; +#endif } winrt::WinMLSamplesGalleryNative::OpenCVImage OpenCVImage::DenoiseMedianBlur(winrt::WinMLSamplesGalleryNative::OpenCVImage image) { +#ifdef USE_OPENCV auto& image_mat = image.as().get()->image_; cv::Mat denoised; cv::medianBlur(image_mat, denoised, 5); return winrt::make(std::move(denoised)); +#else + return nullptr; +#endif } } diff --git a/Samples/WinMLSamplesGallery/WinMLSamplesGalleryNative/OpenCVImage.h b/Samples/WinMLSamplesGallery/WinMLSamplesGalleryNative/OpenCVImage.h index 5887408b..2345394b 100644 --- a/Samples/WinMLSamplesGallery/WinMLSamplesGalleryNative/OpenCVImage.h +++ b/Samples/WinMLSamplesGallery/WinMLSamplesGalleryNative/OpenCVImage.h @@ -1,14 +1,19 @@ #pragma once #include "OpenCVImage.g.h" -#include +#ifdef USE_OPENCV +#include +#endif + namespace winrt::WinMLSamplesGalleryNative::implementation { struct OpenCVImage : OpenCVImageT { OpenCVImage(winrt::hstring path); - OpenCVImage(cv::Mat&& image); +#ifdef USE_OPENCV + OpenCVImage(cv::Mat&& image); +#endif static winrt::WinMLSamplesGalleryNative::OpenCVImage CreateFromPath(hstring const& path); static winrt::WinMLSamplesGalleryNative::OpenCVImage AddSaltAndPepperNoise(winrt::WinMLSamplesGalleryNative::OpenCVImage image); @@ -20,7 +25,9 @@ namespace winrt::WinMLSamplesGalleryNative::implementation void Close(); private: +#ifdef USE_OPENCV cv::Mat image_; +#endif }; } namespace winrt::WinMLSamplesGalleryNative::factory_implementation diff --git a/Samples/WinMLSamplesGallery/WinMLSamplesGalleryNative/WinMLSamplesGalleryNative.vcxproj b/Samples/WinMLSamplesGallery/WinMLSamplesGalleryNative/WinMLSamplesGalleryNative.vcxproj index f5a88948..3f81dc86 100644 --- a/Samples/WinMLSamplesGallery/WinMLSamplesGalleryNative/WinMLSamplesGalleryNative.vcxproj +++ b/Samples/WinMLSamplesGallery/WinMLSamplesGalleryNative/WinMLSamplesGalleryNative.vcxproj @@ -98,42 +98,44 @@ WinMLSamplesGalleryNative.def + + + + $(MSBuildThisFileDirectory)../../build/native/include/;%(AdditionalIncludeDirectories) + + + + + + opencv_world454d.lib + opencv_world454.lib + $(SolutionDir)..\..\build\external\opencv\cmake_config\$(PlatformString)\lib\$(Configuration)\$(OpenCVLib) + False + True + + + + $(SolutionDir)..\..\build\external\opencv\cmake_config\$(PlatformString)\install\include;%(AdditionalIncludeDirectories) + %(AdditionalOptions) /DUSE_OPENCV=1 + + + $(SolutionDir)..\..\build\external\opencv\cmake_config\$(PlatformString)\lib\$(Configuration) + $(OpenCVLib);%(AdditionalDependencies) + + + _DEBUG;%(PreprocessorDefinitions) - $(SolutionDir)..\..\external\opencv\4.5.4\neutral\include;$(MSBuildThisFileDirectory)../../build/native/include/;%(AdditionalIncludeDirectories) - $(SolutionDir)..\..\external\opencv\4.5.4\neutral\include;$(MSBuildThisFileDirectory)../../build/native/include/;%(AdditionalIncludeDirectories) - $(SolutionDir)..\..\external\opencv\4.5.4\neutral\include;$(MSBuildThisFileDirectory)../../build/native/include/;%(AdditionalIncludeDirectories) - - $(SolutionDir)..\..\external\opencv\4.5.4\$(PlatformString)\$(Configuration)\lib - opencv_world454d.lib;%(AdditionalDependencies) - - - $(SolutionDir)..\..\external\opencv\4.5.4\$(PlatformString)\$(Configuration)\lib - opencv_world454d.lib;kernel32.lib;user32.lib;%(AdditionalDependencies) - - - $(SolutionDir)..\..\external\opencv\4.5.4\$(PlatformString)\$(Configuration)\lib - opencv_world454d.lib;kernel32.lib;user32.lib;%(AdditionalDependencies) - NDEBUG;%(PreprocessorDefinitions) - $(SolutionDir)..\..\external\opencv\4.5.4\neutral\include;$(MSBuildThisFileDirectory)../../build/native/include/;%(AdditionalIncludeDirectories) - $(SolutionDir)..\..\external\opencv\4.5.4\neutral\include;$(MSBuildThisFileDirectory)../../build/native/include/;%(AdditionalIncludeDirectories) - $(SolutionDir)..\..\external\opencv\4.5.4\neutral\include;$(MSBuildThisFileDirectory)../../build/native/include/;%(AdditionalIncludeDirectories) true true - $(SolutionDir)..\..\external\opencv\4.5.4\$(PlatformString)\$(Configuration)\lib - $(SolutionDir)..\..\external\opencv\4.5.4\$(PlatformString)\$(Configuration)\lib - $(SolutionDir)..\..\external\opencv\4.5.4\$(PlatformString)\$(Configuration)\lib - opencv_world454.lib;kernel32.lib;user32.lib;%(AdditionalDependencies) - opencv_world454.lib;kernel32.lib;user32.lib;%(AdditionalDependencies) - opencv_world454.lib;kernel32.lib;user32.lib;%(AdditionalDependencies) diff --git a/azure-pipelines-samples.yml b/azure-pipelines-samples.yml index 98048e4d..4a26598b 100644 --- a/azure-pipelines-samples.yml +++ b/azure-pipelines-samples.yml @@ -58,7 +58,6 @@ steps: targetType: inline script: if (-not (Test-Path "${ENV:programfiles(x86)}\windows Kits\10\include\10.0.18362.0\")) { choco install windows-sdk-10-version-1903-all -y } - - task: PowerShell@2 displayName: 'Restore WinMLSamplesGalleryNative Nuget Packages' inputs: @@ -74,7 +73,7 @@ steps: inputs: solution: 'Samples/WinMLSamplesGallery/WinMLSamplesGallery.sln' vsVersion: "16.0" - msbuildArgs: '-v:diag /p:OutDir=$(System.DefaultWorkingDirectory)\bin\$(BuildPlatform)\$(BuildConfiguration)\WinMLSamplesGallery\ /p:WindowsTargetPlatformVersion=$(WindowsTargetPlatformVersion) /p:UseLargeModels=true /t:Restore,Clean,Build' + msbuildArgs: '/p:OutDir=$(System.DefaultWorkingDirectory)\bin\$(BuildPlatform)\$(BuildConfiguration)\WinMLSamplesGallery\ /p:WindowsTargetPlatformVersion=$(WindowsTargetPlatformVersion) /p:UseLargeModels=true /t:Restore,Clean,Build' platform: '$(BuildPlatform)' configuration: '$(BuildConfiguration)' msbuildArchitecture: x64 diff --git a/external/opencv b/external/opencv new file mode 160000 index 00000000..4223495e --- /dev/null +++ b/external/opencv @@ -0,0 +1 @@ +Subproject commit 4223495e6cd67011f86b8ecd9be1fa105018f3b1 diff --git a/external/tools/BuildOpenCV.ps1 b/external/tools/BuildOpenCV.ps1 new file mode 100644 index 00000000..7012070e --- /dev/null +++ b/external/tools/BuildOpenCV.ps1 @@ -0,0 +1,32 @@ +Param +( + # Build architecture. + [ValidateSet( + 'x64', + 'x86', + 'ARM64')] + [string]$Architecture = 'x64', + + # Build configuration. + [ValidateSet('Debug', 'Release')][string]$Configuration = 'Debug', + + # Location to generate build files. + [string]$CMakeBuildDirectory = "$PSScriptRoot\..\..\build\external\opencv\cmake_config\$Architecture\", + + # Cleans build files before proceeding. + [switch]$Clean +) + +if ($Clean) { + Remove-Item -Recurse -Force $CMakeBuildDirectory +} + +& $PSScriptRoot\CMakeConfigureOpenCV.ps1 -Architecture $Architecture + +# Build OpenCV +$solution = $CMakeBuildDirectory + "OpenCV.sln" +msbuild /p:Configuration=$Configuration /t:Build $solution + +# Install +$installProject = $CMakeBuildDirectory + "INSTALL.vcxproj" +msbuild /p:Configuration=$Configuration $installProject \ No newline at end of file diff --git a/external/tools/CMakeConfigureOpenCV.ps1 b/external/tools/CMakeConfigureOpenCV.ps1 new file mode 100644 index 00000000..0fc9649c --- /dev/null +++ b/external/tools/CMakeConfigureOpenCV.ps1 @@ -0,0 +1,48 @@ +Param +( + # Build architecture. + [ValidateSet( + 'x64', + 'x86', + 'ARM64')] + [string]$Architecture = 'x64', + + # CMake generator. + [ValidateSet( + 'Visual Studio 15 2017', + 'Visual Studio 16 2019')] + [string]$Generator='Visual Studio 16 2019', + + # Location to generate build files. + [string]$BuildDirectory = "$PSScriptRoot\..\..\build\external\opencv\cmake_config\$Architecture", + + # Cleans build files before proceeding. + [switch]$Clean +) + + +$Args = New-Object Collections.Generic.List[String] + +if ($Architecture -eq 'x86') { + $Args.Add("-A Win32") +} +else { + $Args.Add("-A " + $Architecture) +} + +$Args.Add("-G " + $Generator) +$Args.Add("-DCMAKE_SYSTEM_NAME=Windows") +$Args.Add("-DCMAKE_SYSTEM_VERSION=10.0") +$Args.Add("-DWITH_OPENCL=OFF") +$Args.Add("-DWITH_FFMPEG=OFF") +$Args.Add("-DWITH_CUDA=OFF") +$Args.Add("-DBUILD_EXAMPLES=OFF") +$Args.Add("-DBUILD_TESTS=OFF") +$Args.Add("-DBUILD_opencv_world=ON") + +if ($Clean) { + $Args.Add("--clean") +} + +$Args.Add("-B " + $BuildDirectory) +cmake $Args "$PSScriptRoot\..\opencv"