Francesco Runci
PhD | Security Researcher | Cyber Observer | IT Security | Programmer | Drone Pilot

Eye4Eye – face detect and recognition on frame video [Microsoft Azure]

Ho di recente visto questo: https://www.youtube.com/watch?v=tD57rVChlM8&t=46s ;devo dire che questo genere di film è molto rilassante per me, si lasciando stare la “fantascienza applicata”, nel film tratta del cosìdetto “occhio di dio” un fantomatico programma che permette di poter hackerare tutti i dispositivi mobile o fissi dotati di una telecamera per poter ricercare la persona di interesse.

Ok a questa bellissima equazione, togliamo le cazzate. Quindi non esiste che hackeri qualsiasi dispositivo con telecamera, e non esiste che per tutti i flussi video (anche stesso riuscissi a farlo) potrebbero essere analizzati frame per frame per l’identificazione “certa” della persona nei pochi secondi necessari come nel video. Quindi, tolte le minchiate andiamo al sodo.

Per effettuare un analisi del frame video “ovvero detect” dei volti mi sono basato su Microsoft cognitive. che cos’è? vi invito a leggere questa pagina:

https://azure.microsoft.com/it-it/services/cognitive-services/

In questo agglomerato di tool messo a disposizione da Microsoft sussistono diverse possibilità, ma quella che a noi interessa per questo software è:

Detect one or more human faces in an image and get back face rectangles for where in the image the faces are, along with face attributes which contain machine learning-based predictions of facial features. The face attribute features available are: Age, Emotion, Gender, Pose, Smile, and Facial Hair along with 27 landmarks for each face in the image.

Avete ben capito; Grazie alla gestione delle API messe a disposizione da Azure e con un pò di dimestichezza in C# (ma volendo anche python) abbiamo ottenuto un risultato simpatico (che alla lontana tenderà ad assomigliare all’eye of god).

Alla base di questo progetto, ho dovuto scompattare in applicativo C# un flusso video derivante da webcam (così da rendere più facile i test) in frame, ed ho analizzato frame per frame inviando le immagini a microsoft (tramite API) restituendomi in json le informazioni che mi servivano per arricchire l’immagine.

Dunque ricapitolando abbiamo inserito la prima fase, ovvero il Detect ( quindi la facoltà di identificare nell’immagine un volto (già cosa non sempre semplice) ed eventualmente da questa analizzare le informazioni che l’intelligenza artificiale di microsoft ci rileva come emozioni, anni, occhiali, sorriso, capelli etc… Noi in questa fase di progetto dobbiamo semplicemente analizzare il volto trovandolo prima, ed estrando le caratteristiche dopo..

Apriamo Visual Studio e creiamo un nuovo progetto, sbizzarendoci sulla sistemazione dei box ovunque vogliamo.

L’importante è fare l’import su nuget di:

Vi sottolineo, essenziali per il progetto Aforge ( analizza i flussi video ) e Newtonsoft.json (ci aiuterà a deserializzare le risposte in json).

VideoCaptureDeviceForm form = new VideoCaptureDeviceForm();       
if (form.ShowDialog(this) == DialogResult.OK)
   { OpenVideoSource(form);}

  private void OpenVideoSource(VideoCaptureDeviceForm form)
  {
   videoSource = form.VideoDevice;
   videoSource.NewFrame += new NewFrameEventHandler(video_NewFrame);
   videoSource.Start();
   }

  private void video_NewFrame(object sender, NewFrameEventArgs eventArgs)
        {
            // get new frame
            Bitmap bitmap = eventArgs.Frame;
            MemoryStream ms = new MemoryStream();
            bitmap.Save(ms,System.Drawing.Imaging.ImageFormat.Jpeg);
            this.Invoke((MethodInvoker)delegate ()
            {   pictureBox1.Image = bitmap;
                MakeRequest(ms.ToArray());
            });
            //questo tempo di attesa è necessario per ricevere la  //risposta da microsoft dell'elaborazione
            attendi(3000);
        }
 public void attendi(int tempo) { try { Thread.Sleep(tempo); } catch (ThreadInterruptedException e) { e.StackTrace.ToString(); } }

La funzione MakeRequest ci restituirà il necessario per poter produrre il risultato finale:

 public async void MakeRequest(byte[] byteData)
        {
            var client = new HttpClient();
            var queryString = HttpUtility.ParseQueryString(string.Empty);

            // Request headers
            client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", "chiave API ricevuta da azure");

            // Request parameters
            queryString["returnFaceId"] = "true";
            queryString["returnFaceLandmarks"] = "false";
            queryString["returnFaceAttributes"] = "age,gender,emotion,smile,glasses";
            queryString["recognitionModel"] = "recognition_02";
            queryString["returnRecognitionModel"] = "false";
            var uri = "https://westeurope.api.cognitive.microsoft.com/face/v1.0/detect?" + queryString;

            HttpResponseMessage response;

            using (ByteArrayContent content = new ByteArrayContent(byteData))
            {
                if (response.IsSuccessStatusCode)
                {
                    var json = response.Content.ReadAsStringAsync().Result;
                    dynamic account = JsonConvert.DeserializeObject(json);

                    if (response.Content.ReadAsStringAsync().Result.CompareTo("[]") != 0)
                    {
                        this.Invoke((MethodInvoker)delegate ()
                        {

                            richTextBox1.Text += "" + account[0].faceId + "\n";

                            richTextBox1.Text += "Anni: " + account[0].faceAttributes.age + "\n";
                            richTextBox1.Text += "Sesso: " + account[0].faceAttributes.gender + "\n";
                            //richTextBox1.Text += "Emozioni:" +  + "\n";

                            ArrayList emozioni = new ArrayList();
                            emozioni.Add(Convert.ToDouble(account[0].faceAttributes.emotion.ager));
                            emozioni.Add(Convert.ToDouble(account[0].faceAttributes.emotion.contempt));
                            emozioni.Add(Convert.ToDouble(account[0].faceAttributes.emotion.disgust));
                            emozioni.Add(Convert.ToDouble(account[0].faceAttributes.emotion.fear));
                            emozioni.Add(Convert.ToDouble(account[0].faceAttributes.emotion.happiness));
                            emozioni.Add(Convert.ToDouble(account[0].faceAttributes.emotion.neutral));
                            emozioni.Add(Convert.ToDouble(account[0].faceAttributes.emotion.sadness));
                            emozioni.Add(Convert.ToDouble(account[0].faceAttributes.emotion.surprise));


                            for (int i = 0; i < emozioni.Count; i++)
                            {
                                if (Convert.ToDouble(emozioni[i].ToString()) > 0.0)
                                {
                                    switch (i)
                                    {
                                        case 0:
                                            richTextBox1.Text += "Emozioni: Rabbia "+ Convert.ToDouble(emozioni[i].ToString()) + "\n";
                                            break;
                                        case 1:
                                            richTextBox1.Text += "Emozioni: Disprezzo " + Convert.ToDouble(emozioni[i].ToString()) + "\n";
                                            break;
                                        case 2:
                                            richTextBox1.Text += "Emozioni: Disgusto " + Convert.ToDouble(emozioni[i].ToString()) + "\n";
                                            break;
                                        case 3:
                                            richTextBox1.Text += "Emozioni: Paura " + Convert.ToDouble(emozioni[i].ToString()) + "\n";
                                            break;
                                        case 4:
                                            richTextBox1.Text += "Emozioni: Felicità " + Convert.ToDouble(emozioni[i].ToString()) + "\n";
                                            break;
                                        case 5:
                                            richTextBox1.Text += "Emozioni: Neutrale " + Convert.ToDouble(emozioni[i].ToString()) + "\n";
                                            break;
                                        case 6:
                                            richTextBox1.Text += "Emozioni: Disprezzo " + Convert.ToDouble(emozioni[i].ToString()) + "\n";
                                            break;
                                        case 7:
                                            richTextBox1.Text += "Emozioni: Sorpresa " + Convert.ToDouble(emozioni[i].ToString()) + "\n";
                                            break;
                                    }
                                }
                            }

                            if (Convert.ToInt16(account[0].faceAttributes.smile) != 0)
                                richTextBox1.Text += "Sorride\n";
                            else
                                richTextBox1.Text += "Non sorride\n";

                            richTextBox1.Text += "<_______________________>\n";

                         //   richTextBox1.Text += "Occhiali?" + account[0].faceAttributes.glasses + "\n";

                            //  richTextBox1.Text += "" + account[0].faceRectangle + "\n";

                        });

                        int top = Convert.ToInt16(account[0].faceRectangle.top);
                        int left = Convert.ToInt16(account[0].faceRectangle.left);
                        int width = Convert.ToInt16(account[0].faceRectangle.width);
                        int height = Convert.ToInt16(account[0].faceRectangle.height);

                        Graphics g = pictureBox1.CreateGraphics();

                        Rectangle ee = new Rectangle(left, top, width, height);
                        using (Pen pen = new Pen(Color.Red, 2))
                        {
                            g.DrawRectangle(pen, ee);
                        }

                        using (Font myFont = new Font("Times", 14))
                        {
                            g.DrawString("" + account[0].faceAttributes.age, myFont, Brushes.Green, left, top);
                        }
                    }
                }
            }
       }

Inserite le funzioni di base descritte sopra, il risultato sarà il seguente:

Ho eliminato parte della foto per evitare i dettagli del luogo.

Come noterete comunque (al di là del ritaglio), è stato riconosciuto il frame con il volto e quindi il volto: disegnandone il rettangolo rosso. All’interno del rettangolo sussite l’età che secondo Microsoft il volto dovrebbe avere, ed in linea con la realtà dato che è esatta!

Sicuramente il software avrà degli aggiornamenti e questi verranno inseriti su github (come sempre). Attualmente il progetto è privato.

Se avete dubbi o vi servono altre parti di codice, non esitate a contattarmi.

A presto.

Share

You may also like...

2 Responses

  1. Forex Review says:

    As stated by Azure Cognitive Services Welcome Page, ” Microsoft Cognitive Services (formerly Project Oxford) are a set of APIs, SDKs and services available to developers to make their applications more intelligent, engaging and discoverable. Face detection, Facial recognition .

  2. oprolevorter says:

    There may be noticeably a bundle to know about this. I assume you made certain nice points in features also.

Leave a Reply

Your email address will not be published. Required fields are marked *