Ich habe ein C++ Projekt, wo ich OpenCV und Libfreenect verwende. Ich möchte nicht etwas so großes und schweres wie OpenNI einbeziehen und OpenCV-Installationsabhängigkeit in dem Prozess erstellen. Ich möchte die Kalibrierungsinformationen here verwenden, um die RGB- und Tiefenbilder zu entzerren und auszurichten.Wie richtet man RGB und Tiefenbild von Kinect in OpenCV aus?
Die Bilder einzeln zu entzerren, basierend auf der Kameramatrix und den Verzerrungskoeffizienten, war einfach genug. Aber jetzt bin ich verwirrt darüber, wie ich die Rektifikations- und Projektionsmatrizen verwenden könnte, um das RGB- und Tiefenbild so auszurichten, dass sie mir im Wesentlichen die gleichen Dinge aus derselben Perspektive zeigen. Nach langem Suchen kann ich nicht feststellen, wie es mit OpenCV funktionieren soll. Es ist eine vage Schätzung, dass reprojectImageTo3D() und warpPerspective() verwendet werden kann, aber ich bin mir nicht sicher, wie.
Wie könnte ich dieses Problem angehen? Ich verwende die alte XBOX360 Kinect (mit 0-2047 Roh-Disparity-Wertebereich).
UPDATE
Hier ist der Teil-Code, den ich bisher geschrieben haben:
// I use callback functions to get RGB (CV_8UC3) and depth (CV_16UC1)
// I undistort them and call the following method
void AlignImages(cv::Mat& pRGB, cv::Mat& pDepth) {
rotationMat = (cv::Mat_<double_t>(3,3) << 9.9984628826577793e-01, 1.2635359098409581e-03, -1.7487233004436643e-02, -1.4779096108364480e-03, 9.9992385683542895e-01, -1.2251380107679535e-02, 1.7470421412464927e-02, 1.2275341476520762e-02, 9.9977202419716948e-01);
translationMat = (cv::Mat_<double_t>(3,1) << 1.9985242312092553e-02, -7.4423738761617583e-04, -1.0916736334336222e-02);
// make a copy in float to convert raw depth data to physical distance
cv::Mat tempDst;
pDepth.convertTo(tempDst, CV_32F);
// create a 3 channel image of precision double for the 3D points
cv::Mat tempDst3D = cv::Mat(cv::Size(640, 480), CV_64FC3, double(0));
float_t* tempDstData = (float_t*)tempDst.data;
double_t* tempDst3DData = (double_t*)tempDst3D.data;
size_t pixelSize = tempDst.step/sizeof(float_t);
size_t pixel3DSize = tempDst3D.step/sizeof(double_t);
for (int row=0; row < tempDst.rows; row++) {
for (int col=0; col < tempDst.cols; col++) {
// convert raw depth values to physical distance (in metres)
float_t& pixel = tempDstData[pixelSize * row + col];
pixel = 0.1236 * tanf(pixel/2842.5 + 1.1863);
// reproject physical distance values to 3D space
double_t& pixel3D_X = tempDst3DData[pixel3DSize * row + col];
double_t& pixel3D_Y = tempDst3DData[pixel3DSize * row + col +1];
double_t& pixel3D_Z = tempDst3DData[pixel3DSize * row + col + 2];
pixel3D_X = (row - 3.3930780975300314e+02) * pixel/5.9421434211923247e+02;
pixel3D_Y = (col - 2.4273913761751615e+02) * pixel/5.9104053696870778e+02;
pixel3D_Z = pixel;
}
}
tempDst3D = rotationMat * tempDst3D + translationMat;
}
ich direkt die Zahlen verwendet haben, anstatt sie auf Variablen zuweisen, aber das sollte nicht sein, Problem beim Verständnis der Logik. An dieser Stelle soll ich folgendes machen:
P2D_rgb.x = (P3D'.x * fx_rgb/P3D'.z) + cx_rgb
P2D_rgb.y = (P3D'.y * fy_rgb/P3D'.z) + cy_rgb
Aber ich verstehe nicht, wie ich es genau machen soll. Vielleicht gehe ich überhaupt in die falsche Richtung. Aber ich kann kein Beispiel dafür finden.
können Sie OpenNI statt openkinect/libfreenect verwenden? –
Ich denke, Sie haben ein Problem damit, wie Sie auf Daten in Ihrem 'tempDst3DData'-Puffer zugreifen. Es sollte 'tempDst3DData [3 * pixel3DSize * row + 3 * col + channel]' sein. In Bezug auf Ihre aktualisierte Frage bearbeite ich meine Antwort, um sie klarer zu machen. – AldurDisciple
Ich glaube auch, du hast 'row' und' col' in deinen 'pixel3D_X' und' pixel3D_Y' Ausdrücken gemischt. – AldurDisciple