OpenCV cv::Mat 到 std::ifstream 用于 base64 编码
OpenCV cv::Mat to std::ifstream for base64 encoding
老实说,到目前为止还没有人 运行 对此感到惊讶。
我正在将一张图片从 OpenCV 加载到 cv::Mat,我想在通过套接字发送它之前对其进行 base64 编码。
对于 base64,我使用 libb64,因为它是 Debian/Ubuntu 的原生格式,而且易于使用且速度非常快。编码函数以一个std::ifstream作为参数,输出一个std::ofstream.
#include <opencv2/opencv.hpp>
#include <b64/encode.h>
#include <fstream>
using namespace cv;
Mat image;
image = imread( "picture.jpg", CV_LOAD_IMAGE_COLOR );
if ( image.data )
{
std::ifstream instream( ???, std::ios_base::in | std::ios_base::binary);
std::ofstream outstream;
// Convert Matrix to ifstream
// ...
base64::encoder E;
E.encode( instream, outstream );
// Now put it in a string, and send it over a socket...
}
我真的不知道如何从 cv::Mat 填充插播。
谷歌搜索,我发现我可以按列和行迭代 cv::Mat,并获取每个(我假设的像素)RGB 值:
for ( int j = 0; j < image.rows; j++ )
{
for ( int i = 0; i < image.cols; i++ )
{
unsigned char b = input [ image.step * j + i ] ;
unsigned char g = input [ image.step * j + i + 1 ];
unsigned char r = input [ image.step * j + i + 2 ];
}
}
这是正确的处理方式吗?有没有更优雅的方式?
为了能够通过 HTTP 发送图像,您还需要对其宽度、高度和类型进行编码。您需要将 Mat
序列化为流并使用 libb64 对该流进行编码。另一方面,您需要解码该流并反序列化图像以检索它。
我实现了一个小型测试程序,它使用 std::stringstream
作为缓冲区来执行此序列化和反序列化。我选择它是因为它扩展了 libb64 使用的 std::istream
和 std::ostream
。
serialize
函数将 cv::Mat
序列化为 std::stringstream
。在里面,我写了图像的宽度、高度、类型、缓冲区的大小和缓冲区本身。
deserialize
函数执行相反的操作。它读取缓冲区和缓冲区的宽度、高度、类型、大小。它的效率不如预期,因为它需要分配一个临时缓冲区来从字符串流中读取数据。此外,它需要克隆图像,以便它不依赖于临时缓冲区,并会处理自己的内存分配。我相信通过一些修补它可以变得更有效率。
主函数加载图像,序列化,使用 libb64 编码,然后解码,反序列化并在 window 中显示。这应该模拟您正在尝试做的事情。
// Serialize a cv::Mat to a stringstream
stringstream serialize(Mat input)
{
// We will need to also serialize the width, height, type and size of the matrix
int width = input.cols;
int height = input.rows;
int type = input.type();
size_t size = input.total() * input.elemSize();
// Initialize a stringstream and write the data
stringstream ss;
ss.write((char*)(&width), sizeof(int));
ss.write((char*)(&height), sizeof(int));
ss.write((char*)(&type), sizeof(int));
ss.write((char*)(&size), sizeof(size_t));
// Write the whole image data
ss.write((char*)input.data, size);
return ss;
}
// Deserialize a Mat from a stringstream
Mat deserialize(stringstream& input)
{
// The data we need to deserialize
int width = 0;
int height = 0;
int type = 0;
size_t size = 0;
// Read the width, height, type and size of the buffer
input.read((char*)(&width), sizeof(int));
input.read((char*)(&height), sizeof(int));
input.read((char*)(&type), sizeof(int));
input.read((char*)(&size), sizeof(size_t));
// Allocate a buffer for the pixels
char* data = new char[size];
// Read the pixels from the stringstream
input.read(data, size);
// Construct the image (clone it so that it won't need our buffer anymore)
Mat m = Mat(height, width, type, data).clone();
// Delete our buffer
delete[]data;
// Return the matrix
return m;
}
void main()
{
// Read a test image
Mat input = imread("D:\test\test.jpg");
// Serialize the input image to a stringstream
stringstream serializedStream = serialize(input);
// Base64 encode the stringstream
base64::encoder E;
stringstream encoded;
E.encode(serializedStream, encoded);
// Base64 decode the stringstream
base64::decoder D;
stringstream decoded;
D.decode(encoded, decoded);
// Deserialize the image from the decoded stringstream
Mat deserialized = deserialize(decoded);
// Show the retrieved image
imshow("Retrieved image", deserialized);
waitKey(0);
}
老实说,到目前为止还没有人 运行 对此感到惊讶。 我正在将一张图片从 OpenCV 加载到 cv::Mat,我想在通过套接字发送它之前对其进行 base64 编码。
对于 base64,我使用 libb64,因为它是 Debian/Ubuntu 的原生格式,而且易于使用且速度非常快。编码函数以一个std::ifstream作为参数,输出一个std::ofstream.
#include <opencv2/opencv.hpp>
#include <b64/encode.h>
#include <fstream>
using namespace cv;
Mat image;
image = imread( "picture.jpg", CV_LOAD_IMAGE_COLOR );
if ( image.data )
{
std::ifstream instream( ???, std::ios_base::in | std::ios_base::binary);
std::ofstream outstream;
// Convert Matrix to ifstream
// ...
base64::encoder E;
E.encode( instream, outstream );
// Now put it in a string, and send it over a socket...
}
我真的不知道如何从 cv::Mat 填充插播。 谷歌搜索,我发现我可以按列和行迭代 cv::Mat,并获取每个(我假设的像素)RGB 值:
for ( int j = 0; j < image.rows; j++ )
{
for ( int i = 0; i < image.cols; i++ )
{
unsigned char b = input [ image.step * j + i ] ;
unsigned char g = input [ image.step * j + i + 1 ];
unsigned char r = input [ image.step * j + i + 2 ];
}
}
这是正确的处理方式吗?有没有更优雅的方式?
为了能够通过 HTTP 发送图像,您还需要对其宽度、高度和类型进行编码。您需要将 Mat
序列化为流并使用 libb64 对该流进行编码。另一方面,您需要解码该流并反序列化图像以检索它。
我实现了一个小型测试程序,它使用 std::stringstream
作为缓冲区来执行此序列化和反序列化。我选择它是因为它扩展了 libb64 使用的 std::istream
和 std::ostream
。
serialize
函数将 cv::Mat
序列化为 std::stringstream
。在里面,我写了图像的宽度、高度、类型、缓冲区的大小和缓冲区本身。
deserialize
函数执行相反的操作。它读取缓冲区和缓冲区的宽度、高度、类型、大小。它的效率不如预期,因为它需要分配一个临时缓冲区来从字符串流中读取数据。此外,它需要克隆图像,以便它不依赖于临时缓冲区,并会处理自己的内存分配。我相信通过一些修补它可以变得更有效率。
主函数加载图像,序列化,使用 libb64 编码,然后解码,反序列化并在 window 中显示。这应该模拟您正在尝试做的事情。
// Serialize a cv::Mat to a stringstream
stringstream serialize(Mat input)
{
// We will need to also serialize the width, height, type and size of the matrix
int width = input.cols;
int height = input.rows;
int type = input.type();
size_t size = input.total() * input.elemSize();
// Initialize a stringstream and write the data
stringstream ss;
ss.write((char*)(&width), sizeof(int));
ss.write((char*)(&height), sizeof(int));
ss.write((char*)(&type), sizeof(int));
ss.write((char*)(&size), sizeof(size_t));
// Write the whole image data
ss.write((char*)input.data, size);
return ss;
}
// Deserialize a Mat from a stringstream
Mat deserialize(stringstream& input)
{
// The data we need to deserialize
int width = 0;
int height = 0;
int type = 0;
size_t size = 0;
// Read the width, height, type and size of the buffer
input.read((char*)(&width), sizeof(int));
input.read((char*)(&height), sizeof(int));
input.read((char*)(&type), sizeof(int));
input.read((char*)(&size), sizeof(size_t));
// Allocate a buffer for the pixels
char* data = new char[size];
// Read the pixels from the stringstream
input.read(data, size);
// Construct the image (clone it so that it won't need our buffer anymore)
Mat m = Mat(height, width, type, data).clone();
// Delete our buffer
delete[]data;
// Return the matrix
return m;
}
void main()
{
// Read a test image
Mat input = imread("D:\test\test.jpg");
// Serialize the input image to a stringstream
stringstream serializedStream = serialize(input);
// Base64 encode the stringstream
base64::encoder E;
stringstream encoded;
E.encode(serializedStream, encoded);
// Base64 decode the stringstream
base64::decoder D;
stringstream decoded;
D.decode(encoded, decoded);
// Deserialize the image from the decoded stringstream
Mat deserialized = deserialize(decoded);
// Show the retrieved image
imshow("Retrieved image", deserialized);
waitKey(0);
}