Skip to Content

Praktikum 1 - Aufnahme und Aufbereitung der Daten einer Stereo-Kamera

Aufgabenblatt

Gesamtziel

Aufeinander aufbauend wird in den drei Praktikumsversuchen ein gr¨oßeres Projekt bearbeitet. Ziel ist es, Handbewegungen in den aufgenommenen Bildern zu unterscheiden. Die Implementierung der Bildverarbeitungsmethoden erfolgt mit der C++ Bibliothek OpenCV und dem Kamera SDK DepthAI.

Lernziele des ersten Praktikums

  • Lesen fremden Codes
  • Einbinden und Verwendung von externen Bibliotheken einschließlich des Gebrauchs der Dokumentation
  • Einlesen von Datein von der kamera und Darstellung von Bildern mittels OpenCV
  • Schreiben und Lesen von Videodatein
  • Arbeiten mit Übergabeparametern

Aufgaben

Nutzen Sie für Ihre Implementierung das Beispielprogramm RGB_Depth_alignment.cpp aus dem moodle-Kurs. Achten Sie bei allen Ergänzungen darauf, alle m¨oglichen auftretenden Fehler durch eine geeignete Fehlerbehandlung abzufangen.

Hol dir den Source Code:

RGB_Depth_alignment.cpp (Source Code)
  1. Vereinfachen Sie den Code zunächst so, dass nur noch das Tiefenbild und das Farbbild angezeigt werden. Nutzen Sie zur Colorierung des Tiefenbildes die JET-Farbtabelle
  2. Untersuchen Sie den Einfluss eines erweiterten Disparitätsbereichs, um dichter an der Kamera befindliche Objekte auch noch darstellen zu können (Stichwort: extended_disparity).
  3. Ergänzen Sie das Programm so, dass Übergabeparameter verwendet werden können. Bei Aufruf des Programms mit einer “1” soll später die Auswertung des Live-Kamerabildes starten.
  4. Bei Übergabe einer “2” sollen zusätzlich zur Anzeige zwei Videos (Tiefenbild, Farbbild) aufgezeichnet werden. In dem Fall soll später keine Auswertung erfolgen. Nutzen Sie hierfür die OpenCV-Klasse VideoWriter.
  5. Bei Übergabe einer “3” soll die Auswertung auf den aufgezeichneten Videos erfolgen. In dem Fall soll kein Zugriff auf die Kamera erforderlich sein. Hierzu können Sie die VideoCapture-Klasse verwenden.

Lösung

Aufgabe 1

Entferne die markierten Stellen aus dem Code um nur noch das Tiefenbild und das Farbbild anzuzeigen:

auto rgbWindowName = "rgb"; auto depthWindowName = "depth"; auto blendedWindowName = "rgb-depth"; cv::namedWindow(rgbWindowName); cv::namedWindow(depthWindowName); cv::namedWindow(blendedWindowName); int defaultValue = (int)(rgbWeight * 100); cv::createTrackbar("RGB Weight %", blendedWindowName, &defaultValue, 100, updateBlendWeights);

Um die JET-Farbtabelle zu nutzen, ändere in der Funktion cv::applyColorMap() COLORMAP_HPT zu COLORMAP_JET:

if(1) cv::applyColorMap(frame[name], frame[name], cv::COLORMAP_JET);

Aufgabe 2

Füge setExtendedDisparity zu der Stereo-Kamera hinzu:

stereo->setDefaultProfilePreset(dai::node::StereoDepth::PresetMode::HIGH_DENSITY); // LR-check is required for depth alignment stereo->setLeftRightCheck(true); stereo->setDepthAlign(dai::CameraBoardSocket::CAM_A); stereo->setExtendedDisparity(true); // Aktiviere extended disparity

Aufgabe 3

Um Übergabeparameter zu verwenden, muss die Funktion main() angepasst werden:

int main(int argc, char** argv) { int arg = 0; if (argc > 1) { arg = std::stoi(argv[1]); } if(arg == 3) { playVideo(); return 0; } // ... }

Aufgabe 4

Damit wir Videos aufzeichnen können, müssen wir den Inhalt in der while(true)-Schleife anpassen:

while(true) { std::unordered_map<std::string, std::shared_ptr<dai::ImgFrame>> latestPacket; auto queueEvents = device.getQueueEvents(queueNames); for(const auto& name : queueEvents) { auto packets = device.getOutputQueue(name)->tryGetAll<dai::ImgFrame>(); auto count = packets.size(); if(count > 0) { latestPacket[name] = packets[count - 1]; } } for(const auto& name : queueNames) { if(latestPacket.find(name) != latestPacket.end()) { if(name == depthWindowName) { frame[name] = latestPacket[name]->getFrame(); auto maxDisparity = stereo->initialConfig.getMaxDisparity(); frame[name].convertTo(frame[name], CV_8UC1, 255. / maxDisparity); cv::applyColorMap(frame[name], frame[name], cv::COLORMAP_JET); } else { frame[name] = latestPacket[name]->getCvFrame(); } cv::imshow(name, frame[name]); if(arg == 2) { bool isColor = (frame[name].type() == CV_8UC3); if(!writerInitializedrgb || !writerInitializeddepth) { int codec = cv::VideoWriter::fourcc('M','J','P','G'); double fps = 30.0; if(name == "depth") { writerdepth.open("live_depth.avi", codec, fps, frame[name].size(), isColor); writerInitializeddepth = true; } if(name == "rgb") { writerrgb.open("live_rgb.avi", codec, fps, frame[name].size(), isColor); writerInitializedrgb = true; } std::cout << "Press q to terminate" << std::endl; } if(name == "depth") { writerdepth.write(frame[name]); } if(name == "rgb") { writerrgb.write(frame[name]); } } } } int key = cv::waitKey(1); if(key == 'q' || key == 'Q') { if(arg == 2) { writerrgb.release(); writerdepth.release(); } return 0; } }

Aufgabe 5

Hierfür nutzen wir eine separate Funktion playVideo() außerhalb der main()-Funktion. In Aufgabe 3 haben wir bereits einen Verweis auf diese Funktion hinzugefügt.:

int playVideo() { while(true) { cv::VideoCapture caprgb("live_rgb.avi"); // RGB Video cv::VideoCapture capdepth("live_depth.avi"); // Depth Video // Überprüfen ob Videos geöffnet werden konnten if (!caprgb.isOpened() || !capdepth.isOpened()) { std::cerr << "Error opening video stream or file" << std::endl; return -1; } cv::Mat frame; cv::Mat frame2; while(true) { caprgb >> frame; // RGB Frame capdepth >> frame2; // Depth Frame if (frame.empty() || frame2.empty()) { std::cerr << "End of video stream" << std::endl; return 0; } // Display RGB and Depth Frame cv::imshow("rgb", frame); cv::waitKey(30); cv::imshow("depth", frame2); cv::waitKey(30); } cv::destroyAllWindows(); } return 0; }

Abschluss

Vollständiger Source Code:

RGB_Depth_alignment_complete.cpp (Source Code)
Last updated on