学习笔记:QT+opencv:基于UDP的视频传输

1 将图片转为QByteArray传输
QBuffer buffer;
    buffer.open(QIODevice::ReadWrite);

//pixmap不能为空,必须先将图片加载到pixmap中
    pixmap.save(&buffer,"jpg");
    QByteArray pixArray;
    pixArray.append(buffer.data());

2 将QByteArray转为图片显示

  QByteArray array;
   while(client->waitForReadyRead(100)){
       array.append((QByteArray)client->readAll());
   }
   QBuffer buffer(&array);
   buffer.open(QIODevice::ReadOnly);
   QImageReader reader(&buffer,"JPG");
   QImage img = reader.read();
   if(!img.isNull()){
       QPixmap pix = QPixmap::fromImage(img);
       ui->showImageLabel->setPixmap(pix.scaled(ui->showImageLabel->size(),Qt::KeepAspectRatio,Qt::SmoothTransformation));
}

视频发送端:
.h头文件:
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <opencv.hpp>
#include <QUdpSocket>
#include<QTimer>

using namespace cv;
namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void on_pushButton_clicked();

    void on_pushButton_2_clicked();
    void video_capture_send();
private:
    Ui::MainWindow *ui;
    VideoCapture camera;//
    QUdpSocket sender;//
    QTimer timer;//
    QHostAddress dstip;//
    quint16 dstport;//
};

#endif // MAINWINDOW_H

.cpp文件:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QBuffer>   //
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    QHostAddress srcip = QHostAddress::Any;//
    quint16 srcport = 5555;

    sender.bind(srcip,srcport);

    dstip = QHostAddress("127.0.0.1");
    //环回地址,等效于用本机IP,发给本机接收。
    //可以用来测试本机的TCP/IP协议栈,数据包不会出网卡,网络设备不会对其做路由。
    //localhost 是个域名,不是地址,它可以被配置为任意的 IP 地址,不过通常情况下都指向 127.0.0.1(ipv4)和 [::1](ipv6)
   //localhost不能直接绑定套接字,必须先gethostbyname转成IP才能绑定
    dstport = 6666;
    //要跟接收方的一致
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_pushButton_clicked()
{
    camera.open(0);
    connect(&timer,SIGNAL(timeout()),this,SLOT(video_capture_send()));
    timer.start(33);//结合上面,每隔33ms截屏一次并发送
}

void MainWindow::on_pushButton_2_clicked()
{
    close();
}
void MainWindow::video_capture_send()
{
    Mat frame;
    //mat也是动态管理内存的数据类型
    //也会尽量避免重复数据拷贝,(通过mat头),节省内存
    //mat是三维数组,但也可通过二维数组初始化
    camera.read(frame);
    
    cvtColor(frame,frame,CV_BGR2RGB); //BGRtoRGB
    //转换为常规的格式RGB

    QImage image((unsigned char *)(frame.data),
                 frame.cols,frame.rows,   
                 QImage::Format_RGB888); 
    
    //图像首地址是unsigned char *格式
    //专用于读取IO图片数据
    //Qpixmap专用于屏幕显示
    //Qpicture是专用于执行QPianter指令作图的。
    
    ui->label->setPixmap(QPixmap::fromImage(image));
    ui->label->resize(image.width(),image.height());
    //   进一步转换为Qpixmap用于屏幕显示
    //调整为适应图像大小
 
    QByteArray byte; 
    //字节数组 要进行传输必须先转换成这个格式
    QBuffer buff(&byte); 
    // 建立一个用于IO读写(网卡)的缓冲区
    //buff作为byte和IO设备的接口(显式)
    // byte在内部作为一个与image的接口(隐式)   
    //操作都是对buff进行的,byte被隐藏
    image.save(&buff,"JPEG");   
    // image先向下转为byte的类型,再存入buff    
 
    QByteArray ss = qCompress(byte,5);
    //数据压缩算法,压缩比为5
    QByteArray vv = ss.toBase64();
    //数据加密算法
    sender.writeDatagram(vv,dstip,dstport);
}

视频接收端:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QUdpSocket>
namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
public slots:
  void video_receive_show();
private:
    Ui::MainWindow *ui;
    QUdpSocket receiver;
};

#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QHostAddress>
#include<QPixmap>
#include<QImageReader>
#include<QBuffer>
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    QHostAddress localip= QHostAddress::Any;// both IPv4 and IPv6 interfaces
    quint64 localport = 6666;

    receiver.bind(localip,localport); //Binds to [address] on port [port]
                   //一般server才用bind(),客户端一般是自动选址

    connect(&receiver,SIGNAL(readyRead()),this,SLOT(video_receive_show()));
    //异步读取数据
}

MainWindow::~MainWindow()
{
    delete ui;
}
void MainWindow::video_receive_show()
{
    quint64 size = receiver.pendingDatagramSize();
    //直接读取异步监听时接收到的数据报
    QByteArray buff;
    // 字节矩阵,大小用qint64描述,适合操作1大量数据2字符串数组3二进制01数据,节省内存,更加安全
    //一般用const char*初始化
    // 默认采用深拷贝,可指定为浅拷贝
    buff.resize(size);
    //为缓冲区规定一个maxsize(没必要用那么大,刚好装下图像就够了)
    receiver.readDatagram(buff.data(),buff.size());
    // 数据报只支持一维操作

    QBuffer buffer(&buff);
    //提供用Qbytearray读写内存中IO缓存区的接口,若无传参内部默认自动创建一个Qbytearray;
    //对IO缓存区读写操作等效于像IO设备读写数据
    //操作QBuffer像在操作文件(其实原理都差不多,各自都是内存中一块特殊区域嘛)

    QImageReader reader(&buffer,"JPG");
    //可读入磁盘文件、设备文件中的图像、以及其他图像数据如pixmap和image,相比较更加专业。
    //buffer属于设备文件一类,
    //专业地读取设备文件的图像数据。


    QImage image = reader.read();
    //read()方法用来读取设备图像,也可读取视频,读取成功返回QImage*,否则返回NULL
    //格式转换
    ui->label->setPixmap(QPixmap::fromImage(image));
    ui->label->resize(image.width(),image.height());

}


猜你喜欢

转载自blog.csdn.net/weixin_41954137/article/details/80303312