Jak pomocí Azure vyrobit aplikaci na rozpoznávání obličeje

10. 6. 2021 Azure, Programming

Chcete si vytvořit aplikaci, která bude vyhledávat obličeje na fotografii, rozpoznávat emoce, barvu vlasů, věk, pohlaví a zda daná osoba nosí brýle? Tento návod vás provede celým postupem tvorby algoritmu na rozpoznávání obličeje pomocí Azure.

Ukázka aplikace na rozpoznávání obličeje
Ukázka užívání aplikace

Požadavky

Přidání služby Face

V následujících několika krocích si ukážeme, jak si přidat službu Face i na váš účet.

Přihlásíte se na stránce portal.azure.com a kliknete na tlačítko Create a resource.

Vytvoření nové recourse group na Azure portálu
Vyhledávání prostředku v Azure Portal | zdroj: portal.azure.com

Vyhledáme si službu Face.

Vyhledání služby Face na Azure portálu
Tvorba prostředku v Azure Portal | zdroj: portal.azure.com
Tvorba prostředku Face v Azure portálu
Tvorba prostředku v Azure Portal | zdroj: portal.azure.com

Doplníme potřebné údaje.

Vyplnění potřebných údajů k vytvoření služby Face
Doplnění informací | zdroj: portal.azure.com

Instalace Visual Studia

Pokud ještě nemáte Visual Studio nainstalované, navštivte náš článek, ve kterém je celý postup pospaný.

Programovací část

Připravení složek a tříd

Spustíme si Visual Studio a založíme si složku Models, do které přidáme tři třídy, ve kterých budeme později pracovat.

Struktura:

Struktura složek a tříd ve Visual Studio
Grafické znázornění struktury, kterou budeme vytvářet

A jak si vlastně vytvořit složku a přidat do ní třídy?

Postuú přidání nové složky do Visual Studio
Tvorba prostředí | zdroj: Visual Studio
Přidání předmětů do složky Models
Tvorba prostředí | zdroj: Visual Studio

NuGet

NuGet je balíček, který obsahuje opakovaný, nebo hodně používaný kód. Má za úkol zjednodušit programovací proces. Pokud chcete zjistit více, klikněte na následující odkaz dokumentace.

Spravování balíčku NuGet ve Visual Studio
Importování NuGet | zdroj: Visual Studio
Instalace balíčku kognitivních služeb do Visual Studio
Instalace balíčku NuGet | zdroj: Visual Studio

Připojení API k naší aplikaci

Přejdeme do classy FaceDetectionHelper, kde si vytvoříme proměnné _endpoint_secret typu string, který je určen pro textové řetězce. Do těchto proměnných uložíme hodnoty z naší založené služby.

Zkopírování endpointu a klíče služby Face
Zkopírování endpointu a klíče | zdroj: portal.azure.com

private string _endpoint = ""; <- vložte zde endpoint

private string _secret = ""; <- vložte zde klíč k naší službě

Přidání ovládacích komponentů

Popis kódu: Rozdělíme si okno (grid) na dvě části, konkrétně pomocí ColumnDefinition.

Přidáme si Button, neboli tlačítko, přes které budeme do našeho program nahrávat obrázek nebo fotku na rozpoznání obličeje. Dále Image, do kterého budeme vykreslovat zvolený obrázek. Jako poslední ListBox, do kterého budeme vykreslovat rozpoznané obličeje + informace.

 <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="7*"/>
            <ColumnDefinition Width="3*"/>
        </Grid.ColumnDefinitions>
        <Image Stretch="Uniform" x:Name="FaceImage" HorizontalAlignment="Left" Grid.Column="0" Grid.Row="0"/>
        <Button x:Name="BtnUpload" VerticalAlignment="Bottom" Content="Select image file" Margin="20,0,20,5" Height="20" Click="BtnUpload_Click" />
        <ListBox x:Name="FaceDetails" Grid.Column="1">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Vertical" HorizontalAlignment="Stretch">
                        <DockPanel HorizontalAlignment="Stretch" >
                            <Image Margin="3" Source="{Binding Image}" Width="100" Height="100"/>
                            <StackPanel Orientation="Vertical">
                                <DockPanel HorizontalAlignment="Stretch" >
                                    <Label Content="Age: "/>
                                    <TextBlock Margin="3" Text="{Binding Attributes.Age}"/>
                                </DockPanel>
                                <DockPanel HorizontalAlignment="Stretch" >
                                    <Label Content="Gender: "/>
                                    <TextBlock Margin="3" Text="{Binding Attributes.Gender}"/>
                                </DockPanel>
                                <DockPanel HorizontalAlignment="Stretch" >
                                    <Label Content="Glasses: "/>
                                    <TextBlock Margin="3" Text="{Binding Attributes.Glasses}"/>
                                </DockPanel>
                                <DockPanel HorizontalAlignment="Stretch">
                                    <Label Content="Dominant hair colour: "/>
                                    <TextBlock Margin="3" Text="{Binding MainHairColor}"/>
                                </DockPanel>
                                <DockPanel HorizontalAlignment="Stretch" >
                                    <Label Content="Emotion: "/>
                                    <StackPanel Orientation="Vertical">
                                        <DockPanel HorizontalAlignment="Stretch" >
                                            <Label Content="Anger: "/>
                                            <TextBlock Margin="3" Text="{Binding Attributes.Emotion.Anger}"/>
                                        </DockPanel>
                                        <DockPanel HorizontalAlignment="Stretch" >
                                            <Label Content="Contempt: "/>
                                            <TextBlock Margin="3" Text="{Binding Attributes.Emotion.Contempt}"/>
                                        </DockPanel>
                                        <DockPanel HorizontalAlignment="Stretch" >
                                            <Label Content="Disgust: "/>
                                            <TextBlock Margin="3" Text="{Binding Attributes.Emotion.Disgust}"/>
                                        </DockPanel>
                                        <DockPanel HorizontalAlignment="Stretch" >
                                            <Label Content="Fear: "/>
                                            <TextBlock Margin="3" Text="{Binding Attributes.Emotion.Fear}"/>
                                        </DockPanel>
                                        <DockPanel HorizontalAlignment="Stretch" >
                                            <Label Content="Happiness: "/>
                                            <TextBlock Margin="3" Text="{Binding Attributes.Emotion.Happiness}"/>
                                        </DockPanel>
                                        <DockPanel HorizontalAlignment="Stretch" >
                                            <Label Content="Neutral: "/>
                                            <TextBlock Margin="3" Text="{Binding Attributes.Emotion.Neutral}"/>
                                        </DockPanel>
                                        <DockPanel HorizontalAlignment="Stretch" >
                                            <Label Content="Sadness: "/>
                                            <TextBlock Margin="3" Text="{Binding Attributes.Emotion.Sadness}"/>
                                        </DockPanel>
                                        <DockPanel HorizontalAlignment="Stretch">
                                            <Label Content="Surprise: "/>
                                            <TextBlock Margin="3" Text="{Binding Attributes.Emotion.Surprise}"/>
                                        </DockPanel>
                                    </StackPanel>
                                </DockPanel>
                            </StackPanel>
                        </DockPanel>
                        <Separator />
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>

MainWindow.xaml.cs

Vytvoříme si metodu na nahrání obrázku, která se vyvolá v moment kliknutí na tlačítko. V MainWindow.xaml.cs si klikneme 2x na tlačítko, nebo přidáme Event handler – CLICK.

Přidání eventu ve Visual Studio
Přidání eventu | zdroj: Visual Studio

Dále si do ní vložíme jednoduchý OpenFileDialog, který nám otevře klasické okno průzkumníka pro zvolení našeho obrázku.

Ukázka Open File Dialogu | zdroj: Visual Studio

Popis kódu: Až se obrázek nahraje, je na čase rozpoznat obličeje. S tím nám pomůže metoda DetectFace v třídě FaceDetectionHelper. Poté všechny obličeje projedeme foreachem, který nám vykreslí na hlavním obrázku bílé kruhy okolo obličejů. Dále si všechny obličeje ořízne a vloží je do listboxu, kde má každý obličej vlastní řádek s oříznutým obličejem a vlastnostmi.

facesDetails.Add(new Models.FaceDetails()
                    {
                        Image = croppedFace,
                        Attributes = faceDetails
                    });
        private async void BtnUpload_Click(object sender, RoutedEventArgs e)
        {

            var openFileDialog = new OpenFileDialog()
            {
                Filter = "Image files (*.png;*.jpeg)|*.png;*.jpeg|All files (*.*)|*.*"
            };

            if (openFileDialog.ShowDialog() == true)
            {
                var filePath = openFileDialog.FileName;
                var imageBitmap = new BitmapImage(new Uri(filePath));
                FaceImage.Source = imageBitmap;

                var drwVisual = new DrawingVisual();
                var drwContext = drwVisual.RenderOpen();
                drwContext.DrawImage(imageBitmap, new Rect(0, 0, imageBitmap.Width, imageBitmap.Height));

                var dpi = imageBitmap.DpiX;
                var resizeFactor = 96 / dpi;

                var faceHelper = new FaceDetectionHelper(filePath, resizeFactor);

                var faces = await faceHelper.DetectFaces();

                var facesDetails = new List<FaceDetails>();

                foreach (var face in faces)
                {
                    var rectangleDetails = face.FaceRectangle;

                    faceHelper.DrawFaceCircle(rectangleDetails, drwContext);

                    var croppedFace = faceHelper.GetCroppedImage(rectangleDetails);
                    var faceDetails = face.FaceAttributes;

                    facesDetails.Add(new Models.FaceDetails()
                    {
                        Image = croppedFace,
                        Attributes = faceDetails
                    });
                }
                FaceDetails.ItemsSource = facesDetails;
                drwContext.Close();
                var renderToImageCtrl = new RenderTargetBitmap((int)(imageBitmap.PixelWidth * resizeFactor), (int)(imageBitmap.PixelHeight * resizeFactor), 96, 96, PixelFormats.Pbgra32);
                renderToImageCtrl.Render(drwVisual);
                FaceImage.Source = renderToImageCtrl;
            }
        }

FaceDetectionHelper.cs

Popis kódu: Zde máme metodu, která nám určuje, jaká data chceme získat z API, konkrétně jaké vlastnosti obličeje chceme vypsat. Dále si tu ještě pomáháme se změnou velikosti jednotlivých obrázků a pozicování kruhů kolem tváří.

private readonly string _imageSrc;
        private readonly double _resizeFactor;

        public FaceDetectionHelper(string imageFilePath, double resizeFactor)
        {
            _imageSrc = imageFilePath;
            _resizeFactor = resizeFactor;
        }


        private IFaceClient GetClient()
        {
            return new FaceClient(new ApiKeyServiceClientCredentials(this._secret)) { Endpoint = this._endpoint, };
        }

        public async Task<IEnumerable<DetectedFace>> DetectFaces()
        {
            var client = GetClient();

            var requiredFaceAttributes = new FaceAttributeType[] {
                     FaceAttributeType.Age,
                     FaceAttributeType.Gender,
                     FaceAttributeType.Smile,
                     FaceAttributeType.FacialHair,
                     FaceAttributeType.Hair,
                     FaceAttributeType.HeadPose,
                     FaceAttributeType.Glasses,
                     FaceAttributeType.Emotion,
                };

            try
            {
                using (var imgStream = File.OpenRead(_imageSrc))
                {
                    var faces = await client.Face.DetectWithStreamAsync(imgStream, returnFaceAttributes: requiredFaceAttributes);
                    return faces;
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw e;
            }

        }

        public Rect GetFaceRectangle(FaceRectangle faceRectangle)
        {
            var rectangle = new Rect(faceRectangle.Left * _resizeFactor, faceRectangle.Top * _resizeFactor, faceRectangle.Width * _resizeFactor, faceRectangle.Height * _resizeFactor);
            return rectangle;
        }

        public Point GetCenter(double x, double y, double radius)
        {
            var center = new Point(x + radius, y + radius);
            return center;
        }

        public void DrawFaceCircle(FaceRectangle faceRectangle, DrawingContext drawingContext)
        {
            var diameter = faceRectangle.Width;
            var radius = diameter / 2;
            var xPosition = faceRectangle.Left * _resizeFactor;
            var yPosition = faceRectangle.Top * _resizeFactor;
            var center = GetCenter(xPosition, yPosition, radius);

            drawingContext.DrawEllipse(Brushes.Transparent,
                new Pen(Brushes.White, 7),
                center,
                diameter * _resizeFactor,
                diameter * _resizeFactor);

        }

        public BitmapImage GetCroppedImage(FaceRectangle faceRectangle)
        {
            var xCenter = (int)(faceRectangle.Left * _resizeFactor);
            var yCenter = (int)(faceRectangle.Top * _resizeFactor);
            var center = new System.Drawing.Point(xCenter, yCenter);

            var diameter = (int)(faceRectangle.Width * _resizeFactor);
            var size = new System.Drawing.Size(diameter, diameter);
            var rectangleToCrop = new System.Drawing.Rectangle(center, size );
            var image = System.Drawing.Image.FromFile(_imageSrc);

            var origBitmap = new System.Drawing.Bitmap(_imageSrc);
            var croppedImage = ImageHelper.CropAtRect(origBitmap, rectangleToCrop);
            var imageSource = ImageHelper.BitmapToImageSource(croppedImage);
            return imageSource;
        }

FaceDetails.cs

Popis kódu: Tuto třídu máme vytvořenou pouze pro získávání určitých dat z API. Pro to využíváme tzv. getter, setter, neboli vlastnosti.

        public FaceAttributes Attributes { get; set; }
        public BitmapImage Image { get; set; }
        public string MainHairColor => this.Attributes.Hair.HairColor.FirstOrDefault().Color.ToString();

ImageHelper.cs

Popis kódu: Zde máme několik metod na ořezávání, načítání a pozicování obrázků.

public static Image CropImage(Image img, Rectangle cropArea)
        {
            Bitmap bmpImage = new Bitmap(img);
            return bmpImage.Clone(cropArea, bmpImage.PixelFormat);
        }

        public static Bitmap CropAtRect(this Bitmap b, Rectangle r)
        {
            Bitmap nb = new Bitmap(r.Width, r.Height);
            Graphics g = Graphics.FromImage(nb);
            g.DrawImage(b, -r.X, -r.Y);
            return nb;
        }

        public static BitmapImage BitmapToImageSource(Bitmap bitmap)
        {
            using (MemoryStream memory = new MemoryStream())
            {
                bitmap.Save(memory, System.Drawing.Imaging.ImageFormat.Bmp);
                memory.Position = 0;
                BitmapImage bitmapimage = new BitmapImage();
                bitmapimage.BeginInit();
                bitmapimage.StreamSource = memory;
                bitmapimage.CacheOption = BitmapCacheOption.OnLoad;
                bitmapimage.EndInit();

                return bitmapimage;
            }
        }

Závěr

Doufáme, že se vám bude aplikace líbit. Rozpoznávání obličeje pomocí Azure je jen jednou z možností jak lze umělou inteligenci využívat. Kdyby se vám aplikace líbila, ale netroufli byste si na programování, nezoufejte, protože tento program je dostupný na našem GitHubu.

Nastavení souborů Cookies

1. Co jsou soubory cookies

Soubory cookies jsou krátké textové soubory, které internetová stránka odešle do vašeho prohlížeče. Umožňují internetové stránce zaznamenat informace o vaší návštěvě, například zvolený jazyk a podobně. Následující návštěva stránek tak pro vás může být snazší a příjemnější. Soubory cookies jsou důležité, neboť bez nich by procházení sítě Internet bylo mnohem složitější. Soubory cookies umožňují lepší využití naší internetové stránky a přizpůsobení jejího obsahu vašim potřebám. Soubory cookies používá téměř každá internetová stránka na světě.

2. Druhy souborů cookies

Relační (tedy dočasné) soubory cookies nám umožňují propojovat vaše jednotlivé aktivity po dobu prohlížení těchto internetových stránek. V okamžiku otevření okna vašeho prohlížeče se tyto soubory vytvoří a po zavření okna vašeho prohlížeče se odstraní.

Trvalé soubory cookies nám pomáhají váš počítač identifikovat, jestliže opětovně navštívíte naši internetovou stránku.

3. Využívání souborů cookies

V souladu s ustanovením § 89 odst. 3 zák. č. 127/2005 Sb., o elektronických komunikacích, v účinném znění, si vás tímto dovolujeme informovat, že naše internetové stránky využívají pro svoji činnost soubory cookies, tedy vaše soubory cookies, včetně trvalých, zpracováváme.

Internetové prohlížeče obvykle obsahují správu souborů cookies. V rámci nastavení vašeho prohlížeče tak pravděpodobně můžete jednotlivé soubory cookies ručně mazat, blokovat či zcela zakázat jejich používání. Pro více informací použijte nápovědu vašeho internetového prohlížeče. Jsou-li cookies povoleny, lze toto nastavení internetového prohlížeče považovat za souhlas se zpracováním osobních údajů.

4. Účel použití souborů cookies

K personalizaci obsahu a reklam, poskytování funkcí sociálních médií a analýze naší návštěvnosti využíváme soubory cookies. Informace o tom, jak náš web používáte, sdílíme se svými partnery působícími v oblasti sociálních médií, inzerce a analýz. Používáním internetových stránek vyjadřujete souhlas propojením následujících služeb: Google Analytics, Google Tag Manager, Facebook Pixel, Microsoft Clarity.

Soubory cookies využíváme, kromě účelu uvedeného v předchozím odstavci, pouze pro měření návštěvnosti webové stránky.

5. Správce osobních údajů

Provozovatelem webové stránky studuj.digital a správcem osobních údajů je společnost: pg-sec s.r.o., sídlem Rybná 716/24, Staré Město, 110 00 Praha 1, identifikační číslo 09580905, zapsaná v obchodním rejstříku Městského soudu v Praze, oddíl C, vložka 338028.

​6. Zásady ochrany osobních údajů

Podrobnější informace o souborech cookies a zpracování tvých osobních údajů najdete v našich Zásadách ochrany osobních údajů.

Nezbytné

Tyto soubory cookie jsou nutné pro základní funkce stránky, a jsou proto vždy povolené. Mezi ně patří soubory cookie, které stránce umožňují si vás zapamatovat při procházení stránky v rámci jedné relace nebo, pokud o ně požádáte, mezi relacemi.

Volitelné

Výkon

Tyto soubory cookie nám pomáhají vylepšovat funkce stránek sledováním využití této webové stránky. V některých případech zrychlují zpracování vašeho požadavku a umožňují nám zapamatovat si vaše vybrané předvolby na stránce. Pokud soubory cookie zakážete, může se tím zhoršit přesnost našich doporučení a zpomalit funkčnost stránek.

Sociální média a relamy

Díky souborům cookies sociálních médií si můžete připojit ke svým sociálním sítím a prostřednictvím sociálních médií sdílet obsah z naší webové stránky. Reklamní soubory cookie (třetích stran) shromažďují informace pro lepší přizpůsobení reklamy tvým zájmům, a to na webových stránkách studuj.digital i mimo ně. V některých případech tyto soubory cookies zpracovávají vaše osobní údaje. Pokud chcete získat více informací o zpracování osobních údajů, přečtěte si naše Zásady ochrany osobních údajů. Pokud zakážete soubory cookies, mohou se zobrazovat reklamy, které méně souvisejí s vašimi zájmy, nebo nebudete moci účinně používat odkazy na Facebook, Instagram či jiné sociální sítě anebo nebudete moci sdílet obsah na sociálnch médiích.