adding Style transfer sample
|
@ -0,0 +1,42 @@
|
|||
|
||||
# Candy Style Transfer Sample
|
||||
|
||||
A simple UWP application that uses a trained machine learning model to transfer the Candy style onto an image selected by the user either from file or captured with a camera.
|
||||
|
||||
This sample demonstrates the use of generic Windows.AI.MachineLearning.Preview API to load a model, bind input and output images, and evaluate a binding. You can use Netron to determine the input and output requirements of your ONNX model which are presumed to be known in this particular sample. https://github.com/lutzroeder/Netron
|
||||
|
||||
|
||||
|
||||
## Build the sample
|
||||
|
||||
|
||||
1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with
|
||||
the sample you want to build.
|
||||
|
||||
2. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the
|
||||
subfolder for this specific sample. Double-click the Visual Studio project file (.csproj) file.
|
||||
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
|
||||
|
||||
## Run the sample
|
||||
|
||||
|
||||
|
||||
The next steps depend on whether you just want to deploy the sample or you want to both deploy and
|
||||
run it.
|
||||
|
||||
|
||||
|
||||
### Deploying the sample
|
||||
|
||||
- Select Build > Deploy Solution.
|
||||
|
||||
|
||||
|
||||
### Deploying and running the sample
|
||||
|
||||
- To debug the sample and then run it, press F5 or select Debug > Start Debugging. To run the sample without debugging, press Ctrl+F5 or selectDebug > Start Without Debugging.
|
|
@ -0,0 +1,16 @@
|
|||
<!--
|
||||
*@@@+++@@@@******************************************************************
|
||||
|
||||
Microsoft Windows Media Foundation
|
||||
Copyright (C) Microsoft Corporation. All rights reserved.
|
||||
|
||||
*@@@+++@@@@******************************************************************
|
||||
-->
|
||||
<Application
|
||||
x:Class="StyleTransfer.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:StyleTransfer"
|
||||
RequestedTheme="Light">
|
||||
|
||||
</Application>
|
|
@ -0,0 +1,97 @@
|
|||
//*@@@+++@@@@******************************************************************
|
||||
//
|
||||
// Microsoft Windows Media Foundation
|
||||
// Copyright (C) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
//*@@@---@@@@******************************************************************
|
||||
|
||||
using System;
|
||||
using Windows.ApplicationModel;
|
||||
using Windows.ApplicationModel.Activation;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
|
||||
namespace StyleTransfer
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides application-specific behavior to supplement the default Application class.
|
||||
/// </summary>
|
||||
sealed partial class App : Application
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes the singleton application object. This is the first line of authored code
|
||||
/// executed, and as such is the logical equivalent of main() or WinMain().
|
||||
/// </summary>
|
||||
public App()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
this.Suspending += OnSuspending;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when the application is launched normally by the end user. Other entry points
|
||||
/// will be used such as when the application is launched to open a specific file.
|
||||
/// </summary>
|
||||
/// <param name="e">Details about the launch request and process.</param>
|
||||
protected override void OnLaunched(LaunchActivatedEventArgs e)
|
||||
{
|
||||
Frame rootFrame = Window.Current.Content as Frame;
|
||||
|
||||
// Do not repeat app initialization when the Window already has content,
|
||||
// just ensure that the window is active
|
||||
if (rootFrame == null)
|
||||
{
|
||||
// Create a Frame to act as the navigation context and navigate to the first page
|
||||
rootFrame = new Frame();
|
||||
|
||||
rootFrame.NavigationFailed += OnNavigationFailed;
|
||||
|
||||
if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
|
||||
{
|
||||
//TODO: Load state from previously suspended application
|
||||
}
|
||||
|
||||
// Place the frame in the current Window
|
||||
Window.Current.Content = rootFrame;
|
||||
}
|
||||
|
||||
if (e.PrelaunchActivated == false)
|
||||
{
|
||||
if (rootFrame.Content == null)
|
||||
{
|
||||
// When the navigation stack isn't restored navigate to the first page,
|
||||
// configuring the new page by passing required information as a navigation
|
||||
// parameter
|
||||
rootFrame.Navigate(typeof(MainPage), e.Arguments);
|
||||
}
|
||||
// Ensure the current window is active
|
||||
Window.Current.Activate();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when Navigation to a certain page fails
|
||||
/// </summary>
|
||||
/// <param name="sender">The Frame which failed navigation</param>
|
||||
/// <param name="e">Details about the navigation failure</param>
|
||||
void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
|
||||
{
|
||||
throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when application execution is being suspended. Application state is saved
|
||||
/// without knowing whether the application will be terminated or resumed with the contents
|
||||
/// of memory still intact.
|
||||
/// </summary>
|
||||
/// <param name="sender">The source of the suspend request.</param>
|
||||
/// <param name="e">Details about the suspend request.</param>
|
||||
private void OnSuspending(object sender, SuspendingEventArgs e)
|
||||
{
|
||||
var deferral = e.SuspendingOperation.GetDeferral();
|
||||
//TODO: Save application state and stop any background activity
|
||||
deferral.Complete();
|
||||
}
|
||||
}
|
||||
}
|
После Ширина: | Высота: | Размер: 277 KiB |
После Ширина: | Высота: | Размер: 2.6 KiB |
После Ширина: | Высота: | Размер: 12 KiB |
После Ширина: | Высота: | Размер: 895 B |
После Ширина: | Высота: | Размер: 14 KiB |
После Ширина: | Высота: | Размер: 43 KiB |
После Ширина: | Высота: | Размер: 1.8 KiB |
После Ширина: | Высота: | Размер: 2.1 KiB |
После Ширина: | Высота: | Размер: 38 KiB |
|
@ -0,0 +1,175 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
|
||||
<ProjectGuid>{97D29DB4-FA18-4816-A9A5-FFBFCFC0104C}</ProjectGuid>
|
||||
<OutputType>AppContainerExe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>CandyStyleTransfer</RootNamespace>
|
||||
<AssemblyName>CandyStyleTransfer</AssemblyName>
|
||||
<DefaultLanguage>en-US</DefaultLanguage>
|
||||
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
|
||||
<TargetPlatformVersion Condition=" '$(TargetPlatformVersion)' == '' ">10.0.17110.0</TargetPlatformVersion>
|
||||
<TargetPlatformMinVersion>10.0.17110.0</TargetPlatformMinVersion>
|
||||
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<WindowsXamlEnableOverview>true</WindowsXamlEnableOverview>
|
||||
<PackageCertificateKeyFile>StyleTransfer_TemporaryKey.pfx</PackageCertificateKeyFile>
|
||||
<AppxAutoIncrementPackageRevision>True</AppxAutoIncrementPackageRevision>
|
||||
<AppxBundle>Always</AppxBundle>
|
||||
<AppxBundlePlatforms>x64</AppxBundlePlatforms>
|
||||
<PackageCertificateThumbprint>ED2E5FC66B1C377DF2340632FDD8F66F6BAF3DE7</PackageCertificateThumbprint>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x86\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||
<OutputPath>bin\x86\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\ARM\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>ARM</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM'">
|
||||
<OutputPath>bin\ARM\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>ARM</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<OutputPath>bin\x64\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="App.xaml.cs">
|
||||
<DependentUpon>App.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="FrameRenderer.cs" />
|
||||
<Compile Include="HelperMethods.cs" />
|
||||
<Compile Include="MainPage.xaml.cs">
|
||||
<DependentUpon>MainPage.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AppxManifest Include="Package.appxmanifest">
|
||||
<SubType>Designer</SubType>
|
||||
</AppxManifest>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Assets\DefaultImage.jpg">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Assets\frame_camera_150.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Assets\frame_camera_24.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Assets\frame_camera_310-150.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Assets\frame_camera_310.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Assets\frame_camera_44.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Assets\frame_camera_50.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Assets\frame_camera_620-300.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Properties\Default.rd.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ApplicationDefinition Include="App.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</ApplicationDefinition>
|
||||
<Page Include="MainPage.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform">
|
||||
<Version>6.0.4</Version>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Assets\Candy.onnx">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="StyleTransfer_TemporaryKey.pfx" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' < '14.0' ">
|
||||
<VisualStudioVersion>14.0</VisualStudioVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
|
@ -0,0 +1,69 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using Windows.Graphics.Imaging;
|
||||
using Windows.UI.Core;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Media.Imaging;
|
||||
|
||||
namespace StyleTransfer
|
||||
{
|
||||
public sealed class FrameRenderer
|
||||
{
|
||||
private Image _imageElement;
|
||||
private SoftwareBitmap _backBuffer;
|
||||
private bool _taskRunning = false;
|
||||
|
||||
public FrameRenderer(Image imageElement)
|
||||
{
|
||||
_imageElement = imageElement;
|
||||
_imageElement.Source = new SoftwareBitmapSource();
|
||||
}
|
||||
|
||||
public void RenderFrame(SoftwareBitmap softwareBitmap)
|
||||
{
|
||||
if (softwareBitmap != null)
|
||||
{
|
||||
// Swap the processed frame to _backBuffer and trigger UI thread to render it
|
||||
softwareBitmap = Interlocked.Exchange(ref _backBuffer, softwareBitmap);
|
||||
|
||||
// UI thread always reset _backBuffer before using it. Unused bitmap should be disposed.
|
||||
softwareBitmap?.Dispose();
|
||||
|
||||
// Changes to xaml ImageElement must happen in UI thread through Dispatcher
|
||||
var task = _imageElement.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
|
||||
async () =>
|
||||
{
|
||||
// Don't let two copies of this task run at the same time.
|
||||
if (_taskRunning)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_taskRunning = true;
|
||||
try
|
||||
{
|
||||
// Keep draining frames from the backbuffer until the backbuffer is empty.
|
||||
SoftwareBitmap latestBitmap;
|
||||
while ((latestBitmap = Interlocked.Exchange(ref _backBuffer, null)) != null)
|
||||
{
|
||||
if (_imageElement.MaxHeight != latestBitmap.PixelHeight)
|
||||
_imageElement.MaxHeight = latestBitmap.PixelHeight;
|
||||
|
||||
if (_imageElement.MaxWidth != latestBitmap.PixelWidth)
|
||||
_imageElement.MaxWidth = latestBitmap.PixelWidth;
|
||||
|
||||
var imageSource = (SoftwareBitmapSource)_imageElement.Source;
|
||||
await imageSource.SetBitmapAsync(latestBitmap);
|
||||
latestBitmap.Dispose();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine(ex.Message);
|
||||
}
|
||||
_taskRunning = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,148 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using Windows.Foundation;
|
||||
using Windows.Graphics.Imaging;
|
||||
using Windows.Media;
|
||||
using Windows.Storage;
|
||||
using Windows.Storage.Pickers;
|
||||
using Windows.Storage.Streams;
|
||||
|
||||
namespace StyleTransfer
|
||||
{
|
||||
public sealed class ImageHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Pass the nput frame to a frame renderer and ensure proper image format is used
|
||||
/// </summary>
|
||||
/// <param name="inputVideoFrame"></param>
|
||||
/// <param name="useDX"></param>
|
||||
/// <returns></returns>
|
||||
public static IAsyncAction RenderFrameAsync(FrameRenderer frameRenderer, VideoFrame inputVideoFrame)
|
||||
{
|
||||
return AsyncInfo.Run(async (token) =>
|
||||
{
|
||||
bool useDX = inputVideoFrame.SoftwareBitmap == null;
|
||||
if (frameRenderer == null)
|
||||
{
|
||||
throw (new InvalidOperationException("FrameRenderer is null"));
|
||||
}
|
||||
|
||||
SoftwareBitmap softwareBitmap = null;
|
||||
if (useDX)
|
||||
{
|
||||
softwareBitmap = await SoftwareBitmap.CreateCopyFromSurfaceAsync(inputVideoFrame.Direct3DSurface);
|
||||
softwareBitmap = SoftwareBitmap.Convert(softwareBitmap, BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied);
|
||||
}
|
||||
else
|
||||
{
|
||||
softwareBitmap = new SoftwareBitmap(
|
||||
inputVideoFrame.SoftwareBitmap.BitmapPixelFormat,
|
||||
inputVideoFrame.SoftwareBitmap.PixelWidth,
|
||||
inputVideoFrame.SoftwareBitmap.PixelHeight,
|
||||
inputVideoFrame.SoftwareBitmap.BitmapAlphaMode);
|
||||
inputVideoFrame.SoftwareBitmap.CopyTo(softwareBitmap);
|
||||
}
|
||||
|
||||
frameRenderer.RenderFrame(softwareBitmap);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Launch file picker for user to select a picture file and return a VideoFrame
|
||||
/// </summary>
|
||||
/// <returns>VideoFrame instanciated from the selected image file</returns>
|
||||
public static IAsyncOperation<VideoFrame> LoadVideoFrameFromFilePickedAsync()
|
||||
{
|
||||
return AsyncInfo.Run(async (token) =>
|
||||
{
|
||||
// Trigger file picker to select an image file
|
||||
FileOpenPicker fileOpenPicker = new FileOpenPicker();
|
||||
fileOpenPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
|
||||
fileOpenPicker.FileTypeFilter.Add(".jpg");
|
||||
fileOpenPicker.FileTypeFilter.Add(".png");
|
||||
fileOpenPicker.ViewMode = PickerViewMode.Thumbnail;
|
||||
StorageFile selectedStorageFile = await fileOpenPicker.PickSingleFileAsync();
|
||||
|
||||
if (selectedStorageFile == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return await LoadVideoFrameFromStorageFileAsync(selectedStorageFile);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decode image from a StorageFile and return a VideoFrame
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <returns></returns>
|
||||
public static IAsyncOperation<VideoFrame> LoadVideoFrameFromStorageFileAsync(StorageFile file)
|
||||
{
|
||||
return AsyncInfo.Run(async (token) =>
|
||||
{
|
||||
VideoFrame resultFrame = null;
|
||||
SoftwareBitmap softwareBitmap;
|
||||
using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.Read))
|
||||
{
|
||||
// Create the decoder from the stream
|
||||
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream);
|
||||
|
||||
// Get the SoftwareBitmap representation of the file in BGRA8 format
|
||||
softwareBitmap = await decoder.GetSoftwareBitmapAsync();
|
||||
softwareBitmap = SoftwareBitmap.Convert(softwareBitmap, BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied);
|
||||
}
|
||||
|
||||
// Encapsulate the image in the WinML image type (VideoFrame) to be bound and evaluated
|
||||
resultFrame = VideoFrame.CreateWithSoftwareBitmap(softwareBitmap);
|
||||
|
||||
return resultFrame;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Launch file picker for user to select a file and save a VideoFrame to it
|
||||
/// </summary>
|
||||
/// <param name="frame"></param>
|
||||
/// <returns></returns>
|
||||
public static IAsyncAction SaveVideoFrameToFilePickedAsync(VideoFrame frame)
|
||||
{
|
||||
return AsyncInfo.Run(async (token) =>
|
||||
{
|
||||
// Trigger file picker to select an image file
|
||||
FileSavePicker fileSavePicker = new FileSavePicker();
|
||||
fileSavePicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
|
||||
fileSavePicker.FileTypeChoices.Add("image file", new List<string>() { ".jpg" });
|
||||
fileSavePicker.SuggestedFileName = "NewImage";
|
||||
|
||||
StorageFile selectedStorageFile = await fileSavePicker.PickSaveFileAsync();
|
||||
|
||||
if (selectedStorageFile == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using (IRandomAccessStream stream = await selectedStorageFile.OpenAsync(FileAccessMode.ReadWrite))
|
||||
{
|
||||
VideoFrame frameToEncode = frame;
|
||||
BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, stream);
|
||||
|
||||
if (frameToEncode.SoftwareBitmap == null)
|
||||
{
|
||||
Debug.Assert(frame.Direct3DSurface != null);
|
||||
frameToEncode = new VideoFrame(BitmapPixelFormat.Bgra8, frame.Direct3DSurface.Description.Width, frame.Direct3DSurface.Description.Height);
|
||||
await frame.CopyToAsync(frameToEncode);
|
||||
}
|
||||
encoder.SetSoftwareBitmap(
|
||||
frameToEncode.SoftwareBitmap.BitmapPixelFormat.Equals(BitmapPixelFormat.Bgra8) ?
|
||||
frameToEncode.SoftwareBitmap
|
||||
: SoftwareBitmap.Convert(frameToEncode.SoftwareBitmap, BitmapPixelFormat.Bgra8));
|
||||
|
||||
await encoder.FlushAsync();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
<Page
|
||||
x:Class="StyleTransfer.MainPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:StyleTransfer"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Page.Resources>
|
||||
<SolidColorBrush x:Key="TranslucentBlackBrush" Color="Black" Opacity="0.3"/>
|
||||
<Style x:Key="TextBlockStyling" TargetType="TextBlock">
|
||||
<Setter Property="Foreground" Value="Black"/>
|
||||
</Style>
|
||||
</Page.Resources>
|
||||
|
||||
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="80"/>
|
||||
<RowDefinition Height="300*"/>
|
||||
<RowDefinition Height="30"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!--Status and result display-->
|
||||
<StackPanel x:Name="UIStatusPanel" Background="#BFFFFFFF" VerticalAlignment="Top" Grid.Row="0">
|
||||
<ContentControl Name="UIModelControls">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<ToggleSwitch Name="UIToggleInferenceDevice"
|
||||
OnContent="GPU"
|
||||
OffContent="CPU"
|
||||
IsOn="True"
|
||||
Toggled="UIToggleInferenceDevice_Toggled"
|
||||
Margin="10,0,0,0"/>
|
||||
|
||||
</StackPanel>
|
||||
</ContentControl>
|
||||
|
||||
|
||||
<!--Image preview and acquisition control-->
|
||||
<ContentControl Name="UIImageControls"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch"
|
||||
IsEnabled="False">
|
||||
|
||||
<StackPanel Orientation="Horizontal">
|
||||
|
||||
<Button Name="UIButtonAcquireImage"
|
||||
ToolTipService.ToolTip="Take a photo"
|
||||
Click="UIButtonAcquireImage_Click">
|
||||
<Button.Content>
|
||||
<SymbolIcon Symbol="Camera"/>
|
||||
</Button.Content>
|
||||
</Button>
|
||||
<Button Name="UIButtonFilePick"
|
||||
ToolTipService.ToolTip="Select an image from a file"
|
||||
Click="UIButtonFilePick_Click">
|
||||
<Button.Content>
|
||||
<SymbolIcon Symbol="OpenFile"/>
|
||||
</Button.Content>
|
||||
</Button>
|
||||
|
||||
<Button Name="UIButtonSaveImage"
|
||||
ToolTipService.ToolTip="Save the image result to a file"
|
||||
IsEnabled="false"
|
||||
VerticalAlignment="Bottom"
|
||||
Click="UIButtonSaveImage_Click"
|
||||
Background="#FF939393" >
|
||||
<Button.Content>
|
||||
<SymbolIcon Symbol="Save"/>
|
||||
</Button.Content>
|
||||
</Button>
|
||||
|
||||
</StackPanel>
|
||||
</ContentControl>
|
||||
</StackPanel>
|
||||
|
||||
<Grid Grid.Row="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="200*"/>
|
||||
<ColumnDefinition Width="200*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Image Name="UIInputImage"
|
||||
Grid.Column="0"
|
||||
Stretch="Uniform"
|
||||
MaxWidth="720"
|
||||
MaxHeight="720"/>
|
||||
|
||||
<Grid Grid.Column="1" VerticalAlignment="Stretch">
|
||||
|
||||
<Image Name="UIResultImage"
|
||||
Stretch="Uniform"
|
||||
MaxWidth="720"
|
||||
MaxHeight="720"/>
|
||||
|
||||
<ProgressRing Name="UIProcessingProgressRing"
|
||||
MaxWidth="720"
|
||||
MaxHeight="720"
|
||||
IsActive="false"
|
||||
Visibility="Collapsed"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Border x:Name="UIStatusBorder" Grid.Row="2">
|
||||
<ScrollViewer VerticalScrollMode="Auto" VerticalScrollBarVisibility="Auto" MaxHeight="200">
|
||||
<TextBlock x:Name="StatusBlock"
|
||||
Text="Select a style to begin"
|
||||
FontWeight="Bold"
|
||||
MaxWidth="{Binding ElementName=Splitter, Path=ActualWidth}"
|
||||
Margin="10,10,10,20"
|
||||
TextWrapping="Wrap" />
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
</Page>
|
|
@ -0,0 +1,367 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.Media.Capture;
|
||||
using Windows.Storage;
|
||||
using Windows.UI.Core;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Media;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
using Windows.Graphics.Imaging;
|
||||
using Windows.AI.MachineLearning.Preview;
|
||||
using Windows.Media;
|
||||
using System.Threading;
|
||||
|
||||
namespace StyleTransfer
|
||||
{
|
||||
/// <summary>
|
||||
/// An empty page that can be used on its own or navigated to within a Frame.
|
||||
/// </summary>
|
||||
public sealed partial class MainPage : Page
|
||||
{
|
||||
// States
|
||||
private bool _isReadyForEval = true;
|
||||
private SemaphoreSlim _evaluationLock = new SemaphoreSlim(1);
|
||||
private bool _useGPU = true;
|
||||
|
||||
// Rendering related
|
||||
private FrameRenderer _resultframeRenderer;
|
||||
private FrameRenderer _inputFrameRenderer;
|
||||
|
||||
// WinML related
|
||||
private const string _kModelFileName = "Candy";
|
||||
private const string _kDefaultImageFileName = "DefaultImage.jpg";
|
||||
private ImageVariableDescriptorPreview _inputImageDescription;
|
||||
private ImageVariableDescriptorPreview _outputImageDescription;
|
||||
private LearningModelPreview _model;
|
||||
private LearningModelBindingPreview _binding = null;
|
||||
VideoFrame _inputFrame = null;
|
||||
VideoFrame _outputFrame = null;
|
||||
|
||||
public MainPage()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
}
|
||||
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
_resultframeRenderer = new FrameRenderer(UIResultImage);
|
||||
_inputFrameRenderer = new FrameRenderer(UIInputImage);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Display a message to the user.
|
||||
/// This method may be called from any thread.
|
||||
/// </summary>
|
||||
/// <param name="strMessage"></param>
|
||||
/// <param name="type"></param>
|
||||
public void NotifyUser(string strMessage, NotifyType type)
|
||||
{
|
||||
// If called from the UI thread, then update immediately.
|
||||
// Otherwise, schedule a task on the UI thread to perform the update.
|
||||
if (Dispatcher.HasThreadAccess)
|
||||
{
|
||||
UpdateStatus(strMessage, type);
|
||||
}
|
||||
else
|
||||
{
|
||||
var task = Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => UpdateStatus(strMessage, type));
|
||||
task.AsTask().Wait();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the status message displayed on the UI
|
||||
/// </summary>
|
||||
/// <param name="strMessage"></param>
|
||||
/// <param name="type"></param>
|
||||
private void UpdateStatus(string strMessage, NotifyType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case NotifyType.StatusMessage:
|
||||
UIStatusBorder.Background = new SolidColorBrush(Windows.UI.Colors.Green);
|
||||
break;
|
||||
case NotifyType.ErrorMessage:
|
||||
UIStatusBorder.Background = new SolidColorBrush(Windows.UI.Colors.Red);
|
||||
break;
|
||||
}
|
||||
|
||||
StatusBlock.Text = strMessage;
|
||||
|
||||
// Collapse the StatusBlock if it has no text to conserve real estate.
|
||||
UIStatusBorder.Visibility = (StatusBlock.Text != String.Empty) ? Visibility.Visible : Visibility.Collapsed;
|
||||
if (StatusBlock.Text != String.Empty)
|
||||
{
|
||||
UIStatusBorder.Visibility = Visibility.Visible;
|
||||
UIStatusPanel.Visibility = Visibility.Visible;
|
||||
}
|
||||
else
|
||||
{
|
||||
UIStatusBorder.Visibility = Visibility.Collapsed;
|
||||
UIStatusPanel.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load the labels and model and initialize WinML
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private async Task LoadModelAsync()
|
||||
{
|
||||
_evaluationLock.Wait();
|
||||
{
|
||||
_binding = null;
|
||||
_model = null;
|
||||
_isReadyForEval = false;
|
||||
|
||||
try
|
||||
{
|
||||
// Load Model
|
||||
StorageFile modelFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri($"ms-appx:///Assets/{_kModelFileName}.onnx"));
|
||||
_model = await LearningModelPreview.LoadModelFromStorageFileAsync(modelFile);
|
||||
|
||||
// Hardcoding to use GPU
|
||||
InferencingOptionsPreview options = _model.InferencingOptions;
|
||||
options.PreferredDeviceKind = _useGPU ? LearningModelDeviceKindPreview.LearningDeviceGpu : LearningModelDeviceKindPreview.LearningDeviceCpu;
|
||||
_model.InferencingOptions = options;
|
||||
|
||||
// Debugging logic to see the input and output of ther model
|
||||
List<ILearningModelVariableDescriptorPreview> inputFeatures = _model.Description.InputFeatures.ToList();
|
||||
List<ILearningModelVariableDescriptorPreview> outputFeatures = _model.Description.OutputFeatures.ToList();
|
||||
var metadata = _model.Description.Metadata;
|
||||
foreach (var md in metadata)
|
||||
{
|
||||
Debug.WriteLine($"{md.Key} | {md.Value}");
|
||||
}
|
||||
|
||||
_inputImageDescription =
|
||||
inputFeatures.FirstOrDefault(feature => feature.ModelFeatureKind == LearningModelFeatureKindPreview.Image)
|
||||
as ImageVariableDescriptorPreview;
|
||||
|
||||
_outputImageDescription =
|
||||
outputFeatures.FirstOrDefault(feature => feature.ModelFeatureKind == LearningModelFeatureKindPreview.Image)
|
||||
as ImageVariableDescriptorPreview;
|
||||
|
||||
_isReadyForEval = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
NotifyUser($"error: {ex.Message}", NotifyType.ErrorMessage);
|
||||
Debug.WriteLine($"error: {ex.Message}");
|
||||
}
|
||||
}
|
||||
_evaluationLock.Release();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Acquire manually an image from the camera preview stream
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private async void UIButtonAcquireImage_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
UIInputImage.Visibility = Visibility.Visible;
|
||||
UIProcessingProgressRing.IsActive = true;
|
||||
UIProcessingProgressRing.Visibility = Visibility.Visible;
|
||||
UIButtonSaveImage.IsEnabled = false;
|
||||
|
||||
CameraCaptureUI dialog = new CameraCaptureUI();
|
||||
dialog.PhotoSettings.AllowCropping = false;
|
||||
dialog.PhotoSettings.Format = CameraCaptureUIPhotoFormat.Png;
|
||||
|
||||
StorageFile file = await dialog.CaptureFileAsync(CameraCaptureUIMode.Photo);
|
||||
if (file != null)
|
||||
{
|
||||
var vf = await ImageHelper.LoadVideoFrameFromStorageFileAsync(file);
|
||||
await Task.Run(async () =>
|
||||
{
|
||||
await EvaluateVideoFrameAsync(vf);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Select and evaluate a picture
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private async void UIButtonFilePick_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
UIInputImage.Visibility = Visibility.Visible;
|
||||
UIProcessingProgressRing.IsActive = true;
|
||||
UIProcessingProgressRing.Visibility = Visibility.Visible;
|
||||
UIButtonSaveImage.IsEnabled = false;
|
||||
|
||||
try
|
||||
{
|
||||
VideoFrame inputFrame = null;
|
||||
|
||||
// use a default image or a picture selected by the user
|
||||
if (sender == null && e == null)
|
||||
{
|
||||
// use a default image..
|
||||
if (_inputFrame == null)
|
||||
{
|
||||
var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri($"ms-appx:///Assets/{_kDefaultImageFileName}"));
|
||||
inputFrame = await ImageHelper.LoadVideoFrameFromStorageFileAsync(file);
|
||||
}
|
||||
// ..or use a picture already selected by the user..
|
||||
else
|
||||
{
|
||||
inputFrame = _inputFrame;
|
||||
}
|
||||
}
|
||||
// ..or use a new picture selected by the user
|
||||
else
|
||||
{
|
||||
inputFrame = await ImageHelper.LoadVideoFrameFromFilePickedAsync();
|
||||
}
|
||||
|
||||
// if the picture is valid, let's process it with the model
|
||||
if (inputFrame == null)
|
||||
{
|
||||
NotifyUser("no valid image file selected", NotifyType.ErrorMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
await Task.Run(async () => await EvaluateVideoFrameAsync(inputFrame));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"error: {ex.Message}");
|
||||
NotifyUser(ex.Message, NotifyType.ErrorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 1) Bind input and output features
|
||||
/// 2) Run evaluation of the model
|
||||
/// 3) Retrieve the result
|
||||
/// </summary>
|
||||
/// <param name="inputVideoFrame"></param>
|
||||
/// <returns></returns>
|
||||
private async Task EvaluateVideoFrameAsync(VideoFrame inputVideoFrame)
|
||||
{
|
||||
LearningModelPreview model = null;
|
||||
bool isReadyForEval = false;
|
||||
_evaluationLock.Wait();
|
||||
{
|
||||
model = _model;
|
||||
isReadyForEval = _isReadyForEval;
|
||||
_isReadyForEval = false;
|
||||
}
|
||||
_evaluationLock.Release();
|
||||
|
||||
if (inputVideoFrame != null && isReadyForEval && model != null)
|
||||
{
|
||||
_inputFrame = inputVideoFrame;
|
||||
try
|
||||
{
|
||||
NotifyUser("Processing...", NotifyType.StatusMessage);
|
||||
|
||||
if (_outputFrame == null)
|
||||
{
|
||||
_outputFrame = new VideoFrame(BitmapPixelFormat.Bgra8, (int)_outputImageDescription.Width, (int)_outputImageDescription.Height);
|
||||
}
|
||||
|
||||
// Create bindings for the input and output buffers
|
||||
if (_binding == null)
|
||||
{
|
||||
_binding = new LearningModelBindingPreview(model as LearningModelPreview);
|
||||
|
||||
// since we reuse the output at each evaluation, bind it only once
|
||||
_binding.Bind(_outputImageDescription.Name, _outputFrame);
|
||||
}
|
||||
_binding.Bind(_inputImageDescription.Name, inputVideoFrame);
|
||||
|
||||
// Render the input frame
|
||||
await ImageHelper.RenderFrameAsync(_inputFrameRenderer, inputVideoFrame);
|
||||
|
||||
// Process the frame with the model
|
||||
var results = await _model.EvaluateAsync(_binding, "test");
|
||||
|
||||
// Parse result
|
||||
IReadOnlyDictionary<string, object> outputs = results.Outputs;
|
||||
foreach (var output in outputs)
|
||||
{
|
||||
Debug.WriteLine($"{output.Key} : {output.Value} -> {output.Value.GetType()}");
|
||||
}
|
||||
|
||||
// Display result
|
||||
VideoFrame vf = results.Outputs[_outputImageDescription.Name] as VideoFrame;
|
||||
await ImageHelper.RenderFrameAsync(_resultframeRenderer, vf);
|
||||
|
||||
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
|
||||
{
|
||||
UIProcessingProgressRing.IsActive = false;
|
||||
UIProcessingProgressRing.Visibility = Visibility.Collapsed;
|
||||
UIButtonSaveImage.IsEnabled = true;
|
||||
UIToggleInferenceDevice.IsEnabled = true;
|
||||
});
|
||||
|
||||
NotifyUser("Done!", NotifyType.StatusMessage);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
NotifyUser(ex.Message, NotifyType.ErrorMessage);
|
||||
Debug.WriteLine(ex.ToString());
|
||||
}
|
||||
|
||||
_evaluationLock.Wait();
|
||||
{
|
||||
_isReadyForEval = true;
|
||||
}
|
||||
_evaluationLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Toggle inference device (GPU or CPU) from UI
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void UIToggleInferenceDevice_Toggled(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_useGPU = (bool)UIToggleInferenceDevice.IsOn;
|
||||
UIToggleInferenceDevice.IsEnabled = false;
|
||||
|
||||
// Reload model
|
||||
Task.Run(async () => await LoadModelAsync()).ContinueWith(async (antecedent) =>
|
||||
{
|
||||
if (antecedent.IsCompletedSuccessfully && _isReadyForEval)
|
||||
{
|
||||
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
|
||||
{
|
||||
NotifyUser($"Ready to stylize! ", NotifyType.StatusMessage);
|
||||
UIImageControls.IsEnabled = true;
|
||||
UIModelControls.IsEnabled = true;
|
||||
|
||||
UIButtonFilePick_Click(null, null);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Save image result to file
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private async void UIButtonSaveImage_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
await ImageHelper.SaveVideoFrameToFilePickedAsync(_outputFrame);
|
||||
}
|
||||
}
|
||||
|
||||
public enum NotifyType
|
||||
{
|
||||
StatusMessage,
|
||||
ErrorMessage
|
||||
};
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" IgnorableNamespaces="uap mp">
|
||||
<Identity Name="029EAC61-59A4-450D-855B-77158271A282" Publisher="CN=Louis-Philippe Bourret" Version="1.0.0.0" />
|
||||
<mp:PhoneIdentity PhoneProductId="3bd922b5-d779-4208-8c35-aec4dea61330" PhonePublisherId="00000000-0000-0000-0000-000000000000" />
|
||||
<Properties>
|
||||
<DisplayName>CandyStyleTransfer</DisplayName>
|
||||
<PublisherDisplayName>Louis-Philippe Bourret</PublisherDisplayName>
|
||||
<Logo>Assets\frame_camera_50.png</Logo>
|
||||
</Properties>
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.0.0" MaxVersionTested="10.0.0.0" />
|
||||
</Dependencies>
|
||||
<Resources>
|
||||
<Resource Language="x-generate" />
|
||||
</Resources>
|
||||
<Applications>
|
||||
<Application Id="App" Executable="$targetnametoken$.exe" EntryPoint="StyleTransfer.App">
|
||||
<uap:VisualElements DisplayName="CandyStyleTransfer" Square150x150Logo="Assets\frame_camera_150.png" Square44x44Logo="Assets\frame_camera_44.png" Description="Passing images taken from a camera or from an image file through style transfer" BackgroundColor="transparent">
|
||||
<uap:LockScreen Notification="badge" BadgeLogo="Assets\frame_camera_24.png" />
|
||||
<uap:DefaultTile Wide310x150Logo="Assets\frame_camera_310-150.png" Square310x310Logo="Assets\frame_camera_310.png">
|
||||
<uap:ShowNameOnTiles>
|
||||
<uap:ShowOn Tile="square150x150Logo" />
|
||||
<uap:ShowOn Tile="wide310x150Logo" />
|
||||
<uap:ShowOn Tile="square310x310Logo" />
|
||||
</uap:ShowNameOnTiles>
|
||||
</uap:DefaultTile>
|
||||
<uap:SplashScreen Image="Assets\frame_camera_620-300.png" />
|
||||
</uap:VisualElements>
|
||||
</Application>
|
||||
</Applications>
|
||||
<Capabilities>
|
||||
<uap:Capability Name="picturesLibrary" />
|
||||
</Capabilities>
|
||||
</Package>
|
|
@ -0,0 +1,36 @@
|
|||
//*@@@+++@@@@******************************************************************
|
||||
//
|
||||
// Microsoft Windows Media Foundation
|
||||
// Copyright (C) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
//*@@@---@@@@******************************************************************
|
||||
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("CandyStyleTransfer")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("CandyStyleTransfer")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2018")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
[assembly: ComVisible(false)]
|
|
@ -0,0 +1,31 @@
|
|||
<!--
|
||||
This file contains Runtime Directives used by .NET Native. The defaults here are suitable for most
|
||||
developers. However, you can modify these parameters to modify the behavior of the .NET Native
|
||||
optimizer.
|
||||
|
||||
Runtime Directives are documented at https://go.microsoft.com/fwlink/?LinkID=391919
|
||||
|
||||
To fully enable reflection for App1.MyClass and all of its public/private members
|
||||
<Type Name="App1.MyClass" Dynamic="Required All"/>
|
||||
|
||||
To enable dynamic creation of the specific instantiation of AppClass<T> over System.Int32
|
||||
<TypeInstantiation Name="App1.AppClass" Arguments="System.Int32" Activate="Required Public" />
|
||||
|
||||
Using the Namespace directive to apply reflection policy to all the types in a particular namespace
|
||||
<Namespace Name="DataClasses.ViewModels" Serialize="All" />
|
||||
-->
|
||||
|
||||
<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
|
||||
<Application>
|
||||
<!--
|
||||
An Assembly element with Name="*Application*" applies to all assemblies in
|
||||
the application package. The asterisks are not wildcards.
|
||||
-->
|
||||
<Assembly Name="*Application*" Dynamic="Required All" />
|
||||
|
||||
|
||||
<!-- Add your application specific runtime directives here. -->
|
||||
|
||||
|
||||
</Application>
|
||||
</Directives>
|