Send lot of data over network

Hi

I am not quite sure about what is the best approach to this problem:

I am trying to program a host computer that analyzes realtime video frames for bright areas. That way I get a lot of coordinate points that I want to stream to a (or maybe multiple) computers or iphones.

What I did as a simple test was analyzing the coordinates, combining them in a single string and then sending them via ofxNetwork udp connection to the clients, where I split the string and process the data. This works, but is, (what a surprise) really slow…

Is there a way to compress the data? would that increase speed? Or should I split the packages to smaller ones? Or shouldn’t I even use this class at all? I think the whole procedure is really close to the technology behind streamed video?

Would be great if anybody has a direction to point me to.

thanks
Philip

an udp connection should be the way to go, it’s the fastest way of sending data as it does introduce almost no headers. when you tell a lot of coordinates how much are you talking about? also what kind of data are you trying to send? perhaps you can simplify it in some way before sending it. if it’s the contour of the brightest areas, an easy way of simplfying it is by sending only one every two or three points that way you’re getting more or less the same shape but with less points.

also this is a function to simplify a polygon using opencv:

  
  
vector<ofPoint> simplifyPoly(vector<ofPoint> & poly, float accuracy){  
	CvMemStorage * storage = cvCreateMemStorage();  
	CvSeq * cvPoly = cvCreateSeq(CV_SEQ_POLYGON, sizeof(CvContour), sizeof(CvPoint2D32f), storage);  
  
  
  
	CvPoint2D32f point;  
	std::list<ofPoint>::iterator it;  
	for(it = poly.begin(); it!=poly.end(); it++){  
		ofPoint p2d = (*it);  
		point.x = p2d.x;  
		point.y = p2d.y;  
  
		cvSeqPush(cvPoly, &point);  
	}  
  
	CvSeq * aprox = cvApproxPoly( cvPoly, sizeof(CvContour), storage, CV_POLY_APPROX_DP, accuracy, 0 );  
	CvSeqReader       reader;  
	cvStartReadSeq( aprox, &reader, 0 );  
	vector<ofPoint> aproxPoly;  
  
	for( int j=0; j < aprox->total; j++ ) {  
		CV_READ_SEQ_ELEM( point, reader );  
		aproxPoly.push_back( ofPoint((float)point.x, (float)point.y) );  
	}  
  
	cvReleaseMemStorage(&storage);  
	return aproxPoly;  
}  

i’m looking but can’t remember right now in what units is the accuracy parameter expressed, i think it’s related to the polygon perimeter but not sure, so try with different values till you get something enough similar to your original poly and as few points as posible.

Great, thanks

I’m talking about 200 points or so. But if this is too much, we’ll simplify.

The data we send are x y coordinates of the center of bright areas and maybe some counters storing the framecount they’re already visible.

i dont think it’s that much. but note that sending things as strings is not the most optimal as each character is going to be a byte, by sending it as binary each number is only 4 bytes as integer or if you can do with 0…255 just one byte. perhaps you can compress each coordinate to just an int by doing something like:

  
unsigned coord = point.x + point.y*10000;  

then when receiving it you can just:

  
int y = coord / 10000;  
int x = coord - y * 10000;  

you can send an array of ints and use a terminator if you’re not sending always the same number of coordinates:

  
unsigned coords[200];  
//do the point to int trick here   
//for each coord and store them in the array  
udp.SendAll((const char*)coords,200*4); // an int is 4 bytes so 200 ints...  

to receeive:

  
unsigned coords[200];  
udp.Receive((char*)coords, 200*4);  
//do the reverse int to point trick here for each int in the array  
  

also if you can avoid wifi do it : ) an ethernet cable is like 10 times faster if the wifi is going at full speed (no noise…)

oh, and set the receive and send buffers to 200*4 or more:

  
  
udp.SetSendBuffer(200*4);  
udp.SetReceiveBuffer(200*4)  

EDIT: also you can make it even faster by using bit displacement to pack the point in an interger instead of multiplying and dividing, this way you can have the y in 2 bits and the x in the other 2 bits of the integer. although i don’t think this is going to be an issue compared to the network transmission but anyway:

to pack it

  
int coord = (int)point.y << 15;  
coord += point.x;  

to unpack:

  
point.y = coord >> 15;  
point.x = coord - ((int)point.y << 15);  

thanks for your tips. very useful. This compresses the whole thing way more than my first try with characters!

I almost got it working. But there seems to be some error receiving the data.

I send like this (666 is my delimiter)

  
  
                unsigned coords[300];  
		for (int i = 0; i < contourFinder.nBlobs && i<300; i++){  
			p = contourFinder.blobs[i].centroid;  
			unsigned coord = p.x + p.y*10000;  
			coords[i] = coord;  
			//msg << numToString(p.x) << numToString(p.y);  
		}  
		if(contourFinder.nBlobs < 300){  
			coords[contourFinder.nBlobs] = 666;  
		}  
		int sent = udpConnection.SendAll((const char*)coords,300*4);  
  

and receive like that

  
unsigned coords[300];  
	udpConnection.Receive((char*)coords,300*4);  
	//string message=udpMessage;  
	unsigned coord = coords[0];  
	int y = coord / 10000;  
	int x = coord - y * 10000;  
	cout << "print " << x <<  y << endl;  

but the cout always says print 00

I am pretty sure the udp connection works. But if you say this should work, I’ll double check :wink:

EDIT: saw your edit too late, implemented it with the same result

this is working for me:

testApp.h:

  
#include "ofMain.h"  
  
#include "ofxNetwork.h"  
  
  
  
class testApp : public ofBaseApp{  
  
	public:  
  
		void setup();  
		void update();  
  
		void keyPressed(int key);  
  
		ofxUDPManager sender;  
		ofxUDPManager receiver;  
  
  
		unsigned scoords[300];  
		unsigned rcoords[300];  
  
};  

testApp.cpp:

  
#include "testApp.h"  
  
void testApp::setup(){  
	sender.Create();  
	sender.SetSendBufferSize(300*4);  
	sender.SetNonBlocking(true);  
	receiver.Create();  
	receiver.SetReceiveBufferSize(300*4);  
	receiver.SetNonBlocking(true);  
	sender.Connect("127.0.0.1",11111);  
	if(!receiver.Bind(11111)) cout << "error binding" << endl;  
	ofSetFrameRate(1);  
}  
void testApp::update(){  
   int ret = receiver.Receive((char*)rcoords,300*4);  
   cout << "received: " << ret << " bytes" << endl;  
   //string message=udpMessage;  
   if(ret!=-1){  
	   for(int i=0; i<300; i++){  
		   unsigned coord = rcoords[i];  
		   int y = coord >> 15;  
		   int x = coord - (y << 15);  
		   cout << "print " << x << "," <<  y << endl;  
	   }  
   }  
}  
  
void testApp::keyPressed(int key){  
  
	ofPoint p;  
	for (int i = 0; i<300; i++){  
		p = ofPoint(i,i+100);  
		unsigned coord = (int)p.y << 15;  
		coord += p.x;  
		scoords[i] = coord;  
		//msg << numToString(p.x) << numToString(p.y);  
	}  
	int sent = sender.SendAll((const char*)scoords,300*4);  
	cout << sent << " bytes sent" << endl;  
}  

Thanks. Great to have a working sample.

Strange thing. The error was

  
receiver.SetReceiveBufferSize(300*4);  

After I took this line out of the receiver everything worked just fine?

what platform are you using? it works for me without problem, under linux.

I use OS X 10.6 to send and a jailbreaked iPhone to receive

EDIT: final product will probably be a windows System to send and OS X 10.6 to receive.

i suppose the problem is in the iphone network stack not supporting buffer that big, but don’t know for sure.

Default buffer (GetReceiveBufferSize) size is 42080.
But that doesn’t matter for now. It’s working nicely and fast enough. Even over a wireless network. Thanks!

cool! yes, you should be sending 300*4*30fps so about 36kb per second which isn’t that much indeed.