2

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;
}
Dave
  • 23
  • 2
  • 4

2 Answers2

1

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.

Sam Miller
  • 23,808
  • 4
  • 67
  • 87
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

Martin Beckett
  • 94,801
  • 28
  • 188
  • 263
  • you are right! but how can I do this? I tried the following: IplImage *img2 = cvCreateImage(cvSize(atoi(parts[5].c_str()),atoi(parts[4].c_str())),atoi(parts[2].c_str()),atoi(parts[1].c_str())); cvSetImageData(img2,imgdata,img2->widthStep); But this doesn't work! – Dave Feb 26 '11 at 17:37
  • That's the best way of making the new image header. The data loss might be from using char rather than unsigned char - it may be loosing the top bit – Martin Beckett Feb 26 '11 at 17:44
  • in the opencv source code the imagedata is char* and not unsigned char*. And when I do it as in the source code of my initial post it works if client and server run on the same OS. So i dont think this is the problem. – Dave Feb 26 '11 at 18:00
  • Was the same Os still over a network? The network copy may just shortcut to an in memory copy on the same machine and not convert to ascii – Martin Beckett Feb 26 '11 at 18:17
  • now it works! I forgot to remove the & from cvReleaseImage(&img); It also works for Linux-Windows settings. thx a lot! – Dave Feb 26 '11 at 18:30