【问题标题】:OpenCV cv::Mat to std::ifstream for base64 encodingOpenCV cv::Mat 到 std::ifstream 用于 base64 编码
【发布时间】:2015-03-16 05:45:11
【问题描述】:

说实话,我很惊讶到目前为止还没有人遇到这种情况。 我正在将 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 ];
    }
}

这是正确的处理方式吗?还有更优雅的方式吗?

【问题讨论】:

  • 你到底想完成什么?你想序列化图像(你希望能够在另一边读取它)吗?如果您只对图像数据进行编码,那么您将不知道它的宽度、高度或通道数。为什么不对输入文件而不是 Mat 进行 base64 编码?此外,如果您想通过套接字发送图像,您实际上不需要对其进行 base64 编码,您可以按原样发送并减少开销。
  • @Ove 套接字的另一端可能是不同的架构或平台,并且不会使用 C++。我希望通过使用 base64 序列化来避免某些问题,但我愿意接受任何建议。所以,你认为序列化图片而不是 cv::Mat 更好吗?问题是,可能没有任何图片,而是相机拍摄的图像。另外,套接字使用的是 HTTP 协议,所以我发布的是 JSON 文本。

标签: c++ opencv stream base64


【解决方案1】:

为了能够通过 HTTP 发送图像,您还需要对其宽度、高度和类型进行编码。您需要将Mat 序列化为流并使用libb64 对该流进行编码。另一方面,您需要解码该流并反序列化图像以检索它。

我实现了一个小测试程序,它使用std::stringstream 作为缓冲区来进行序列化和反序列化。我选择它是因为它扩展了 libb64 使用的 std::istreamstd::ostream

serialize 函数将cv::Mat 序列化为std::stringstream。在里面我写了图片的宽度、高度、类型、缓冲区的大小和缓冲区本身。

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);
}

【讨论】:

  • 哇,非常感谢!我没想到会得到答案:-)
  • 这段代码似乎过时了,使用了已删除的字符串流实用程序
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多