From ed3fb6187f19b71f5d8015c16f4753d050510021 Mon Sep 17 00:00:00 2001 From: builder Date: Tue, 4 Aug 2026 07:01:05 +0000 Subject: [PATCH] Samples: Add CLI options to Connect; fix live 3D visualization Connect: - Connect now accepts --serial, --ip, and --hostname options to specify camera identifiers instead of editing the source code. Live 3D visualization: - CaptureVis3DInLoop and CaptureVis3DInLoopWithKeypressExit now run the visualizer on the main thread while capturing in the background. This fixes issues on some platforms and reports capture errors instead of failing silently. Fixes and docs: - Update the list of tested HALCON versions in the README (adds 25.11 Progress-Steady and 26.05 Progress). - Tidy wording in the DLPack tensor sample description. --- README.md | 4 +- .../CaptureVis3DInLoop/CaptureVis3DInLoop.cpp | 68 +++++++------- .../CaptureVis3DInLoopWithKeypressExit.cpp | 91 ++++++++----------- source/CMakeLists.txt | 1 + source/Camera/Basic/Connect/Connect.cpp | 50 +++++++--- 5 files changed, 113 insertions(+), 101 deletions(-) diff --git a/README.md b/README.md index 0b35a72a..45817420 100644 --- a/README.md +++ b/README.md @@ -177,7 +177,7 @@ from the camera can be used. CUDA device using OpenCV. - [CaptureAndConvertToDlpackTensorOnCuda] - Capture a 2D+3D frame with the Zivid SDK and build DLPack tensors directly from the - Zivid DeviceArrays on the CUDA device. + Zivid DeviceArrays on the CUDA - **Transform** - [TransformPointCloudFromMillimetersToMeters] - Transform point cloud data from millimeters to meters. @@ -329,7 +329,7 @@ The following HALCON versions have been tested and confirmed to work with Zivid cameras: - 19.05 Progress, 20.05 Progress, 21.11 Progress, 24.05 Progress, 24.11 - Progress-Steady, 25.05 Progress + Progress-Steady, 25.05 Progress, 25.11 Progress, 26.05 Progress We recommend using one of the HALCON versions we have tested. diff --git a/source/Applications/Advanced/Visualization/CaptureVis3DInLoop/CaptureVis3DInLoop.cpp b/source/Applications/Advanced/Visualization/CaptureVis3DInLoop/CaptureVis3DInLoop.cpp index e6a5289b..9f3bf093 100644 --- a/source/Applications/Advanced/Visualization/CaptureVis3DInLoop/CaptureVis3DInLoop.cpp +++ b/source/Applications/Advanced/Visualization/CaptureVis3DInLoop/CaptureVis3DInLoop.cpp @@ -5,7 +5,8 @@ Capture point clouds, with color, from the Zivid camera, and visualize them in a #include #include -#include +#include +#include #include #include @@ -26,49 +27,48 @@ int main() Zivid::Settings2D::Acquisitions{ Zivid::Settings2D::Acquisition{} } } } }; std::cout << "Capturing frame" << std::endl; - auto frame = camera.capture2D3D(settings); + const auto frame = camera.capture2D3D(settings); std::cout << "Settings:" << frame.settings() << std::endl; std::cout << "Setting up visualization" << std::endl; - std::atomic_bool visualizerRunning{ false }; - auto visualizerPromise = std::promise(); - auto visualizerFuture = visualizerPromise.get_future(); + auto visualizer = Zivid::Visualization::Visualizer(); - std::thread visualizationThread([&frame, &visualizerPromise, &visualizerRunning]() { - auto visualizer = Zivid::Visualization::Visualizer(); + std::cout << "Visualizing point cloud" << std::endl; + visualizer.showMaximized(); + visualizer.show(frame); + visualizer.resetToFit(); - // Pass the visualizer to the main thread - visualizerPromise.set_value(&visualizer); + std::atomic_bool visualizerRunning{ true }; + std::exception_ptr captureException; - std::cout << "Visualizing point cloud" << std::endl; - visualizer.showMaximized(); - visualizer.show(frame); - visualizer.resetToFit(); - - std::cout << "Running visualizer. Blocking until window closes." << std::endl; - visualizerRunning = true; - visualizer.run(); - visualizerRunning = false; + std::thread captureThread([&camera, &settings, &visualizer, &visualizerRunning, &captureException]() { + try + { + while(visualizerRunning) + { + const auto newFrame = camera.capture2D3D(settings); + if(visualizerRunning) + { + visualizer.show(newFrame); + } + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + } + catch(...) + { + captureException = std::current_exception(); + visualizer.close(); + } }); - // Get the visualizer handle in the main thread - auto visualizerHandle = visualizerFuture.get(); - - while(!visualizerRunning) - { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - while(visualizerRunning) + std::cout << "Running visualizer. Blocking until window closes." << std::endl; + visualizer.run(); + visualizerRunning = false; + captureThread.join(); + if(captureException) { - frame = camera.capture2D3D(settings); - if(!visualizerRunning) - { - break; - } - visualizerHandle->show(frame); - std::this_thread::sleep_for(std::chrono::milliseconds(10)); + std::rethrow_exception(captureException); } - visualizationThread.join(); std::cout << "Visualizer closed" << std::endl; } catch(const std::exception &e) diff --git a/source/Applications/Advanced/Visualization/CaptureVis3DInLoopWithKeypressExit/CaptureVis3DInLoopWithKeypressExit.cpp b/source/Applications/Advanced/Visualization/CaptureVis3DInLoopWithKeypressExit/CaptureVis3DInLoopWithKeypressExit.cpp index b3c95f71..ccceae7b 100644 --- a/source/Applications/Advanced/Visualization/CaptureVis3DInLoopWithKeypressExit/CaptureVis3DInLoopWithKeypressExit.cpp +++ b/source/Applications/Advanced/Visualization/CaptureVis3DInLoopWithKeypressExit/CaptureVis3DInLoopWithKeypressExit.cpp @@ -5,7 +5,8 @@ Capture point clouds, with color, from the Zivid camera, and visualize them in a #include #include -#include +#include +#include #include #include #ifdef _WIN32 @@ -71,70 +72,54 @@ int main() Zivid::Settings2D::Acquisitions{ Zivid::Settings2D::Acquisition{} } } } }; std::cout << "Capturing frame" << std::endl; - auto frame = camera.capture2D3D(settings); + const auto frame = camera.capture2D3D(settings); std::cout << "Setting up visualization" << std::endl; - std::atomic_bool visualizerRunning{ false }; - std::atomic_bool acceptEnd{ true }; - std::atomic_bool quitRequested{ false }; - auto visualizerPromise = std::promise(); - auto visualizerFuture = visualizerPromise.get_future(); + auto visualizer = Zivid::Visualization::Visualizer(); - std::thread visualizationThread([&frame, &visualizerPromise, &visualizerRunning, &acceptEnd, &quitRequested]() { - auto visualizer = Zivid::Visualization::Visualizer(); + std::cout << "Visualizing point cloud" << std::endl; + visualizer.showMaximized(); + visualizer.show(frame); + visualizer.resetToFit(); - // Pass the visualizer to the main thread - visualizerPromise.set_value(&visualizer); + std::atomic_bool visualizerRunning{ true }; + std::exception_ptr captureException; - std::cout << "Visualizing point cloud" << std::endl; - visualizer.showMaximized(); - visualizer.show(frame); - visualizer.resetToFit(); - - std::cout << "Running visualizer. Blocking until window closes." << std::endl; - do + std::thread captureThread([&camera, &settings, &visualizer, &visualizerRunning, &captureException]() { + try { - visualizerRunning = true; - visualizer.run(); - visualizerRunning = false; - - if(quitRequested) + std::cout << "Press 'q' in the terminal to quit " << std::endl; + while(visualizerRunning) { - break; + if(getKeyNonBlocking() == 'q') + { + std::cout << "Closing application because user pressed 'q'" << std::endl; + visualizer.close(); + break; + } + const auto newFrame = camera.capture2D3D(settings); + if(visualizerRunning) + { + visualizer.show(newFrame); + } + std::this_thread::sleep_for(std::chrono::milliseconds(10)); } - std::cout << "Visualizer window closed by user. It will be reopened if we're currently capturing." - << std::endl; - - } while(!acceptEnd); - }); - - // Get the visualizer handle in the main thread - auto visualizerHandle = visualizerFuture.get(); - - while(!visualizerRunning) - { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - std::cout << "Press 'q' in the terminal to quit " << std::endl; - while(visualizerRunning) - { - int key = getKeyNonBlocking(); - if(key == 'q') - { - std::cout << "Closing application because user pressed 'q'" << std::endl; - quitRequested = true; - visualizerHandle->close(); } - else + catch(...) { - acceptEnd = false; - frame = camera.capture2D3D(settings); - visualizerHandle->show(frame); - acceptEnd = true; + captureException = std::current_exception(); + visualizer.close(); } - std::this_thread::sleep_for(std::chrono::milliseconds(10)); + }); + + std::cout << "Running visualizer. Blocking until the window closes or 'q' is pressed." << std::endl; + visualizer.run(); + visualizerRunning = false; + captureThread.join(); + if(captureException) + { + std::rethrow_exception(captureException); } - visualizationThread.join(); std::cout << "Visualizer closed" << std::endl; } catch(const std::exception &e) diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index ed5b7d9f..f44f9d0c 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -157,6 +157,7 @@ set(Clipp_DEPENDING CaptureViaGenICam CaptureWithSettingsFromYML CaptureWritePCLVis3D + Connect ConvertZDF GammaCorrection HandEyeCalibration diff --git a/source/Camera/Basic/Connect/Connect.cpp b/source/Camera/Basic/Connect/Connect.cpp index 4f55aa6f..0adedb00 100644 --- a/source/Camera/Basic/Connect/Connect.cpp +++ b/source/Camera/Basic/Connect/Connect.cpp @@ -1,15 +1,43 @@ /* Connect to a Zivid camera using the different available methods. -Replace the IP address and serial number in the code with the ones of your camera. +Replace the IP address, serial number and hostname in the code with the ones of your camera, +or provide them with --serial, --ip and --hostname. */ #include +#include + #include namespace { + struct CameraIdentifiers + { + std::string serialNumber{ "2020C0DE" }; + std::string ipAddress{ "172.28.60.5" }; + std::string hostname{ "zivid-2020C0DE.local" }; + }; + + CameraIdentifiers parseOptions(int argc, char **argv) + { + CameraIdentifiers identifiers; + auto cli = + (clipp::option("--serial") + & clipp::value("serial number", identifiers.serialNumber).doc("Serial number of the camera"), + clipp::option("--ip") & clipp::value("ip address", identifiers.ipAddress).doc("IP address of the camera"), + clipp::option("--hostname") + & clipp::value("hostname", identifiers.hostname).doc("Hostname of the camera")); + + if(!clipp::parse(argc, argv, cli)) + { + std::cout << clipp::usage_lines(cli, "Connect") << std::endl; + throw std::runtime_error{ "Invalid usage" }; + } + return identifiers; + } + void printDiscoveredCameras(Zivid::Application &zivid) { std::cout << "Discovered cameras:" << std::endl; @@ -21,18 +49,16 @@ namespace } } // namespace -int main() +int main(int argc, char **argv) { try { + const auto identifiers = parseOptions(argc, argv); + Zivid::Application zivid; printDiscoveredCameras(zivid); - std::cout << "The serial number, IP address and hostname below are placeholders. " - "Replace them with the ones of your camera." - << std::endl; - { std::cout << "Connecting to the first available camera" << std::endl; auto camera = zivid.connectCamera(); @@ -40,22 +66,22 @@ int main() } { - std::cout << "Connecting to the camera with a specific serial number" << std::endl; - auto camera = zivid.connectCamera(Zivid::CameraInfo::SerialNumber{ "2020C0DE" }); + std::cout << "Connecting to the camera with serial number " << identifiers.serialNumber << std::endl; + auto camera = zivid.connectCamera(Zivid::CameraInfo::SerialNumber{ identifiers.serialNumber }); camera.disconnect(); } { - std::cout << "Connecting to the camera at a specific IP address" << std::endl; - auto camera = zivid.connectCamera(Zivid::CameraAddress{ "172.28.60.5" }); + std::cout << "Connecting to the camera at IP address " << identifiers.ipAddress << std::endl; + auto camera = zivid.connectCamera(Zivid::CameraAddress{ identifiers.ipAddress }); camera.disconnect(); } { - std::cout << "Connecting to the camera at a specific hostname" << std::endl; + std::cout << "Connecting to the camera at hostname " << identifiers.hostname << std::endl; // The default hostname format is "zivid-.local". // The hostname cannot be read or set through the SDK. - auto camera = zivid.connectCamera(Zivid::CameraAddress{ "zivid-2020C0DE.local" }); + auto camera = zivid.connectCamera(Zivid::CameraAddress{ identifiers.hostname }); camera.disconnect(); }