I've built a C program to send a single jpg frame (along with a metadata header beforehand) over a TCP socket.. my trouble is.. I am getting the bytes successfully.. parsing my header and seeing my dimenions.. the number of bytes... but my question is.. how do I take this data now.. and recreate my JPEG?
I keep trying to cast the buffer but getting stopped out
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);
error I get from 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
Full 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;
}
the eventual finished program will keep reading the socket, receiving a header with the metadata.. and showing the next frame.. hopefully 30 Frames per second will be hit but.. first thing first I just want to prove i can do this with one frame.. and build up from there.
Thanks !
CodePudding user response:
after some clarification on my part with @Dan in the chat.. I modified both the server side and client side.. I append them both here now for anyone else trying to send JPG data over the wire
#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 '\0';
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;
}
Client retrieval
#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;
}