【问题标题】:Receiving raw image data through TCP for display using Qt通过 TCP 接收原始图像数据以使用 Qt 显示
【发布时间】:2026-01-12 19:25:02
【问题描述】:

我正在开发一个 GUI 来显示来自传感器的图像。 GUI 充当客户端,而传感器充当服务器。一旦我向传感器发送命令,传感器将通过 TCP 将流式原始图像数据(二进制数据)连续发送到 GUI。数据将是图像内存的精确副本,大小为宽度 (1240) x 高度 (1028),以 U8(无符号 8 位)编码。一个传入数据的大小是(1240 x 1028 x 1 字节)+ 20 字节(元头)= 1.3MByte。

我最大的障碍是: 1.) 如何连续接收和存储来自传感器的流数据用于显示目的? 2.) 如何显示原始数据?

我尝试了以下代码,但它不起作用。请指教:

“客户端.h”

#ifndef CLIENT_H
#define CLIENT_H

#include <QObject>
#include <QWidget>
#include <QTcpSocket>

class Client : public QWidget
{
    Q_OBJECT
public:
    explicit Client(QWidget *parent = 0);
    int capture (int mode, int NBRLine);

signals:

public slots:

private:
    QTcpSocket* socket;

};

#endif // CLIENT_H

“客户端.cpp”

#include "client.h"
#include <QHostAddress>
#include "mainwindow.h"
#include <QtGui>
#include <QAbstractSocket>
#include <QImage>

Client::Client(QWidget *parent) :
    QWidget(parent)
{
    socket = new QTcpSocket(this);  
}

int Client::capture(int mode, int NBRLine)
{
    if (socket->state() != QTcpSocket::ConnectedState)
    {
        socket->connectToHost("192.168.0.65", 1096);
    }

    /* send command to retrieve raw image data from sensor */
    if(socket->waitForConnected(5000))
    {
        QByteArray block;
        QDataStream out(&block, QIODevice::WriteOnly);
        out.setVersion(QDataStream::Qt_4_0);
        out.setByteOrder(QDataStream::LittleEndian);
        out << qint32(0) << qint32(0) << qint32(0) << qint32(1);
        out << qint32(9) << qint32(1) << qint32(0) << mode << qint32(10) << qint32(2) << qint32(0) << NBRLine ;
        socket->write(block);
        socket->flush();
    }
    else
    {
        return false;
    }
    /**********************************************************/

    /* to get data size of each scan through width and height in the meta header */
    QDataStream input(socket);
    input.setVersion(QDataStream::Qt_4_0);
    input.setByteOrder(QDataStream::LittleEndian);
    qint32 buffer, cmdID, counter, metaSize, width, height;
    do
    {
        if (socket->waitForReadyRead(1000))
        {
            input >> cmdID;
            if (cmdID == 101)
            {
                input >> buffer >>  buffer >> buffer >> buffer;
            }
        }
        else
        {
            socket->disconnectFromHost();
            break;

        }
    } while (cmdID != 1);

    input >> counter >> metaSize;
    if (metaSize != 8) return false;

    input >> width >> height;
    quint32 datasize =  width * height;

    /**********************************************************/

    /* Receiving streaming data which I have problem here !!!! */
    while (socket->bytesAvailable() < datasize + 80) {
        if (!socket->waitForReadyRead(1000)) {
            socket->disconnectFromHost();
            break;
        }
    }

    QImage img;
    input >> img;

    if (img.isNull())
    {
        return 0;
    }
    img.save("E:/temp1");
     return 1;
}

【问题讨论】:

  • QTcoSocket 类有一个不间断的readyRead() 信号,可以连接到您的数据处理器。对于显示原始数据,this thread 可能会对您有所帮助。

标签: qt tcp


【解决方案1】:

在您可以发送缓冲区的内容之前,您需要找到一种方法来告诉客户端需要多少数据。所以首先你应该发送数据大小,然后是数据。

在服务器端,您应该发送如下图像数据:

QTcpSocket socket;

QBuffer buffer;
QImageWriter writer(&buffer, "PNG");
writer.write(QImage("myImage.png") );

QByteArray data;
QDataStream stream( &data, QIODevice::WriteOnly );
stream.setVersion( QDataStream::Qt_4_8 );
stream << (quint32)buffer.data().size();
data.append( buffer.data() );

socket.write( data );

在客户端,您应该将套接字的readyRead 信号连接到插槽以在接收到新数据时读取数据:

connect( socket, SIGNAL(readyRead()),this, SLOT(tcpReady()) );

图像数据可以这样读取:

void Client::tcpReady()
{
    if( dataSize == 0 )
    {
        QDataStream stream( &socket );
        stream.setVersion( QDataStream::Qt_4_8 );

        if( socket.bytesAvailable() < sizeof(quint32) )
            return;

        stream >> dataSize;
    }

    if( dataSize > socket.bytesAvailable() )
        return;

    QByteArray array = socket.read( dataSize );
    QBuffer buffer(&array);
    buffer.open( QIODevice::ReadOnly );

    QImageReader reader(&buffer, "PNG");
    QImage image = reader.read();

    if( !image.isNull() )
    {
        image.save("E:/temp1");
    }
    else
    {
        QDebug()<<"Invalid image received!";
    }
}

【讨论】:

  • 每次扫描我会收到的响应数据如下: )> 首先我需要检查 Cmd_ID 的值是否与预期值匹配。然后我需要通过乘以宽度和高度来计算图像数据的大小。通常图像数据的大小为 1280 x 1024 字节 = 1.3 字节。那么在我的情况下如何应用你的 tcpReady() 呢?我使用您向我展示的方法读取数据,但 QImage 返回 NULL。这可能是什么原因?
  • 读取标题后,通过stream &gt;&gt; imageWidth &gt;&gt; imageHeight ;读取宽度和高度并将它们相乘得到dataSize。