将 boost ASIO 缓冲区数据转换为 JPEG 格式的 opencv 矩阵

translate a boost ASIO buffer data to an opencv matrix of JPEG format

我已经构建了一个 C++ 程序来通过 TCP 套接字发送单个 jpg 帧(以及预先的元数据 header)。我的问题是。我正在成功获取字节。正在解析我的 header 并看到了我的尺寸..字节数...但我的问题是..我现在如何获取这些数据..并重新创建我的 JPEG?

我一直在尝试抛出缓冲区但被阻止了

std::cout << "[IMAGE_WIDTH]  = " << std::to_string(IMAGE_WIDTH) << std::endl;
std::cout << "[IMAGE_HEIGHT] = " << std::to_string(IMAGE_HEIGHT) << std::endl;
std::cout << "image bytes  = " << std::to_string(header_data.image_size_bytes) << std::endl;

Mat img = Mat::zeros(IMAGE_WIDTH, IMAGE_HEIGHT, CV_8UC3);
const unsigned char* image_data_matrix = boost::asio::buffer_cast<const unsigned char*>(second_receive_buffer.data());
img.data = image_data_matrix;
imshow("server", img);
waitKey(100);

我从 gcc

得到的错误
[ 50%] Building CXX object CMakeFiles/sockets-client.dir/src/client.cpp.o
/bootstrap-cpp-sockets/client/src/client.cpp:81:28: error: assigning to 'uchar *' (aka 'unsigned char *') from 'const unsigned char *' discards qualifiers
                img.data = image_data_matrix;
                           ^~~~~~~~~~~~~~~~~
1 error generated.
make[2]: *** [CMakeFiles/sockets-client.dir/src/client.cpp.o] Error 1
make[1]: *** [CMakeFiles/sockets-client.dir/all] Error 2
make: *** [all] Error 2

完整 Client.cpp

int main()
{
    try{
        boost::asio::io_service io_service;
        tcp::endpoint end_point(boost::asio::ip::address::from_string("127.0.0.1"), 3200);
        tcp::socket socket(io_service);
        socket.connect(end_point);
        boost::system::error_code ignored_error;
        boost::asio::streambuf receive_buffer;

        // Now we retrieve the message header of 64 bytes
        size_t header_size = 64;
        boost::asio::read(socket, receive_buffer, boost::asio::transfer_exactly(header_size), ignored_error);

        if ( ignored_error && ignored_error != boost::asio::error::eof ) {
            cout << "first receive failed: " << ignored_error.message() << endl;
        } else {
            image_metadata_t header_data = parse_header(receive_buffer);

            const int IMAGE_WIDTH = header_data.width;
            const int IMAGE_HEIGHT = header_data.height;

            // Now we retrieve the frame itself
            boost::asio::streambuf second_receive_buffer;
            boost::asio::read(socket, second_receive_buffer, boost::asio::transfer_exactly(header_data.image_size_bytes), ignored_error);
            if( ignored_error && ignored_error != boost::asio::error::eof ) {
                cout << "SECOND receive failed: " << ignored_error.message() << endl;
            }
            else {
                std::cout << "[IMAGE_WIDTH]  = " << std::to_string(IMAGE_WIDTH) << std::endl;
                std::cout << "[IMAGE_HEIGHT] = " << std::to_string(IMAGE_HEIGHT) << std::endl;
                std::cout << "image bytes  = " << std::to_string(header_data.image_size_bytes) << std::endl;

                Mat img = Mat::zeros(IMAGE_WIDTH, IMAGE_HEIGHT, CV_8UC3);
                const unsigned char* image_data_matrix = boost::asio::buffer_cast<const unsigned char*>(second_receive_buffer.data());
                img.data = image_data_matrix;
                imshow("server", img);
                waitKey(100);
            }
        }
    } catch (std::exception& e) {
        std::cerr << e.what() << std::endl;
    }
 
    return 0;
}

最终完成的程序将继续读取套接字,接收带有元数据的 header.. 并显示下一帧.. 希望达到每秒 30 帧但是.. 首先我只是想证明我可以用一帧做到这一点..并从那里建立起来。

谢谢!

我在聊天中与@Dan 进行了一些澄清之后。我修改了服务器端和客户端。我现在将它们都附加在这里,以供其他任何试图通过网络发送 JPG 数据的人使用

#include <iostream>
#include <boost/array.hpp>
#include <boost/asio.hpp>
#include <boost/thread/thread.hpp>
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <opencv2/core/core.hpp> 
#include <string>
#include <vector>

using boost::asio::ip::tcp;
using namespace std;
using namespace cv;
 
// source https://www.programmerall.com/article/7721373696/
// source https://cppsecrets.com/users/14041151035752494957504952535764103109971051084699111109/Programming-in-C00-using-boostasio.php
bool flag = false;    

void servershow()
{
    while (true)
    {
        if (flag)
        {
            //imshow("server",img);
            waitKey(1);
        }   
    }
}

cv::Mat retrieve_data(){

    std::string image_path = "/YOUR_IMAGE.jpg";
    cv::Mat image;
    image = imread(image_path, cv::IMREAD_COLOR);
    if(! image.data ) {
        std::cout << "Could not open or find the image" << std::endl;
    }
    return image;
}


int main()
{
    boost::thread thrd(&servershow);
    try
    {
        boost::asio::io_service io_service;
        tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), 3200));
        
        for (;;) {
            tcp::socket socket(io_service);
            acceptor.accept(socket);
            boost::system::error_code ignored_error;

            //retrieve the frame to be sent
            cv::Mat frame = retrieve_data();
            std::vector<std::uint8_t> buff;
            cv::imencode(".jpg", frame, buff, param);

            // now we send the header message
            std:: string image_dimensions = "6016Wx3384H";
            std:: string image_buff_bytes = std::to_string(buff.size());
            std::string message_header = image_dimensions + "," +  image_buff_bytes;
            std::cout << "sending measage header of " << std::to_string(message_header.length()) << " bytes...." << std::endl;
            message_header.append(63 - message_header.length(), ' ');
            message_header = message_header + '[=10=]';

            socket.write_some(boost::asio::buffer(message_header), ignored_error);

            socket.write_some(boost::asio::buffer(buff), ignored_error);

            flag = true;
        }
    }
    catch (std::exception& e)
    {
        std::cerr << e.what() << std::endl;
    }
    thrd.join();

    return 0; 
}

客户端检索

#include <iostream>
#include <boost/asio.hpp>
#include <boost/array.hpp>
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <opencv2/objdetect/objdetect.hpp>
#include <string>
#include <vector>


using boost::asio::ip::tcp;

using namespace std;
using namespace cv;

// source https://www.programmerall.com/article/7721373696/
// source https://cppsecrets.com/users/14041151035752494957504952535764103109971051084699111109/Programming-in-C00-using-boostasio.php

struct image_metadata_t {
    int width;
    int height;
    size_t image_size_bytes;
};

image_metadata_t parse_header(boost::asio::streambuf &buffer){

    std::string data_buff_str = std::string(boost::asio::buffer_cast<const char*>(buffer.data()));
    cout << data_buff_str << endl;

    int width_pos = data_buff_str.find("W"); 
    int x_pos = data_buff_str.find("x"); 
    int height_pos = data_buff_str.find("H"); 
    int comma_pos = data_buff_str.find(","); 

    std::cout << "data_buff_str.substr(x_pos+1,height_pos) " << data_buff_str.substr(x_pos+1,height_pos) <<std::endl;

    image_metadata_t meta_data;
    meta_data.width = std::stoi(data_buff_str.substr(0,width_pos));
    meta_data.height = std::stoi(data_buff_str.substr(x_pos+1,height_pos));
    meta_data.image_size_bytes = std::stoi(data_buff_str.substr(data_buff_str.find(",") + 1));

    return meta_data;
}


cv::Mat GetImageFromMemory(uchar* image, int length, int flag) {
    std::vector<uchar> data = std::vector<uchar>(image, image + length);
    cv::Mat ImMat = imdecode(data, flag);

    return ImMat;
}

int main()
{
    try{
        boost::asio::io_service io_service;
        tcp::endpoint end_point(boost::asio::ip::address::from_string("127.0.0.1"), 3200);
        tcp::socket socket(io_service);
        socket.connect(end_point);
        boost::system::error_code ignored_error;
        boost::asio::streambuf receive_buffer;

        // Now we retrieve the message header of 64 bytes
        size_t header_size = 64;
        boost::asio::read(socket, receive_buffer, boost::asio::transfer_exactly(header_size), ignored_error);

        if ( ignored_error && ignored_error != boost::asio::error::eof ) {
            cout << "first receive failed: " << ignored_error.message() << endl;
        } else {
            image_metadata_t header_data = parse_header(receive_buffer);

            const int IMAGE_WIDTH = header_data.width;
            const int IMAGE_HEIGHT = header_data.height;

            // Now we retrieve the frame itself
            std::cout << "Now asing for image bytes of size " << std::to_string(header_data.image_size_bytes) << std::endl;
            //boost::asio::streambuf second_receive_buffer;
            std::vector<std::uint8_t> buff(header_data.image_size_bytes);
            boost::asio::read(socket, boost::asio::buffer(buff), boost::asio::transfer_exactly(header_data.image_size_bytes), ignored_error);
            if( ignored_error && ignored_error != boost::asio::error::eof ) {
                cout << "SECOND receive failed: " << ignored_error.message() << endl;
            }
            else {
                std::cout << "[IMAGE_WIDTH]  = " << std::to_string(IMAGE_WIDTH) << std::endl;
                std::cout << "[IMAGE_HEIGHT] = " << std::to_string(IMAGE_HEIGHT) << std::endl;
                std::cout << "image bytes  = " << std::to_string(header_data.image_size_bytes) << std::endl;

                cv::Mat img(cv::imdecode(buff, cv::IMREAD_ANYCOLOR));

                imshow("client", img);
                waitKey(5000);
            }
        }
    } catch (std::exception& e) {
        std::cerr << e.what() << std::endl;
    }
 
    return 0;
}