I try to transmit an OpenCV IplImage from a Server (Ubuntu x64) to a Client (Win7 x64) using the boost asio library.
The following code works fine if both (Client and Server) are on the same operating system. But when the server is on Ubuntu and the client on Win7 it doesn't work. The image header is correct, but something with the image data is wrong.
I think this is because of the different bit-order between the two OS. Is it? How can I resolve this problem?
And second: The transmission with this code is very slow. How can I improve the speed?
Client:
#define _WIN32_WINNT 0x0601
#include <iostream>
#include <sstream>
#include <boost/array.hpp>
#include <boost/asio.hpp>
#include <cv.h>
#include <cxcore.h>
#include <highgui.h>
using boost::asio::ip::tcp;
using namespace std;
char* splitImage(const string& str, const string& delim, vector<string>& parts) {
size_t start, end = 0;
int i = 0;
while (end < str.size() && i < 8) {
start = end;
while (start < str.size() && (delim.find(str[start]) != string::npos)) {
start++; // skip initial whitespace
}
end = start;
while (end < str.size() && (delim.find(str[end]) == string::npos)) {
end++; // skip to end of word
}
if (end-start != 0) { // just ignore zero-length strings.
parts.push_back(string(str, start, end-start));
}
i++;
}
int size = atoi(parts[6].c_str());
char *imgdata = new char[size];
memcpy(imgdata, string(str, end+1, size).c_str(), size);
return imgdata;
}
int main(int argc, char* argv[])
{
string header;
try
{
boost::asio::io_service io_service;
tcp::resolver resolver(io_service);
tcp::resolver::query query("localhost", "1234");
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
tcp::resolver::iterator end;
tcp::socket socket(io_service);
boost::system::error_code error = boost::asio::error::host_not_found;
while (error && endpoint_iterator != end)
{
socket.close();
socket.connect(*endpoint_iterator++, error);
}
if (error)
throw boost::system::system_error(error);
stringstream ss;
cout << "reading";
for (;;)
{
boost::array<char, 1024> buf;
boost::system::error_code error;
size_t len = socket.read_some(boost::asio::buffer(buf), error);
cout << ".";
if (error == boost::asio::error::eof)
break; // Connection closed cleanly by peer.
else if (error)
throw boost::system::system_error(error); // Some other error.
ss.write(buf.data(), len);
header = ss.str();
}
cout << "done: data size: "<< header.size() << endl;
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
return 1;
}
vector<string> parts;
char* imgdata = splitImage(header,"#",parts);
IplImage img2;
img2.nSize = atoi(parts[0].c_str());
img2.ID = 0;
img2.nChannels = atoi(parts[1].c_str());
img2.depth = atoi(parts[2].c_str());
img2.dataOrder = atoi(parts[3].c_str());;
img2.height = atoi(parts[4].c_str());
img2.width = atoi(parts[5].c_str());
img2.roi = NULL;
img2.maskROI = NULL;
img2.imageId = NULL;
img2.tileInfo = NULL;
img2.imageSize = atoi(parts[6].c_str());
img2.widthStep = atoi(parts[7].c_str());
img2.imageData = imgdata;
cvNamedWindow("Image:",1);
cvShowImage("Image:",&img2);
cvWaitKey();
cvDestroyWindow("Image:");
delete[] imgdata;
return 0;
}
Server:
#define _WIN32_WINNT 0x0601
#define WIN32_LEAN_AND_MEAN
#include <string>
#include <iostream>
#include <cv.h>
#include <cxcore.h>
#include <highgui.h>
#include <boost/asio.hpp>
#define DELIMITER "#"
using boost::asio::ip::tcp;
using namespace std;
IplImage *img;
string serializeImageHeader(){
stringstream ss;
ss << img->nSize << DELIMITER;
ss << img->nChannels << DELIMITER;
ss << img->depth << DELIMITER;
ss << img->dataOrder << DELIMITER;
ss << img->height << DELIMITER;
ss << img->width << DELIMITER;
ss << img->imageSize << DELIMITER;
ss << img->widthStep << DELIMITER;
return ss.str();
}
int main()
{
try
{
boost::asio::io_service io_service;
tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), 1234));
img = cvLoadImage("Test.bmp");
cout << "Server is running" << endl;
for (;;)
{
tcp::socket socket(io_service);
acceptor.accept(socket);
cout << "socket accepted" << endl;
string message = serializeImageHeader().append(img->imageData, img->imageSize);
boost::system::error_code ignored_error;
boost::asio::write(socket, boost::asio::buffer(message),
boost::asio::transfer_all(), ignored_error);
cout << "sent: size: "<< message.size() << endl;
}
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
cvReleaseImage(&img);
return 0;
}
You should also create a new image on the destination, with the values for the image header parameters you copied over then copy the image data into the new image (ideally a row at a time)
There is no guarrantee that openCV lays out the image data in the same way, it may have different padding or different rowstrides
You might try a library like Boost.Serialization rather than rolling your own version to see if it makes a difference:
7) Data Portability - Streams of bytes created on one platform should be readable on any other.
来源:https://stackoverflow.com/questions/5126923/boost-asio-send-opencv-iplimage-from-ubuntu-server-to-win7-client