mirror of
https://github.com/orbbec/OrbbecSDK_ROS2.git
synced 2026-10-04 20:17:47 +08:00
Merge branch 'fix/undistortion' into v2-main
This commit is contained in:
@@ -3085,6 +3085,10 @@ void OBCameraNode::setupPublishers() {
|
||||
camera_info_qos_profile));
|
||||
}
|
||||
if (stream_index == COLOR && enable_color_undistortion_) {
|
||||
color_undistortion_camera_info_publisher_ = node_->create_publisher<CameraInfo>(
|
||||
"color/camera_info_undistorted",
|
||||
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(camera_info_qos_profile),
|
||||
camera_info_qos_profile));
|
||||
if (use_intra_process_) {
|
||||
color_undistortion_publisher_ = std::make_shared<image_rcl_publisher>(
|
||||
*node_, "color/image_undistorted", image_qos_profile);
|
||||
@@ -4299,11 +4303,28 @@ void OBCameraNode::onNewFrameCallback(const std::shared_ptr<ob::Frame> &frame,
|
||||
undistorted_image_msg->step = width * unit_step_size_[stream_index];
|
||||
undistorted_image_msg->header.frame_id = frame_id;
|
||||
color_undistortion_publisher_->publish(std::move(undistorted_image_msg));
|
||||
// Update intrinsic with the new camera matrix from undistortion
|
||||
camera_info.p.at(0) = undistort_result.new_intrinsic.fx;
|
||||
camera_info.p.at(5) = undistort_result.new_intrinsic.fy;
|
||||
camera_info.p.at(2) = undistort_result.new_intrinsic.cx;
|
||||
camera_info.p.at(6) = undistort_result.new_intrinsic.cy;
|
||||
|
||||
if (color_undistortion_camera_info_publisher_) {
|
||||
auto undistorted_camera_info = camera_info;
|
||||
const auto distortion_coeff_count =
|
||||
undistorted_camera_info.d.empty() ? 5 : undistorted_camera_info.d.size();
|
||||
undistorted_camera_info.d.assign(distortion_coeff_count, 0.0);
|
||||
undistorted_camera_info.distortion_model = sensor_msgs::distortion_models::PLUMB_BOB;
|
||||
undistorted_camera_info.roi.do_rectify = false;
|
||||
undistorted_camera_info.k.fill(0.0);
|
||||
undistorted_camera_info.k.at(0) = undistort_result.new_intrinsic.fx;
|
||||
undistorted_camera_info.k.at(4) = undistort_result.new_intrinsic.fy;
|
||||
undistorted_camera_info.k.at(2) = undistort_result.new_intrinsic.cx;
|
||||
undistorted_camera_info.k.at(5) = undistort_result.new_intrinsic.cy;
|
||||
undistorted_camera_info.k.at(8) = 1.0;
|
||||
undistorted_camera_info.p.fill(0.0);
|
||||
undistorted_camera_info.p.at(0) = undistort_result.new_intrinsic.fx;
|
||||
undistorted_camera_info.p.at(5) = undistort_result.new_intrinsic.fy;
|
||||
undistorted_camera_info.p.at(2) = undistort_result.new_intrinsic.cx;
|
||||
undistorted_camera_info.p.at(6) = undistort_result.new_intrinsic.cy;
|
||||
undistorted_camera_info.p.at(10) = 1.0;
|
||||
color_undistortion_camera_info_publisher_->publish(undistorted_camera_info);
|
||||
}
|
||||
}
|
||||
|
||||
CHECK(camera_info_publishers_.count(stream_index) > 0);
|
||||
@@ -4314,23 +4335,25 @@ void OBCameraNode::onNewFrameCallback(const std::shared_ptr<ob::Frame> &frame,
|
||||
auto depth_scale = video_frame->as<ob::DepthFrame>()->getValueScale();
|
||||
image = image * depth_scale;
|
||||
}
|
||||
sensor_msgs::msg::Image::UniquePtr image_msg(new sensor_msgs::msg::Image());
|
||||
|
||||
cv_bridge::CvImage(std_msgs::msg::Header(), encoding_[stream_index], image)
|
||||
.toImageMsg(*image_msg);
|
||||
CHECK_NOTNULL(image_msg.get());
|
||||
image_msg->header.stamp = timestamp;
|
||||
image_msg->is_bigendian = false;
|
||||
image_msg->step = width * unit_step_size_[stream_index];
|
||||
image_msg->header.frame_id = frame_id;
|
||||
CHECK(image_publishers_.count(stream_index) > 0);
|
||||
saveImageToFile(stream_index, image, *image_msg);
|
||||
if (stream_index == COLOR) {
|
||||
fps_delay_status_color_->tick(frame_timestamp);
|
||||
} else if (stream_index == DEPTH) {
|
||||
fps_delay_status_depth_->tick(frame_timestamp);
|
||||
}
|
||||
if (has_raw_image_subscriber) {
|
||||
if (has_raw_image_subscriber || save_images_[stream_index]) {
|
||||
sensor_msgs::msg::Image::UniquePtr image_msg(new sensor_msgs::msg::Image());
|
||||
cv_bridge::CvImage(std_msgs::msg::Header(), encoding_[stream_index], image)
|
||||
.toImageMsg(*image_msg);
|
||||
CHECK_NOTNULL(image_msg.get());
|
||||
image_msg->header.stamp = timestamp;
|
||||
image_msg->is_bigendian = false;
|
||||
image_msg->step = width * unit_step_size_[stream_index];
|
||||
image_msg->header.frame_id = frame_id;
|
||||
saveImageToFile(stream_index, image, *image_msg);
|
||||
if (!has_raw_image_subscriber) {
|
||||
return;
|
||||
}
|
||||
if (frame_timestamp_csv_logger_ && frame_timestamp_csv_logger_->enabled() &&
|
||||
(stream_index == COLOR || stream_index == DEPTH)) {
|
||||
frame_timestamp_csv_logger_->recordPreImagePublish(stream_index.first, frame,
|
||||
|
||||
+72
-20
@@ -14,7 +14,10 @@
|
||||
* limitations under the License.
|
||||
*******************************************************************************/
|
||||
|
||||
#include <algorithm>
|
||||
#include <mutex>
|
||||
#include <regex>
|
||||
#include <vector>
|
||||
#include "orbbec_camera/utils.h"
|
||||
#include <sensor_msgs/point_cloud2_iterator.hpp>
|
||||
#include "orbbec_camera/constants.h"
|
||||
@@ -995,30 +998,79 @@ OBStreamType obStreamTypeFromString(const std::string &stream_type) {
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
bool isSameIntrinsic(const OBCameraIntrinsic &lhs, const OBCameraIntrinsic &rhs) {
|
||||
return lhs.fx == rhs.fx && lhs.fy == rhs.fy && lhs.cx == rhs.cx && lhs.cy == rhs.cy &&
|
||||
lhs.width == rhs.width && lhs.height == rhs.height;
|
||||
}
|
||||
|
||||
bool isSameDistortion(const OBCameraDistortion &lhs, const OBCameraDistortion &rhs) {
|
||||
return lhs.model == rhs.model && lhs.k1 == rhs.k1 && lhs.k2 == rhs.k2 && lhs.k3 == rhs.k3 &&
|
||||
lhs.k4 == rhs.k4 && lhs.k5 == rhs.k5 && lhs.k6 == rhs.k6 && lhs.p1 == rhs.p1 &&
|
||||
lhs.p2 == rhs.p2;
|
||||
}
|
||||
|
||||
struct UndistortMapCacheEntry {
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
int image_type = 0;
|
||||
OBCameraIntrinsic intrinsic{};
|
||||
OBCameraDistortion distortion{};
|
||||
cv::Mat map1;
|
||||
cv::Mat map2;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
UndistortedImageResult undistortImage(const cv::Mat &image, const OBCameraIntrinsic &intrinsic,
|
||||
const OBCameraDistortion &distortion) {
|
||||
UndistortedImageResult result;
|
||||
cv::Mat camera_matrix = cv::Mat::eye(3, 3, CV_64F);
|
||||
camera_matrix.at<double>(0, 0) = intrinsic.fx;
|
||||
camera_matrix.at<double>(1, 1) = intrinsic.fy;
|
||||
camera_matrix.at<double>(0, 2) = intrinsic.cx;
|
||||
camera_matrix.at<double>(1, 2) = intrinsic.cy;
|
||||
result.new_intrinsic = intrinsic;
|
||||
|
||||
// Create the distortion coefficients matrix using the extended distortion model
|
||||
cv::Mat dist_coeffs = (cv::Mat_<float>(8, 1) << distortion.k1, distortion.k2, distortion.p1,
|
||||
distortion.p2, distortion.k3, distortion.k4, distortion.k5, distortion.k6);
|
||||
cv::Size image_size(image.cols, image.rows);
|
||||
// cv::Mat new_camera_matrix =
|
||||
// cv::getOptimalNewCameraMatrix(camera_matrix, dist_coeffs, image_size, 0.0, image_size);
|
||||
// Undistort the image using the new camera matrix
|
||||
// cv::undistort(image, result.image, camera_matrix, dist_coeffs, new_camera_matrix);
|
||||
cv::undistort(image, result.image, camera_matrix, dist_coeffs);
|
||||
// Update the intrinsic parameters with the new camera matrix
|
||||
result.new_intrinsic = intrinsic; // Copy original values first
|
||||
// result.new_intrinsic.fx = new_camera_matrix.at<double>(0, 0);
|
||||
// result.new_intrinsic.fy = new_camera_matrix.at<double>(1, 1);
|
||||
// result.new_intrinsic.cx = new_camera_matrix.at<double>(0, 2);
|
||||
// result.new_intrinsic.cy = new_camera_matrix.at<double>(1, 2);
|
||||
if (image.empty()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
cv::Mat map1;
|
||||
cv::Mat map2;
|
||||
{
|
||||
static std::mutex cache_mutex;
|
||||
static std::vector<UndistortMapCacheEntry> map_cache;
|
||||
|
||||
std::lock_guard<std::mutex> lock(cache_mutex);
|
||||
auto cache_it = std::find_if(
|
||||
map_cache.begin(), map_cache.end(), [&](const UndistortMapCacheEntry &entry) {
|
||||
return entry.width == image.cols && entry.height == image.rows &&
|
||||
entry.image_type == image.type() && isSameIntrinsic(entry.intrinsic, intrinsic) &&
|
||||
isSameDistortion(entry.distortion, distortion);
|
||||
});
|
||||
|
||||
if (cache_it == map_cache.end()) {
|
||||
UndistortMapCacheEntry entry;
|
||||
entry.width = image.cols;
|
||||
entry.height = image.rows;
|
||||
entry.image_type = image.type();
|
||||
entry.intrinsic = intrinsic;
|
||||
entry.distortion = distortion;
|
||||
|
||||
cv::Mat camera_matrix =
|
||||
(cv::Mat_<double>(3, 3) << intrinsic.fx, 0.0, intrinsic.cx, 0.0, intrinsic.fy,
|
||||
intrinsic.cy, 0.0, 0.0, 1.0);
|
||||
cv::Mat dist_coeffs =
|
||||
(cv::Mat_<double>(8, 1) << distortion.k1, distortion.k2, distortion.p1, distortion.p2,
|
||||
distortion.k3, distortion.k4, distortion.k5, distortion.k6);
|
||||
cv::initUndistortRectifyMap(camera_matrix, dist_coeffs, cv::Mat(), camera_matrix,
|
||||
cv::Size(image.cols, image.rows), CV_16SC2, entry.map1,
|
||||
entry.map2);
|
||||
map_cache.emplace_back(std::move(entry));
|
||||
cache_it = std::prev(map_cache.end());
|
||||
}
|
||||
|
||||
map1 = cache_it->map1;
|
||||
map2 = cache_it->map2;
|
||||
}
|
||||
|
||||
result.image.create(image.size(), image.type());
|
||||
cv::remap(image, result.image, map1, map2, cv::INTER_LINEAR);
|
||||
result.new_intrinsic.width = image.cols;
|
||||
result.new_intrinsic.height = image.rows;
|
||||
return result;
|
||||
|
||||
Reference in New Issue
Block a user