2015-01-09 15 views
6

Attualmente sto programmando con Microsoft Kinect per Windows SDK 2 su Windows 8.1. Le cose stanno andando bene, e in un ambiente di sviluppo domestico ovviamente non c'è molto rumore in sottofondo rispetto al "mondo reale".Microsoft Kinect e rumore ambientale/di sfondo

Mi piacerebbe chiedere un consiglio a chi ha esperienza nelle applicazioni del "mondo reale" con Kinect. In che modo Kinect (specialmente v2) fa un ambiente live con passanti, spettatori e oggetti inaspettati sullo sfondo? Mi aspetto che, nello spazio dal sensore Kinect all'utente, di solito non ci sia l'interferenza - ciò di cui sono molto attento ora è il rumore di fondo in quanto tale.

Mentre sono consapevole del fatto che il Kinect non tiene traccia correttamente alla luce solare diretta (sul sensore o sull'utente) - ci sono determinate condizioni di illuminazione o altri fattori esterni che devo inserire nel codice?

La risposta che sto cercando è:

  1. Che tipo di problemi possono sorgere in un ambiente vivo?
  2. Come hai codificato o lavorato intorno ad esso?
+0

Non ho ricevuto la seconda domanda. – GLHF

+1

@howaboutNO è il rumore di fondo puramente un problema hardware? O c'è qualcosa che può essere fatto a livello di codice? L'SDK non consente un tracciamento migliore? –

risposta

4

Ho creato un'applicazione per uso domestico come prima, quindi ho presentato la stessa applicazione in un ambiente pubblico. Il risultato è stato imbarazzante per me, perché c'erano molti errori che non avrei mai previsto in un ambiente controllato. Comunque questo mi ha aiutato perché mi ha portato ad aggiungere alcune modifiche interessanti al mio codice, che è centrato solo sulla rilevazione umana.

  1. Possedere condizioni per verificare la validità di un "umano".

    Quando ho mostrato la mia applicazione nel mezzo di un piano di presentazione con molti altri oggetti e oggetti di scena, ho scoperto che anche le sedie potevano essere scambiate per persone per brevi momenti, il che ha portato alla mia applicazione a passare tra l'utente e un oggetto inanimato , facendola perdere la traccia dell'utente e ha perso i suoi progressi. Per contrastare questo o altri rilevamenti umani falsi positivi, ho aggiunto i miei assegni supplementari per un essere umano. Il mio metodo di maggior successo è stato confrontare le proporzioni di un corpo umano. Ho implementato questo misurato in unità principali. (head units picture) Di seguito è riportato il codice di come ho fatto questo (SDK versione 1.8, C#)

    bool PersonDetected = false; 
    double[] humanRatios = { 1.0f, 4.0, 2.33, 3.0 }; 
    /*Array indexes 
    * 0 - Head (shoulder to head) 
    * 1 - Leg length (foot to knee to hip) 
    * 2 - Width (shoulder to shoulder center to shoulder) 
    * 3 - Torso (hips to shoulder) 
    */ 
    
    .... 
    
    double[] currentRatios = new double[4]; 
    double headSize = Distance(skeletons[0].Joints[JointType.ShoulderCenter], skeletons[0].Joints[JointType.Head]); 
    
    currentRatios[0] = 1.0f; 
    
    currentRatios[1] = (Distance(skeletons[0].Joints[JointType.FootLeft], skeletons[0].Joints[JointType.KneeLeft]) + Distance(skeletons[0].Joints[JointType.KneeLeft], skeletons[0].Joints[JointType.HipLeft]))/headSize; 
    
    currentRatios[2] = (Distance(skeletons[0].Joints[JointType.ShoulderLeft], skeletons[0].Joints[JointType.ShoulderCenter]) + Distance(skeletons[0].Joints[JointType.ShoulderCenter], skeletons[0].Joints[JointType.ShoulderRight]))/headSize; 
    
    currentRatios[3] = Distance(skeletons[0].Joints[JointType.HipCenter], skeletons[0].Joints[JointType.ShoulderCenter])/headSize; 
    
    int correctProportions = 0; 
    
    for (int i = 1; i < currentRatios.Length; i++) 
    { 
        diff = currentRatios[i] - humanRatios[i]; 
    
        if (abs(diff) <= MaximumDiff)//I used .2 for my MaximumDiff 
         correctProportions++; 
    } 
    
    if (correctProportions >= 2) 
        PersonDetected = true; 
    

    Un altro metodo che ho avuto successo con era trovare la media della somma della distanza al quadrato giunti l'uno dall'altro. Ho scoperto che le rilevazioni non umane avevano distanze sommate più variabili, mentre gli umani erano più coerenti. La media Ho imparato utilizzando una sola macchina Support Vector dimensionale (ho trovato distanze riassunto degli utenti sono stati generalmente meno di 9)

    //in AllFramesReady or SkeletalFrameReady 
    Skeleton data; 
    
    ... 
    
    float lastPosX = 0; // trying to detect false-positives 
    float lastPosY = 0; 
    float lastPosZ = 0; 
    float diff = 0; 
    foreach (Joint joint in data.Joints) 
    { 
        //add the distance squared 
        diff += (joint.Position.X - lastPosX) * (joint.Position.X - lastPosX); 
        diff += (joint.Position.Y - lastPosY) * (joint.Position.Y - lastPosY); 
        diff += (joint.Position.Z - lastPosZ) * (joint.Position.Z - lastPosZ); 
        lastPosX = joint.Position.X; 
        lastPosY = joint.Position.Y; 
        lastPosZ = joint.Position.Z; 
    } 
    
    if (diff < 9)//this is what my svm learned 
        PersonDetected = true; 
    
  2. ID Usa giocatori e gli indici di ricordare chi è chi

    Ciò concorda con la problema precedente, in cui se Kinect scambiava i due utenti che stava tracciando altri, la mia applicazione si arrestava in modo anomalo a causa di improvvisi cambiamenti nei dati. Per contrastare questo, terrei traccia di entrambi l'indice scheletrico di ciascun giocatore e il suo ID giocatore. Per ulteriori informazioni su come ho fatto questo, vedere Kinect user Detection.

  3. Aggiungi parametri regolabili da adottare per diverse situazioni

    Dove ho presentato, lo stesso angolo di inclinazione e di altri parametri di Kinect di base (come quasi-mode) non ha funzionato nel nuovo ambiente. Consenti all'utente di regolare alcuni di questi parametri in modo che possano ottenere la migliore configurazione per il lavoro.

  4. invitare la gente a fare cose stupide

    La prossima volta che ho presentato, ho avuto inclinazione regolabile, e si può indovinare se qualcuno bruciato il motore del Kinect. Tutto ciò che può essere rotto su Kinect, qualcuno si romperà. Lasciare un avviso nella documentazione non sarà sufficiente. Dovresti aggiungere dei controlli cautelativi sull'hardware di Kinect per assicurarti che le persone non si arrabbino quando rompono qualcosa inavvertitamente. Ecco alcuni codici per verificare se l'utente ha utilizzato il motore più di 20 volte in due minuti.

    int motorAdjustments = 0; 
    DateTime firstAdjustment; 
    
    ... 
    
    //in motor adjustment code 
    if (motorAdjustments == 0) 
        firstAdjustment = DateTime.Now; 
    ++motorAdjustments; 
    
    if (motorAdjustments < 20) 
    { 
        //adjust the tilt 
    } 
    
    else 
    { 
        DateTime timeCheck = firstAdjustment; 
    
        if (DateTime.Now > timeCheck.AddMinutes(2)) 
        { 
         //reset all variables 
         motorAdjustments = 1; 
         firstAdjustment = DateTime.Now; 
    
         //adjust the tilt 
        } 
    } 
    

    Vorrei far notare che tutti questi sono stati problemi per me con la prima versione di Kinect, e non so quanti di loro sono stati risolti nella seconda versione come io purtroppo non ho ottenuto il mio mani su uno ancora. Tuttavia, implementerei comunque alcune di queste tecniche se non le tecniche di back-up perché ci saranno eccezioni, specialmente nella visione artificiale.

+0

Approfondimento molto approfondito - grazie. –

+0

@FrancisKim Nessun problema! Se vuoi posso pubblicare alcuni esempi di codice per la distinzione degli utenti, anche se saranno versioni precedenti dell'SDK ... –

+0

Sì, qualsiasi tipo di codice di riferimento è molto apprezzato. –

5

Outlaw Lemur ha descritto dettagliatamente la maggior parte dei problemi che è possibile incontrare negli scenari del mondo reale.

Utilizzando Kinect per Windows versione 2, non è necessario regolare il motore, poiché non vi è alcun motore e il sensore ha un campo visivo più ampio. Questo renderà la tua vita molto più facile.

vorrei aggiungere le seguenti suggerimenti e consigli:

1) Evitare la luce diretta (fisico o illuminazione interna)

Kinect ha un sensore a infrarossi che potrebbe essere confuso. Questo sensore non dovrebbe avere contatto diretto con alcuna fonte di luce. Puoi emulare un tale ambiente a casa tua/ufficio giocando con un normale puntatore laser e torce.

2) Se si sta seguendo una sola persona, selezionare l'utente cingolato più vicino

Se la tua applicazione necessita di un solo giocatore, quel giocatore deve essere a) completamente monitorato e b) più vicino al sensore di gli altri. È un modo semplice per far capire ai partecipanti chi viene tracciato senza rendere più complessa la tua interfaccia utente.

public static Body Default(this IEnumerable<Body> bodies) 
    { 
     Body result = null; 
     double closestBodyDistance = double.MaxValue; 

     foreach (var body in bodies) 
     { 
      if (body.IsTracked) 
      { 
       var position = body.Joints[JointType.SpineBase].Position; 
       var distance = position.Length(); 

       if (result == null || distance < closestBodyDistance) 
       { 
        result = body; 
        closestBodyDistance = distance; 
       } 
      } 
     } 

     return result; 
    } 

3) Utilizzare gli ID di monitoraggio per distinguere i diversi giocatori

Ogni giocatore ha una proprietà TrackingID. Usa quella proprietà quando i giocatori interferiscono o si muovono in posizioni casuali. Non usare questa proprietà come alternativa al riconoscimento facciale.

ulong _trackinfID1 = 0; 
    ulong _trackingID2 = 0; 

    void BodyReader_FrameArrived(object sender, BodyFrameArrivedEventArgs e) 
    { 
     using (var frame = e.FrameReference.AcquireFrame()) 
     { 
      if (frame != null) 
      { 
       frame.GetAndRefreshBodyData(_bodies); 

       var bodies = _bodies.Where(b => b.IsTracked).ToList(); 

       if (bodies != null && bodies.Count >= 2 && _trackinfID1 == 0 && _trackingID2 == 0) 
       { 
        _trackinfID1 = bodies[0].TrackingId; 
        _trackingID2 = bodies[1].TrackingId; 

        // Alternatively, specidy body1 and body2 according to their distance from the sensor. 
       } 

       Body first = bodies.Where(b => b.TrackingId == _trackinfID1).FirstOrDefault(); 
       Body second = bodies.Where(b => b.TrackingId == _trackingID2).FirstOrDefault(); 

       if (first != null) 
       { 
        // Do something... 
       } 

       if (second != null) 
       { 
        // Do something... 
       } 
      } 
     } 
    } 

4) avvertimenti di visualizzazione quando un giocatore è troppo lontano o troppo vicino al sensore.

Per ottenere una maggiore precisione, i giocatori devono stare a una distanza specifica: non troppo lontano o troppo vicino al sensore. Ecco come controllare questo:

const double MIN_DISTANCE = 1.0; // in meters 
const double MAX_DISTANCE = 4.0; // in meters 

double distance = body.Joints[JointType.SpineBase].Position.Z; // in meters, too 

if (distance > MAX_DISTANCE) 
{ 
    // Prompt the player to move closer. 
} 
else if (distance < MIN_DISTANCE) 
{ 
    // Prompt the player to move farther. 
} 
else 
{ 
    // Player is in the right distance. 
} 

5) sanno sempre quando un giocatore è entrato o uscito di scena.

Vitruvius fornisce un modo semplice per capire quando qualcuno è entrato o ha lasciato la scena.

Here is the source code e qui è come utilizzarlo nella vostra applicazione:

UsersController userReporter = new UsersController(); 
    userReporter.BodyEntered += UserReporter_BodyEntered; 
    userReporter.BodyLeft += UserReporter_BodyLeft; 
    userReporter.Start(); 

    void UserReporter_BodyEntered(object sender, UsersControllerEventArgs e) 
    { 
     // A new user has entered the scene. Get the ID from e param. 
    } 

    void UserReporter_BodyLeft(object sender, UsersControllerEventArgs e) 
    { 
     // A user has left the scene. Get the ID from e param. 
    } 

6) Avere un indizio visivo di quale giocatore è monitorato

Se ci sono un sacco di persone che circondano il giocatore , potrebbe essere necessario mostrare sullo schermo chi è monitorato. È possibile evidenziare la bitmap del frame di profondità o utilizzare le interazioni Kinect di Microsoft.

This is an example of removing the background and keeping the player pixels only.

7) Evitare pavimenti lucidi

alcuni piani (brillante, lucido) possono rispecchiare le persone e Kinect possono confondere alcune delle loro articolazioni (per esempio, Kinect può estendere le gambe al corpo riflessa). Se non è possibile evitare i pavimenti lucidi, utilizzare la proprietà FloorClipPlane di BodyFrame. Tuttavia, la soluzione migliore sarebbe quella di avere un semplice tappeto dove ci si aspetta che le persone stiano in piedi. Un tappeto fungerà anche da indicazione della giusta distanza, in modo da fornire un'esperienza utente migliore.

+1

Wow non sapevo nulla del pavimento lucido ... +1 –

+3

Infatti, se il pavimento è troppo lucido, Kinect può estendere le gambe al corpo riflesso. – Vangos