Compression.cpp
Go to the documentation of this file.
00001 /*
00002 Copyright (c) 2010-2016, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
00003 All rights reserved.
00004 
00005 Redistribution and use in source and binary forms, with or without
00006 modification, are permitted provided that the following conditions are met:
00007     * Redistributions of source code must retain the above copyright
00008       notice, this list of conditions and the following disclaimer.
00009     * Redistributions in binary form must reproduce the above copyright
00010       notice, this list of conditions and the following disclaimer in the
00011       documentation and/or other materials provided with the distribution.
00012     * Neither the name of the Universite de Sherbrooke nor the
00013       names of its contributors may be used to endorse or promote products
00014       derived from this software without specific prior written permission.
00015 
00016 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00017 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00018 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00019 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
00020 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00021 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00022 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00023 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00024 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00025 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00026 */
00027 
00028 #include "rtabmap/core/Compression.h"
00029 #include <rtabmap/utilite/ULogger.h>
00030 #include <rtabmap/utilite/UConversion.h>
00031 #include <opencv2/opencv.hpp>
00032 
00033 #include <zlib.h>
00034 
00035 namespace rtabmap {
00036 
00037 // format : ".png" ".jpg" "" (empty is general)
00038 CompressionThread::CompressionThread(const cv::Mat & mat, const std::string & format) :
00039         uncompressedData_(mat),
00040         format_(format),
00041         image_(!format.empty()),
00042         compressMode_(true)
00043 {
00044         UASSERT(format.empty() || format.compare(".png") == 0 || format.compare(".jpg") == 0);
00045 }
00046 // assume image
00047 CompressionThread::CompressionThread(const cv::Mat & bytes, bool isImage) :
00048         compressedData_(bytes),
00049         image_(isImage),
00050         compressMode_(false)
00051 {}
00052 void CompressionThread::mainLoop()
00053 {
00054         try
00055         {
00056                 if(compressMode_)
00057                 {
00058                         if(!uncompressedData_.empty())
00059                         {
00060                                 if(image_)
00061                                 {
00062                                         compressedData_ = compressImage2(uncompressedData_, format_);
00063                                 }
00064                                 else
00065                                 {
00066                                         compressedData_ = compressData2(uncompressedData_);
00067                                 }
00068                         }
00069                 }
00070                 else // uncompress
00071                 {
00072                         if(!compressedData_.empty())
00073                         {
00074                                 if(image_)
00075                                 {
00076                                         uncompressedData_ = uncompressImage(compressedData_);
00077                                 }
00078                                 else
00079                                 {
00080                                         uncompressedData_ = uncompressData(compressedData_);
00081                                 }
00082                         }
00083                 }
00084         }
00085         catch (cv::Exception & e) {
00086                 UERROR("Exception while compressing/uncompressing data: %s", e.what());
00087                 if(compressMode_)
00088                 {
00089                         compressedData_ = cv::Mat();
00090                 }
00091                 else
00092                 {
00093                         uncompressedData_ = cv::Mat();
00094                 }
00095         }
00096         this->kill();
00097 }
00098 
00099 // ".png" or ".jpg"
00100 std::vector<unsigned char> compressImage(const cv::Mat & image, const std::string & format)
00101 {
00102         std::vector<unsigned char> bytes;
00103         if(!image.empty())
00104         {
00105                 if(image.type() == CV_32FC1)
00106                 {
00107                         //save in 8bits-4channel
00108                         cv::Mat bgra(image.size(), CV_8UC4, image.data);
00109                         cv::imencode(format, bgra, bytes);
00110                 }
00111                 else
00112                 {
00113                         cv::imencode(format, image, bytes);
00114                 }
00115         }
00116         return bytes;
00117 }
00118 
00119 // ".png" or ".jpg"
00120 cv::Mat compressImage2(const cv::Mat & image, const std::string & format)
00121 {
00122         std::vector<unsigned char> bytes = compressImage(image, format);
00123         if(bytes.size())
00124         {
00125                 return cv::Mat(1, (int)bytes.size(), CV_8UC1, bytes.data()).clone();
00126         }
00127         return cv::Mat();
00128 }
00129 
00130 cv::Mat uncompressImage(const cv::Mat & bytes)
00131 {
00132          cv::Mat image;
00133         if(!bytes.empty())
00134         {
00135 #if CV_MAJOR_VERSION>2 || (CV_MAJOR_VERSION >=2 && CV_MINOR_VERSION >=4)
00136                 image = cv::imdecode(bytes, cv::IMREAD_UNCHANGED);
00137 #else
00138                 image = cv::imdecode(bytes, -1);
00139 #endif
00140                 if(image.type() == CV_8UC4)
00141                 {
00142                         // Using clone() or copyTo() caused a memory leak !?!?
00143                         // image = cv::Mat(image.size(), CV_32FC1, image.data).clone();
00144                         cv::Mat depth(image.size(), CV_32FC1);
00145                         memcpy(depth.data, image.data, image.total()*image.elemSize());
00146                         image = depth;
00147                 }
00148         }
00149         return image;
00150 }
00151 
00152 cv::Mat uncompressImage(const std::vector<unsigned char> & bytes)
00153 {
00154          cv::Mat image;
00155         if(bytes.size())
00156         {
00157 #if CV_MAJOR_VERSION>2 || (CV_MAJOR_VERSION >=2 && CV_MINOR_VERSION >=4)
00158                 image = cv::imdecode(bytes, cv::IMREAD_UNCHANGED);
00159 #else
00160                 image = cv::imdecode(bytes, -1);
00161 #endif
00162                 if(image.type() == CV_8UC4)
00163                 {
00164                         image = cv::Mat(image.size(), CV_32FC1, image.data).clone();
00165                 }
00166         }
00167         return image;
00168 }
00169 
00170 std::vector<unsigned char> compressData(const cv::Mat & data)
00171 {
00172         std::vector<unsigned char> bytes;
00173         if(!data.empty())
00174         {
00175                 uLong sourceLen = uLong(data.total())*uLong(data.elemSize());
00176                 uLong destLen = compressBound(sourceLen);
00177                 bytes.resize(destLen);
00178                 int errCode = compress(
00179                                                 (Bytef *)bytes.data(),
00180                                                 &destLen,
00181                                                 (const Bytef *)data.data,
00182                                                 sourceLen);
00183 
00184                 bytes.resize(destLen+3*sizeof(int));
00185                 *((int*)&bytes[destLen]) = data.rows;
00186                 *((int*)&bytes[destLen+sizeof(int)]) = data.cols;
00187                 *((int*)&bytes[destLen+2*sizeof(int)]) = data.type();
00188 
00189                 if(errCode == Z_MEM_ERROR)
00190                 {
00191                         UERROR("Z_MEM_ERROR : Insufficient memory.");
00192                 }
00193                 else if(errCode == Z_BUF_ERROR)
00194                 {
00195                         UERROR("Z_BUF_ERROR : The buffer dest was not large enough to hold the uncompressed data.");
00196                 }
00197         }
00198         return bytes;
00199 }
00200 
00201 cv::Mat compressData2(const cv::Mat & data)
00202 {
00203         cv::Mat bytes;
00204         if(!data.empty())
00205         {
00206                 uLong sourceLen = uLong(data.total())*uLong(data.elemSize());
00207                 uLong destLen = compressBound(sourceLen);
00208                 bytes = cv::Mat(1, destLen+3*sizeof(int), CV_8UC1);
00209                 int errCode = compress(
00210                                                 (Bytef *)bytes.data,
00211                                                 &destLen,
00212                                                 (const Bytef *)data.data,
00213                                                 sourceLen);
00214                 bytes = cv::Mat(bytes, cv::Rect(0,0, destLen+3*sizeof(int), 1));
00215                 *((int*)&bytes.data[destLen]) = data.rows;
00216                 *((int*)&bytes.data[destLen+sizeof(int)]) = data.cols;
00217                 *((int*)&bytes.data[destLen+2*sizeof(int)]) = data.type();
00218 
00219                 if(errCode == Z_MEM_ERROR)
00220                 {
00221                         UERROR("Z_MEM_ERROR : Insufficient memory.");
00222                 }
00223                 else if(errCode == Z_BUF_ERROR)
00224                 {
00225                         UERROR("Z_BUF_ERROR : The buffer dest was not large enough to hold the uncompressed data.");
00226                 }
00227         }
00228         return bytes;
00229 }
00230 
00231 cv::Mat uncompressData(const cv::Mat & bytes)
00232 {
00233         UASSERT(bytes.empty() || bytes.type() == CV_8UC1);
00234         return uncompressData(bytes.data, bytes.cols*bytes.rows);
00235 }
00236 
00237 cv::Mat uncompressData(const std::vector<unsigned char> & bytes)
00238 {
00239         return uncompressData(bytes.data(), (unsigned long)bytes.size());
00240 }
00241 
00242 cv::Mat uncompressData(const unsigned char * bytes, unsigned long size)
00243 {
00244         cv::Mat data;
00245         if(bytes && size>=3*sizeof(int))
00246         {
00247                 //last 3 int elements are matrix size and type
00248                 int height = *((int*)&bytes[size-3*sizeof(int)]);
00249                 int width = *((int*)&bytes[size-2*sizeof(int)]);
00250                 int type = *((int*)&bytes[size-1*sizeof(int)]);
00251 
00252                 data = cv::Mat(height, width, type);
00253                 uLongf totalUncompressed = uLongf(data.total())*uLongf(data.elemSize());
00254 
00255                 int errCode = uncompress(
00256                                                 (Bytef*)data.data,
00257                                                 &totalUncompressed,
00258                                                 (const Bytef*)bytes,
00259                                                 uLong(size));
00260 
00261                 if(errCode == Z_MEM_ERROR)
00262                 {
00263                         UERROR("Z_MEM_ERROR : Insufficient memory.");
00264                 }
00265                 else if(errCode == Z_BUF_ERROR)
00266                 {
00267                         UERROR("Z_BUF_ERROR : The buffer dest was not large enough to hold the uncompressed data.");
00268                 }
00269                 else if(errCode == Z_DATA_ERROR)
00270                 {
00271                         UERROR("Z_DATA_ERROR : The compressed data (referenced by source) was corrupted.");
00272                 }
00273         }
00274         return data;
00275 }
00276 
00277 cv::Mat compressString(const std::string & str)
00278 {
00279         // +1 to include null character
00280         return compressData2(cv::Mat(1, str.size()+1, CV_8SC1, (void *)str.data()));
00281 }
00282 
00283 std::string uncompressString(const cv::Mat & bytes)
00284 {
00285         cv::Mat strMat = uncompressData(bytes);
00286         if(!strMat.empty())
00287         {
00288                 UASSERT(strMat.type() == CV_8SC1 && strMat.rows == 1);
00289                 return (const char*)strMat.data;
00290         }
00291         return "";
00292 }
00293 
00294 } /* namespace rtabmap */


rtabmap
Author(s): Mathieu Labbe
autogenerated on Thu Jun 6 2019 21:59:19