Program Listing for File channel-serialization.h

Return to documentation for file (aslam_cv2/aslam_cv_common/include/aslam/common/channel-serialization.h)

#ifndef ASLAM_CHANNEL_SERIALIZATION_H_
#define ASLAM_CHANNEL_SERIALIZATION_H_

#include <cstdint>
#include <iostream>
#include <sstream>
#include <string>
#include <type_traits>

#include <glog/logging.h>
#include <Eigen/Dense>
#include <opencv2/core/core.hpp>

namespace aslam {
namespace internal {

struct HeaderInformation {
  uint32_t rows;
  uint32_t cols;
  uint32_t depth;
  uint32_t channels;
  size_t size() const;
  bool serializeToBuffer(char* buffer, size_t offset) const;
  bool deSerializeFromBuffer(const char* const bufferIn, size_t offset);
};

template<typename Scalar>
void makeHeaderInformation(int rows, int cols, int channels,
                           HeaderInformation* headerInformation) {
  CHECK_NOTNULL(headerInformation);
  headerInformation->rows = rows;
  headerInformation->cols = cols;
  headerInformation->channels = channels;
  headerInformation->depth = cv::DataType<Scalar>::depth;
}

template<typename Scalar>
bool serializeToString(const char* const matrixData,
                       int rows, int cols, int channels, std::string* string) {
  CHECK_GE(rows, 0);
  CHECK_GE(cols, 0);
  CHECK_NOTNULL(string);
  HeaderInformation header;
  makeHeaderInformation<Scalar>(rows, cols, channels, &header);
  size_t matrixSize = sizeof(Scalar) * rows * cols * channels;
  size_t totalSize = matrixSize + header.size();

  CHECK_GT(totalSize, 0u);

  string->resize(totalSize);
  char* buffer = &(*string)[0];
  bool success = header.serializeToBuffer(buffer, 0);
  if (!success) {
    LOG(ERROR) << "Failed to serialize header";
    return false;
  }
  size_t offset = header.size();
  memcpy(buffer + offset, matrixData, matrixSize);
  return true;
}

template<typename Scalar>
bool serializeToBuffer(const char* const matrixData, int rows, int cols,
                       int channels, char** buffer, size_t* totalSize) {
  CHECK_NOTNULL(totalSize);
  CHECK_NOTNULL(buffer);
  HeaderInformation header;
  makeHeaderInformation<Scalar>(rows, cols, channels, &header);
  size_t matrixSize = sizeof(Scalar) * rows * cols * channels;
  *totalSize = matrixSize + header.size();

  *buffer = new char[*totalSize];
  bool success = header.serializeToBuffer(*buffer, 0);
  if (!success) {
    delete[] *buffer;
    *buffer = nullptr;
    return false;
  }
  size_t offset = header.size();
  memcpy(*buffer + offset, matrixData, matrixSize);
  return true;
}

template<typename Scalar, int ROWS, int COLS>
bool serializeToBuffer(const Eigen::Matrix<Scalar, ROWS, COLS>& matrix,
                       char** buffer, size_t* size) {
  const char* const matrixData = reinterpret_cast<const char*>(matrix.data());
  // Eigen matrices have only one channel
  constexpr int numChannels = 1;
  return serializeToBuffer<Scalar>(matrixData, matrix.rows(), matrix.cols(),
                                   numChannels, buffer, size);
}

template<typename Scalar, int ROWS, int COLS>
bool serializeToString(const Eigen::Matrix<Scalar, ROWS, COLS>& matrix,
                       std::string* string) {
  const char* const matrixData = reinterpret_cast<const char*>(matrix.data());
  // Eigen matrices have only one channel
  constexpr int numChannels = 1;
  return serializeToString<Scalar>(matrixData, matrix.rows(), matrix.cols(),
                                   numChannels, string);
}

template<typename Scalar, int ROWS, int COLS>
bool deSerializeFromBuffer(const char* const buffer, size_t size,
                           Eigen::Matrix<Scalar, ROWS, COLS>* matrix) {
  CHECK_NOTNULL(matrix);
  HeaderInformation header;
  CHECK_GE(size, header.size());
  bool success = header.deSerializeFromBuffer(buffer, 0);
  if (!success) {
    LOG(ERROR) << "Failed to deserialize header from string: " <<
        std::string(buffer, size);
    return false;
  }
  if (ROWS != Eigen::Dynamic) {
    CHECK_EQ(header.rows, static_cast<uint32_t>(ROWS));
  }
  if (COLS != Eigen::Dynamic) {
    CHECK_EQ(header.cols, static_cast<uint32_t>(COLS));
  }
  CHECK_EQ(header.depth, cv::DataType<Scalar>::depth);
  CHECK_EQ(1u, header.channels) << "Eigen matrices must have one channel.";

  if (ROWS == Eigen::Dynamic && COLS == Eigen::Dynamic) {
    matrix->resize(header.rows, header.cols);
  } else if (ROWS == Eigen::Dynamic && COLS != Eigen::Dynamic) {
    matrix->resize(header.rows, Eigen::NoChange);
  } else if (ROWS != Eigen::Dynamic && COLS == Eigen::Dynamic) {
    matrix->resize(Eigen::NoChange, header.cols);
  }

  size_t matrix_size = sizeof(Scalar) * matrix->rows() * matrix->cols();
  size_t total_size = matrix_size + header.size();
  CHECK_EQ(size, total_size);
  memcpy(matrix->data(), buffer + header.size(), matrix_size);
  return true;
}

template<typename Scalar, int ROWS, int COLS>
bool deSerializeFromString(const std::string& string,
                           Eigen::Matrix<Scalar, ROWS, COLS>* matrix) {
  CHECK_NOTNULL(matrix);
  return deSerializeFromBuffer(string.data(), string.size(), matrix);
}

bool serializeToString(const cv::Mat& image,
                       std::string* string);

bool deSerializeFromString(const std::string& string,
                           cv::Mat* image);

bool deSerializeFromBuffer(const char* const buffer, size_t size,
                           cv::Mat* image);

bool serializeToBuffer(const cv::Mat& matrix,
                       char** buffer, size_t* size);

template<typename Scalar>
bool serializeToString(const Scalar& value, std::string* string) {
  CHECK_NOTNULL(string);
  std::string value_string = std::to_string(value);
  string->swap(value_string);
  return true;
}

template<typename Scalar>
bool deSerializeFromString(const std::string& string,
                           Scalar* value,
                           typename std::enable_if<std::is_integral<Scalar>::value>::type* = 0) {
  CHECK_NOTNULL(value);
  CHECK(!string.empty());
  (*value) = static_cast<Scalar>(std::stoll(string));
  return true;
}

template<typename Scalar>
bool deSerializeFromString(const std::string& string,
                           Scalar* value,
                           typename std::enable_if<std::is_floating_point<Scalar>::value>::type*
                             = 0) {
  CHECK_NOTNULL(value);
  CHECK(!string.empty());
  (*value) = static_cast<Scalar>(std::stod(string));
  return true;
}

template<typename Scalar>
bool serializeToBuffer(const Scalar& value, char** buffer, size_t* size) {
  CHECK_NOTNULL(buffer);
  CHECK_NOTNULL(size);
  *size = sizeof(Scalar);
  *buffer = new char[*size];
  memcpy(*buffer, &value, *size);
  return true;
}
template<typename Scalar>
bool deSerializeFromBuffer(const char* const buffer, size_t size, Scalar* value) {
  CHECK_NOTNULL(value);
  CHECK_EQ(size, sizeof(Scalar));
  memcpy(value, buffer, size);
  return true;
}

}  // namespace internal
}  // namespace aslam

#endif  // ASLAM_CHANNEL_SERIALIZATION_H_