2014-09-11 10 views
14

Derzeit entwickle ich ein Tool für die Kinect für Windows v2 (ähnlich dem in XBOX ONE). Ich habe versucht, einigen Beispielen zu folgen, und habe ein Arbeitsbeispiel, das das Kamerabild, das Tiefenbild und ein Bild zeigt, das die Tiefe mit rgb unter Verwendung von opencv abbildet. Aber ich sehe, dass es meine Hand dupliziert, wenn ich das Mapping mache, und ich denke, es liegt an etwas falsch in dem Koordinaten-Mapperteil.Kinect für Windows v2 Bildfehler in der Tiefe

hier ist ein Beispiel dafür: error

Und hier ist der Code-Schnipsel, die das Bild (rgbd Bild im Beispiel)

void KinectViewer::create_rgbd(cv::Mat& depth_im, cv::Mat& rgb_im, cv::Mat& rgbd_im){ 
    HRESULT hr = m_pCoordinateMapper->MapDepthFrameToColorSpace(cDepthWidth * cDepthHeight, (UINT16*)depth_im.data, cDepthWidth * cDepthHeight, m_pColorCoordinates); 
    rgbd_im = cv::Mat::zeros(depth_im.rows, depth_im.cols, CV_8UC3); 
    double minVal, maxVal; 
    cv::minMaxLoc(depth_im, &minVal, &maxVal); 
    for (int i=0; i < cDepthHeight; i++){ 
     for (int j=0; j < cDepthWidth; j++){ 
      if (depth_im.at<UINT16>(i, j) > 0 && depth_im.at<UINT16>(i, j) < maxVal * (max_z/100) && depth_im.at<UINT16>(i, j) > maxVal * min_z /100){ 
       double a = i * cDepthWidth + j; 
       ColorSpacePoint colorPoint = m_pColorCoordinates[i*cDepthWidth+j]; 
       int colorX = (int)(floor(colorPoint.X + 0.5)); 
       int colorY = (int)(floor(colorPoint.Y + 0.5)); 
       if ((colorX >= 0) && (colorX < cColorWidth) && (colorY >= 0) && (colorY < cColorHeight)) 
       { 
        rgbd_im.at<cv::Vec3b>(i, j) = rgb_im.at<cv::Vec3b>(colorY, colorX); 
       } 
      } 

     } 
    } 
} 

Hat jemand eine Ahnung, wie zu lösen schaffen Dies? Wie kann diese Duplizierung verhindert werden?

Vielen Dank im Voraus

UPDATE:

Wenn ich eine einfache Tiefenbild Schwellwertbildung kann ich folgendes Bild erhalten: thresholding

Dies ist, was mehr oder weniger ich passieren zu erwarten, und keine doppelte Hand im Hintergrund zu haben. Gibt es eine Möglichkeit, diese doppelte Hand im Hintergrund zu verhindern?

+1

Woher kommt dieses Mapping? von? sehr wahrscheinlich müssen Sie die Kalibrierung zwischen Tiefenbild und Farbbild bearbeiten, da die Vorgaben nicht perfekt sind. Sie müssen also Ihre eigene Kalibrierung durchführen. Sehen Sie sich dazu an: http://nicolas.burrus.name/index.php/Research/KinectCalibration – Micka

+0

Es stammt aus dem kinect SDK v2. Ich habe erwartet, dass ich das verwenden werde, das von der Firmware/SDK kommt, die die Intrigen der Kamera verwendet, um diese Berechnungen durchzuführen ... aber ich denke, der Fehler ist riesig im Vergleich zu anderen Kameras Firmware/Software wie Primesense mit Openni. Ich erwartete bessere Ergebnisse, oder zumindest ähnlich zu anderen Kameras .... Danke für den Link obwohl :) – api55

+0

Afaik die Auto-Kalibrierung Daten des Kinect in der Firmware gespeichert ist nicht das grear. Aber vielleicht liege ich da falsch. – Micka

Antwort

0

Endlich habe ich etwas Zeit, um die lang erwartete Antwort zu schreiben.

Beginnen wir mit einer Theorie, um zu verstehen, was wirklich passiert und dann eine mögliche Antwort.

Zunächst sollten wir wissen, wie man von einer 3D-Punktwolke mit der Tiefenkamera als Koordinatensystemursprung zu einem Bild in der Bildebene der RGB-Kamera gelangt.Um das zu tun, es ist genug, die Kamera Pinhole-Modell zu verwenden:

enter image description here

Hier drin u und v sind die Koordinaten in der Bildebene der RGB-Kamera. Die erste Matrix auf der rechten Seite der Gleichung ist die Kameramatrix AKA intrinsics der RGB-Kamera. Die folgende Matrix ist die Rotation und Translation der Extrinsik, oder besser gesagt, der Transformation, die benötigt wird, um vom Koordinatensystem der Tiefenkamera zum Koordinatensystem der RGB-Kamera zu gelangen. Der letzte Teil ist der 3D-Punkt.

Im Grunde genommen ist das Kinect SDK so etwas. Also, was könnte schief gehen, dass die Hand verdoppelt wird? naja, eigentlich projiziert mehr als ein Punkt auf den gleichen Pixel ....

Um es mit anderen Worten und im Zusammenhang mit dem Problem in der Frage zu sagen.

Das Tiefenbild, ist eine Darstellung einer geordneten Punktwolke, und ich frage die u v Werte von jedem seiner Pixel, die in der Realität leicht in 3D-Punkte umgewandelt werden können. Das SDK gibt Ihnen die Projektion, aber es kann auf den gleichen Pixel zeigen (normalerweise kann der Abstand in der z-Achse zwischen zwei benachbarten Punkten dieses Problem ziemlich leicht verursachen.)

Jetzt ist die große Frage, wie Sie vermeiden können das ... nun, ich bin mir nicht sicher, ob ich das Kinect SDK benutze, da du den Z-Wert der Punkte NICHT kennst, nachdem die Extrinsics angewendet wurden, also ist es nicht möglich, eine Technik wie die Z buffering .... zu verwenden Sie können davon ausgehen, dass der Z-Wert sehr ähnlich ist und verwenden Sie diese aus der ursprünglichen Pointcloud (auf eigene Gefahr)

Wenn Sie es manuell und nicht mit dem SDK tun, können Sie die Extrinsics auf die Punkte anwenden , und die Verwendung der projizieren sie in die Bildebene, Markieren in einer anderen Matrix, welcher Punkt auf welche p zugeordnet ist ixel und wenn bereits ein Punkt vorhanden ist, überprüfen Sie die z-Werte und vergleichen Sie sie und lassen Sie immer den nächsten Punkt zur Kamera. Dann haben Sie ein gültiges Mapping ohne Probleme. Dieser Weg ist irgendwie naiv, wahrscheinlich kann man bessere bekommen, da das Problem jetzt klar ist :)

Ich hoffe es ist klar genug.

S.S .: Ich habe Kinect 2 im Moment nicht, also kann ich nicht versuchen zu sehen, ob es ein Update in Bezug auf dieses Problem gibt oder ob es immer noch dasselbe passiert. Ich habe die erste veröffentlichte Version (nicht vor der Veröffentlichung) des SDK verwendet ... Also, viele Änderungen waren vielleicht passiert ... Wenn jemand weiß, ob das gelöst wurde, hinterlasse einfach einen Kommentar :)

1

Ich empfehle Ihnen, den BodyIndexFrame zu verwenden, um zu identifizieren, ob ein bestimmter Wert zu einem Spieler gehört oder nicht. Auf diese Weise können Sie RGB-Pixel, die nicht zu einem Player gehören, ablehnen und den Rest behalten. Ich denke nicht, dass CoordinateMapper lügt.

Ein paar Anmerkungen:

  • Fügen Sie die BodyIndexFrame Quelle Leser an den Rahmen
  • Verwenden MapColorFrameToDepthSpace statt MapDepthFrameToColorSpace; Auf diese Weise werden Sie
  • Suchen Sie die entsprechende DepthSpacePoint und Deep Phreatic Thermal Explorer, depthY, statt ColorSpacePoint und ColorX, Colory

Hier mein Ansatz ist, wenn ein Rahmen ankommt (es ist in C#, um die HD-Bild für den Vordergrund bekommen):

depthFrame.CopyFrameDataToArray(_depthData); 
colorFrame.CopyConvertedFrameDataToArray(_colorData, ColorImageFormat.Bgra); 
bodyIndexFrame.CopyFrameDataToArray(_bodyData); 

_coordinateMapper.MapColorFrameToDepthSpace(_depthData, _depthPoints); 

Array.Clear(_displayPixels, 0, _displayPixels.Length); 

for (int colorIndex = 0; colorIndex < _depthPoints.Length; ++colorIndex) 
{ 
    DepthSpacePoint depthPoint = _depthPoints[colorIndex]; 

    if (!float.IsNegativeInfinity(depthPoint.X) && !float.IsNegativeInfinity(depthPoint.Y)) 
    { 
     int depthX = (int)(depthPoint.X + 0.5f); 
     int depthY = (int)(depthPoint.Y + 0.5f); 

     if ((depthX >= 0) && (depthX < _depthWidth) && (depthY >= 0) && (depthY < _depthHeight)) 
     { 
      int depthIndex = (depthY * _depthWidth) + depthX; 
      byte player = _bodyData[depthIndex]; 

      // Identify whether the point belongs to a player 
      if (player != 0xff) 
      { 
       int sourceIndex = colorIndex * BYTES_PER_PIXEL; 

       _displayPixels[sourceIndex] = _colorData[sourceIndex++]; // B 
       _displayPixels[sourceIndex] = _colorData[sourceIndex++]; // G 
       _displayPixels[sourceIndex] = _colorData[sourceIndex++]; // R 
       _displayPixels[sourceIndex] = 0xff;       // A 
      } 
     } 
    } 
} 

Hier ist die Initialisierung der Arrays:

BYTES_PER_PIXEL = (PixelFormats.Bgr32.BitsPerPixel + 7)/8; 

_colorWidth = colorFrame.FrameDescription.Width; 
_colorHeight = colorFrame.FrameDescription.Height; 
_depthWidth = depthFrame.FrameDescription.Width; 
_depthHeight = depthFrame.FrameDescription.Height; 
_bodyIndexWidth = bodyIndexFrame.FrameDescription.Width; 
_bodyIndexHeight = bodyIndexFrame.FrameDescription.Height; 
_depthData = new ushort[_depthWidth * _depthHeight]; 
_bodyData = new byte[_depthWidth * _depthHeight]; 
_colorData = new byte[_colorWidth * _colorHeight * BYTES_PER_PIXEL]; 
_displayPixels = new byte[_colorWidth * _colorHeight * BYTES_PER_PIXEL]; 
_depthPoints = new DepthSpacePoint[_colorWidth * _colorHeight]; 

bemerken, dass die Anordnung eine _depthPoints 1920x1080 Größe hat.

Noch einmal, das Wichtigste ist die Verwendung der BodyIndexFrame-Quelle.

+0

Ich denke, das Beispiel Bild mit der Hand ist ein wenig irreführend. Wir versuchen, ein Werkzeug zu implementieren, um einen Datensatz in verschiedenen Formaten aufzuzeichnen. Eine der Sachen, die wir mit diesem Datensatz machen können, ist, eine farbige Punktwolke zu erstellen, aber die Punkte im Hintergrund haben die falsche Farbe (sieht aus wie eine doppelte Hand). Gibt es eine Möglichkeit, nur dieses "ungültig" zu entfernen (wir betrachten sie als ungültig, da es keine Zuordnung zu Farben geben sollte, wahrscheinlich weil diese Pixel im Farbbild nicht sichtbar sind). – api55

+0

Oh, ich habe es. In Ihrem Beispiel erstellen Sie ein RGB-Bild mit dem Tiefenrahmen als Basis. Sie können es also nicht auf das 1920x1080 Bild projizieren. In dem Code, den ich Ihnen zur Verfügung gestellt habe, wird eine RGBA-Bitmap mit einer Größe von 1920x1080 erzeugt. Daher können Sie es auf einer anderen 1920 x 1080-Bitmap platzieren. Hast du das versucht? – Vangos

+0

Ich habe es versucht, und habe etwas ohne Duplikate, aber ich denke, dass viele ungültige Pixel verschwunden sind, und mich wundern, wie gut ist das Mapping? Wenn Sie im Beispiel das Fenster über der Tür sehen, enthält das Tiefenbild viele ungültige Pixel. Wenn ich dieses Mapping mache, das du vorschlägst, verschwinden die meisten tatsächlich ... also habe ich mich gefragt, was mit ihnen passiert? Vielleicht ein Interpolationsproblem im Framework? – api55

Verwandte Themen