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 : ".jpg" ".png" ".rvl" "" (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(".jpg") == 0 || format.compare(".png") == 0 || format.compare(".rvl") == 0);
45 }
46 // assume image
47 CompressionThread::CompressionThread(const cv::Mat & bytes, bool isImage) :
48  compressedData_(bytes),
49  image_(isImage),
50  compressMode_(false)
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 // ".jpg" or ".png" or ".rvl"
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(".png", bgra, bytes);
110  }
111  else if(format == ".rvl")
112  {
113  bytes = {'D', 'E', 'P', 'T', 'H', 'R', 'V', 'L'};
114  int numPixels = image.rows * image.cols;
115  // In the worst case, RVL compression results in ~1.5x larger data.
116  bytes.resize(3 * numPixels + 20);
117  uint32_t cols = image.cols;
118  uint32_t rows = image.rows;
119  memcpy(&bytes[8], &cols, 4);
120  memcpy(&bytes[12], &rows, 4);
121  RvlCodec rvl;
122  int compressedSize = rvl.CompressRVL(image.ptr<uint16_t>(), &bytes[16], numPixels);
123  bytes.resize(16 + compressedSize);
124  }
125  else
126  {
127  cv::imencode(format, image, bytes);
128  }
129  }
130  return bytes;
131 }
132 
133 // ".jpg" or ".png" or ".rvl"
134 cv::Mat compressImage2(const cv::Mat & image, const std::string & format)
135 {
136  std::vector<unsigned char> bytes = compressImage(image, format);
137  if(bytes.size())
138  {
139  return cv::Mat(1, (int)bytes.size(), CV_8UC1, bytes.data()).clone();
140  }
141  return cv::Mat();
142 }
143 
144 cv::Mat uncompressImage(const cv::Mat & bytes)
145 {
146  cv::Mat image;
147  if(!bytes.empty())
148  {
149  if (compressedDepthFormat(bytes) == ".rvl")
150  {
151  uint32_t cols, rows;
152  memcpy(&cols, &bytes.data[8], 4);
153  memcpy(&rows, &bytes.data[12], 4);
154  image = cv::Mat(rows, cols, CV_16UC1);
155  RvlCodec rvl;
156  rvl.DecompressRVL(&bytes.data[16], image.ptr<uint16_t>(), cols * rows);
157  }
158  else
159  {
160 #if CV_MAJOR_VERSION>2 || (CV_MAJOR_VERSION >=2 && CV_MINOR_VERSION >=4)
161  image = cv::imdecode(bytes, cv::IMREAD_UNCHANGED);
162 #else
163  image = cv::imdecode(bytes, -1);
164 #endif
165  if(image.type() == CV_8UC4)
166  {
167  // Using clone() or copyTo() caused a memory leak !?!?
168  // image = cv::Mat(image.size(), CV_32FC1, image.data).clone();
169  cv::Mat depth(image.size(), CV_32FC1);
170  memcpy(depth.data, image.data, image.total()*image.elemSize());
171  image = depth;
172  }
173  }
174  }
175  return image;
176 }
177 
178 cv::Mat uncompressImage(const std::vector<unsigned char> & bytes)
179 {
180  cv::Mat image;
181  if(bytes.size())
182  {
183  if (compressedDepthFormat(bytes) == ".rvl")
184  {
185  uint32_t cols, rows;
186  memcpy(&cols, &bytes[8], 4);
187  memcpy(&rows, &bytes[12], 4);
188  image = cv::Mat(rows, cols, CV_16UC1);
189  RvlCodec rvl;
190  rvl.DecompressRVL(&bytes[16], image.ptr<uint16_t>(), cols * rows);
191  }
192  else
193  {
194 #if CV_MAJOR_VERSION>2 || (CV_MAJOR_VERSION >=2 && CV_MINOR_VERSION >=4)
195  image = cv::imdecode(bytes, cv::IMREAD_UNCHANGED);
196 #else
197  image = cv::imdecode(bytes, -1);
198 #endif
199  if(image.type() == CV_8UC4)
200  {
201  image = cv::Mat(image.size(), CV_32FC1, image.data).clone();
202  }
203  }
204  }
205  return image;
206 }
207 
208 std::vector<unsigned char> compressData(const cv::Mat & data)
209 {
210  std::vector<unsigned char> bytes;
211  if(!data.empty())
212  {
213  uLong sourceLen = uLong(data.total())*uLong(data.elemSize());
214  uLong destLen = compressBound(sourceLen);
215  bytes.resize(destLen);
216  int errCode = compress(
217  (Bytef *)bytes.data(),
218  &destLen,
219  (const Bytef *)data.data,
220  sourceLen);
221 
222  bytes.resize(destLen+3*sizeof(int));
223  *((int*)&bytes[destLen]) = data.rows;
224  *((int*)&bytes[destLen+sizeof(int)]) = data.cols;
225  *((int*)&bytes[destLen+2*sizeof(int)]) = data.type();
226 
227  if(errCode == Z_MEM_ERROR)
228  {
229  UERROR("Z_MEM_ERROR : Insufficient memory.");
230  }
231  else if(errCode == Z_BUF_ERROR)
232  {
233  UERROR("Z_BUF_ERROR : The buffer dest was not large enough to hold the uncompressed data.");
234  }
235  }
236  return bytes;
237 }
238 
239 cv::Mat compressData2(const cv::Mat & data)
240 {
241  cv::Mat bytes;
242  if(!data.empty())
243  {
244  uLong sourceLen = uLong(data.total())*uLong(data.elemSize());
245  uLong destLen = compressBound(sourceLen);
246  bytes = cv::Mat(1, destLen+3*sizeof(int), CV_8UC1);
247  int errCode = compress(
248  (Bytef *)bytes.data,
249  &destLen,
250  (const Bytef *)data.data,
251  sourceLen);
252  bytes = cv::Mat(bytes, cv::Rect(0,0, destLen+3*sizeof(int), 1));
253  *((int*)&bytes.data[destLen]) = data.rows;
254  *((int*)&bytes.data[destLen+sizeof(int)]) = data.cols;
255  *((int*)&bytes.data[destLen+2*sizeof(int)]) = data.type();
256 
257  if(errCode == Z_MEM_ERROR)
258  {
259  UERROR("Z_MEM_ERROR : Insufficient memory.");
260  }
261  else if(errCode == Z_BUF_ERROR)
262  {
263  UERROR("Z_BUF_ERROR : The buffer dest was not large enough to hold the uncompressed data.");
264  }
265  }
266  return bytes;
267 }
268 
269 cv::Mat uncompressData(const cv::Mat & bytes)
270 {
271  UASSERT(bytes.empty() || bytes.type() == CV_8UC1);
272  return uncompressData(bytes.data, bytes.cols*bytes.rows);
273 }
274 
275 cv::Mat uncompressData(const std::vector<unsigned char> & bytes)
276 {
277  return uncompressData(bytes.data(), (unsigned long)bytes.size());
278 }
279 
280 cv::Mat uncompressData(const unsigned char * bytes, unsigned long size)
281 {
282  cv::Mat data;
283  if(bytes && size>=3*sizeof(int))
284  {
285  //last 3 int elements are matrix size and type
286  int height = *((int*)&bytes[size-3*sizeof(int)]);
287  int width = *((int*)&bytes[size-2*sizeof(int)]);
288  int type = *((int*)&bytes[size-1*sizeof(int)]);
289 
290  data = cv::Mat(height, width, type);
291  uLongf totalUncompressed = uLongf(data.total())*uLongf(data.elemSize());
292 
293  int errCode = uncompress(
294  (Bytef*)data.data,
295  &totalUncompressed,
296  (const Bytef*)bytes,
297  uLong(size));
298 
299  if(errCode == Z_MEM_ERROR)
300  {
301  UERROR("Z_MEM_ERROR : Insufficient memory.");
302  }
303  else if(errCode == Z_BUF_ERROR)
304  {
305  UERROR("Z_BUF_ERROR : The buffer dest was not large enough to hold the uncompressed data.");
306  }
307  else if(errCode == Z_DATA_ERROR)
308  {
309  UERROR("Z_DATA_ERROR : The compressed data (referenced by source) was corrupted.");
310  }
311  }
312  return data;
313 }
314 
315 cv::Mat compressString(const std::string & str)
316 {
317  // +1 to include null character
318  return compressData2(cv::Mat(1, str.size()+1, CV_8SC1, (void *)str.data()));
319 }
320 
321 std::string uncompressString(const cv::Mat & bytes)
322 {
323  cv::Mat strMat = uncompressData(bytes);
324  if(!strMat.empty())
325  {
326  UASSERT(strMat.type() == CV_8SC1 && strMat.rows == 1);
327  return (const char*)strMat.data;
328  }
329  return "";
330 }
331 
332 std::string compressedDepthFormat(const cv::Mat & bytes)
333 {
334  return compressedDepthFormat(bytes.data, bytes.rows * bytes.cols * bytes.elemSize());
335 }
336 std::string compressedDepthFormat(const std::vector<unsigned char> & bytes)
337 {
338  return compressedDepthFormat(bytes.data(), bytes.size());
339 }
340 std::string compressedDepthFormat(const unsigned char * bytes, size_t size)
341 {
342  std::string format;
343  if(bytes && size)
344  {
345  size_t maxlen = std::min(size, size_t(8));
346  std::vector<unsigned char> signature(maxlen);
347  memcpy(&signature[0], bytes, maxlen);
348  if (std::string(signature.begin(), signature.end()) == "DEPTHRVL")
349  {
350  format = ".rvl";
351  }
352  else
353  {
354  // Assuming png by default
355  format = ".png";
356  }
357  }
358  return format;
359 }
360 
361 } /* namespace rtabmap */
glm::min
GLM_FUNC_DECL genType min(genType const &x, genType const &y)
int
int
Compression.h
rtabmap::uncompressImage
cv::Mat RTABMAP_CORE_EXPORT uncompressImage(const cv::Mat &bytes)
Definition: Compression.cpp:144
bytes
format
std::string format(const std::string &str, const std::vector< std::string > &find, const std::vector< std::string > &replace)
rtabmap::compressedDepthFormat
std::string RTABMAP_CORE_EXPORT compressedDepthFormat(const cv::Mat &bytes)
Definition: Compression.cpp:332
uint32_t
::uint32_t uint32_t
size
Index size
rtabmap::CompressionThread::mainLoop
virtual void mainLoop()
Definition: Compression.cpp:52
rtabmap::CompressionThread::compressMode_
bool compressMode_
Definition: Compression.h:71
type
rtabmap::compressImage
std::vector< unsigned char > RTABMAP_CORE_EXPORT compressImage(const cv::Mat &image, const std::string &format=".png")
Definition: Compression.cpp:100
true
#define true
Definition: ConvertUTF.c:57
rtabmap::RvlCodec::CompressRVL
int CompressRVL(const uint16_t *input, unsigned char *output, int numPixels)
Definition: rvl_codec.cpp:50
rows
int rows
compressedSize
char int compressedSize
Definition: lz4.h:354
rtabmap::compressData
std::vector< unsigned char > RTABMAP_CORE_EXPORT compressData(const cv::Mat &data)
Definition: Compression.cpp:208
uint16_t
::uint16_t uint16_t
rtabmap::RvlCodec::DecompressRVL
void DecompressRVL(const unsigned char *input, uint16_t *output, int numPixels)
Definition: rvl_codec.cpp:77
data
int data[]
UConversion.h
Some conversion functions.
UThread::kill
void kill()
Definition: UThread.cpp:48
UASSERT
#define UASSERT(condition)
rtabmap::CompressionThread::uncompressedData_
cv::Mat uncompressedData_
Definition: Compression.h:68
str
rtabmap::compressData2
cv::Mat RTABMAP_CORE_EXPORT compressData2(const cv::Mat &data)
Definition: Compression.cpp:239
rtabmap::CompressionThread::compressedData_
cv::Mat compressedData_
Definition: Compression.h:67
e
Array< double, 1, 3 > e(1./3., 0.5, 2.)
ULogger.h
ULogger class and convenient macros.
empty
rtabmap::compressString
cv::Mat RTABMAP_CORE_EXPORT compressString(const std::string &str)
Definition: Compression.cpp:315
rtabmap::RvlCodec
Definition: rvl_codec.h:14
rtabmap::CompressionThread::CompressionThread
CompressionThread(const cv::Mat &mat, const std::string &format="")
Definition: Compression.cpp:38
false
#define false
Definition: ConvertUTF.c:56
handle::ptr
PyObject *& ptr()
rtabmap::CompressionThread::format_
std::string format_
Definition: Compression.h:69
cols
int cols
rtabmap
Definition: CameraARCore.cpp:35
UERROR
#define UERROR(...)
rtabmap::compressImage2
cv::Mat RTABMAP_CORE_EXPORT compressImage2(const cv::Mat &image, const std::string &format=".png")
Definition: Compression.cpp:134
rtabmap::uncompressString
std::string RTABMAP_CORE_EXPORT uncompressString(const cv::Mat &bytes)
Definition: Compression.cpp:321
rtabmap::CompressionThread::image_
bool image_
Definition: Compression.h:70
mat
else mat
rtabmap::uncompressData
cv::Mat RTABMAP_CORE_EXPORT uncompressData(const cv::Mat &bytes)
Definition: Compression.cpp:269


rtabmap
Author(s): Mathieu Labbe
autogenerated on Thu Feb 13 2025 03:44:52