OpenCV cv :: Mat to std :: ifstream for base64 encoding

Honestly, I am surprised that so far no one has come across this. I am loading an image from OpenCV into cv :: Mat which I want to encode base64 before sending it over the socket.

For base64, I use libb64 as it is native to Debian / Ubuntu and is easy to use and very fast. The encoding function takes std :: ifstream as a parameter and outputs 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... } 

I really don't know how to populate the stream from cv :: Mat. Approaching it, I found that I can iterate over cv :: Mat by columns and rows and get each (pixel that I accept) RGB values:

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

Is this happening right? Is there an even more elegant way?

+6
source share
1 answer

To be able to send an image via HTTP, you also need to encode its width, height and type. You need to serialize Mat into a stream and encode this stream using libb64. On the other hand, you need to decode this stream and deserialize the image to get it.

I implemented a small test program that does this serialization and deserialization using std::stringstream as a buffer. I chose it because it extends both std::istream and std::ostream , which libb64 uses.

The serialize function serialize cv::Mat to std::stringstream . In it I write the width, height, type, size of the buffer and the buffer itself.

The deserialize function does the opposite. It reads the width, height, type, buffer size and buffer. This is not as efficient as it could be, because it needs to allocate a temporary buffer to read data from the string stream. In addition, it must clone the image so that it does not rely on a temporary buffer, and it will process its own memory allocation. I am sure that with some mastering this can be done more efficiently.

The main function loads the image, serializes it, encodes it with libb64, then decodes, deserializes and displays it in the window. This should mimic what you are trying to do.

 // 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); } 
+7
source

Source: https://habr.com/ru/post/981156/


All Articles