2 #include <GLFW/glfw3.h>
23 #include <opencv2/imgcodecs.hpp>
24 #include <opencv2/imgproc.hpp>
25 #include <opencv2/photo.hpp>
31 #include <unordered_map>
35 #include <boost/optional.hpp>
38 #include <dynamic_reconfigure/server.h>
39 #include <quori_face/CalibrationConfig.h>
41 #include <yaml-cpp/yaml.h>
51 sensor_msgs::ImageConstPtr latest_image;
58 std::atomic<bool> static_params_updated(
false);
64 .
theta = -M_PI * 0.45,
73 void reconfigureCallback(CalibrationConfig &calibration, uint32_t
level)
75 static bool debounce =
true;
82 static_params.delta.x = calibration.dx;
83 static_params.delta.y = calibration.dy;
85 center.theta = calibration.center_theta;
86 center.psi = calibration.center_psi;
88 min_coord.
theta = center.theta + calibration.min_theta;
89 min_coord.
psi = center.psi + calibration.min_psi;
91 max_coord.
theta = center.theta + calibration.max_theta;
92 max_coord.
psi = center.psi + calibration.max_psi;
94 static_params_updated =
true;
109 const std::unordered_map<std::string, std::uint32_t> ENCODING_GL_MAPPINGS {
114 const std::unordered_map<std::string, std::uint32_t> ENCODING_CV_MAPPINGS {
119 const std::unordered_map<std::string, boost::optional<cv::ColorConversionCodes>> ENCODING_CV_CVT_MAPPINGS {
124 std::size_t encodingSize(
const std::string &encoding)
128 return bitDepth / 8 * numChannels;
131 void mapImage(std::uint8_t *
const data,
const cv::Mat &
image)
133 const std::size_t elementSize =
image.elemSize();
134 for (std::size_t row = 0; row <
image.rows; ++row)
143 int main(
int argc,
char *argv[])
155 boost::recursive_mutex reconfigure_mutex;
156 dynamic_reconfigure::Server<quori_face::CalibrationConfig> reconfigure_server(reconfigure_mutex);
157 reconfigure_server.setCallback(boost::bind(&reconfigureCallback, _1, _2));
159 const auto lookup_table_resolution =
param(pnh,
"lookup_table_resolution", LOOKUP_TABLE_RESOLUTION);
160 const auto image_resolution =
param(pnh,
"image_resolution", IMAGE_RESOLUTION);
161 center =
param(pnh,
"center", center);
163 min_coord = center +
param(pnh,
"min", min_coord);
164 max_coord = center +
param(pnh,
"max", max_coord);
166 const bool update_params =
param(pnh,
"update_params",
false);
170 static_params =
param(pnh,
"transform", static_params);
174 CalibrationConfig config;
175 config.dx = static_params.delta.x;
176 config.dy = static_params.delta.y;
177 config.center_theta = center.theta;
178 config.center_psi = center.psi;
179 config.min_theta = min_coord.
theta - center.theta;
180 config.min_psi = min_coord.
psi - center.psi;
181 config.max_theta = max_coord.
theta - center.theta;
182 config.max_psi = max_coord.
psi - center.psi;
183 reconfigure_server.updateConfig(config);
185 const auto generate_lookup_table = [&]() {
186 const auto start_time = std::chrono::system_clock::now();
187 cout <<
"Updating lookup table (this may take several seconds)...";
191 const auto end_time = std::chrono::system_clock::now();
192 cout <<
" done (took " << std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time).count() <<
"ms)" << endl;
195 GLfloat *lookup_table = generate_lookup_table();
238 size_t image_size = image_resolution.x * image_resolution.y * 3;
239 uint8_t *
const image_texture_data =
new uint8_t[image_size];
240 memset(image_texture_data, 0, image_size);
242 delete[] image_texture_data;
243 const auto lookup_table_texture =
Texture::create(static_params.screen_size.y, static_params.screen_size.x, lookup_table);
248 GLint i_resolution[] = {
249 static_cast<GLint>(static_params.screen_size.x),
250 static_cast<GLint>(static_params.screen_size.y),
259 std::size_t image_pbo_index = 0;
260 std::size_t lookup_table_pbo_index = 0;
261 PixelBufferObject image_pbo(image_resolution.x * image_resolution.y *
sizeof(uint8_t) * 3);
262 PixelBufferObject lookup_table_pbo(lookup_table_resolution.x * lookup_table_resolution.y *
sizeof(
float) * 3);
264 const auto copy_current_image_pbo = [&]()
266 image_texture->bind();
267 image_pbo.
bind(image_pbo_index);
273 const auto write_next_image_pbo = [&](
const cv::Mat &
image)
275 image_pbo.
bind(image_pbo_index + 1);
288 sensor_msgs::ImageConstPtr prev_image;
290 while (!window->isClosed() &&
ros::ok())
294 if (!latest_image)
continue;
295 if (latest_image == prev_image)
continue;
297 const auto &encoding = override_image_encoding.empty() ? latest_image->encoding : override_image_encoding;
299 const auto cv_it = ENCODING_CV_MAPPINGS.find(encoding);
300 if (cv_it == ENCODING_CV_MAPPINGS.cend())
302 cerr <<
"Unsupported image encoding (no CV encoding) \"" << encoding <<
"\"" << endl;
308 cv::Size(latest_image->width, latest_image->height),
311 const_cast<uint8_t *
>(latest_image->data.data()),
315 const auto cvt_it = ENCODING_CV_CVT_MAPPINGS.find(encoding);
316 if (cvt_it == ENCODING_CV_CVT_MAPPINGS.cend())
318 cerr <<
"Unsupported image encoding (no conversion) \"" << encoding <<
"\"" << endl;
329 cv::cvtColor(
image, final_image, cvt_it->second.get());
332 if (final_image.rows != image_resolution.y || final_image.cols != image_resolution.x)
335 cv::resize(final_image, resized, cv::Size(image_resolution.x, image_resolution.y));
336 final_image = resized;
339 prev_image = latest_image;
341 if (static_params_updated)
343 static_params_updated =
false;
344 GLfloat *
const next_lookup_table = generate_lookup_table();
349 lookup_table_texture->bind();
351 delete[] lookup_table;
352 lookup_table = next_lookup_table;
365 copy_current_image_pbo();
366 write_next_image_pbo(final_image);
371 lookup_table_texture->bind();
374 image_texture->bind();
380 window->swapBuffers();
391 delete[] lookup_table;
400 ROS_ERROR(
"Failed to update parameter file. quori_face package not found.");
404 std::ofstream out(
path +
"/config/params.yaml");
408 ROS_ERROR(
"Failed to update parameter file. Couldn't open parameter file for writing.");
413 delta[
"x"] = static_params.delta.x;
414 delta[
"y"] = static_params.delta.y;
416 YAML::Node screen_size;
417 screen_size[
"x"] = static_params.screen_size.x;
418 screen_size[
"y"] = static_params.screen_size.y;
426 transform[
"epsilon"] = static_params.epsilon;
430 YAML::Node lookup_table_resolution_node;
431 lookup_table_resolution_node[
"x"] = lookup_table_resolution.
x;
432 lookup_table_resolution_node[
"y"] = lookup_table_resolution.y;
434 YAML::Node image_resolution_node;
435 image_resolution_node[
"x"] = image_resolution.x;
436 image_resolution_node[
"y"] = image_resolution.y;
439 min_node[
"theta"] = (min_coord.
theta - center.theta);
440 min_node[
"psi"] = (min_coord.
psi - center.psi);
443 max_node[
"theta"] = (max_coord.
theta - center.theta);
444 max_node[
"psi"] = (max_coord.
psi - center.psi);
446 YAML::Node center_node;
447 center_node[
"theta"] = center.theta;
448 center_node[
"psi"] = center.psi;
452 root[
"lookup_table_resolution"] = lookup_table_resolution_node;
453 root[
"image_resolution"] = image_resolution_node;
454 root[
"max"] = max_node;
455 root[
"min"] = min_node;
456 root[
"center"] = center_node;
459 YAML::Emitter emitter;
462 out << emitter.c_str();