mirror of
https://github.com/introlab/rtabmap.git
synced 2026-10-05 17:47:49 +08:00
Support Inverted Depth compression (with png or rvl) (#1785)
* Support Inverted Depth compression (with png or rvl) * Updated parameter's ui description * ios: fixing minor version bump * Improved test coverage for this branch * fixing opencv debug assert * SensorData: ignore invalid CameraModel * added lazy decoding check
This commit is contained in:
@@ -41,7 +41,8 @@ namespace rtabmap {
|
||||
* @brief Background thread to compress or uncompress images and generic matrices.
|
||||
*
|
||||
* In compress mode, pass a source matrix to the constructor with an optional image
|
||||
* format (".png", ".jpg", ".rvl", or empty for zlib data). In uncompress mode, pass
|
||||
* format (".png", ".jpg", ".rvl", or empty for zlib data, see @ref compressImage() for
|
||||
* depth options). In uncompress mode, pass
|
||||
* compressed bytes and set @c isImage accordingly. Call @ref UThread::start() then
|
||||
* @ref UThread::join() to obtain the result from @ref getCompressedData() or
|
||||
* @ref getUncompressedData().
|
||||
@@ -70,7 +71,7 @@ public:
|
||||
/**
|
||||
* @brief Constructs a thread in compress mode.
|
||||
* @param mat Source image or data matrix to compress.
|
||||
* @param format Image format: @c ".png", @c ".jpg", @c ".rvl", or empty for zlib (@ref compressData2).
|
||||
* @param format Image format: @c ".png", @c ".jpg", @c ".rvl" (see @ref compressImage()), or empty for zlib (@ref compressData2).
|
||||
*/
|
||||
CompressionThread(const cv::Mat & mat, const std::string & format = "");
|
||||
/**
|
||||
@@ -93,7 +94,63 @@ private:
|
||||
bool compressMode_;
|
||||
};
|
||||
|
||||
/** @brief Encodes @p image to a byte buffer (OpenCV @c imencode or RVL for depth). */
|
||||
/*
|
||||
* Compressed depth image layouts (all values little-endian). They are stable: they are
|
||||
* saved in databases, and rtabmap_ros converts them to and from ROS's
|
||||
* compressed_depth_image_transport messages without decompressing the images.
|
||||
*
|
||||
* - ".png": a standard PNG file. 16UC1 depth images are 16 bits grayscale PNGs,
|
||||
* 32FC1 depth images (legacy) are 4-channel 8 bits PNGs holding the float bytes.
|
||||
* - ".rvl" (16UC1):
|
||||
* [0..7] "DEPTHRVL"
|
||||
* [8..11] uint32 cols
|
||||
* [12..15] uint32 rows
|
||||
* [16..] RVL data (see RvlCodec)
|
||||
* - ".png:<maxDepth>:<quantization>" or ".rvl:<maxDepth>:<quantization>" (32FC1):
|
||||
* [0..7] "DEPTHINV"
|
||||
* [8..11] float depthQuantA = quantization*(quantization+1)
|
||||
* [12..15] float depthQuantB = 1 - depthQuantA/maxDepth
|
||||
* [16..] the 16UC1 inverse depth image in ".png" or ".rvl" layout above, where
|
||||
* 0 is invalid and v>0 is the depth depthQuantA/(v-depthQuantB).
|
||||
*/
|
||||
|
||||
/** @brief Signature of the ".rvl" layout (8 bytes, not null-terminated). */
|
||||
const char kCompressedDepthRvlSignature[8] = {'D', 'E', 'P', 'T', 'H', 'R', 'V', 'L'};
|
||||
/** @brief Size of the ".rvl" header: signature, uint32 cols, uint32 rows. */
|
||||
const size_t kCompressedDepthRvlHeaderSize = 16;
|
||||
/** @brief Signature of the inverse depth layout (8 bytes, not null-terminated). */
|
||||
const char kCompressedDepthInvSignature[8] = {'D', 'E', 'P', 'T', 'H', 'I', 'N', 'V'};
|
||||
/** @brief Size of the inverse depth header: signature, float depthQuantA, float depthQuantB. */
|
||||
const size_t kCompressedDepthInvHeaderSize = 16;
|
||||
|
||||
/**
|
||||
* @brief Parses an image compression format "<codec>[:<maxDepth>[:<quantization>]]".
|
||||
*
|
||||
* @param format Format, e.g., @c ".jpg", @c ".png", @c ".rvl", @c ".png:10" or @c ".rvl:20:100".
|
||||
* The empty format is valid (general zlib compression, see @ref CompressionThread).
|
||||
* @param codec Output codec (e.g., @c ".png").
|
||||
* @param maxDepth Output maximum depth (m) of the inverse depth format, 0 if not set.
|
||||
* @param quantization Output depth quantization of the inverse depth format
|
||||
* (100 if not set but @p maxDepth is), 0 if @p maxDepth is not set.
|
||||
* @return false if the format is invalid. The inverse depth parameters are only
|
||||
* valid with @c ".png" and @c ".rvl", and should be positive.
|
||||
*/
|
||||
bool RTABMAP_CORE_EXPORT parseImageCompressionFormat(const std::string & format, std::string & codec, float & maxDepth, float & quantization);
|
||||
|
||||
/**
|
||||
* @brief Encodes @p image to a byte buffer (OpenCV @c imencode or RVL for depth).
|
||||
*
|
||||
* @param format @c ".png", @c ".jpg" or @c ".rvl" (16UC1 only), optionally followed by
|
||||
* @c ":<maxDepth>[:<quantization>]" (see @ref parseImageCompressionFormat()).
|
||||
* For 32FC1 depth images, if @c maxDepth is set, depth is quantized on 16 bits
|
||||
* as inverse depth (as ROS's @c compressed_depth_image_transport) and compressed
|
||||
* with the codec. With A=quantization*(quantization+1) and B=1-A/maxDepth, the
|
||||
* precision is ~d^2/(2A), and depth values over @c maxDepth or under A/(65535-B)
|
||||
* are lost (set to 0). For example, ".png:10:100" keeps depth between 0.15 and
|
||||
* 10 m with errors of 0.05 mm at 1 m and 5 mm at 10 m. Otherwise, 32FC1 depth
|
||||
* images are compressed losslessly as 4-channel 8 bits PNG (legacy format). Other
|
||||
* image types ignore the depth parameters.
|
||||
*/
|
||||
std::vector<unsigned char> RTABMAP_CORE_EXPORT compressImage(const cv::Mat & image, const std::string & format = ".png");
|
||||
/** @brief Same as @ref compressImage() but returns a @c CV_8UC1 row matrix. */
|
||||
cv::Mat RTABMAP_CORE_EXPORT compressImage2(const cv::Mat & image, const std::string & format = ".png");
|
||||
@@ -102,6 +159,8 @@ cv::Mat RTABMAP_CORE_EXPORT compressImage2(const cv::Mat & image, const std::str
|
||||
cv::Mat RTABMAP_CORE_EXPORT uncompressImage(const cv::Mat & bytes);
|
||||
/** @brief Decodes compressed image bytes to a @cv::Mat. */
|
||||
cv::Mat RTABMAP_CORE_EXPORT uncompressImage(const std::vector<unsigned char> & bytes);
|
||||
/** @brief Decodes compressed image bytes to a @cv::Mat. */
|
||||
cv::Mat RTABMAP_CORE_EXPORT uncompressImage(const unsigned char * bytes, size_t size);
|
||||
|
||||
/** @brief Compresses a matrix with zlib; appends rows, cols and type at the end. */
|
||||
std::vector<unsigned char> RTABMAP_CORE_EXPORT compressData(const cv::Mat & data);
|
||||
@@ -122,7 +181,10 @@ std::string RTABMAP_CORE_EXPORT uncompressString(const cv::Mat & bytes);
|
||||
|
||||
/**
|
||||
* @brief Detects the compression format of depth image bytes.
|
||||
* @return @c ".rvl" if the buffer has an RVL signature, otherwise @c ".png".
|
||||
* @return @c ".rvl" if the buffer has an RVL signature, @c ".png:<maxDepth>:<quantization>"
|
||||
* or @c ".rvl:<maxDepth>:<quantization>" for inverse depth images (see
|
||||
* @ref compressImage()), otherwise @c ".png". The returned format can be passed
|
||||
* back to @ref compressImage() to compress in the same format.
|
||||
*/
|
||||
std::string RTABMAP_CORE_EXPORT compressedDepthFormat(const cv::Mat & bytes);
|
||||
/** @overload */
|
||||
@@ -130,5 +192,6 @@ std::string RTABMAP_CORE_EXPORT compressedDepthFormat(const std::vector<unsigned
|
||||
/** @overload */
|
||||
std::string RTABMAP_CORE_EXPORT compressedDepthFormat(const unsigned char * bytes, size_t size);
|
||||
|
||||
|
||||
} /* namespace rtabmap */
|
||||
#endif /* COMPRESSION_H_ */
|
||||
|
||||
@@ -848,6 +848,7 @@ private:
|
||||
unsigned int _imagePreDecimation;
|
||||
unsigned int _imagePostDecimation;
|
||||
bool _legacyDecimatedOctave;
|
||||
bool _inverseDepthCompressionAllowed; // database version >= 0.24
|
||||
bool _compressionParallelized;
|
||||
float _laserScanDownsampleStepSize;
|
||||
float _laserScanVoxelSize;
|
||||
|
||||
@@ -222,7 +222,7 @@ class RTABMAP_CORE_EXPORT Parameters
|
||||
RTABMAP_PARAM(Mem, NotLinkedNodesKept, bool, true, "Keep not linked nodes in db (rehearsed nodes and deleted nodes).");
|
||||
RTABMAP_PARAM(Mem, IntermediateNodeDataKept, bool, false, "Keep intermediate node data in db.");
|
||||
RTABMAP_PARAM_STR(Mem, ImageCompressionFormat, ".jpg", "RGB image compression format. It should be \".jpg\" or \".png\".");
|
||||
RTABMAP_PARAM_STR(Mem, DepthCompressionFormat, ".rvl", "Depth image compression format for 16UC1 depth type. It should be \".png\" or \".rvl\". If depth type is 32FC1, \".png\" is used.");
|
||||
RTABMAP_PARAM_STR(Mem, DepthCompressionFormat, ".rvl", "Depth image compression format. It should be \".png\" or \".rvl\", optionally followed by \":maxDepth[:quantization]\" (e.g., \".rvl:10:100\", quantization is 100 by default) to compress 32FC1 depth images as 16 bits inverse depth with that codec (same quantization than ROS's compressed_depth_image_transport). 16UC1 depth images are always compressed losslessly with the codec. Warning: the inverse depth format is lossy, the precision is ~d^2/(2*q*(q+1)) (q=quantization, e.g., 0.05 mm at 1 m and 5 mm at 10 m with q=100) and depth values over maxDepth or under ~q*(q+1)/65535 meters (0.15 m with q=100) are lost. Without depth parameters, 32FC1 depth images are compressed losslessly in \".png\" format (4 channels 8 bits). Databases with depth images compressed in inverse depth format cannot be opened by rtabmap versions under 0.24.");
|
||||
RTABMAP_PARAM(Mem, STMSize, unsigned int, 10, "Short-term memory size.");
|
||||
RTABMAP_PARAM(Mem, IncrementalMemory, bool, true, "SLAM mode, otherwise it is Localization mode.");
|
||||
RTABMAP_PARAM(Mem, LocalizationReadOnly, bool, false, uFormat("In localization mode, open the database in read-only mode (ignored if %s=true). Currrenty incompatible with memory management (%s and %s cannot be used) and if there are disjoint sessions in working memory. Last localization pose won't be saved back in the database at the end of the session, so the robot will always restart to original last localization pose, unless %s is used or an external initial pose is provided on initialization.", kMemIncrementalMemory().c_str(), kRtabmapLoopThr().c_str(), kRtabmapMemoryThr().c_str(), kRGBDStartAtOrigin().c_str()).c_str());
|
||||
|
||||
@@ -598,6 +598,8 @@ public:
|
||||
/**
|
||||
* Set image data. Detect automatically if raw or compressed.
|
||||
* A matrix of type CV_8UC1 with 1 row is considered as compressed.
|
||||
* An invalid @p model (not CameraModel::isValidForProjection()) without any image is
|
||||
* a placeholder (e.g., scan-only data): it is not added, so cameraModels() is empty.
|
||||
* @param clearPreviousData, clear previous raw and compressed images before setting the new ones.
|
||||
*/
|
||||
void setRGBDImage(const cv::Mat & rgb, const cv::Mat & depth, const CameraModel & model, bool clearPreviousData = true);
|
||||
@@ -1025,6 +1027,9 @@ public:
|
||||
#endif
|
||||
|
||||
private:
|
||||
/// Whether setRGBDImage() keeps @p model: not an invalid model without any image.
|
||||
bool keepCameraModel(const CameraModel & model, const cv::Mat & rgb, const cv::Mat & depth, bool clearPreviousData) const;
|
||||
|
||||
int _id; ///< Unique sensor data ID (0 if invalid)
|
||||
double _stamp; ///< Timestamp in seconds
|
||||
|
||||
|
||||
Reference in New Issue
Block a user