Compression.cpp
Go to the documentation of this file.
1 /*
2 Copyright (c) 2010-2016, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7  * Redistributions of source code must retain the above copyright
8  notice, this list of conditions and the following disclaimer.
9  * Redistributions in binary form must reproduce the above copyright
10  notice, this list of conditions and the following disclaimer in the
11  documentation and/or other materials provided with the distribution.
12  * Neither the name of the Universite de Sherbrooke nor the
13  names of its contributors may be used to endorse or promote products
14  derived from this software without specific prior written permission.
15 
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 
31 #include <opencv2/opencv.hpp>
32 
33 #include <zlib.h>
34 
35 namespace rtabmap {
36 
37 // format : ".png" ".jpg" "" (empty is general)
38 CompressionThread::CompressionThread(const cv::Mat & mat, const std::string & format) :
39  uncompressedData_(mat),
40  format_(format),
41  image_(!format.empty()),
42  compressMode_(true)
43 {
44  UASSERT(format.empty() || format.compare(".png") == 0 || format.compare(".jpg") == 0);
45 }
46 // assume image
47 CompressionThread::CompressionThread(const cv::Mat & bytes, bool isImage) :
48  compressedData_(bytes),
49  image_(isImage),
51 {}
53 {
54  try
55  {
56  if(compressMode_)
57  {
58  if(!uncompressedData_.empty())
59  {
60  if(image_)
61  {
63  }
64  else
65  {
67  }
68  }
69  }
70  else // uncompress
71  {
72  if(!compressedData_.empty())
73  {
74  if(image_)
75  {
77  }
78  else
79  {
81  }
82  }
83  }
84  }
85  catch (cv::Exception & e) {
86  UERROR("Exception while compressing/uncompressing data: %s", e.what());
87  if(compressMode_)
88  {
89  compressedData_ = cv::Mat();
90  }
91  else
92  {
93  uncompressedData_ = cv::Mat();
94  }
95  }
96  this->kill();
97 }
98 
99 // ".png" or ".jpg"
100 std::vector<unsigned char> compressImage(const cv::Mat & image, const std::string & format)
101 {
102  std::vector<unsigned char> bytes;
103  if(!image.empty())
104  {
105  if(image.type() == CV_32FC1)
106  {
107  //save in 8bits-4channel
108  cv::Mat bgra(image.size(), CV_8UC4, image.data);
109  cv::imencode(format, bgra, bytes);
110  }
111  else
112  {
113  cv::imencode(format, image, bytes);
114  }
115  }
116  return bytes;
117 }
118 
119 // ".png" or ".jpg"
120 cv::Mat compressImage2(const cv::Mat & image, const std::string & format)
121 {
122  std::vector<unsigned char> bytes = compressImage(image, format);
123  if(bytes.size())
124  {
125  return cv::Mat(1, (int)bytes.size(), CV_8UC1, bytes.data()).clone();
126  }
127  return cv::Mat();
128 }
129 
130 cv::Mat uncompressImage(const cv::Mat & bytes)
131 {
132  cv::Mat image;
133  if(!bytes.empty())
134  {
135 #if CV_MAJOR_VERSION>2 || (CV_MAJOR_VERSION >=2 && CV_MINOR_VERSION >=4)
136  image = cv::imdecode(bytes, cv::IMREAD_UNCHANGED);
137 #else
138  image = cv::imdecode(bytes, -1);
139 #endif
140  if(image.type() == CV_8UC4)
141  {
142  // Using clone() or copyTo() caused a memory leak !?!?
143  // image = cv::Mat(image.size(), CV_32FC1, image.data).clone();
144  cv::Mat depth(image.size(), CV_32FC1);
145  memcpy(depth.data, image.data, image.total()*image.elemSize());
146  image = depth;
147  }
148  }
149  return image;
150 }
151 
152 cv::Mat uncompressImage(const std::vector<unsigned char> & bytes)
153 {
154  cv::Mat image;
155  if(bytes.size())
156  {
157 #if CV_MAJOR_VERSION>2 || (CV_MAJOR_VERSION >=2 && CV_MINOR_VERSION >=4)
158  image = cv::imdecode(bytes, cv::IMREAD_UNCHANGED);
159 #else
160  image = cv::imdecode(bytes, -1);
161 #endif
162  if(image.type() == CV_8UC4)
163  {
164  image = cv::Mat(image.size(), CV_32FC1, image.data).clone();
165  }
166  }
167  return image;
168 }
169 
170 std::vector<unsigned char> compressData(const cv::Mat & data)
171 {
172  std::vector<unsigned char> bytes;
173  if(!data.empty())
174  {
175  uLong sourceLen = uLong(data.total())*uLong(data.elemSize());
176  uLong destLen = compressBound(sourceLen);
177  bytes.resize(destLen);
178  int errCode = compress(
179  (Bytef *)bytes.data(),
180  &destLen,
181  (const Bytef *)data.data,
182  sourceLen);
183 
184  bytes.resize(destLen+3*sizeof(int));
185  *((int*)&bytes[destLen]) = data.rows;
186  *((int*)&bytes[destLen+sizeof(int)]) = data.cols;
187  *((int*)&bytes[destLen+2*sizeof(int)]) = data.type();
188 
189  if(errCode == Z_MEM_ERROR)
190  {
191  UERROR("Z_MEM_ERROR : Insufficient memory.");
192  }
193  else if(errCode == Z_BUF_ERROR)
194  {
195  UERROR("Z_BUF_ERROR : The buffer dest was not large enough to hold the uncompressed data.");
196  }
197  }
198  return bytes;
199 }
200 
201 cv::Mat compressData2(const cv::Mat & data)
202 {
203  cv::Mat bytes;
204  if(!data.empty())
205  {
206  uLong sourceLen = uLong(data.total())*uLong(data.elemSize());
207  uLong destLen = compressBound(sourceLen);
208  bytes = cv::Mat(1, destLen+3*sizeof(int), CV_8UC1);
209  int errCode = compress(
210  (Bytef *)bytes.data,
211  &destLen,
212  (const Bytef *)data.data,
213  sourceLen);
214  bytes = cv::Mat(bytes, cv::Rect(0,0, destLen+3*sizeof(int), 1));
215  *((int*)&bytes.data[destLen]) = data.rows;
216  *((int*)&bytes.data[destLen+sizeof(int)]) = data.cols;
217  *((int*)&bytes.data[destLen+2*sizeof(int)]) = data.type();
218 
219  if(errCode == Z_MEM_ERROR)
220  {
221  UERROR("Z_MEM_ERROR : Insufficient memory.");
222  }
223  else if(errCode == Z_BUF_ERROR)
224  {
225  UERROR("Z_BUF_ERROR : The buffer dest was not large enough to hold the uncompressed data.");
226  }
227  }
228  return bytes;
229 }
230 
231 cv::Mat uncompressData(const cv::Mat & bytes)
232 {
233  UASSERT(bytes.empty() || bytes.type() == CV_8UC1);
234  return uncompressData(bytes.data, bytes.cols*bytes.rows);
235 }
236 
237 cv::Mat uncompressData(const std::vector<unsigned char> & bytes)
238 {
239  return uncompressData(bytes.data(), (unsigned long)bytes.size());
240 }
241 
242 cv::Mat uncompressData(const unsigned char * bytes, unsigned long size)
243 {
244  cv::Mat data;
245  if(bytes && size>=3*sizeof(int))
246  {
247  //last 3 int elements are matrix size and type
248  int height = *((int*)&bytes[size-3*sizeof(int)]);
249  int width = *((int*)&bytes[size-2*sizeof(int)]);
250  int type = *((int*)&bytes[size-1*sizeof(int)]);
251 
252  data = cv::Mat(height, width, type);
253  uLongf totalUncompressed = uLongf(data.total())*uLongf(data.elemSize());
254 
255  int errCode = uncompress(
256  (Bytef*)data.data,
257  &totalUncompressed,
258  (const Bytef*)bytes,
259  uLong(size));
260 
261  if(errCode == Z_MEM_ERROR)
262  {
263  UERROR("Z_MEM_ERROR : Insufficient memory.");
264  }
265  else if(errCode == Z_BUF_ERROR)
266  {
267  UERROR("Z_BUF_ERROR : The buffer dest was not large enough to hold the uncompressed data.");
268  }
269  else if(errCode == Z_DATA_ERROR)
270  {
271  UERROR("Z_DATA_ERROR : The compressed data (referenced by source) was corrupted.");
272  }
273  }
274  return data;
275 }
276 
277 cv::Mat compressString(const std::string & str)
278 {
279  // +1 to include null character
280  return compressData2(cv::Mat(1, str.size()+1, CV_8SC1, (void *)str.data()));
281 }
282 
283 std::string uncompressString(const cv::Mat & bytes)
284 {
285  cv::Mat strMat = uncompressData(bytes);
286  if(!strMat.empty())
287  {
288  UASSERT(strMat.type() == CV_8SC1 && strMat.rows == 1);
289  return (const char*)strMat.data;
290  }
291  return "";
292 }
293 
294 } /* namespace rtabmap */
cv::Mat RTABMAP_EXP uncompressData(const cv::Mat &bytes)
void kill()
Definition: UThread.cpp:48
GLM_FUNC_DECL genType e()
Some conversion functions.
#define UASSERT(condition)
std::vector< unsigned char > RTABMAP_EXP compressImage(const cv::Mat &image, const std::string &format=".png")
#define true
Definition: ConvertUTF.c:57
std::vector< unsigned char > RTABMAP_EXP compressData(const cv::Mat &data)
cv::Mat RTABMAP_EXP compressData2(const cv::Mat &data)
CompressionThread(const cv::Mat &mat, const std::string &format="")
Definition: Compression.cpp:38
#define false
Definition: ConvertUTF.c:56
cv::Mat RTABMAP_EXP compressString(const std::string &str)
#define UERROR(...)
ULogger class and convenient macros.
std::string RTABMAP_EXP uncompressString(const cv::Mat &bytes)
cv::Mat RTABMAP_EXP uncompressImage(const cv::Mat &bytes)
cv::Mat RTABMAP_EXP compressImage2(const cv::Mat &image, const std::string &format=".png")


rtabmap
Author(s): Mathieu Labbe
autogenerated on Mon Dec 14 2020 03:34:58