IRSOL
C++ code implementing socket server for interacting with Baumer camera.
interface.cpp
Go to the documentation of this file.
2
3#include "irsol/assert.hpp"
4#include "irsol/logging.hpp"
5#include "irsol/utils.hpp"
6
7#include <neoapi/neoapi.hpp>
8#include <tabulate/table.hpp>
9
10namespace irsol {
11namespace camera {
12
13Interface::Interface(NeoAPI::Cam cam): m_cam(cam)
14{
15
16 // Here we configure the camera settings so that we can trigger it on-demand via software
17 // triggers.
18 IRSOL_LOG_INFO("Configuring camera for manual trigger via software events");
19 setMultiParam({{"TriggerMode", {"On"}}, // Enable software trigger
20 {"AcquisitionMode", {"SingleFrame"}}, // Take a single frame, only when triggered
21 {"TriggerSource", {"Software"}}});
22
23 // Here we set the exposure parameters, so that they can be controlled via software
24 IRSOL_LOG_INFO("Configuring camera for manual exposure");
26 {"ExposureAuto", {"Off"}}, // Disable automatic exposure
27 {"ExposureMode", {"Timed"}}, // Exposure mode: timed
28 });
30 // Store the current exposure of the camera
32
33 // Here we configure the default bit-depth
34 IRSOL_LOG_INFO("Setting bit-depth to 12bits/pixel");
35 auto setPixelFormat = setParam("PixelFormat", "Mono12");
37 setPixelFormat == "Mono12", "Pixel format is not 'Mono12', but is %s", setPixelFormat.c_str());
38}
39
40Interface::Interface(Interface&& other): m_cam(other.m_cam) {}
43{
44 m_cam = other.m_cam;
45 return *this;
46}
47
50{
52
53 Interface interface(cam);
54 interface.setMultiParam({{"BinningVertical", {1}},
55 {"BinningVerticalMode", {"Sum"}},
56 {"BinningHorizontal", {1}},
57 {"BinningHorizontalMode", {"Sum"}}});
58 interface.resetSensorArea();
59 return interface;
60}
61
64{
66
67 Interface interface(cam);
68 // For 'HalfResolution' we bin in both vertical and horizontal direction.
69 interface.setMultiParam({{"BinningVertical", {2}},
70 {"BinningVerticalMode", {"Average"}},
71 {"BinningHorizontal", {2}},
72 {"BinningHorizontalMode", {"Average"}}});
73 interface.resetSensorArea();
74
75 return interface;
76}
77
78std::string
80{
81 auto info = m_cam.GetInfo();
82 const auto model = info.GetModelName();
83 const auto camId = info.GetId();
84 const auto serial = info.GetSerialNumber();
85 const auto tlType = info.GetTLType();
86 const auto vendor = info.GetVendorName();
87 const auto usb3VisionGuid = info.GetUSB3VisionGUID();
88 const auto usbPortId = info.GetUSBPortID();
89 const auto gevIpAddress = info.GetGevIpAddress();
90 const auto gevSubnetMask = info.GetGevSubnetMask();
91 const auto gevGateway = info.GetGevGateway();
92 const auto gevMacAddress = info.GetGevMACAddress();
93
94 tabulate::Table camInfo;
95 camInfo.add_row({"Name", "Value"});
96 camInfo.add_row({"Camera Model Name", model.c_str()});
97 camInfo.add_row({"Camera ID", camId.c_str()});
98 camInfo.add_row({"Camera Serial Number", serial.c_str()});
99 camInfo.add_row({"Camera Transport Layer Type", tlType.c_str()});
100 camInfo.add_row({"Camera Vendor Name", vendor.c_str()});
101 camInfo.add_row({"Camera USB3 Vision GUID", usb3VisionGuid.c_str()});
102 camInfo.add_row({"Camera USB Port ID", usbPortId.c_str()});
103 camInfo.add_row({"Camera GEV IP Address", gevIpAddress.c_str()});
104 camInfo.add_row({"Camera GEV Subnet Mask", gevSubnetMask.c_str()});
105 camInfo.add_row({"Camera GEV Gateway", gevGateway.c_str()});
106 camInfo.add_row({"Camera GEV MAC Address", gevMacAddress.c_str()});
107 camInfo.add_row({"Is connectable", info.IsConnectable() ? "true" : "false"});
108
109 camInfo.column(0).format().font_align(tabulate::FontAlign::right);
110 return camInfo.str();
111}
112
113std::string
115{
116 static const char* const FEATURE_NAMES[] = {"AcquisitionMode",
117 "BinningHorizontalMode",
118 "BinningHorizontal",
119 "BinningVerticalMode",
120 "BinningVertical",
121 "DeviceTemperatureStatus",
122 "DeviceTemperature",
123 "ExposureAuto",
124 "ExposureMode",
125 "ExposureTime",
126 "FrameCounter",
127 "Height",
128 "HeightMax",
129 "OffsetX",
130 "OffsetY",
131 "PayloadSize",
132 "PixelFormat",
133 "ReadOutTime",
134 "ReverseX",
135 "ReverseY",
136 "TriggerMode",
137 "TriggerOverlap",
138 "Width",
139 "WidthMax"};
140
141 tabulate::Table featureInfo;
142 featureInfo.add_row({"Feature", "Value"});
143
144 for(const auto featureName : FEATURE_NAMES) {
145 std::string featureValue = getParam(featureName);
146 featureInfo.add_row({featureName, featureValue});
147 }
148 featureInfo.column(0).format().font_align(tabulate::FontAlign::right);
149 return featureInfo.str();
150}
151
152NeoAPI::Cam&
154{
155 return m_cam;
156}
157
158void
160{
161 IRSOL_LOG_INFO("Resetting sensor area");
162 int maxWidth = getParam<int>("WidthMax");
163 int maxHeight = getParam<int>("HeightMax");
164
166 {{"Width", {maxWidth}}, {"Height", {maxHeight}}, {"OffsetX", {0}}, {"OffsetY", {0}}});
167}
168
171{
172 auto exposureInMicroSeconds = getParam<int64_t>("ExposureTime");
173 return std::chrono::microseconds(exposureInMicroSeconds);
174}
175
178{
179 IRSOL_ASSERT_ERROR(exposure.count() > 0, "Cannot set non-positive exposure");
180 auto exposureInMicroseconds =
181 std::chrono::duration_cast<std::chrono::microseconds>(exposure).count();
182 auto setExposureInMicroseconds =
183 setParam("ExposureTime", static_cast<int64_t>(exposureInMicroseconds));
184 m_CachedExposureTime = std::chrono::microseconds(setExposureInMicroseconds);
186}
187
188std::string
189Interface::getParam(const std::string& param) const
190{
191 IRSOL_LOG_DEBUG("Getting parameter '{}'", param);
192 try {
193 NeoAPI::NeoString neoParam(param.c_str());
194 auto feature = m_cam.GetFeature(neoParam);
195 return NeoAPI::NeoString(feature).c_str();
196 } catch(const std::exception& e) {
197 IRSOL_LOG_ERROR("Failed to get parameter '{}': {}", param, e.what());
198 return "Unknown";
199 }
200}
201
202void
203Interface::setMultiParam(const std::unordered_map<std::string, camera_param_t>& params)
204{
205 IRSOL_LOG_DEBUG("Setting multiple parameters");
206 std::scoped_lock<std::mutex> lock(m_camMutex);
207 for(const auto& [param, value] : params) {
208 std::visit(
209 [&param, this](auto&& arg) {
210 using U = std::decay_t<decltype(arg)>;
211 IRSOL_LOG_TRACE("Setting parameter '{}' to value '{}'", param, arg);
212 setParamNonThreadSafe<U>(param, arg);
213 },
214 value);
215 }
216}
217
218void
219Interface::trigger(const std::string& param)
220{
221 IRSOL_LOG_TRACE("Triggering camera with parameter '{}'", param);
222 try {
223 NeoAPI::NeoString neoParam(param.c_str());
224 auto feature = m_cam.GetFeature(neoParam);
225 feature.Execute();
226 } catch(const std::exception& e) {
227 IRSOL_LOG_ERROR("Failed to trigger camera with parameter '{}': {}", param, e.what());
228 }
229}
230
232Interface::captureImage(std::optional<irsol::types::duration_t> timeout)
233{
234 std::scoped_lock<std::mutex> lock(m_camMutex);
235
236 // Send software trigger to get an image
237 trigger("AcquisitionStart");
238 trigger("TriggerSoftware");
239 // Wait for image, either using the current cached exposure time with a small buffer
240 // or using the user-provided timeout
241 irsol::types::duration_t actualTimeout = m_CachedExposureTime + std::chrono::milliseconds(200);
242 if(timeout.has_value()) {
244 "User provided a custom timeout of capturing camera of {}",
246 actualTimeout = *timeout;
247 } else {
249 "Using exposure from camera {} with buffer", irsol::utils::durationToString(actualTimeout));
250 }
251
252 uint32_t timeoutMs = static_cast<uint32_t>(
253 std::chrono::duration_cast<std::chrono::milliseconds>(actualTimeout).count());
254 auto image = m_cam.GetImage(timeoutMs);
255 if(image.IsEmpty() || image.GetSize() == 0) {
256 IRSOL_LOG_WARN("Timeout or empty image received.");
257 }
258 trigger("AcquisitionStop");
259 return image;
260}
261} // namespace camera
262} // namespace irsol
Assertion macros and utilities based on the PPK_ASSERT library.
High-level wrapper around the NeoAPI camera for synchronized access.
Definition interface.hpp:61
std::string cameraStatusAsString() const
Get current camera status.
image_t captureImage(std::optional< irsol::types::duration_t > timeout=std::nullopt)
Capture a single image from the camera.
std::mutex m_camMutex
Mutex to protect access to camera parameters and image acquisition.
void trigger(const std::string &param)
Trigger a camera feature (e.g., software trigger).
static Interface HalfResolution()
Factory method to create a camera interface using half sensor resolution.
Definition interface.cpp:63
T setParam(const std::string &param, T value)
Set a camera parameter of arbitrary type T.
T getParam(const std::string &param) const
Retrieve a camera parameter of arbitrary type T.
NeoAPI::Image image_t
Alias for the image type returned by the NeoAPI.
Definition interface.hpp:64
NeoAPI::Cam & getNeoCam()
Access the underlying NeoAPI camera instance.
std::string cameraInfoAsString() const
Get human-readable camera information.
Definition interface.cpp:79
irsol::types::duration_t setExposure(irsol::types::duration_t exposure)
Set the exposure time of the camera.
Interface(NeoAPI::Cam cam=irsol::utils::loadDefaultCamera())
Constructs the Interface by loading the default camera.
Definition interface.cpp:13
static constexpr irsol::types::duration_t DEFAULT_EXPOSURE_TIME
Default exposure time (2 milliseconds) used to initialize the camera.
Definition interface.hpp:70
Interface & operator=(Interface &&other)
Move assignment operator.
Definition interface.cpp:42
void resetSensorArea()
Reset the sensor area to the full sensor dimensions.
void setMultiParam(const std::unordered_map< std::string, camera_param_t > &params)
Set multiple parameters in one call.
static Interface FullResolution()
Factory method to create a camera interface using full sensor resolution.
Definition interface.cpp:49
NeoAPI::Cam m_cam
Internal camera instance from NeoAPI.
irsol::types::duration_t getExposure() const
Get the current exposure time from the camera.
irsol::types::duration_t m_CachedExposureTime
#define IRSOL_ASSERT_ERROR
Error-level assertion macro.
Definition assert.hpp:134
#define IRSOL_ASSERT_FATAL
Fatal-level assertion macro.
Definition assert.hpp:135
#define IRSOL_LOG_INFO(...)
Logs an info-level message using the default logger.
Definition logging.hpp:92
#define IRSOL_LOG_ERROR(...)
Logs an error-level message using the default logger.
Definition logging.hpp:94
#define IRSOL_LOG_WARN(...)
Logs a warning-level message using the default logger.
Definition logging.hpp:93
#define IRSOL_LOG_DEBUG(...)
Logs a debug-level message using the default logger.
Definition logging.hpp:91
#define IRSOL_LOG_TRACE(...)
Logs a trace-level message using the default logger.
Definition logging.hpp:90
High-level wrapper around NeoAPI camera control for the irsol library.
Logging utilities and configuration for the irsol library.
clock_t::duration duration_t
Alias for a duration of time as defined by clock_t.
Definition types.hpp:128
NeoAPI::Cam loadDefaultCamera()
Loads the default camera device.
Definition utils.cpp:196
std::string durationToString(irsol::types::duration_t dr)
Converts a duration to a human-readable string.
Definition utils.cpp:133
auto value
General utility functions used throughout the irsol library.