老实说,我很惊讶到目前为止还没有人遇到过这种情况。我正在将图片从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缓冲区来进行序列化和反序列化。我选择了它,因为它同时扩展std::istream和std::ostream其libb64用途。
std::stringstream
std::istream
std::ostream
该serialize函数将a序列cv::Mat化为a std::stringstream。在其中,我写了图像的宽度,高度,类型,缓冲区的大小以及缓冲区本身。
serialize
该deserialize功能相反。它读取缓冲区的宽度,高度,类型,大小以及缓冲区。它效率不高,因为它需要分配一个临时缓冲区以从字符串流中读取数据。此外,它需要克隆映像,以便它不依赖临时缓冲区,并且它将处理自己的内存分配。我敢肯定,通过进行一些修补,它可以变得更有效率。
主要功能加载图像,对其进行序列化,使用libb64对其进行编码,然后对其进行解码,对其进行反序列化并将其显示在窗口中。这应该模拟您要尝试执行的操作。
// 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); }