Benutzer mit den meisten Antworten
[C++] Kinect Distanzmessung

Frage
-
Guten Morgen!
Ich versuche schon seit Stunden die Distanz mittels der Kinect auf dem Bildschirm auszugeben... vergeblich... :/
Ich habe zwei Probleme, erstens werden falsche Werte ausgeworfen und zweitens geht die Framerate extrem in die Knie, wenn ich den String für die Bildschirmausgabe einfüge. Hier mal der Code der Funktion die die Depthdaten auswertet und ausgeben soll. Der String wird in einer Renderfunktion dann aufgerufen, was auch funtkioniert. Bin noch ein ziemlicher Programmierneuling btw :P
void updateImageFrame(NUI_IMAGE_FRAME &imageFrame, bool isDepthFrame) { INuiFrameTexture *nuiTexture = imageFrame.pFrameTexture; NUI_LOCKED_RECT lockedRect; nuiTexture->LockRect(0, &lockedRect, NULL, 0); if (lockedRect.Pitch != NULL) { const BYTE *pbuffer = (const BYTE*)lockedRect.pBits; for (int i = 0; i<480; ++i) { const BYTE *line = pbuffer + i * lockedRect.Pitch; const USHORT *bufferWord = (const USHORT*)line; for (int j = 0; j<640; ++j) { if (!isDepthFrame) { std::cout << "No Depth-Stream" << std::endl; } else { unsigned char *pDepth = depthTexture->bits + (i * 640 + j); *pDepth = (unsigned char)NuiDepthPixelToDepth(bufferWord[j]); std::stringstream String; String << "Distanz[mm]:" << *pDepth << std::endl; Text = String.str(); } } } TextureObject* tobj = (depthTexture); glBindTexture(GL_TEXTURE_2D, tobj->id); glTexImage2D(GL_TEXTURE_2D, 0, tobj->internalFormat, tobj->width, tobj->height, 0, tobj->imageFormat, GL_UNSIGNED_BYTE, tobj->bits); } nuiTexture->UnlockRect(0); } // updateImageFrame
Also die Distanz sollte also laufend am Bildschirm ausgegeben werden.
Lg Epi
- Bearbeitet Epiphany99 Montag, 24. August 2015 09:03
Antworten
-
Endlich hab ich es geschafft!!! :D
Ich habe es aber auf eine etwas andere Weise gelöst, sondern mittels Skeleton-Tracking. Die Update-Funktion bleibt eig genau so wie sie war, nur das ich jetzt den RGB-Stream verwende und nicht mehr den Depthstream:
void updateImageFrame(NUI_IMAGE_FRAME &imageFrame) { // Buffer sperren INuiFrameTexture *nuiTexture = imageFrame.pFrameTexture; NUI_LOCKED_RECT lockedRect; nuiTexture->LockRect(0, &lockedRect, NULL, 0); if (lockedRect.Pitch != NULL) { // Bildschirmauflösung annehmen und initialisieren const BYTE *buffer = (const BYTE*)lockedRect.pBits; for (int i = 0; i<480; ++i) { const BYTE *line = buffer + i * lockedRect.Pitch; const USHORT *bufferWord = (const USHORT*)line; for (int j = 0; j<640; ++j) { unsigned char* ptr = colorTexture->bits + 3 * (i * 640 + j); *(ptr + 0) = line[4 * j + 2]; *(ptr + 1) = line[4 * j + 1]; *(ptr + 2) = line[4 * j + 0]; } } // Texturen an OpenGL senden und ausgeben TextureObject *tobj = colorTexture; glBindTexture(GL_TEXTURE_2D, tobj->id); glTexImage2D(GL_TEXTURE_2D, 0, tobj->internalFormat, tobj->width, tobj->height, 0, tobj->imageFormat, GL_UNSIGNED_BYTE, tobj->bits); } // Buffer wieder entsperren nuiTexture->UnlockRect(0); } // updateFrameImage
Und nachdem ich die ganzen Verbindungen eingerichtet habe, gebe ich die Distanz einfach bei der Berechnung der einzelnen Punkte des Skeletts aus. Somit wird der String nicht mehr 307200mal (640*480) sondern nur mehr 20mal erstellt, also genau soviel, wie Punke am Skelett definiert sind und voilà... es funktioniert :D :D :D
void updateSkeletonData(NUI_SKELETON_DATA& data) { POINT coordInDepth; USHORT depth = 0; // Alle Verbindungen durchlaufen for (int i = 0; i < NUI_SKELETON_POSITION_COUNT; i++) { // Verbindungspositionen erhalten und // in Tiefeninformationen umrechnen NuiTransformSkeletonToDepthImage(data.SkeletonPositions[i], &coordInDepth.x, &coordInDepth.y, &depth, NUI_IMAGE_RESOLUTION_640x480); // Distanz in Millimeter am Bildschirm ausgeben std::stringstream depthText; depthText << "Distanz[mm]: " << NuiDepthPixelToDepth(depth) << std::endl; Text = depthText.str(); // Alle Koordinaten in das Array abspeichern skeletonVertices[i][0] = (GLfloat)coordInDepth.x / 640.0f; skeletonVertices[i][1] = 1.0f - (GLfloat)coordInDepth.y / 480.0f; skeletonVertices[i][2] = (GLfloat)NuiDepthPixelToDepth(depth) * 0.00025f; } } // updateSkeletonData
Nochmal herzlichen Dank an Iso7 für die Unterstützung.
Lg Epi
- Als Antwort markiert Epiphany99 Freitag, 28. August 2015 10:45
Alle Antworten
-
Hallo,
die Funktion NuiDepthPixelToDepth liefert einen USHORT Wert zurück. Richtig wäre:
USHORT usDepth = NuiDepthPixelToDepth(bufferWord[j]);
Und noch paar Punkte:
Es ist empfohlen die Variablen eindeutigen Namen zu vergeben:
std::stringstream depthString; depthString << "Distanz[mm]:" << usDepth << std::endl;
Typkonvertierung:
const USHORT *bufferWord = reinterpret_cast<const USHORT*>(line);
Grüße
- Bearbeitet Iso7 Montag, 24. August 2015 13:23
-
Hey!
Erstmal danke für die Antwort! Mir stellt sich aber die Frage, was ich dann mit
unsigned char *pDepth = depthTexture->bits + (i * 640 + j);
mache. Benötige ich nicht davon die Daten um die Distanz mit der Funktion NuiDepthPixeltoDepth errechnen zu können? Weil dann hab ich ja einmal einen unsigned char und einmal USHORT.
-
Hallo,
hier steht, dass der Depth-Wert 13 Bits lang ist. Also um den Wert zu speichern wird 2 Byte benötigt.
Bei der Zuweisung
*pDepth = (unsigned char)NuiDepthPixelToDepth(bufferWord[j]);
wird den Wert in unsigned char umgewandelt und abgeschnitten( Maximum-Wert 255).Wenn Du den Depth–Wert speichern willst, dann kannst Du über einen USHORT-Pointer auf den Speicher zugreifen( bevor muss der Speicher selbstverständlich allokiert werden).
USHORT *pDepth =/*Adresse berechnen*/; (*pDepth) = NuiDepthPixelToDepth(bufferWord[j]);
Wie deine Datenstruktur detphTexture aussieht, weiß ich nicht.Grüße
- Bearbeitet Iso7 Montag, 24. August 2015 20:25
-
Die Struktur dephtTexture ist eine Instanz von TextureObject:
struct TextureObject { GLuint id; GLenum imageFormat; GLint internalFormat; unsigned int width; unsigned int height; unsigned char* bits; };
Deswegen auch meine Umwandlung in einen "unsigned char"
Hab jetzt mal Datenstruktur gecastet und bekomme jetzt Distanzen die vl stimmen könnten. Da ich aber eine Framerate von geschätzten 0,25 habe, ist das schwer einzuschätzen. Das liegt eindeutig am String den ich erstelle, kommentiere ich ihn aus, läuft alles flüssig, versuche ich die Struktur außerhalb der Schleife anzulegen, wird nur ein graues Bild angezeigt :/
if (lockedRect.Pitch != NULL) { const BYTE *pbuffer = reinterpret_cast <const BYTE*>(lockedRect.pBits); for (int i = 0; i < 480; ++i) { const BYTE *line = pbuffer + i * lockedRect.Pitch; const USHORT *bufferWord = reinterpret_cast <const USHORT*>(line); for (int j = 0; j < 640; ++j) { if (!isDepthFrame) { std::cout << "No Depth-Stream" << std::endl; } else { USHORT *pDepth = reinterpret_cast<USHORT*>(depthTexture->bits + (i * 640 + j)); *pDepth = NuiDepthPixelToDepth(bufferWord[j]); std::stringstream depthString; depthString << "Distanz[mm]:" << *pDepth << std::endl; Text = depthString.str(); } } }
- Bearbeitet Epiphany99 Montag, 24. August 2015 15:57
-
Hallo,
ich bin nicht sicher, ob deine Berechnung der Adresse für pDepth richtig ist. Wieviel Bytes sind für eine Pixel in depthTexture->bits vorgesehen? Ich nehme an: 2 Bytes. Dann die Berechnung wäre:
USHORT *pDepth = reinterpret_cast<USHORT*>(depthTexture->bits + 2*(i * 640 + j));
Deine Text Variable wird in der Methode 307119 Mal überschrieben. Ist das so geplannt?
Grüße
-
Mahlzeit!
Berechnung sollte eig so stimmen. Habs mal versucht mit 2 zu multiplizieren und bekam eine Fehlermeldung.
Zum Thema Text, jein, ich bin mir zwar bewusst, dass der Text so oft überschrieben wird, was ja auch der Grund für die schwache Framerate sein wird, aber mir fällt gerade keine andere Variante ein, wie ich das außerhalb der Schleife ausgeben soll, da ich ja immer die aktuellen Daten von pDepth brauche. Hmmm... mit ner Liste vl?
lg Epi
-
Hallo,
in deiner Berechnung wird die neue Adresse nicht um 2 Bytes sondern um 1 Byte erhöht, also bei der neuen Berechnung wird das nächste Byte in unsigned char Array adressiert. Dann wird bei der Zuweisung von USHORT Typs ein Byte von dem zuletzt geschriebenen Wert überschrieben.
Du speicherst schon deine Depth-Werte in depthTexture. Hier kannst Du auf die benötigte Werte zugreifen.
Grüße
- Bearbeitet Iso7 Dienstag, 25. August 2015 12:22
-
Endlich hab ich es geschafft!!! :D
Ich habe es aber auf eine etwas andere Weise gelöst, sondern mittels Skeleton-Tracking. Die Update-Funktion bleibt eig genau so wie sie war, nur das ich jetzt den RGB-Stream verwende und nicht mehr den Depthstream:
void updateImageFrame(NUI_IMAGE_FRAME &imageFrame) { // Buffer sperren INuiFrameTexture *nuiTexture = imageFrame.pFrameTexture; NUI_LOCKED_RECT lockedRect; nuiTexture->LockRect(0, &lockedRect, NULL, 0); if (lockedRect.Pitch != NULL) { // Bildschirmauflösung annehmen und initialisieren const BYTE *buffer = (const BYTE*)lockedRect.pBits; for (int i = 0; i<480; ++i) { const BYTE *line = buffer + i * lockedRect.Pitch; const USHORT *bufferWord = (const USHORT*)line; for (int j = 0; j<640; ++j) { unsigned char* ptr = colorTexture->bits + 3 * (i * 640 + j); *(ptr + 0) = line[4 * j + 2]; *(ptr + 1) = line[4 * j + 1]; *(ptr + 2) = line[4 * j + 0]; } } // Texturen an OpenGL senden und ausgeben TextureObject *tobj = colorTexture; glBindTexture(GL_TEXTURE_2D, tobj->id); glTexImage2D(GL_TEXTURE_2D, 0, tobj->internalFormat, tobj->width, tobj->height, 0, tobj->imageFormat, GL_UNSIGNED_BYTE, tobj->bits); } // Buffer wieder entsperren nuiTexture->UnlockRect(0); } // updateFrameImage
Und nachdem ich die ganzen Verbindungen eingerichtet habe, gebe ich die Distanz einfach bei der Berechnung der einzelnen Punkte des Skeletts aus. Somit wird der String nicht mehr 307200mal (640*480) sondern nur mehr 20mal erstellt, also genau soviel, wie Punke am Skelett definiert sind und voilà... es funktioniert :D :D :D
void updateSkeletonData(NUI_SKELETON_DATA& data) { POINT coordInDepth; USHORT depth = 0; // Alle Verbindungen durchlaufen for (int i = 0; i < NUI_SKELETON_POSITION_COUNT; i++) { // Verbindungspositionen erhalten und // in Tiefeninformationen umrechnen NuiTransformSkeletonToDepthImage(data.SkeletonPositions[i], &coordInDepth.x, &coordInDepth.y, &depth, NUI_IMAGE_RESOLUTION_640x480); // Distanz in Millimeter am Bildschirm ausgeben std::stringstream depthText; depthText << "Distanz[mm]: " << NuiDepthPixelToDepth(depth) << std::endl; Text = depthText.str(); // Alle Koordinaten in das Array abspeichern skeletonVertices[i][0] = (GLfloat)coordInDepth.x / 640.0f; skeletonVertices[i][1] = 1.0f - (GLfloat)coordInDepth.y / 480.0f; skeletonVertices[i][2] = (GLfloat)NuiDepthPixelToDepth(depth) * 0.00025f; } } // updateSkeletonData
Nochmal herzlichen Dank an Iso7 für die Unterstützung.
Lg Epi
- Als Antwort markiert Epiphany99 Freitag, 28. August 2015 10:45