0

を介してクライアントからサーバーにイメージ ( OpenCV )を送信しようとしています。最初の項目は、バッファーのサイズである int です。10 ~ 15 個の画像に対して機能し、サーバーは最初の int 乱数 (通常は ~2^30) を読み取り、アプリをクラッシュさせます。これはループ内のクライアント側です (画像は周期 500 ミリ秒の Web カメラから取得されます)。MatQDataStream

//1) encode to jpg
 cv::vector<uchar> buf;
 cv::imencode(".jpg", *mat, buf);

 //2) write to buffer
 QByteArray buffer;
 QDataStream out(&buffer, QIODevice::WriteOnly);
 out << int(0); // save place for an int which represents the buffer size

 for(cv::vector<uchar>::iterator it = buf.begin(); it != buf.end(); ++it)
 {
  out << *it; //write each byte
 }

 out.device()->seek(0); //write the buffer size
 out << buffer.size();
 qDebug() << "Sent " << buffer.size() << "bytes";

 qint64 bytesSent = socket->write(buffer);
 if(bytesSent < buffer.size())
 {
  if(bytesSent != -1)
  {
   qDebug() << "Transmit Error! Sent " << bytesSent << " out of " << buffer.size();
  }
  else
  {
   qDebug() << socket->errorString();
  }
 }

サーバ側:

QDataStream in(socket);
 int msgSize = -1;

 //first read the size as an int
 if(socket->bytesAvailable())
 {
  in >> msgSize;
 }

 qDebug() << "Read image size: " << msgSize << "bytes";
 //wait until all bytes all available
 while(socket->bytesAvailable() < ( qint64 ) ( ( qint64 )msgSize - sizeof(int) ) )
 {
  if(!socket->waitForReadyRead())
  {
   qDebug() << "Disconnected: " << socket->errorString();
   socket->disconnectFromHost();
   break;
  }
 }
 qDebug() << "Bytes recieved: " << msgSize;


 QByteArray ba;
 quint8 byte;
 for(int i = 0; i < msgSize - 1; ++i)
 {
  in >> byte;
  ba.append(byte);
 }
        cv::Mat imgbuf = cv::Mat(FRAME_WIDTH, FRAME_HEIGHT, CV_8UC3, ba.data());
 cv::Mat matImg = cv::imdecode(imgbuf, CV_LOAD_IMAGE_COLOR);

両方のソケットはQTcpSocket.

出力例:

The server side: 

Read image size: 67551 bytes 
Bytes recieved: 67551 
Read image size: 56924 bytes 
Bytes recieved: 56924 
Read image size: 70027 bytes 
Bytes recieved: 70027 
Read image size: -2046830337 bytes 
Bytes recieved: -2046830337 
Read image size: -536866742 bytes 
Bytes recieved: -536866742 
Read image size: 1179207168 bytes 

At this point it tries to read 1179207168 bytes. 

The client side: 
Sent 67551 bytes 
Sent 56924 bytes 
Sent 70027 bytes 
Sent 70277 bytes 
Sent 85633 bytes 
Sent 65155 bytes 
etc ... 

最初の 3 つだけが成功します。

4

1 に答える 1

1

まず第一に、このタスクに QDataStream は必要ないと思います。QDataStream は、Qt 型のシリアル化/逆シリアル化を目的としており、使用している Qt のバージョンに固有です。単純にネットワーク経由で uchar を書きたいので、cv::vector を直接反復処理し、これらのバイトをワイヤ経由で直接書き込むことができます (実際、中間の QByteArray も必要ありません。元のベクトル)。

ただし、QDataStream を使用することはできます (QDataStream のバージョン間で変更される可能性が低い非常に基本的な型を使用しているため)。そのように開始したため、それに応じて回答を提供します。

これは(クライアント側)のようになります:

// 1) encode to jpg
cv::vector<uchar> buf;
cv::imencode(".jpg", *mat, buf);

// 2) write to buffer, your 'protocol' assumes buffer length first, then the data.
// REMEMBER: QDataStream operates on -any- QIODevice, so no need for the extra buffer here
QDataStream out(socket, QIODevice::WriteOnly);
out << buf.size();

cv::vector<uchar>::const_iterator it;
cv::vector<uchar>::const_iterator itEnd = buf.end();
for (it = buf.begin(); it != itEnd; ++it)
    out << *it;

サーバ側:

QDataStream in(socket, QIODevice::ReadOnly);
cv::vector<uchar> buf;
socket->waitForReadyRead();

qint64 bytesRead = 0;
qint64 size;
in >> size;

buf.reserve(size);
while (buf.size() < size) {
    if (!socket->bytesAvailable())
        socket->waitForReadyRead();

    qint8 byte;
    in >> byte;
    buf.push_back(byte);
}

cv::Mat imgbuf = cv::Mat(FRAME_WIDTH, FRAME_HEIGHT, CV_8UC3, buf);
cv::Mat matImg = cv::imdecode(imgbuf, CV_LOAD_IMAGE_COLOR);

注:これはすべて思いつきです。コンパイルできない可能性が非常に高く、これを行うためのはるかに効率的な方法は確かにありますが、既存のコードを修正する方法の基本的なアイデアが得られると思います

于 2014-05-10T22:19:57.253 に答える