Skip to content

Commit 46578b4

Browse files
committed
implementation of ImageForegroundExtractor
1 parent 081a0f4 commit 46578b4

File tree

9 files changed

+204
-0
lines changed

9 files changed

+204
-0
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
using var inputImage = await LoadYourImageAsSoftwareBitmap();
2+
using ImageForegroundExtractor extractor = await ImageForegroundExtractor.CreateAsync();
3+
using var foregroundMask = extractor.GetMaskFromSoftwareBitmap(inputImage);
4+
// Apply the mask to extract the foreground
5+
var foregroundImage = inputImage.ApplyMask(foregroundMask);
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
if (ImageForegroundExtractor.GetReadyState() == AIFeatureReadyState.NotReady)
2+
{
3+
await ImageForegroundExtractor.EnsureReadyAsync();
4+
}

Samples/WindowsAIFoundry/cs-winui/MainWindow.xaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@
2929
<NavigationViewItem Content="Image Object Extractor"
3030
Tag="ImageObjectExtractor"
3131
Icon="Cut"/>
32+
<NavigationViewItem Content="Image Foreground Extractor"
33+
Tag="ImageForegroundExtractor"
34+
Icon="ContactInfo"/>
3235
<NavigationViewItem Content="Image Description"
3336
Tag="ImageDescription"
3437
Icon="Caption"/>

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ private void NavView_SelectionChanged(NavigationView sender, NavigationViewSelec
3535
case "ImageObjectExtractor":
3636
rootFrame.Navigate(typeof(ImageObjectExtractorPage));
3737
break;
38+
case "ImageForegroundExtractor":
39+
rootFrame.Navigate(typeof(ImageForegroundExtractorPage));
40+
break;
3841
case "ImageDescription":
3942
rootFrame.Navigate(typeof (ImageDescriptionPage));
4043
break;
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
using WindowsAISample.Models.Contracts;
4+
using System;
5+
using System.Threading;
6+
using System.Threading.Tasks;
7+
using Windows.Graphics.Imaging;
8+
using Microsoft.Windows.AI;
9+
using Microsoft.Windows.AI.Imaging;
10+
11+
namespace WindowsAISample.Models;
12+
13+
class ImageForegroundExtractorModel : IModelManager
14+
{
15+
public async Task CreateModelSessionWithProgress(IProgress<double> progress, CancellationToken cancellationToken = default)
16+
{
17+
if (ImageForegroundExtractor.GetReadyState() == AIFeatureReadyState.NotReady)
18+
{
19+
var foregroundExtractorDeploymentOperation = ImageForegroundExtractor.EnsureReadyAsync();
20+
foregroundExtractorDeploymentOperation.Progress = (_, modelDeploymentProgress) =>
21+
{
22+
progress.Report(modelDeploymentProgress % 0.75); // all progress is within 75%
23+
};
24+
using var _ = cancellationToken.Register(() => foregroundExtractorDeploymentOperation.Cancel());
25+
await foregroundExtractorDeploymentOperation;
26+
}
27+
else
28+
{
29+
progress.Report(0.75);
30+
}
31+
progress.Report(1.0); // 100% progress
32+
}
33+
34+
public async Task<SoftwareBitmap> ExtractForegroundMaskAsync(SoftwareBitmap inputImage, CancellationToken cancellationToken = default)
35+
{
36+
using var extractor = await ImageForegroundExtractor.CreateAsync();
37+
return extractor.GetMaskFromSoftwareBitmap(inputImage);
38+
}
39+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
<!-- Copyright (c) Microsoft Corporation.
2+
Licensed under the MIT License. -->
3+
<Page
4+
x:Class="WindowsAISample.Pages.ImageForegroundExtractorPage"
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:models="using:WindowsAISample.ViewModels"
10+
xmlns:controls="using:WindowsAISample.Controls"
11+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
12+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
13+
d:DataContext="{d:DesignInstance Type=models:ImageForegroundExtractorViewModel}"
14+
mc:Ignorable="d"
15+
DataContext="{Binding ImageForegroundExtractor}"
16+
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
17+
18+
<ScrollViewer VerticalScrollBarVisibility="Auto"
19+
HorizontalAlignment="Stretch">
20+
<StackPanel Orientation="Vertical"
21+
HorizontalAlignment="Stretch"
22+
Margin="20">
23+
<TextBlock Text="Image Foreground Extractor"
24+
Style="{StaticResource TitleTextBlockStyle}"
25+
Margin="10"/>
26+
<TextBlock Text="The Image Foreground Extractor API lets you automatically extract the foreground from an image using an AI model, creating a mask that separates the main subject from the background."
27+
Style="{StaticResource BodyTextBlockStyle}"
28+
Margin="10"/>
29+
30+
<controls:ModelInitializationControl SourceFile="Examples/ImageForegroundExtractorInit.md"/>
31+
32+
<TextBlock Text="Extract Foreground"
33+
Style="{StaticResource SubtitleTextBlockStyle}"
34+
Margin="10"/>
35+
<TextBlock Text="Once the model is available, click the button below to automatically extract the foreground from the input image."
36+
Style="{StaticResource BodyTextBlockStyle}"
37+
Margin="10"/>
38+
39+
<Border Margin="10"
40+
CornerRadius="10"
41+
BorderThickness="2"
42+
BorderBrush="{ThemeResource CardBackgroundFillColorSecondaryBrush}"
43+
Background="{ThemeResource CardBackgroundFillColorDefault}">
44+
<StackPanel Orientation="Vertical">
45+
<Grid>
46+
<Grid.ColumnDefinitions>
47+
<ColumnDefinition Width="*"/>
48+
<ColumnDefinition Width="*"/>
49+
</Grid.ColumnDefinitions>
50+
<StackPanel Orientation="Vertical"
51+
Margin="10">
52+
<TextBlock Margin="10"
53+
Style="{StaticResource BodyStrongTextBlockStyle}">Input image</TextBlock>
54+
<Image x:Name="InputImage"
55+
Source="{Binding InputSource}"
56+
Stretch="Uniform"/>
57+
</StackPanel>
58+
<StackPanel Orientation="Vertical"
59+
Grid.Column="1"
60+
HorizontalAlignment="Center"
61+
Margin="10">
62+
<TextBlock Margin="10"
63+
Style="{StaticResource BodyStrongTextBlockStyle}">Output image</TextBlock>
64+
<Image x:Name="OutputImage"
65+
Source="{Binding ExtractForegroundCommand.Result}"/>
66+
</StackPanel>
67+
</Grid>
68+
69+
<StackPanel Orientation="Horizontal"
70+
HorizontalAlignment="Left"
71+
Margin="10">
72+
<Button Margin="0,0,10,0"
73+
Command="{Binding PickInputImageCommand}">Load Image</Button>
74+
<Button Margin="0,0,10,0"
75+
Command="{Binding ExtractForegroundCommand}"
76+
IsEnabled="{Binding IsAvailable}">Extract Foreground</Button>
77+
<ProgressRing Visibility="{Binding ExtractForegroundCommand.IsExecuting, Converter={StaticResource BoolToVisibilityConverter}}"/>
78+
</StackPanel>
79+
80+
<controls:CodeBlockControl SourceFile="Examples/ImageForegroundExtractor.md"
81+
Margin="10"/>
82+
</StackPanel>
83+
</Border>
84+
</StackPanel>
85+
</ScrollViewer>
86+
</Page>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
using Microsoft.UI.Xaml.Controls;
4+
5+
namespace WindowsAISample.Pages;
6+
7+
/// <summary>
8+
/// An empty page that can be used on its own or navigated to within a Frame.
9+
/// </summary>
10+
public sealed partial class ImageForegroundExtractorPage : Page
11+
{
12+
public ImageForegroundExtractorPage()
13+
{
14+
InitializeComponent();
15+
}
16+
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ internal CopilotRootViewModel()
1717
ImageObjectExtractor = new(new Models.ImageObjectExtractorModel());
1818
ImageDescriptionGenerator = new(new Models.ImageDescriptionModel());
1919
ImageObjectRemover = new(new Models.ImageObjectRemoverModel());
20+
ImageForegroundExtractor = new(new Models.ImageForegroundExtractorModel());
2021
}
2122

2223
public LanguageModelViewModel LanguageModel { get; }
@@ -30,4 +31,6 @@ internal CopilotRootViewModel()
3031
public ImageObjectExtractorViewModel ImageObjectExtractor { get; }
3132

3233
public ImageObjectRemoverViewModel ImageObjectRemover { get; }
34+
35+
public ImageForegroundExtractorViewModel ImageForegroundExtractor { get; }
3336
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
using WindowsAISample.Models.Contracts;
4+
using WindowsAISample.Util;
5+
using Microsoft.UI.Xaml.Media.Imaging;
6+
using System;
7+
using System.Windows.Input;
8+
using Windows.Graphics.Imaging;
9+
using WindowsAISample.Models;
10+
11+
namespace WindowsAISample.ViewModels;
12+
13+
internal partial class ImageForegroundExtractorViewModel : InputImageViewModelBase<ImageForegroundExtractorModel>
14+
{
15+
private readonly AsyncCommand<SoftwareBitmap, SoftwareBitmapSource> _extractForegroundCommand;
16+
17+
public ImageForegroundExtractorViewModel(ImageForegroundExtractorModel imageForegroundExtractorSession)
18+
: base(imageForegroundExtractorSession)
19+
{
20+
_extractForegroundCommand = new(
21+
async _ =>
22+
{
23+
if (Input == null)
24+
{
25+
throw new InvalidOperationException();
26+
}
27+
28+
var foregroundMask = await Session.ExtractForegroundMaskAsync(Input);
29+
var outputBitmap = Input.ApplyMask(foregroundMask);
30+
31+
return await DispatcherQueue.EnqueueAsync(async () =>
32+
{
33+
return await outputBitmap.ToSourceAsync();
34+
});
35+
},
36+
(_) => IsAvailable && Input is not null);
37+
}
38+
39+
public ICommand ExtractForegroundCommand => _extractForegroundCommand;
40+
41+
protected override void OnIsAvailableChanged()
42+
{
43+
_extractForegroundCommand.FireCanExecuteChanged();
44+
}
45+
}

0 commit comments

Comments
 (0)