c++ - convertto - Serialización de OpenCV Mat_<Vec3f>
opencv mat library (5)
Recientemente me hice una pregunta similar, aunque específicamente estaba tratando de serializar los objetos Mat
y MatND
. Usar boost::serialize
es bueno, pero requiere un par de trucos. Como no quiere modificar las partes internas de OpenCV para serializar estos objetos, se ve obligado a utilizar lo que se llama una función "libre". Dado que es complicado serializar los objetos de OpenCV, descubrí que me vi obligado a dividir la operación de serialización en guardar y cargar, cada uno con una implementación ligeramente diferente. Necesita usar boost/serialization/split_free.hpp
para esta tarea. Boost proporciona una buena documentación para esto aquí: http://www.boost.org/doc/libs/1_45_0/libs/serialization/doc/index.html .
¡Buena suerte!
Estoy trabajando en un proyecto de investigación de robótica en el que necesito serializar matrices 2D de puntos 3D: básicamente, cada píxel es un vector de 3 flotadores. Estos píxeles se guardan en una matriz OpenCV, y deben enviarse a través de la comunicación entre procesos y guardarse en archivos para procesarlos en varias computadoras. Me gustaría serializarlos de una manera endian / independiente de la arquitectura y con un uso eficiente del espacio , tan rápido como sea posible. cv::imencode
aquí sería perfecto, excepto que solo funciona en elementos de 8 y 16 bits, y no queremos perder precisión. No es necesario que los archivos sean legibles por humanos (aunque lo hacemos ahora para garantizar la portabilidad de los datos, y es increíblemente lento). ¿Hay mejores prácticas para esto o maneras elegantes de hacerlo?
¡Gracias!
Editar: Christoph Heindl ha comentado esta publicación con un enlace a su blog donde ha mejorado este código de serialización. ¡Muy recomendable!
http://cheind.wordpress.com/2011/12/06/serialization-of-cvmat-objects-using-boost/
-
Para quien sea que se pueda beneficiar: Algunos códigos para serializar Mat & con boost :: serialización
No he probado con datos multicanal, pero todo debería funcionar bien.
#include <iostream>
#include <fstream>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/split_free.hpp>
#include <boost/serialization/vector.hpp>
BOOST_SERIALIZATION_SPLIT_FREE(Mat)
namespace boost {
namespace serialization {
/*** Mat ***/
template<class Archive>
void save(Archive & ar, const Mat& m, const unsigned int version)
{
size_t elemSize = m.elemSize(), elemType = m.type();
ar & m.cols;
ar & m.rows;
ar & elemSize;
ar & elemType; // element type.
size_t dataSize = m.cols * m.rows * m.elemSize();
//cout << "Writing matrix data rows, cols, elemSize, type, datasize: (" << m.rows << "," << m.cols << "," << m.elemSize() << "," << m.type() << "," << dataSize << ")" << endl;
for (size_t dc = 0; dc < dataSize; ++dc) {
ar & m.data[dc];
}
}
template<class Archive>
void load(Archive & ar, Mat& m, const unsigned int version)
{
int cols, rows;
size_t elemSize, elemType;
ar & cols;
ar & rows;
ar & elemSize;
ar & elemType;
m.create(rows, cols, elemType);
size_t dataSize = m.cols * m.rows * elemSize;
//cout << "reading matrix data rows, cols, elemSize, type, datasize: (" << m.rows << "," << m.cols << "," << m.elemSize() << "," << m.type() << "," << dataSize << ")" << endl;
for (size_t dc = 0; dc < dataSize; ++dc) {
ar & m.data[dc];
}
}
}
}
Ahora, mat se puede serializar y deserializar de la siguiente manera:
void saveMat(Mat& m, string filename) {
ofstream ofs(filename.c_str());
boost::archive::binary_oarchive oa(ofs);
//boost::archive::text_oarchive oa(ofs);
oa << m;
}
void loadMat(Mat& m, string filename) {
std::ifstream ifs(filename.c_str());
boost::archive::binary_iarchive ia(ifs);
//boost::archive::text_iarchive ia(ifs);
ia >> m;
}
He usado el binary_oarchive y el binary_iarchive aquí para mantener el uso de la memoria. El formato binario no proporciona portabilidad entre plataformas, pero si lo desea, se puede usar text_oarchive / iarchive.
Podría usar boost::serialization
para eso. Está muy optimizado y es bastante fácil de integrar.
Las posibles aceleraciones para su caso incluyen la serialización de cada objeto como un bloque binario sin boost::serialization::make_binary
(consulte boost::serialization::make_binary
) y deshabilitar el seguimiento de versiones ( BOOST_SERIALIZATION_DISABLE_TRACKING
).
Además, puede experimentar agregando compresión en sus rutinas de serialización para ahorrar espacio (y tiempo en el caso de datos que se pueden comprimir fácilmente ). Esto se puede implementar con boost::iostreams
, por ejemplo.
¿Qué tal simplemente convertir tu Mat a un vector y usar fwrite?
El proceso de conversión a vector puede afectar el rendimiento, pero es seguro. Sospecho que todas las respuestas anteriores, ya sea recorriendo los datos de la imagen como en la respuesta aceptada, o utilizando make_array como en la publicación de Christoph, supongamos que los datos de Mat son contiguos, lo que no es necesariamente el caso. Cuando los datos de Mat no son contiguos, el resultado de estas respuestas no será correcto.
Las respuestas anteriores son buenas, pero no funcionarán para matrices no continuas que surgen cuando desea serializar regiones de interés (entre otras cosas). Además, no es necesario serializar elemSize()
porque esto se deriva del valor de type
.
Aquí hay un código que funcionará independientemente de la continuidad (con includes / namespace)
#pragma once
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/utility.hpp>
#include <opencv2/opencv.hpp>
namespace boost {
namespace serialization {
template<class Archive>
void serialize(Archive &ar, cv::Mat& mat, const unsigned int)
{
int cols, rows, type;
bool continuous;
if (Archive::is_saving::value) {
cols = mat.cols; rows = mat.rows; type = mat.type();
continuous = mat.isContinuous();
}
ar & cols & rows & type & continuous;
if (Archive::is_loading::value)
mat.create(rows, cols, type);
if (continuous) {
const unsigned int data_size = rows * cols * mat.elemSize();
ar & boost::serialization::make_array(mat.ptr(), data_size);
} else {
const unsigned int row_size = cols*mat.elemSize();
for (int i = 0; i < rows; i++) {
ar & boost::serialization::make_array(mat.ptr(i), row_size);
}
}
}
} // namespace serialization
} // namespace boost