AzureKinectIRImageProvider.cpp
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * ArmarX is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * ArmarX is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * @package VisionX::ArmarXObjects::AzureKinectIRImageProvider
17 * @author Mirko Wächter
18 * @author Christian R. G. Dreher <c.dreher@kit.edu>
19 * @date 2019
20 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
21 * GNU General Public License
22 */
23
24
26
28
29
30// IVT
31#include <Calibration/Calibration.h>
32#include <Image/ImageProcessor.h>
33
34// ArmarX
39
40// VisionX
44
45namespace
46{
47 /**
48 * @brief Converts a k4a image to an IVT image.
49 * @param color_image
50 * @param result
51 */
52 void
53 k4aToIvtImage(const k4a::image& color_image, ::CByteImage& result)
54 {
55 auto cw = static_cast<unsigned int>(color_image.get_width_pixels());
56 auto ch = static_cast<unsigned int>(color_image.get_height_pixels());
57 ARMARX_CHECK_EQUAL(static_cast<unsigned int>(result.width), cw);
58 ARMARX_CHECK_EQUAL(static_cast<unsigned int>(result.height), ch);
59 auto color_buffer = reinterpret_cast<const unsigned char*>(color_image.get_buffer());
60 auto rgb_buffer_ivt = result.pixels;
61
62 int index_ivt = 0;
63 int index_k4a = 0;
64 for (unsigned int y = 0; y < ch; ++y)
65 {
66 for (unsigned int x = 0; x < cw; ++x)
67 {
68 rgb_buffer_ivt[index_ivt] =
69 float(color_buffer[index_k4a] + color_buffer[index_k4a + 1]) / 2.f;
70 index_ivt += 1;
71 index_k4a += 2;
72 }
73 }
74 }
75} // namespace
76
77namespace visionx
78{
79
85
93
94 void
95 AzureKinectIRImageProvider::onStartCapture(float /* framesPerSecond */)
96 {
97 // Check for devices.
98 const uint32_t DEVICE_COUNT = k4a::device::get_installed_count();
99 if (DEVICE_COUNT == 0)
100 {
101 getArmarXManager()->asyncShutdown();
102 throw armarx::LocalException("No Azure Kinect devices detected!");
103 }
104
105 device = k4a::device::open(K4A_DEVICE_DEFAULT);
106 k4aCalibration = device.get_calibration(config.depth_mode, config.color_resolution);
107
108 transformation = k4a::transformation(k4aCalibration);
109
110 device.start_cameras(&config);
111
112 setMetaInfo("serialNumber", new armarx::Variant(device.get_serialnum()));
113 setMetaInfo("rgbVersion", new armarx::Variant(VersionToString(device.get_version().rgb)));
114 setMetaInfo("depthVersion",
115 new armarx::Variant(VersionToString(device.get_version().depth)));
116 setMetaInfo("depthSensorVersion",
117 new armarx::Variant(VersionToString(device.get_version().depth_sensor)));
118 setMetaInfo("audioVersion",
119 new armarx::Variant(VersionToString(device.get_version().audio)));
120 }
121
122 bool
123 AzureKinectIRImageProvider::capture(void** pp_image_buffers)
124 {
126
127 k4a::capture capture;
128 const std::chrono::milliseconds TIMEOUT{1000};
129
130 bool status;
131 try
132 {
133 status = device.get_capture(&capture, TIMEOUT);
134 }
135 catch (const std::exception&)
136 {
137 ARMARX_WARNING << "Failed to get capture from device. Restarting camera.";
138 StopWatch sw;
139 device.stop_cameras();
140 device.start_cameras(&config);
141 ARMARX_INFO << "Restarting took " << sw.stop() << ".";
142 return false;
143 }
144
145 if (status)
146 {
147 setMetaInfo("temperature", new armarx::Variant(capture.get_temperature_c()));
148
149 const k4a::image irImage = capture.get_ir_image();
150 CByteImage buffer(depthDim.first, depthDim.second, CByteImage::eGrayScale);
151 k4aToIvtImage(irImage, buffer);
152
153 std::memcpy(pp_image_buffers[0], buffer.pixels, 1024 * 1024);
154 return true;
155 }
156 return false;
157 }
158
159 std::string
161 {
162 return "AzureKinectIRImageProvider";
163 }
164
165 std::string
170
171 void
173 {
174 config = K4A_DEVICE_CONFIG_INIT_DISABLE_ALL;
175 auto fps = getProperty<float>("framerate").getValue();
176 if (fps == 5.0f)
177 {
178 config.camera_fps = K4A_FRAMES_PER_SECOND_5;
179 }
180 else if (fps == 15.0f)
181 {
182 config.camera_fps = K4A_FRAMES_PER_SECOND_15;
183 }
184 else if (fps == 30.0f)
185 {
186 config.camera_fps = K4A_FRAMES_PER_SECOND_30;
187 }
188 else
189 {
190 throw armarx::LocalException("Invalid framerate: ")
191 << fps << " - Only framerates 5, 15 and 30 are "
192 << "supported by Azure Kinect.";
193 }
194 frameRate = fps;
195 config.depth_mode = K4A_DEPTH_MODE_PASSIVE_IR;
196 config.color_format = K4A_IMAGE_FORMAT_COLOR_BGRA32;
197 config.color_resolution = K4A_COLOR_RESOLUTION_1080P;
198
199 // This means that we'll only get captures that have both color and depth images, so we don't
200 // need to check if the capture contains a particular type of image.
201 config.synchronized_images_only = true;
202
204 depthDim = GetDepthDimensions(config.depth_mode);
205 auto color_dim = GetColorDimensions(config.color_resolution);
206 ARMARX_INFO << "Depth image size: " << depthDim.first << "x" << depthDim.second;
207 ARMARX_INFO << "Color image size: " << color_dim.first << "x" << color_dim.second;
208
209 setImageFormat(visionx::ImageDimension(depthDim.first, depthDim.second),
210 visionx::eGrayScale,
211 visionx::eBayerPatternGr);
212 resultIRImage.reset(visionx::tools::createByteImage(getImageFormat(), visionx::eRgb));
213 }
214
215 void
219
220 void
224
225 std::string
227 {
228 return std::string();
229 }
230
231 bool
233 {
234 return false;
235 }
236
237 StereoCalibration
239 {
240 using namespace Eigen;
241 using Matrix3fRowMajor = Matrix<float, 3, 3, StorageOptions::RowMajor>;
243
244 const auto convert_calibration =
245 [](const k4a_calibration_camera_t& k4a_calib, float scale = 1.)
246 {
247 MonocularCalibration calibration;
248
249 const k4a_calibration_intrinsic_parameters_t& params = k4a_calib.intrinsics.parameters;
250 calibration.cameraParam.principalPoint = {params.param.cx * scale,
251 params.param.cy * scale};
252 calibration.cameraParam.focalLength = {params.param.fx * scale,
253 params.param.fy * scale};
254 // TODO: Figure out convertions. IVT (Calibration.h) expects 4 parameters:
255 // - The first radial lens distortion parameter.
256 // - The second radial lens distortion parameter.
257 // - The first tangential lens distortion parameter.
258 // - The second tangential lens distortion parameter.
259 // However, the Kinect offers k1-k6 radial distortion coefficients and 2 p1-p2
260 // tangential distortion parameters, which means that k3-k6 are unused.
261 // It is even unclear whether this is correct now, as previously it was a vector of all
262 // 6 k-params, which resulted in failed assertions in TypeMapping.cpp in the function
263 // CStereoCalibration* visionx::tools::convert(const visionx::StereoCalibration& stereoCalibration)
264 // lin 314 at time of this commit.
265 // See: https://microsoft.github.io/Azure-Kinect-Sensor-SDK/master/structk4a__calibration__intrinsic__parameters__t_1_1__param.html
266 calibration.cameraParam.distortion = {
267 params.param.k1,
268 params.param.k2,
269 params.param.p1,
270 params.param.p2,
271 };
272 calibration.cameraParam.width = k4a_calib.resolution_width;
273 calibration.cameraParam.height = k4a_calib.resolution_height;
274 const Matrix3fRowMajor ROTATION =
275 Map<const Matrix3fRowMajor>{k4a_calib.extrinsics.rotation};
276 calibration.cameraParam.rotation = convertEigenMatToVisionX(ROTATION);
277 calibration.cameraParam.translation = {k4a_calib.extrinsics.translation,
278 k4a_calib.extrinsics.translation + 3};
279
280 return calibration;
281 };
282
283 StereoCalibration calibration;
284
285 calibration.calibrationLeft = calibration.calibrationRight =
286 convert_calibration(k4aCalibration.color_camera_calibration);
287
288 calibration.rectificationHomographyLeft = calibration.rectificationHomographyRight =
289 convertEigenMatToVisionX(Matrix3f::Identity());
290
291
292 return calibration;
293 }
294
295
296
298} // namespace visionx
#define float
Definition 16_Level.h:22
#define ARMARX_REGISTER_COMPONENT_EXECUTABLE(ComponentT, applicationName)
Definition Decoupled.h:29
Eigen::Matrix< T, 3, 3 > Matrix
std::string getConfigIdentifier()
Retrieve config identifier for this component as set in constructor.
Definition Component.cpp:90
Property< PropertyType > getProperty(const std::string &name)
void setMetaInfo(const std::string &id, const VariantBasePtr &value)
Allows to set meta information that can be queried live via Ice interface on the ArmarXManager.
ArmarXManagerPtr getArmarXManager() const
Returns the ArmarX manager used to add and remove components.
std::string prefix
Prefix of the properties such as namespace, domain, component name, etc.
The Variant class is described here: Variants.
Definition Variant.h:224
Measures the passed time between the construction or calling reset() and stop().
Definition StopWatch.h:42
Brief description of class AzureKinectIRImageProvider.
bool capture(void **pp_image_buffers) override
Main capturing function.
static std::pair< int, int > GetDepthDimensions(const k4a_depth_mode_t depth_mode)
void onStartCapture(float frames_per_second) override
This is called when the image provider capturing has been started.
static std::pair< int, int > GetColorDimensions(const k4a_color_resolution_t resolution)
virtual armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
static std::string VersionToString(const k4a_version_t &version)
bool getImagesAreUndistorted(const Ice::Current &current) override
void onStopCapture() override
This is called when the image provider capturing has been stopped.
void onExitCapturingImageProvider() override
This is called when the Component::onExitComponent() setup is called.
std::string getReferenceFrame(const Ice::Current &current) override
StereoCalibration getStereoCalibration(const Ice::Current &current) override
void onInitCapturingImageProvider() override
This is called when the Component::onInitComponent() is called.
std::string getDefaultName() const override
Retrieve default name of component.
ImageFormatInfo getImageFormat(const Ice::Current &c=Ice::emptyCurrent) override
Returns the entire image format info struct via Ice.
void setImageFormat(ImageDimension imageDimension, ImageType imageType, BayerPatternType bayerPatternType=visionx::eBayerPatternRg)
Sets the image basic format data.
void setNumberImages(int numberImages)
Sets the number of images on each capture.
#define ARMARX_CHECK_EQUAL(lhs, rhs)
This macro evaluates whether lhs is equal (==) rhs and if it turns out to be false it will throw an E...
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:193
This file offers overloads of toIce() and fromIce() functions for STL container types.
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
CByteImage * createByteImage(const ImageFormatInfo &imageFormat, const ImageType imageType)
Creates a ByteImage for the destination type specified in the given imageProviderInfo.
visionx::types::Mat convertEigenMatToVisionX(Eigen::MatrixXf m)
ArmarX headers.