树莓派与QT上位机之间通过socket进行实时图像传输

效果如下:

整体的软件框图如下:

树莓派与QT上位机之间通过socket进行实时图像传输_第1张图片

其中QT上位机作为服务器端,通过socket监听特定端口,当有设备连入时,会产生相应的信号,我们捕获此信号并且自定义槽函数来进行数据接收,当接收到完整的一帧图像信息后,将图像数据流复原成图像矩阵并通过Qlabel控件显示出来。

树莓派作为客户端,其通过opencv捕获到摄像头的图像,捕获图像之后可以根据自己需求对图像进行滤波、形态学腐蚀、膨胀处理、边缘检测等操作,最后将图像数据转化成字节流,同时通过socket嵌套字连接入QT上位机服务器,实现tcp通信,将图像数据字节流发送给QT上位机。

一、QT上位机端:

        QT的TCP Socket通信下的服务端通过监听某个端口来监听是否有客户端连接到来,如果有连接到来,则建立新的SOCKET连接。  建立socket通信需要用到两个类QTcpServer和QTcpSocket。其中QTcpServer是用来建立QT的Server端对象,QTcpSocket是用来建立socket通信的Socket套接字对象。

具体代码如下:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include 
#include 
#include 
#include 

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

    uint16_t port = 5555; //自定义端口,需要和树莓派接入的端口一样

    QTcpServer *tcpserver = new QTcpServer(this); //创建QTcpServer对象
    QTcpSocket *tcpsocket = new QTcpSocket(this); //创建QTcpSocket 对象

    QByteArray Img_Data;   //存放图像字节数据
    int Recv_Length=0;     //存放图像数据长度

public slots :
    void ClientRecvData();  //自定义的槽函数,当监听到设备后进入
    void TcpNewConnection();//自定义的槽函数,当socket接收到数据后进入

private:
    Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include 
#include 

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    connect(timer1,&QTimer::timeout,this,&MainWindow::TIM1_IQ_Handle);
    timer1->setInterval(1);
    timer1->start();

    ui->image_fps->setAlignment(Qt::AlignCenter);
    ui->image_fps->setStyleSheet("border:2px solid blue;border-radius:10px;padding:6px 4px;"
                                 "font-size:20px");
    ui->image->setStyleSheet("border:2px solid green;border-radius:10px;padding:2px 2px;"
                             );
    tcpserver->listen(QHostAddress::Any , port);
    connect(tcpserver,&QTcpServer::newConnection,this,&MainWindow::TcpNewConnection);

    ui->MyCustomPlot->setInteractions(QCP::iRangeDrag|QCP::iRangeZoom| QCP::iSelectAxes );
    ui->MyCustomPlot->addGraph();
    ui->MyCustomPlot->graph(0)->setPen(QPen(Qt::blue));
    ui->MyCustomPlot->graph(0)->setName("曲线");
    ui->MyCustomPlot->xAxis->setLabel("X");
    //ui->MyCustomPlot->xAxis->setRange(0,60,Qt::AlignRight);
    ui->MyCustomPlot->yAxis->setLabel("Y");
    ui->MyCustomPlot->yAxis->setRange(-1.2,1.2);

    QSharedPointer dateTick(new QCPAxisTickerTime);
    dateTick->setTimeFormat("%h:%m:%s");
    ui->MyCustomPlot->xAxis->setTicker(dateTick);
//    ui->MyCustomPlot->xAxis->setTickLabels(true);*/


}

MainWindow::~MainWindow()
{
    delete ui;
}
void MainWindow::TIM1_IQ_Handle()
{
    // 声明时间获取变量,实际情况中,获取的是当前时间的总秒数
    int nowtime = QTime::currentTime().msecsSinceStartOfDay();
   // long long currentTime = QDateTime::currentDateTime().toMSecsSinceEpoch();

    static int tim  = 0;
    static int mtim = 0;
    tim++;

    qDebug()<MyCustomPlot->xAxis->setRange((tim-5000)*0.001,tim*0.001);

    ui->MyCustomPlot->graph(0)->addData(tim*0.001*2, qSin(ui->MyCustomPlot->graph(0)->dataCount()/50.0)+qSin(ui->MyCustomPlot->graph(0)->dataCount()/50.0/0.3843)*0.25);

    ui->MyCustomPlot->replot();
}

void MainWindow::TcpNewConnection()
{
    tcpsocket =tcpserver->nextPendingConnection();
    connect(tcpsocket,&QTcpSocket::readyRead,this,&MainWindow::ClientRecvData);
}

void MainWindow::ClientRecvData()
{
    static long long currentTime;
    static long long lastcurrentTime;

    QByteArray temp_array = tcpsocket->readAll();
    if(temp_array.contains("size="))
    {
        lastcurrentTime = currentTime;
        currentTime = QDateTime::currentDateTime().toMSecsSinceEpoch();
        double fps = 1/(double)(currentTime - lastcurrentTime)*1000;
        ui->image_fps->setText("FPS:"+QString::number(fps));

        qDebug()<<"step 1 : recv img length!";
        Recv_Length = temp_array.split('=')[1].toInt();
        qDebug()<<"图像数据长度:"<write("ack!");
        tcpsocket->waitForBytesWritten();
    }
    else
    {
        Img_Data.append(temp_array);
        qDebug()<<"step 2 : recv img data~";
        qDebug()<<"step 2 : now length = "<image->setPixmap(QPixmap::fromImage(bmpBuf));
        tcpsocket->write("finsh!");
        Img_Data.clear();
    }
}


void MainWindow::on_pushButton_clicked()
{
    //qsrand(QDateTime::currentDateTime().toMSecsSinceEpoch());
    arrX.append(arrX.count());
    arrY.append(qrand()%4777);


}

树莓派 python代码如下:

import cv2
import socket
import numpy as np
import time
ip  = "192.168.137.1"
port = 5011
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
cap = cv2.VideoCapture(0)

try:
    s.connect((ip,port))
except socket.error as e:
    print("Failed connecting...")

def send_pic():
    ret,frame = cap.read()
    encode_param = [int(cv2.IMWRITE_JPEG_QUALITY),70]
    while ret:
        time.sleep(0.01)
        result , imgencode = cv2.imencode('.JPG',frame,encode_param)
        # print(imgencode)
        data = np.array(imgencode)
        stringdata = data.tostring()
        send = str.encode('size='+str(len(stringdata)).ljust(5))
        print(send)
        s.send(send)
        rx = s.recv(10)
        if rx==b'ack!':
            print('step 2 : recv length ack!')
            s.send(stringdata)
            if s.recv(100)==b'finsh!':
                print("step 3 : recv finsh ack!")

        ret,frame = cap.read()
        # cv2.imread("sad",frame)
        # t = input("server>>>:")
        # s.send(t.encode('utf-8'))
        # if t == "exit":
        #     break
    s.close()
if __name__ =="__main__":
    send_pic()

你可能感兴趣的:(qt,opencv,c++,linux,物联网)