Hello
Here is the code I made in order to read one or more matrices written in a text file.
It is all but the most efficient way to do it and it is limitted to the numpy formating.
utils.h
#include <opencv2/core.hpp>
#include <fstream>
namespace utils
{
class StdFileStreamFormater
{
public:
inline StdFileStreamFormater(std::fstream& _stream):
stream(_stream)
{}
StdFileStreamFormater(const StdFileStreamFormater&) = delete;
StdFileStreamFormater(StdFileStreamFormater&&) = delete;
~StdFileStreamFormater() = default;
StdFileStreamFormater& operator=(const StdFileStreamFormater&) = delete;
StdFileStreamFormater& operator=(StdFileStreamFormater&&) = delete;
void writeMatrixWithNumpyFmt(cv::InputArray _tmp);
void readFileWithNumpyFmt(cv::OutputArray _out);
inline std::fstream& getStream()const { return this->stream; }
inline operator std::fstream&()const { return this->stream; }
private:
std::fstream& stream;
};
} //utils
utils.cpp
#include <fstream>
#include <sstream>
#include <iterator>
#include <numeric>
namespace utils
{
void StdFileStreamFormater::writeMatrixWithNumpyFmt(cv::InputArray _tmp)
{
CV_Assert(_tmp.isMat() || _tmp.isUMat() || _tmp.isGpuMat() || _tmp.isMatVector() || _tmp.isUMatVector() || _tmp.isGpuMatVector() || (_tmp.kind() == cv::_InputArray::EXPR));
if(!_tmp.isVector())
{
if(!_tmp.isGpuMat())
this->stream<<cv::format(_tmp.getMat(), cv::Formatter::FMT_NUMPY)<<std::endl;
else
{
cv::Mat tmp(_tmp.getGpuMat());
this->stream<<cv::format(tmp, cv::Formatter::FMT_NUMPY)<<std::endl;
}
}
else
{
std::vector<cv::Mat> tmp;
if(!_tmp.isGpuMatVector())
_tmp.getMatVector(tmp);
else
{
std::vector<cv::cuda::GpuMat> tmp2;
_tmp.getGpuMatVector(tmp2);
tmp.resize(tmp2.size());
std::transform(tmp2.begin(), tmp2.end(), tmp.begin(),[](const cv::cuda::GpuMat& src)->cv::Mat{ return cv::Mat(src); });
}
for(const cv::Mat& image : tmp)
this->stream<<cv::format(image, cv::Formatter::FMT_NUMPY)<<std::endl;
}
}
void StdFileStreamFormater::readFileWithNumpyFmt(cv::OutputArray _out)
{
static std::unordered_map<cv::String, int> Strings2Types =
{
std::make_pair("uint8",CV_8U),
std::make_pair("int8",CV_8S),
std::make_pair("uint16",CV_16U),
std::make_pair("int16",CV_16S),
std::make_pair("int32",CV_32S),
std::make_pair("float32",CV_32F),
std::make_pair("foat64",CV_64F),
};
// Step 0-a): Copy the content of the file in memory.
std::ostringstream oss;
oss<<this->stream.rdbuf();
cv::String buffer = oss.str();
// Step 0-b): Count the number of matrices in the file.
int nb_images = 0;
size_t init = buffer.find("array");
while(init != cv::String::npos)
{
nb_images++;
init = buffer.find("array",init + 5);
}
std::vector<cv::Mat> images;
images.resize(nb_images);
init = 0;
// For each matrix... (there is prior that each matrix represent an image. This prior may be wrong.)
for(int i=0;i<nb_images;i++)
{
// Step 0-c): Copy the data of the current matrix to a local buffer.
init = buffer.find("array", init);
// Step 1): From the buffer get the depth of the current matrix.
cv::Range matrix_position;
matrix_position.start = static_cast<int>(init)+7;
matrix_position.end = buffer.find("dtype", static_cast<size_t>(matrix_position.start));
cv::String strType;
size_t j = static_cast<size_t>(matrix_position.end + 7);
if(buffer[j] == '\'')
j++;
while(buffer[j]!='\'')
strType.push_back(buffer[j++]);
int depth = Strings2Types[strType];
cv::String data = buffer.substr(static_cast<size_t>(matrix_position.start), static_cast<size_t>(matrix_position.size()) );
// Step 2): From the duplication of the data for the current matrix count the number of channels.
int cns = 1;
init = data.find("[[[");
if(init != cv::String::npos)
{
size_t end = data.find("]",init+3);
init = data.find(",",init+3);
while(init != cv::String::npos)
{
cns++;
init = data.find(",",init+1);
if(init>end)
break;
}
}
// Step 3): From the duplication of the data for the current matrix count the number of ...
(more)