Skip to content

Commit f3b5807

Browse files
committed
change
1 parent 70e13b7 commit f3b5807

File tree

12 files changed

+324
-6
lines changed

12 files changed

+324
-6
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
var inputImageBuffer = ImageBuffer.CreateForBuffer(
2+
inputBuffer.AsBuffer(),
3+
ImageBufferPixelFormat.Bgr8,
4+
width,
5+
height,
6+
width * 3);
7+
var outputImageBuffer = ImageBuffer.CreateForBuffer(
8+
outputBuffer.AsBuffer(),
9+
ImageBufferPixelFormat.Bgr8,
10+
width,
11+
height,
12+
width * 3);
13+
14+
var result = model.ScaleFrame(inputImageBuffer, outputImageBuffer, new VideoScalerOptions());
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
var catalog = ExecutionProviderCatalog.GetDefault();
2+
await catalog.EnsureAndRegisterCertifiedAsync();
3+
4+
if (VideoScaler.GetReadyState() == AIFeatureReadyState.NotReady)
5+
{
6+
var videoScalerDeploymentOperation = VideoScaler.EnsureReadyAsync();
7+
await videoScalerDeploymentOperation;
8+
}
9+
VideoScaler _session = await VideoScaler.CreateAsync();

Samples/WindowsAIFoundry/cs-winui/MainWindow.xaml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,11 @@
3535
<NavigationViewItem Content="Text Recognizer"
3636
Tag="TextRecognizer"
3737
Icon="Directions"/>
38+
<NavigationViewItem Content="Video Scaler"
39+
Tag="VideoScaler"
40+
Icon="Video"/>
3841
</NavigationView.MenuItems>
3942
<Frame Margin="0,0,0,0"
4043
x:Name="rootFrame"/>
4144
</NavigationView>
42-
</Window>
45+
</Window>

Samples/WindowsAIFoundry/cs-winui/MainWindow.xaml.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,10 @@ private void NavView_SelectionChanged(NavigationView sender, NavigationViewSelec
4141
case "TextRecognizer":
4242
rootFrame.Navigate(typeof(TextRecognizerPage));
4343
break;
44+
case "VideoScaler":
45+
rootFrame.Navigate(typeof(VideoScalerPage));
46+
break;
4447
}
4548
}
4649
}
47-
}
50+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
using Microsoft.Graphics.Imaging;
4+
using Microsoft.Windows.AI;
5+
using Microsoft.Windows.AI.MachineLearning;
6+
using Microsoft.Windows.AI.Video;
7+
using Microsoft.Windows.Management.Deployment;
8+
using System;
9+
using System.Reflection;
10+
using System.Runtime.InteropServices;
11+
using System.Threading;
12+
using System.Threading.Tasks;
13+
using Windows.Graphics.Imaging;
14+
using Windows.Media;
15+
using Windows.Storage.Streams;
16+
using WindowsAISample.Models.Contracts;
17+
using WindowsAISample.Util;
18+
19+
namespace WindowsAISample.Models;
20+
21+
internal class VideoScalerModel : IModelManager
22+
{
23+
private VideoScaler? _session;
24+
25+
private VideoScaler Session => _session ?? throw new InvalidOperationException("Video Scaler session was not created yet");
26+
27+
public async Task CreateModelSessionWithProgress(IProgress<double> progress, CancellationToken cancellationToken = default)
28+
{
29+
var catalog = ExecutionProviderCatalog.GetDefault();
30+
await catalog.EnsureAndRegisterCertifiedAsync();
31+
32+
progress.Report(0.5);
33+
34+
if (VideoScaler.GetReadyState() == AIFeatureReadyState.NotReady)
35+
{
36+
var videoScalerDeploymentOperation = VideoScaler.EnsureReadyAsync();
37+
videoScalerDeploymentOperation.Progress = (_, modelDeploymentProgress) =>
38+
{
39+
progress.Report(0.5 + (modelDeploymentProgress * 0.25) % 0.25); // all progress is within 50% and 75%
40+
};
41+
using var _ = cancellationToken.Register(() => videoScalerDeploymentOperation.Cancel());
42+
await videoScalerDeploymentOperation;
43+
}
44+
else
45+
{
46+
progress.Report(0.75);
47+
}
48+
_session = await VideoScaler.CreateAsync();
49+
progress.Report(1.0); // 100% progress
50+
}
51+
52+
public SoftwareBitmap ScaleVideoFrame(SoftwareBitmap inputFrame)
53+
{
54+
ImageBuffer inputImageBuffer = SoftwareBitmapExtensions.ConvertToBgr8ImageBuffer(inputFrame);
55+
var size = (uint)(inputFrame.PixelWidth * inputFrame.PixelHeight * 3);
56+
IBuffer outputBuffer = new global::Windows.Storage.Streams.Buffer(size);
57+
outputBuffer.Length = size;
58+
ImageBuffer outputImageBuffer = ImageBuffer.CreateForBuffer(
59+
outputBuffer,
60+
ImageBufferPixelFormat.Bgr8,
61+
inputFrame.PixelWidth,
62+
inputFrame.PixelHeight,
63+
inputFrame.PixelWidth * 3);
64+
var result = Session.ScaleFrame(inputImageBuffer, outputImageBuffer, new VideoScalerOptions());
65+
if (result.Status != ScaleFrameStatus.Success)
66+
{
67+
throw new Exception($"Failed to scale video frame: {result.Status}");
68+
}
69+
70+
return SoftwareBitmapExtensions.ConvertBgr8ImageBufferToBgra8SoftwareBitmap(outputImageBuffer);
71+
}
72+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<!-- Copyright (c) Microsoft Corporation.
2+
Licensed under the MIT License. -->
3+
<Page
4+
x:Class="WindowsAISample.Pages.VideoScalerPage"
5+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
6+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
7+
xmlns:local="using:WindowsAISample"
8+
xmlns:pages="using:WindowsAISample.Pages"
9+
xmlns:controls="using:WindowsAISample.Controls"
10+
xmlns:models="using:WindowsAISample.ViewModels"
11+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
12+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
13+
mc:Ignorable="d"
14+
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
15+
d:DataContext="{d:DesignInstance Type=models:VideoScalerViewModel}"
16+
DataContext="{Binding VideoScaler}"
17+
NavigationCacheMode="Enabled">
18+
19+
<ScrollViewer VerticalScrollBarVisibility="Auto"
20+
HorizontalAlignment="Stretch">
21+
<StackPanel Orientation="Vertical"
22+
HorizontalAlignment="Stretch"
23+
Margin="20">
24+
25+
<TextBlock Text="Video Scaler"
26+
Style="{StaticResource TitleTextBlockStyle}"
27+
Margin="10"/>
28+
<TextBlock Text="The Video Scaler API lets you scale video frames to better resolution using an AI model."
29+
Style="{StaticResource BodyTextBlockStyle}"
30+
Margin="10"/>
31+
32+
<controls:ModelInitializationControl SourceFile="Examples/VideoScalerInit.md"/>
33+
34+
<TextBlock Text="Scale Video Frame"
35+
Style="{StaticResource SubtitleTextBlockStyle}"
36+
Margin="10"/>
37+
<TextBlock Text="Once the model is initialized, load a video frame and click the button below to scale it up."
38+
Style="{StaticResource BodyTextBlockStyle}"
39+
Margin="10"/>
40+
41+
<Border Margin="10"
42+
CornerRadius="10"
43+
BorderThickness="2"
44+
BorderBrush="{ThemeResource CardBackgroundFillColorSecondaryBrush}"
45+
Background="{ThemeResource CardBackgroundFillColorDefault}">
46+
<StackPanel Orientation="Vertical">
47+
<Grid>
48+
<Grid.ColumnDefinitions>
49+
<ColumnDefinition Width="*"/>
50+
<ColumnDefinition Width="*"/>
51+
</Grid.ColumnDefinitions>
52+
53+
<StackPanel Orientation="Vertical"
54+
Margin="10">
55+
<TextBlock Margin="10"
56+
Style="{StaticResource BodyStrongTextBlockStyle}">Input image</TextBlock>
57+
<Image Source="{Binding InputSource}"/>
58+
</StackPanel>
59+
<StackPanel Orientation="Vertical"
60+
Margin="10"
61+
Grid.Column="1">
62+
<TextBlock Margin="10"
63+
Style="{StaticResource BodyStrongTextBlockStyle}">Output image</TextBlock>
64+
<Image x:Name="OutputImage"
65+
Source="{Binding ScaleCommand.Result}"/>
66+
</StackPanel>
67+
</Grid>
68+
<StackPanel Orientation="Horizontal"
69+
HorizontalAlignment="Left"
70+
Margin="10">
71+
<Button Margin="0,0,10,0"
72+
Command="{Binding PickInputImageCommand}">Load Image</Button>
73+
74+
<Button Margin="0,0,10,0"
75+
Command="{Binding ScaleCommand}">Scale Image</Button>
76+
<ProgressRing Visibility="{Binding ScaleCommand.IsExecuting, Converter={StaticResource BoolToVisibilityConverter}}"/>
77+
</StackPanel>
78+
<controls:CodeBlockControl SourceFile="Examples/VideoScaler.md"
79+
Margin="10"/>
80+
</StackPanel>
81+
</Border>
82+
</StackPanel>
83+
</ScrollViewer>
84+
</Page>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
using Microsoft.UI.Xaml.Controls;
5+
6+
namespace WindowsAISample.Pages;
7+
8+
public sealed partial class VideoScalerPage : Page
9+
{
10+
public VideoScalerPage()
11+
{
12+
InitializeComponent();
13+
}
14+
}

Samples/WindowsAIFoundry/cs-winui/Properties/launchSettings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"profiles": {
33
"WindowsAISample (Package)": {
44
"commandName": "MsixPackage",
5-
"nativeDebugging": false,
5+
"nativeDebugging": true,
66
"hotReloadEnabled": true
77
},
88
"WindowsAISample (Unpackaged)": {

Samples/WindowsAIFoundry/cs-winui/Util/SoftwareBitmapExtensions.cs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT License.
3+
using Microsoft.Graphics.Imaging;
34
using Microsoft.UI.Xaml.Media.Imaging;
45
using System;
56
using System.Runtime.InteropServices.WindowsRuntime;
@@ -95,4 +96,71 @@ public static SoftwareBitmap ApplyMask(this SoftwareBitmap inputBitmap, Software
9596
segmentedBitmap.CopyFromBuffer(inputBuffer.AsBuffer());
9697
return segmentedBitmap;
9798
}
99+
100+
public static ImageBuffer ConvertToBgr8ImageBuffer(SoftwareBitmap input)
101+
{
102+
var bgraBitmap = input;
103+
if (input.BitmapPixelFormat != BitmapPixelFormat.Bgra8)
104+
{
105+
bgraBitmap = SoftwareBitmap.Convert(input, BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied);
106+
}
107+
108+
int width = bgraBitmap.PixelWidth;
109+
int height = bgraBitmap.PixelHeight;
110+
111+
byte[] bgraBuffer = new byte[width * height * 4];
112+
bgraBitmap.CopyToBuffer(bgraBuffer.AsBuffer());
113+
114+
byte[] bgrBuffer = new byte[width * height * 3];
115+
for (int i = 0, j = 0; i < bgraBuffer.Length; i += 4, j += 3)
116+
{
117+
bgrBuffer[j] = bgraBuffer[i];
118+
bgrBuffer[j + 1] = bgraBuffer[i + 1];
119+
bgrBuffer[j + 2] = bgraBuffer[i + 2];
120+
}
121+
122+
return ImageBuffer.CreateForBuffer(
123+
bgrBuffer.AsBuffer(),
124+
ImageBufferPixelFormat.Bgr8,
125+
width,
126+
height,
127+
width * 3);
128+
}
129+
130+
public static SoftwareBitmap ConvertBgr8ImageBufferToBgra8SoftwareBitmap(ImageBuffer bgrImageBuffer)
131+
{
132+
if (bgrImageBuffer.PixelFormat != ImageBufferPixelFormat.Bgr8)
133+
{
134+
throw new ArgumentException("Input ImageBuffer must be in Bgr8 format");
135+
}
136+
137+
int width = bgrImageBuffer.PixelWidth;
138+
int height = bgrImageBuffer.PixelHeight;
139+
140+
// Get BGR data from ImageBuffer
141+
byte[] bgrBuffer = new byte[width * height * 3];
142+
bgrImageBuffer.CopyToByteArray(bgrBuffer);
143+
144+
// Create BGRA buffer (4 bytes per pixel)
145+
byte[] bgraBuffer = new byte[width * height * 4];
146+
147+
for (int i = 0, j = 0; i < bgrBuffer.Length; i += 3, j += 4)
148+
{
149+
bgraBuffer[j] = bgrBuffer[i]; // B
150+
bgraBuffer[j + 1] = bgrBuffer[i + 1]; // G
151+
bgraBuffer[j + 2] = bgrBuffer[i + 2]; // R
152+
bgraBuffer[j + 3] = 255; // A (full opacity)
153+
}
154+
155+
// Create SoftwareBitmap and copy data
156+
var softwareBitmap = new SoftwareBitmap(
157+
BitmapPixelFormat.Bgra8,
158+
width,
159+
height,
160+
BitmapAlphaMode.Premultiplied);
161+
162+
softwareBitmap.CopyFromBuffer(bgraBuffer.AsBuffer());
163+
164+
return softwareBitmap;
165+
}
98166
}

Samples/WindowsAIFoundry/cs-winui/ViewModels/CopilotRootViewModel.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ internal CopilotRootViewModel()
1616
ImageScaler = new(new Models.ImageScalerModel());
1717
ImageObjectExtractor = new(new Models.ImageObjectExtractorModel());
1818
ImageDescriptionGenerator = new(new Models.ImageDescriptionModel());
19+
VideoScaler = new(new Models.VideoScalerModel());
1920
}
2021

2122
public LanguageModelViewModel LanguageModel { get; }
@@ -28,4 +29,5 @@ internal CopilotRootViewModel()
2829

2930
public ImageObjectExtractorViewModel ImageObjectExtractor { get; }
3031

31-
}
32+
public VideoScalerViewModel VideoScaler { get; }
33+
}

0 commit comments

Comments
 (0)