00001
00018 #include <ivt_bridge/ivt_image.h>
00019 #include <opencv2/imgproc/imgproc.hpp>
00020 #include <Image/ImageProcessor.h>
00021 #include <sensor_msgs/image_encodings.h>
00022 #include <boost/make_shared.hpp>
00023
00024 namespace enc = sensor_msgs::image_encodings;
00025
00026 namespace ivt_bridge {
00027
00028 int getCvType(const std::string& encoding) {
00029
00030 if (encoding == enc::BGR8) return CV_8UC3;
00031 if (encoding == enc::MONO8) return CV_8UC1;
00032 if (encoding == enc::RGB8) return CV_8UC3;
00033 if (encoding == enc::MONO16) return CV_16UC1;
00034 if (encoding == enc::BGR16) return CV_16UC3;
00035 if (encoding == enc::RGB16) return CV_16UC3;
00036 if (encoding == enc::BGRA8) return CV_8UC4;
00037 if (encoding == enc::RGBA8) return CV_8UC4;
00038 if (encoding == enc::BGRA16) return CV_16UC4;
00039 if (encoding == enc::RGBA16) return CV_16UC4;
00040
00041
00042 if (encoding == enc::BAYER_RGGB8) return CV_8UC1;
00043 if (encoding == enc::BAYER_BGGR8) return CV_8UC1;
00044 if (encoding == enc::BAYER_GBRG8) return CV_8UC1;
00045 if (encoding == enc::BAYER_GRBG8) return CV_8UC1;
00046 if (encoding == enc::BAYER_RGGB16) return CV_16UC1;
00047 if (encoding == enc::BAYER_BGGR16) return CV_16UC1;
00048 if (encoding == enc::BAYER_GBRG16) return CV_16UC1;
00049 if (encoding == enc::BAYER_GRBG16) return CV_16UC1;
00050
00051
00052 #define CHECK_ENCODING(code) \
00053 if (encoding == enc::TYPE_##code) return CV_##code \
00054
00055 #define CHECK_CHANNEL_TYPE(t) \
00056 CHECK_ENCODING(t##1); \
00057 CHECK_ENCODING(t##2); \
00058 CHECK_ENCODING(t##3); \
00059 CHECK_ENCODING(t##4); \
00060
00061
00062 CHECK_CHANNEL_TYPE(8UC);
00063 CHECK_CHANNEL_TYPE(8SC);
00064 CHECK_CHANNEL_TYPE(16UC);
00065 CHECK_CHANNEL_TYPE(16SC);
00066 CHECK_CHANNEL_TYPE(32SC);
00067 CHECK_CHANNEL_TYPE(32FC);
00068 CHECK_CHANNEL_TYPE(64FC);
00069
00070 #undef CHECK_CHANNEL_TYPE
00071 #undef CHECK_ENCODING
00072
00073 throw Exception("Unrecognized image encoding [" + encoding + "]");
00074 }
00075
00076 CByteImage::ImageType getIvtType(const std::string& encoding) {
00077 if (encoding == enc::RGB8) return CByteImage::eRGB24;
00078 if (encoding == enc::MONO8) return CByteImage::eGrayScale;
00079 throw Exception("No IVT equivalent to image encoding [" + encoding + "]");
00080 }
00081
00083
00084 enum Format { INVALID = -1, GRAY = 0, RGB, BGR, RGBA, BGRA };
00085
00086 Format getFormat(const std::string& encoding) {
00087 if (encoding == enc::BGR8) return BGR;
00088 if (encoding == enc::MONO8) return GRAY;
00089 if (encoding == enc::RGB8) return RGB;
00090 if (encoding == enc::MONO16) return GRAY;
00091 if (encoding == enc::BGR16) return BGR;
00092 if (encoding == enc::RGB16) return RGB;
00093 if (encoding == enc::BGRA8) return BGRA;
00094 if (encoding == enc::RGBA8) return RGBA;
00095 if (encoding == enc::BGRA16) return BGRA;
00096 if (encoding == enc::RGBA16) return RGBA;
00097
00098
00099 return INVALID;
00100 }
00101
00102 static const int SAME_FORMAT = -1;
00103
00104 int getConversionCode(Format src_format, Format dst_format) {
00105 static const int CONVERSION_CODES[] = { SAME_FORMAT, CV_GRAY2RGB, CV_GRAY2BGR, CV_GRAY2RGBA, CV_GRAY2BGRA,
00106 CV_RGB2GRAY, SAME_FORMAT, CV_RGB2BGR, CV_RGB2RGBA, CV_RGB2BGRA,
00107 CV_BGR2GRAY, CV_BGR2RGB, SAME_FORMAT, CV_BGR2RGBA, CV_BGR2BGRA,
00108 CV_RGBA2GRAY, CV_RGBA2RGB, CV_RGBA2BGR, SAME_FORMAT, CV_RGBA2BGRA,
00109 CV_BGRA2GRAY, CV_BGRA2RGB, CV_BGRA2BGR, CV_BGRA2RGBA, SAME_FORMAT };
00110 return CONVERSION_CODES[src_format*5 + dst_format];
00111 }
00112
00113
00114 IvtImagePtr toIvtCopyImpl(const cv::Mat& source, const std_msgs::Header& src_header, const std::string& src_encoding, const std::string& dst_encoding) {
00116
00117
00118 IvtImagePtr ptr = boost::make_shared<IvtImage>();
00119 ptr->header = src_header;
00120
00121
00122 Format src_format = getFormat(src_encoding);
00123 if (dst_encoding.empty()) {
00124 if (src_format == GRAY)
00125 ptr->encoding = enc::MONO8;
00126 else
00127 ptr->encoding = enc::RGB8;
00128 }
00129 else
00130 ptr->encoding = dst_encoding;
00131 Format dst_format = getFormat(ptr->encoding);
00132
00133 cv::Mat tmp;
00134 if (ptr->encoding == src_encoding) {
00135 tmp = source;
00136 }
00137 else {
00138
00139 if (src_format == INVALID || dst_format == INVALID)
00140 throw Exception("Unsupported conversion from [" + src_encoding + "] to [" + ptr->encoding + "]");
00141
00142 int conversion_code = getConversionCode(src_format, dst_format);
00143 if (conversion_code == SAME_FORMAT) {
00144
00145 double alpha = 1.0;
00146 int src_depth = enc::bitDepth(src_encoding);
00147 int dst_depth = enc::bitDepth(dst_encoding);
00148
00149 if (src_depth == 8 && dst_depth == 16)
00150 alpha = 65535. / 255.;
00151 else if (src_depth == 16 && dst_depth == 8)
00152 alpha = 255. / 65535.;
00153 source.convertTo(tmp, getCvType(ptr->encoding), alpha);
00154 }
00155 else {
00156
00157 cv::cvtColor(source, tmp, conversion_code);
00158 }
00159 }
00160
00161 ptr->image = new CByteImage(tmp.cols, tmp.rows, getIvtType(ptr->encoding));
00162
00163 if (tmp.step == tmp.cols * tmp.elemSize()) {
00164 memcpy(ptr->image->pixels, tmp.data, tmp.cols * tmp.rows * tmp.elemSize());
00165 } else {
00166 int ivtImgStep = ptr->image->bytesPerPixel*ptr->image->width;
00167 uchar *ivtImgPtr = ptr->image->pixels;
00168 uchar *cvImgPtr = tmp.data;
00169 for (int i=0; i < tmp.rows; i++){
00170 memcpy(ivtImgPtr, cvImgPtr, ivtImgStep);
00171 ivtImgPtr += ivtImgStep;
00172 cvImgPtr += tmp.step;
00173 }
00174 }
00175 return ptr;
00176 }
00177
00179
00180 IvtImage::~IvtImage(){
00181 delete image;
00182 }
00183
00184 sensor_msgs::ImagePtr IvtImage::toImageMsg() const {
00185 sensor_msgs::ImagePtr ptr = boost::make_shared<sensor_msgs::Image>();
00186 toImageMsg(*ptr);
00187 return ptr;
00188 }
00189
00190 void IvtImage::toImageMsg(sensor_msgs::Image& ros_image) const {
00191 ros_image.header = header;
00192 ros_image.height = image->height;
00193 ros_image.width = image->width;
00194 ros_image.encoding = encoding;
00195 ros_image.is_bigendian = false;
00196 ros_image.step = 0;
00197 size_t size = image->width * image->height * image->bytesPerPixel;
00198 ros_image.data.resize(size);
00199 memcpy((char*)(&ros_image.data[0]), image->pixels, size);
00200 }
00201
00202
00203 IvtImagePtr toIvtCopy(const sensor_msgs::ImageConstPtr& source, const std::string& encoding) {
00204 return toIvtCopy(*source, encoding);
00205 }
00206
00207 IvtImagePtr toIvtCopy(const sensor_msgs::Image& source, const std::string& encoding) {
00208
00209 if (encoding != enc::MONO8 && encoding != enc::RGB8 && !encoding.empty())
00210 throw Exception("Encoding " + encoding + " not supported");
00211 int source_type = getCvType(source.encoding);
00212 const cv::Mat tmp((int)source.height, (int)source.width, source_type, const_cast<uint8_t*>(&source.data[0]), (size_t)source.step);
00213 return toIvtCopyImpl(tmp, source.header, source.encoding, encoding);
00214 }
00215
00217 IvtImageConstPtr toIvtShare(const sensor_msgs::ImageConstPtr& source, const std::string& encoding) {
00218 return toIvtShare(*source, source, encoding);
00219 }
00220
00221 IvtImageConstPtr toIvtShare(const sensor_msgs::Image& source, const boost::shared_ptr<void const>& tracked_object, const std::string& encoding) {
00222 bool hasPadding = source.step != source.width * (source.encoding == enc::RGB8 ? 3 : 1);
00223 if ((!encoding.empty() && source.encoding != encoding) || (source.encoding != enc::MONO8 && source.encoding != enc::RGB8) || hasPadding)
00224 return toIvtCopy(source, encoding);
00225 IvtImagePtr ptr = boost::make_shared<IvtImage>();
00226 ptr->header = source.header;
00227 ptr->encoding = source.encoding;
00228 ptr->tracked_object_ = tracked_object;
00229 ptr->image = new CByteImage(source.width, source.height, getIvtType(ptr->encoding), true);
00230 ptr->image->pixels = const_cast<uchar*>(&source.data[0]);
00231 return ptr;
00232 }
00233
00234
00235
00236 }