36 #include "boost/endian/conversion.hpp" 40 #include <boost/make_shared.hpp> 41 #include <boost/regex.hpp> 43 #include <opencv2/imgcodecs.hpp> 44 #include <opencv2/imgproc/imgproc.hpp> 58 }
else if (depth ==
"8S") {
60 }
else if (depth ==
"16U") {
62 }
else if (depth ==
"16S") {
64 }
else if (depth ==
"32S") {
66 }
else if (depth ==
"32F") {
75 if (encoding == enc::BGR8)
return CV_8UC3;
76 if (encoding == enc::MONO8)
return CV_8UC1;
77 if (encoding == enc::RGB8)
return CV_8UC3;
78 if (encoding == enc::MONO16)
return CV_16UC1;
79 if (encoding == enc::BGR16)
return CV_16UC3;
80 if (encoding == enc::RGB16)
return CV_16UC3;
81 if (encoding == enc::BGRA8)
return CV_8UC4;
82 if (encoding == enc::RGBA8)
return CV_8UC4;
83 if (encoding == enc::BGRA16)
return CV_16UC4;
84 if (encoding == enc::RGBA16)
return CV_16UC4;
87 if (encoding == enc::BAYER_RGGB8)
return CV_8UC1;
88 if (encoding == enc::BAYER_BGGR8)
return CV_8UC1;
89 if (encoding == enc::BAYER_GBRG8)
return CV_8UC1;
90 if (encoding == enc::BAYER_GRBG8)
return CV_8UC1;
91 if (encoding == enc::BAYER_RGGB16)
return CV_16UC1;
92 if (encoding == enc::BAYER_BGGR16)
return CV_16UC1;
93 if (encoding == enc::BAYER_GBRG16)
return CV_16UC1;
94 if (encoding == enc::BAYER_GRBG16)
return CV_16UC1;
97 if (encoding == enc::YUV422)
return CV_8UC2;
102 if (boost::regex_match(encoding.c_str(), m,
103 boost::regex(
"(8U|8S|16U|16S|32S|32F|64F)C([0-9]+)"))) {
104 return CV_MAKETYPE(
depthStrToInt(m[1].str()), atoi(m[2].str().c_str()));
107 if (boost::regex_match(encoding.c_str(), m,
108 boost::regex(
"(8U|8S|16U|16S|32S|32F|64F)"))) {
112 throw Exception(
"Unrecognized image encoding [" + encoding +
"]");
117 enum Encoding { INVALID = -1,
GRAY = 0, RGB, BGR, RGBA, BGRA,
YUV422, BAYER_RGGB, BAYER_BGGR, BAYER_GBRG, BAYER_GRBG};
119 Encoding getEncoding(
const std::string& encoding)
121 if ((encoding == enc::MONO8) || (encoding == enc::MONO16))
return GRAY;
122 if ((encoding == enc::BGR8) || (encoding == enc::BGR16))
return BGR;
123 if ((encoding == enc::RGB8) || (encoding == enc::RGB16))
return RGB;
124 if ((encoding == enc::BGRA8) || (encoding == enc::BGRA16))
return BGRA;
125 if ((encoding == enc::RGBA8) || (encoding == enc::RGBA16))
return RGBA;
126 if (encoding == enc::YUV422)
return YUV422;
128 if ((encoding == enc::BAYER_RGGB8) || (encoding == enc::BAYER_RGGB16))
return BAYER_RGGB;
129 if ((encoding == enc::BAYER_BGGR8) || (encoding == enc::BAYER_BGGR16))
return BAYER_BGGR;
130 if ((encoding == enc::BAYER_GBRG8) || (encoding == enc::BAYER_GBRG16))
return BAYER_GBRG;
131 if ((encoding == enc::BAYER_GRBG8) || (encoding == enc::BAYER_GRBG16))
return BAYER_GRBG;
137 static const int SAME_FORMAT = -1;
143 std::map<std::pair<Encoding, Encoding>, std::vector<int> > getConversionCodes() {
144 std::map<std::pair<Encoding, Encoding>, std::vector<int> > res;
145 for(
int i=0; i<=5; ++i)
146 res[std::pair<Encoding, Encoding>(Encoding(i),Encoding(i))].push_back(SAME_FORMAT);
148 res[std::make_pair(
GRAY, RGB)].push_back(cv::COLOR_GRAY2RGB);
149 res[std::make_pair(
GRAY, BGR)].push_back(cv::COLOR_GRAY2BGR);
150 res[std::make_pair(
GRAY, RGBA)].push_back(cv::COLOR_GRAY2RGBA);
151 res[std::make_pair(
GRAY, BGRA)].push_back(cv::COLOR_GRAY2BGRA);
153 res[std::make_pair(RGB,
GRAY)].push_back(cv::COLOR_RGB2GRAY);
154 res[std::make_pair(RGB, BGR)].push_back(cv::COLOR_RGB2BGR);
155 res[std::make_pair(RGB, RGBA)].push_back(cv::COLOR_RGB2RGBA);
156 res[std::make_pair(RGB, BGRA)].push_back(cv::COLOR_RGB2BGRA);
158 res[std::make_pair(BGR,
GRAY)].push_back(cv::COLOR_BGR2GRAY);
159 res[std::make_pair(BGR, RGB)].push_back(cv::COLOR_BGR2RGB);
160 res[std::make_pair(BGR, RGBA)].push_back(cv::COLOR_BGR2RGBA);
161 res[std::make_pair(BGR, BGRA)].push_back(cv::COLOR_BGR2BGRA);
163 res[std::make_pair(RGBA,
GRAY)].push_back(cv::COLOR_RGBA2GRAY);
164 res[std::make_pair(RGBA, RGB)].push_back(cv::COLOR_RGBA2RGB);
165 res[std::make_pair(RGBA, BGR)].push_back(cv::COLOR_RGBA2BGR);
166 res[std::make_pair(RGBA, BGRA)].push_back(cv::COLOR_RGBA2BGRA);
168 res[std::make_pair(BGRA,
GRAY)].push_back(cv::COLOR_BGRA2GRAY);
169 res[std::make_pair(BGRA, RGB)].push_back(cv::COLOR_BGRA2RGB);
170 res[std::make_pair(BGRA, BGR)].push_back(cv::COLOR_BGRA2BGR);
171 res[std::make_pair(BGRA, RGBA)].push_back(cv::COLOR_BGRA2RGBA);
173 res[std::make_pair(
YUV422,
GRAY)].push_back(cv::COLOR_YUV2GRAY_UYVY);
174 res[std::make_pair(
YUV422, RGB)].push_back(cv::COLOR_YUV2RGB_UYVY);
175 res[std::make_pair(
YUV422, BGR)].push_back(cv::COLOR_YUV2BGR_UYVY);
176 res[std::make_pair(
YUV422, RGBA)].push_back(cv::COLOR_YUV2RGBA_UYVY);
177 res[std::make_pair(
YUV422, BGRA)].push_back(cv::COLOR_YUV2BGRA_UYVY);
180 res[std::make_pair(BAYER_RGGB,
GRAY)].push_back(cv::COLOR_BayerBG2GRAY);
181 res[std::make_pair(BAYER_RGGB, RGB)].push_back(cv::COLOR_BayerBG2RGB);
182 res[std::make_pair(BAYER_RGGB, BGR)].push_back(cv::COLOR_BayerBG2BGR);
184 res[std::make_pair(BAYER_BGGR,
GRAY)].push_back(cv::COLOR_BayerRG2GRAY);
185 res[std::make_pair(BAYER_BGGR, RGB)].push_back(cv::COLOR_BayerRG2RGB);
186 res[std::make_pair(BAYER_BGGR, BGR)].push_back(cv::COLOR_BayerRG2BGR);
188 res[std::make_pair(BAYER_GBRG,
GRAY)].push_back(cv::COLOR_BayerGR2GRAY);
189 res[std::make_pair(BAYER_GBRG, RGB)].push_back(cv::COLOR_BayerGR2RGB);
190 res[std::make_pair(BAYER_GBRG, BGR)].push_back(cv::COLOR_BayerGR2BGR);
192 res[std::make_pair(BAYER_GRBG,
GRAY)].push_back(cv::COLOR_BayerGB2GRAY);
193 res[std::make_pair(BAYER_GRBG, RGB)].push_back(cv::COLOR_BayerGB2RGB);
194 res[std::make_pair(BAYER_GRBG, BGR)].push_back(cv::COLOR_BayerGB2BGR);
199 const std::vector<int> getConversionCode(std::string src_encoding, std::string dst_encoding)
201 Encoding src_encod = getEncoding(src_encoding);
202 Encoding dst_encod = getEncoding(dst_encoding);
203 bool is_src_color_format = enc::isColor(src_encoding) || enc::isMono(src_encoding) ||
204 enc::isBayer(src_encoding) || (src_encoding == enc::YUV422);
205 bool is_dst_color_format = enc::isColor(dst_encoding) || enc::isMono(dst_encoding) ||
206 enc::isBayer(dst_encoding) || (dst_encoding == enc::YUV422);
207 bool is_num_channels_the_same = (enc::numChannels(src_encoding) == enc::numChannels(dst_encoding));
211 if (!is_src_color_format) {
212 if (is_dst_color_format)
213 throw Exception(
"[" + src_encoding +
"] is not a color format. but [" + dst_encoding +
214 "] is. The conversion does not make sense");
215 if (!is_num_channels_the_same)
216 throw Exception(
"[" + src_encoding +
"] and [" + dst_encoding +
"] do not have the same number of channel");
217 return std::vector<int>(1, SAME_FORMAT);
222 if (!is_dst_color_format) {
223 if (!is_num_channels_the_same)
224 throw Exception(
"[" + src_encoding +
"] is a color format but [" + dst_encoding +
"] " +
225 "is not so they must have the same OpenCV type, CV_8UC3, CV_16UC1 ....");
226 return std::vector<int>(1, SAME_FORMAT);
230 static const std::map<std::pair<Encoding, Encoding>, std::vector<int> > CONVERSION_CODES = getConversionCodes();
232 std::pair<Encoding, Encoding> key(src_encod, dst_encod);
233 std::map<std::pair<Encoding, Encoding>, std::vector<int> >::const_iterator val = CONVERSION_CODES.find(key);
234 if (val == CONVERSION_CODES.end())
235 throw Exception(
"Unsupported conversion from [" + src_encoding +
236 "] to [" + dst_encoding +
"]");
239 std::vector<int> res = val->second;
240 if ((enc::bitDepth(src_encoding) != enc::bitDepth(dst_encoding)) && (getEncoding(src_encoding) != getEncoding(dst_encoding)))
241 res.push_back(SAME_FORMAT);
249 cv::Mat matFromImage(
const sensor_msgs::Image& source)
251 int source_type =
getCvType(source.encoding);
252 int byte_depth = enc::bitDepth(source.encoding) / 8;
253 int num_channels = enc::numChannels(source.encoding);
255 if (source.step < source.width * byte_depth * num_channels)
257 std::stringstream ss;
258 ss <<
"Image is wrongly formed: step < width * byte_depth * num_channels or " << source.step <<
" != " <<
259 source.width <<
" * " << byte_depth <<
" * " << num_channels;
263 if (source.height * source.step != source.data.size())
265 std::stringstream ss;
266 ss <<
"Image is wrongly formed: height * step != size or " << source.height <<
" * " <<
267 source.step <<
" != " << source.data.size();
272 cv::Mat mat(source.height, source.width, source_type, const_cast<uchar*>(&source.data[0]), source.step);
273 if ((boost::endian::order::native == boost::endian::order::big && source.is_bigendian) ||
274 (boost::endian::order::native == boost::endian::order::little && !source.is_bigendian) ||
279 mat = cv::Mat(source.height, source.width, CV_MAKETYPE(CV_8U, num_channels*byte_depth),
280 const_cast<uchar*>(&source.data[0]), source.step);
281 cv::Mat mat_swap(source.height, source.width, mat.type());
283 std::vector<int> fromTo;
284 fromTo.reserve(num_channels*byte_depth);
285 for(
int i = 0; i < num_channels; ++i)
286 for(
int j = 0; j < byte_depth; ++j)
288 fromTo.push_back(byte_depth*i + j);
289 fromTo.push_back(byte_depth*i + byte_depth - 1 - j);
291 cv::mixChannels(std::vector<cv::Mat>(1, mat), std::vector<cv::Mat>(1, mat_swap), fromTo);
294 mat_swap.reshape(num_channels);
300 CvImagePtr toCvCopyImpl(
const cv::Mat& source,
301 const std_msgs::Header& src_header,
302 const std::string& src_encoding,
303 const std::string& dst_encoding)
306 CvImagePtr ptr = boost::make_shared<CvImage>();
307 ptr->header = src_header;
310 if (dst_encoding.empty() || dst_encoding == src_encoding)
312 ptr->encoding = src_encoding;
313 source.copyTo(ptr->image);
318 const std::vector<int> conversion_codes = getConversionCode(src_encoding, dst_encoding);
319 cv::Mat image1 = source;
321 for(
size_t i=0; i<conversion_codes.size(); ++i) {
322 int conversion_code = conversion_codes[i];
323 if (conversion_code == SAME_FORMAT)
326 int src_depth = enc::bitDepth(src_encoding);
327 int dst_depth = enc::bitDepth(dst_encoding);
329 int image2_type = CV_MAKETYPE(CV_MAT_DEPTH(
getCvType(dst_encoding)), image1.channels());
332 if (src_depth == 8 && dst_depth == 16)
333 image1.convertTo(image2, image2_type, 65535. / 255.);
334 else if (src_depth == 16 && dst_depth == 8)
335 image1.convertTo(image2, image2_type, 255. / 65535.);
337 image1.convertTo(image2, image2_type);
347 ptr->encoding = dst_encoding;
357 sensor_msgs::ImagePtr ptr = boost::make_shared<sensor_msgs::Image>();
364 ros_image.header =
header;
365 ros_image.height =
image.rows;
366 ros_image.width =
image.cols;
368 ros_image.is_bigendian = (boost::endian::order::native == boost::endian::order::big);
369 ros_image.step =
image.cols *
image.elemSize();
370 size_t size = ros_image.step *
image.rows;
371 ros_image.data.resize(size);
373 if (
image.isContinuous())
375 memcpy((
char*)(&ros_image.data[0]),
image.data, size);
380 uchar* ros_data_ptr = (uchar*)(&ros_image.data[0]);
381 uchar* cv_data_ptr =
image.data;
382 for (
int i = 0; i <
image.rows; ++i)
384 memcpy(ros_data_ptr, cv_data_ptr, ros_image.step);
385 ros_data_ptr += ros_image.step;
386 cv_data_ptr +=
image.step;
393 const std::string& encoding)
399 const std::string& encoding)
402 return toCvCopyImpl(matFromImage(source), source.header, source.encoding, encoding);
407 const std::string& encoding)
409 return toCvShare(*source, source, encoding);
414 const std::string& encoding)
417 if ((!encoding.empty() && source.encoding !=
encoding) || (source.is_bigendian &&
418 (boost::endian::order::native != boost::endian::order::big)))
421 CvImagePtr ptr = boost::make_shared<CvImage>();
422 ptr->header = source.header;
423 ptr->encoding = source.encoding;
424 ptr->tracked_object_ = tracked_object;
425 ptr->image = matFromImage(source);
430 const std::string& encoding)
432 return toCvCopyImpl(source->image, source->header, source->encoding, encoding);
439 sensor_msgs::CompressedImagePtr ptr = boost::make_shared<sensor_msgs::CompressedImage>();
477 throw Exception(
"Unrecognized image format");
482 ros_image.header =
header;
484 if (encoding == enc::BGR8 || encoding == enc::BGRA8)
490 CvImagePtr tempThis = boost::make_shared<CvImage>(*this);
492 if (enc::hasAlpha(encoding))
494 temp =
cvtColor(tempThis, enc::BGRA8);
498 temp =
cvtColor(tempThis, enc::BGR8);
503 std::string format =
getFormat(dst_format);
504 ros_image.format = format;
505 cv::imencode(
"." + format, image, ros_image.data);
510 const std::string& encoding)
518 const cv::Mat_<uchar> in(1, source.data.size(),
const_cast<uchar*
>(&source.data[0]));
520 const cv::Mat rgb_a = cv::imdecode(in, cv::IMREAD_UNCHANGED);
522 switch (rgb_a.channels())
525 return toCvCopyImpl(rgb_a, source.header, enc::BGRA8, encoding);
528 return toCvCopyImpl(rgb_a, source.header, enc::BGR8, encoding);
531 return toCvCopyImpl(rgb_a, source.header, enc::MONO8, encoding);
539 const std::string& encoding_out,
546 throw Exception(
"cv_bridge.cvtColorForDisplay() called with empty image.");
548 std::string encoding = encoding_out;
549 if (encoding.empty())
554 if (enc::numChannels(source->encoding) == 1)
556 if ((source->encoding == enc::TYPE_32SC1) ||
557 (enc::bitDepth(source->encoding) == 8) ||
558 (enc::bitDepth(source->encoding) == 16) ||
559 (enc::bitDepth(source->encoding) == 32))
560 encoding = enc::BGR8;
562 throw std::runtime_error(
"Unsupported depth of the source encoding " + encoding);
567 if ((enc::bitDepth(source->encoding) == 8) ||
568 (enc::bitDepth(source->encoding) == 16))
569 encoding = enc::BGR8;
571 throw std::runtime_error(
"Unsupported depth of the source encoding " + encoding);
575 catch (
const std::runtime_error& e)
577 throw Exception(
"cv_bridge.cvtColorForDisplay() output encoding is empty and cannot be guessed.");
582 if ((!enc::isColor(encoding_out) && !enc::isMono(encoding_out)) ||
583 (enc::bitDepth(encoding) != 8))
584 throw Exception(
"cv_bridge.cvtColorForDisplay() does not have an output encoding that is color or mono, and has is bit in depth");
590 source->encoding == enc::TYPE_32SC1)
593 result->header = source->header;
595 result->image = cv::Mat(source->image.rows, source->image.cols, CV_8UC3);
596 for (
size_t j = 0; j < source->image.rows; ++j) {
597 for (
size_t i = 0; i < source->image.cols; ++i) {
598 int label = source->image.at<
int>(j, i);
600 result->image.at<cv::Vec3b>(j, i) = cv::Vec3b(0, 0, 0);
606 result->image.at<cv::Vec3b>(j, i) = cv::Vec3b(
int(rgb[2] * 255), int(rgb[1] * 255), int(rgb[0] * 255));
616 cv::minMaxLoc(source->image, &min_image_value, &max_image_value);
617 if (min_image_value == max_image_value)
620 result->header = source->header;
622 if (enc::bitDepth(encoding) == 1)
624 result->image = cv::Mat(source->image.size(), CV_8UC1);
625 result->image.setTo(255./2.);
627 result->image = cv::Mat(source->image.size(), CV_8UC3);
628 result->image.setTo(cv::Scalar(1., 1., 1.)*255./2.);
634 if (min_image_value != max_image_value)
636 if (enc::numChannels(source->encoding) != 1)
637 throw Exception(
"cv_bridge.cvtColorForDisplay() scaling for images with more than one channel is unsupported");
639 img_scaled->header = source->header;
641 img_scaled->encoding = enc::MONO8;
642 cv::Mat(source->image-min_image_value).convertTo(img_scaled->image, CV_8UC1, 255.0 /
643 (max_image_value - min_image_value));
645 img_scaled->encoding = enc::BGR8;
646 cv::Mat(source->image-min_image_value).convertTo(img_scaled->image, CV_8UC3, 255.0 /
647 (max_image_value - min_image_value));
648 cv::applyColorMap(img_scaled->image, img_scaled->image, options.
colormap);
650 if (source->encoding == enc::TYPE_32FC1) {
651 for (
size_t j = 0; j < source->image.rows; ++j) {
652 for (
size_t i = 0; i < source->image.cols; ++i) {
653 float float_value = source->image.at<
float>(j, i);
654 if (std::isnan(float_value)) {
655 img_scaled->image.at<cv::Vec3b>(j, i) = cv::Vec3b(0, 0, 0);
661 return cvtColor(img_scaled, encoding);
666 source_typed->image = source->image;
667 source_typed->header = source->header;
668 source_typed->encoding = source->encoding;
671 if (source->encoding ==
"CV_8UC1")
672 source_typed->encoding = enc::MONO8;
673 else if (source->encoding ==
"16UC1")
674 source_typed->encoding = enc::MONO16;
675 else if (source->encoding ==
"CV_8UC3")
676 source_typed->encoding = enc::BGR8;
677 else if (source->encoding ==
"CV_8UC4")
678 source_typed->encoding = enc::BGRA8;
679 else if (source->encoding ==
"CV_16UC3")
680 source_typed->encoding = enc::BGR8;
681 else if (source->encoding ==
"CV_16UC4")
682 source_typed->encoding = enc::BGRA8;
685 if (source_typed->encoding == encoding)
691 return cvtColor(source_typed, encoding);
695 throw Exception(
"cv_bridge.cvtColorForDisplay() while trying to convert image from '" + source->encoding +
"' to '" + encoding +
"' an exception was thrown (" + e.what() +
")");
CvImageConstPtr toCvShare(const sensor_msgs::ImageConstPtr &source, const std::string &encoding=std::string())
Convert an immutable sensor_msgs::Image message to an OpenCV-compatible CvImage, sharing the image da...
boost::shared_ptr< CvImage > CvImagePtr
std::string encoding
Image encoding ("mono8", "bgr8", etc.)
CvImagePtr cvtColor(const CvImageConstPtr &source, const std::string &encoding)
Convert a CvImage to another encoding using the same rules as toCvCopy.
CvImage()
Empty constructor.
CvImagePtr toCvCopy(const sensor_msgs::ImageConstPtr &source, const std::string &encoding=std::string())
Convert a sensor_msgs::Image message to an OpenCV-compatible CvImage, copying the image data...
static int depthStrToInt(const std::string depth)
sensor_msgs::CompressedImagePtr toCompressedImageMsg(const Format dst_format=JPG) const
cv::Mat image
Image data for use with OpenCV.
int getCvType(const std::string &encoding)
Get the OpenCV type enum corresponding to the encoding.
CvImageConstPtr cvtColorForDisplay(const CvImageConstPtr &source, const std::string &encoding=std::string(), const CvtColorForDisplayOptions options=CvtColorForDisplayOptions())
Converts an immutable sensor_msgs::Image message to another CvImage for display purposes, using practical conversion rules if needed.
cv::Vec3d getRGBColor(const int color)
get rgb color with enum.
sensor_msgs::ImagePtr toImageMsg() const
Convert this message to a ROS sensor_msgs::Image message.
std::string getFormat(Format format)
std_msgs::Header header
ROS header.