SMACC2
cv_mat_sensor_msgs_image_type_adapter.cpp
Go to the documentation of this file.
1// Copyright 2021 Open Source Robotics Foundation, Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include <cstddef>
16#include <memory>
17#include <string>
18#include <utility>
19#include <variant> // NOLINT[build/include_order]
20
21#include "opencv2/core/mat.hpp"
22
23#include "sensor_msgs/msg/image.hpp"
24#include "std_msgs/msg/header.hpp"
25
27
28namespace image_tools
29{
30
31namespace
32{
33int
34encoding2mat_type(const std::string & encoding)
35{
36 if (encoding == "mono8") {
37 return CV_8UC1;
38 } else if (encoding == "bgr8") {
39 return CV_8UC3;
40 } else if (encoding == "mono16") {
41 return CV_16SC1;
42 } else if (encoding == "rgba8") {
43 return CV_8UC4;
44 } else if (encoding == "bgra8") {
45 return CV_8UC4;
46 } else if (encoding == "32FC1") {
47 return CV_32FC1;
48 } else if (encoding == "rgb8") {
49 return CV_8UC3;
50 } else if (encoding == "yuv422") {
51 return CV_8UC2;
52 } else {
53 throw std::runtime_error("Unsupported encoding type");
54 }
55}
56
57template<typename T>
58struct NotNull
59{
60 NotNull(const T * pointer_in, const char * msg)
61 : pointer(pointer_in)
62 {
63 if (pointer == nullptr) {
64 throw std::invalid_argument(msg);
65 }
66 }
67
68 const T * pointer;
69};
70
71} // namespace
72
74 std::unique_ptr<sensor_msgs::msg::Image> unique_sensor_msgs_image)
75: header_(NotNull(
76 unique_sensor_msgs_image.get(),
77 "unique_sensor_msgs_image cannot be nullptr"
78).pointer->header),
79 frame_(
80 unique_sensor_msgs_image->height,
81 unique_sensor_msgs_image->width,
82 encoding2mat_type(unique_sensor_msgs_image->encoding),
83 unique_sensor_msgs_image->data.data(),
84 unique_sensor_msgs_image->step),
85 storage_(std::move(unique_sensor_msgs_image))
86{}
87
89 std::shared_ptr<sensor_msgs::msg::Image> shared_sensor_msgs_image)
90: header_(shared_sensor_msgs_image->header),
91 frame_(
92 shared_sensor_msgs_image->height,
93 shared_sensor_msgs_image->width,
94 encoding2mat_type(shared_sensor_msgs_image->encoding),
95 shared_sensor_msgs_image->data.data(),
96 shared_sensor_msgs_image->step),
97 storage_(shared_sensor_msgs_image)
98{}
99
101 const cv::Mat & mat_frame,
102 const std_msgs::msg::Header & header,
103 bool is_bigendian)
104: header_(header),
105 frame_(mat_frame),
106 storage_(nullptr),
107 is_bigendian_(is_bigendian)
108{}
109
111 cv::Mat && mat_frame,
112 const std_msgs::msg::Header & header,
113 bool is_bigendian)
114: header_(header),
115 frame_(std::forward<cv::Mat>(mat_frame)),
116 storage_(nullptr),
117 is_bigendian_(is_bigendian)
118{}
119
121 const sensor_msgs::msg::Image & sensor_msgs_image)
122: ROSCvMatContainer(std::make_unique<sensor_msgs::msg::Image>(sensor_msgs_image))
123{}
124
125bool
127{
128 return std::holds_alternative<std::nullptr_t>(storage_);
129}
130
131const cv::Mat &
133{
134 return frame_;
135}
136
137cv::Mat
139{
140 return frame_;
141}
142
143const std_msgs::msg::Header &
145{
146 return header_;
147}
148
149std_msgs::msg::Header &
151{
152 return header_;
153}
154
155std::shared_ptr<const sensor_msgs::msg::Image>
157{
158 if (!std::holds_alternative<std::shared_ptr<sensor_msgs::msg::Image>>(storage_)) {
159 return nullptr;
160 }
161 return std::get<std::shared_ptr<sensor_msgs::msg::Image>>(storage_);
162}
163
164std::unique_ptr<sensor_msgs::msg::Image>
166{
167 auto unique_image = std::make_unique<sensor_msgs::msg::Image>();
168 this->get_sensor_msgs_msg_image_copy(*unique_image);
169 return unique_image;
170}
171
172void
174 sensor_msgs::msg::Image & sensor_msgs_image) const
175{
176 sensor_msgs_image.height = frame_.rows;
177 sensor_msgs_image.width = frame_.cols;
178 switch (frame_.type()) {
179 case CV_8UC1:
180 sensor_msgs_image.encoding = "mono8";
181 break;
182 case CV_8UC3:
183 sensor_msgs_image.encoding = "bgr8";
184 break;
185 case CV_16SC1:
186 sensor_msgs_image.encoding = "mono16";
187 break;
188 case CV_8UC4:
189 sensor_msgs_image.encoding = "rgba8";
190 break;
191 default:
192 throw std::runtime_error("unsupported encoding type");
193 }
194 sensor_msgs_image.step = static_cast<sensor_msgs::msg::Image::_step_type>(frame_.step);
195 size_t size = frame_.step * frame_.rows;
196 sensor_msgs_image.data.resize(size);
197 memcpy(&sensor_msgs_image.data[0], frame_.data, size);
198 sensor_msgs_image.header = header_;
199}
200
201bool
203{
204 return is_bigendian_;
205}
206
207} // namespace image_tools
A potentially owning, potentially non-owning, container of a cv::Mat and ROS header.
IMAGE_TOOLS_PUBLIC sensor_msgs::msg::Image get_sensor_msgs_msg_image_copy() const
Get a copy of the image as a sensor_msgs::msg::Image.
IMAGE_TOOLS_PUBLIC bool is_bigendian() const
Return true if the data is stored in big endian, otherwise return false.
IMAGE_TOOLS_PUBLIC std::unique_ptr< sensor_msgs::msg::Image > get_sensor_msgs_msg_image_pointer_copy() const
Get copy as a unique pointer to the sensor_msgs::msg::Image.
IMAGE_TOOLS_PUBLIC bool is_owning() const
Return true if this class owns the data the cv_mat references.
IMAGE_TOOLS_PUBLIC std::shared_ptr< const sensor_msgs::msg::Image > get_sensor_msgs_msg_image_pointer() const
Get shared const pointer to the sensor_msgs::msg::Image if available, otherwise nullptr.
IMAGE_TOOLS_PUBLIC ROSCvMatContainer()=default
IMAGE_TOOLS_PUBLIC const std_msgs::msg::Header & header() const
Const access the ROS Header.
IMAGE_TOOLS_PUBLIC const cv::Mat & cv_mat() const
Const access the cv::Mat in this class.