• 项目简述

  实现客户端调用摄像头,并以帧的形式将每一帧传输到服务端,服务端将图片进行某些处理后再返回给客户端。(客户端与服务端通信代码部分参考《Qt5 开发及实例》)

  • 项目步骤

  • 客户端的编写

  •   通过Qt Designer画出如下界面

  • 在客户端工程文件“client、pro”中加入 QT += network语句,并将环境路径配置好。
  • 在头文件“client.h”中加入如下代码:
     1 class Client : public QWidget
    2 {
    3 Q_OBJECT
    4
    5 public:
    6 explicit Client(QWidget *parent = 0);
    7 ~Client();
    8
    9 private slots:
    10 void slotEnter();
    11 void slotConnected();
    12 void slotDisconnected();
    13 void dataReceived();
    14 void slotSend();
    15 void nextFrame();
    16 signals:
    17 void connectedToServer(void);
    18
    19 private:
    20 Ui::Client *ui;
    21 bool status;
    22 int port;
    23 QHostAddress *serverIP;
    24 QString userName;
    25 QTcpSocket *tcpSocket;
    26
    27 qint64 receiveBlockSize;
    28
    29 Mat frame;
    30 VideoCapture cap;
    31 QTimer* timer;
    32 QImage image;
    33
    34 void ShowImage(QByteArray ba);
    35 QByteArray picToData(cv::Mat frame);
    36 QImage Mat2QImage(cv::Mat cvImg);
    37 };
  • 在源文件“client.cpp”的构造函数中加入如下代码:
     1 Client::Client(QWidget *parent) :
    2 QWidget(parent),
    3 ui(new Ui::Client)
    4 {
    5 ui->setupUi(this);
    6
    7 setWindowFlags(windowFlags()&~Qt::WindowMaximizeButtonHint);
    8 setFixedSize(this->width(),this->height());
    9
    10 status=false;
    11 port=8010;
    12 ui->portLineEdit->setText(QString::number(port));
    13
    14 serverIP=new QHostAddress();
    15 ui->serverIPLineEdit->setText("127.0.0.1");
    16 connect(ui->ConnectPushButton,SIGNAL(clicked(bool)),this,SLOT(slotEnter()));
    17
    18 receiveBlockSize=0;
    19
    20 timer=new QTimer(this);
    21 timer->start(30);
    22
    23 cap.open(0);
    24 if(!cap.isOpened())
    25 {
    26 QMessageBox::information(this,tr("error"),tr("cam don't open"));
    27 }
    28
    29 connect(timer,&QTimer::timeout,this,&Client::nextFrame);
    30 }

槽函数nextFrame()通过调用openCV,实现获取每一帧图像:

 1 void Client::nextFrame()
2 {
3 cap>>frame;
4 if (!frame.empty())
5 {
6 image = Mat2QImage(frame);
7
8 //使图像适应label的大小
9 QPixmap *pixmap = new QPixmap(QPixmap::fromImage(image));
10 pixmap->scaled(ui->capturedImage->size(), Qt::KeepAspectRatio);
11 ui->capturedImage->setScaledContents(true);
12 ui->capturedImage->setPixmap(*pixmap);
13 delete pixmap;//避免内存泄漏
14 }
15 }

函数Mat2QImage(cv::Mat cvImg)代码如下:

 1 QImage Client::Mat2QImage(cv::Mat cvImg)
2 {
3 QImage qImg;
4 if(cvImg.channels()==3) //3 channels color image
5 {
6
7 cv::cvtColor(cvImg,cvImg,CV_BGR2RGB);
8 qImg =QImage((const unsigned char*)(cvImg.data),
9 cvImg.cols, cvImg.rows,
10 cvImg.cols*cvImg.channels(),
11 QImage::Format_RGB888);
12 }
13 else if(cvImg.channels()==1) //grayscale image
14 {
15 qImg =QImage((const unsigned char*)(cvImg.data),
16 cvImg.cols,cvImg.rows,
17 cvImg.cols*cvImg.channels(),
18 QImage::Format_Indexed8);
19 }
20 else
21 {
22 qImg =QImage((const unsigned char*)(cvImg.data),
23 cvImg.cols,cvImg.rows,
24 cvImg.cols*cvImg.channels(),
25 QImage::Format_RGB888);
26 }
27 return qImg;
28 }

  以上代码中,槽函数slotEnter()实现连接和断开服务器功能(但现在断开后再连上数据传输有问题),代码如下:

 1 void Client::slotEnter()
2 {
3 if(!status)
4 {
5 QString ip=ui->serverIPLineEdit->text();
6 if(!serverIP->setAddress(ip))
7 {
8 QMessageBox::information(this,tr("error"),
9 tr("server ip address error"));
10 return;
11 }
12
13 tcpSocket=new QTcpSocket(this);
14
15 connect(tcpSocket,&QAbstractSocket::connected,this,&Client::slotConnected);
16
17 connect(tcpSocket,&QAbstractSocket::disconnected,this,&Client::slotDisconnected);
18
19 connect(tcpSocket,&QIODevice::readyRead,this,&Client::dataReceived);
20
21 connect(this,&Client::connectedToServer,this,&Client::slotSend);
22
23 tcpSocket->connectToHost(*serverIP,port);
24
25
26 status=true;
27 }
28 else
29 {
30
31 tcpSocket->disconnectFromHost();
32
33 status=false;
34 }
35 }

槽函数“slotConnected()”是connected()信号的响应槽,当与服务器连接成功后,客户端进行一些操作,具体代码如下:

1 void Client::slotConnected()
2 {
3 ui->handPushButton->setEnabled(true);
4 ui->facePushButton->setEnabled(true);
5 ui->ConnectPushButton->setText(tr("Leave"));
6 //ui->ConnectPushButton->setEnabled(false);
7 emit connectedToServer();
8 }

槽函数“slotDisconnected()”是disconnected()信号的响应槽,当与服务器断开连接时,进行如下操作:

1 void Client::slotDisconnected()
2 {
3 ui->handPushButton->setEnabled(false);
4 ui->facePushButton->setEnabled(false);
5 ui->ConnectPushButton->setText(tr("Enter"));
6 }

  

  当发出connectedToServer()信号后,槽函数slotSend()响应,具体代码如下:

 1 void Client::slotSend()
2 {
3 if(frame.empty())
4 return;
5
6 QByteArray byteArrayData=picToData(frame);
7 QByteArray ba;
8 QDataStream out(&ba,QIODevice::WriteOnly);
9 out.setVersion(QDataStream::Qt_5_6);
10
11 out<<(quint64)0;
12 out<<byteArrayData;
13 out.device()->seek(0);
14 out<<(quint64)(ba.size()-sizeof(quint64));
15 tcpSocket->write(ba);
16 }

  其中函数picToData(cv::Mat frame)代码如下:

 1 QByteArray Client::picToData(Mat frame)
2 {
3 QImage img((unsigned const char*)frame.data,frame.cols,frame.rows,QImage::Format_RGB888);
4
5 QByteArray block;
6 QBuffer buf(&block);
7 img.save(&buf,"JPEG");//按照JPG解码保存数据
8 QByteArray cc = qCompress(block,1);
9 QByteArray hh;
10 hh=cc.toBase64();//base64数据
11 return hh;
12 }

  函数dataReceived()当客户端收到服务端数据时响应,代码如下:

 1 void Client::dataReceived()
2 {
3 ui->noteLabel->setText(tr("receive data"));
4 QDataStream in(tcpSocket);
5 QByteArray message;//存放从服务器接收到的字符串
6 in.setVersion(QDataStream::Qt_5_6);
7 if (receiveBlockSize==0)
8 {
9 //判断接收的数据是否有两字节(文件大小信息)
10 //如果有则保存到basize变量中,没有则返回,继续接收数据
11 if (tcpSocket->bytesAvailable()<(int)sizeof(quint64))
12 {
13 return;
14 }
15 in>>receiveBlockSize;
16 }
17 //如果没有得到全部数据,则返回继续接收数据
18 if (tcpSocket->bytesAvailable()<receiveBlockSize)
19 {
20 //qDebug()<<"tcpSocket->bytesAvailable()<receiveBlockSize";
21 return;
22 }
23 in>>message;//将接收到的数据存放到变量中
24 ShowImage(message);
25 receiveBlockSize=0;
26 emit connectedToServer();
27 }

  最后的emit connectedToServer();实现每次发送一次数据给服务端后,等待服务端响应后再发送数据,避免一直发数据,同时又接收数据而出现问题。

  最后,将处理后的图像显示,调用函数ShowImage(QByteArray ba)实现,代码如下:

 1 void Client::ShowImage(QByteArray ba)
2 {
3 QString ss=QString::fromLatin1(ba.data(),ba.size());
4 QByteArray rc;
5 rc=QByteArray::fromBase64(ss.toLatin1());
6 QByteArray rdc=qUncompress(rc);
7 QImage img;
8 img.loadFromData(rdc);
9 ui->processedImage->setPixmap(QPixmap::fromImage(img));
10 ui->processedImage->resize(img.size());
11 update();
12 }

  

  最后的最后,不要忘了调用析构函数:

1 Client::~Client()
2 {
3 delete ui;
4 delete tcpSocket;
5 delete timer;
6 delete serverIP;
7 }

基于Qt的tcp客户端和服务器实现摄像头帧数据处理(客户端部分)的更多相关文章

  1. 基于Qt的Tcp协议的流程图

    TCP(Transmission Control Protocol传输控制协议)是一种面向连接的.可靠的.基于字节流的传输层通信协议.在qt中,Tcp协议主要是用QTcpServer和QTcpSock ...

  2. 用java语言构建一个网络服务器,实现客户端和服务器之间通信,实现客户端拥有独立线程,互不干扰

    服务器: 1.与客户端的交流手段多是I/O流的方式 2.对接的方式是Socket套接字,套接字通过IP地址和端口号来建立连接 3.(曾经十分影响理解的点)服务器发出的输出流的所有信息都会成为客户端的输 ...

  3. QT创建TCP Socket通信

    最近在学习QT,了解到QT可以进行SOCKET网络通信,进行学习,并建立一个简单的聊天DEMO.为了测试是否能与VS2012下的程序进行通信,在VS2012下建立一个客户端程序,进行通信测试,发现可以 ...

  4. xmpp笔记2(客户端到服务器的例子)--xml

    xmpp( 客户端到服务器的例子 ) 1 步:客户端初始流给服务器: <stream:stream xmlns='jabber:client' xmlns:stream='http://ethe ...

  5. HTTP要点概述:三,客户端和服务器,请求和响应

    一,客户端和服务器: HTTP协议主要用于客户端和服务器之间的通信. 1,客户端(client):请求访问资源的一端.(知道为啥用C表示客户端了吧) 2,服务器(server):提供资源响应的一端. ...

  6. 基于Qt实现的TCP端口数据转发服务器

    对于Qt,比较喜欢qt的sdk框架,我也是用于做一些工作中用到的工具软件,基于qt的sdk做起来也比较快: 一.概述 今天要说的这个tcp端口转发服务器,主要是用于将监听端口的数据转发到另外一个服务器 ...

  7. 一个基于TCP/IP的服务器与客户端通讯的小项目(超详细版)

    1.目的:实现客户端向服务器发送数据 原理: 2.建立两个控制台应用,一个为服务器,用于接收数据.一个为客户端,用于发送数据. 关键类与对应方法: 1)类IPEndPoint: 1.是抽象类EndPo ...

  8. 一种基于Qt的可伸缩的全异步C/S架构服务器实现(流浪小狗,六篇,附下载地址)

    本文向大家介绍一种基于Qt的伸缩TCP服务实现.该实现针对C/S客户端-服务集群应用需求而搭建.连接监听.数据传输.数据处理均在独立的线程池中进行,根据特定任务不同,可安排负责监听.传输.处理的线程数 ...

  9. Qt实现客户端与服务器消息发送

    这里用Qt来简单设计实现一个场景,即: ①两端:服务器QtServer和客户端QtClient ②功能:服务端连接客户端,两者能够互相发送消息,传送文件,并且显示文件传送进度. 环境:VS20013+ ...

随机推荐

  1. Sentry(v20.12.1) K8S 云原生架构探索,玩转前/后端监控与事件日志大数据分析,高性能+高可用+可扩展+可伸缩集群部署

    Sentry 算是目前开源界集错误监控,日志打点上报,事件数据实时分析最好用的软件了,没有之一.将它部署到 Kubernetes,再搭配它本身自带的利用 Clickhouse (大数据实时分析引擎)构 ...

  2. 第1章 什么是JavaScript

    目录 1. JavaScript实现 1.1 ECMAScript 1.2 DOM 1.3 BOM 1995年JavaScript问世时主要用途时代替Perl等服务器段语言处理输入验证 1. Java ...

  3. 【小菜学网络】MAC地址详解

    上一小节介绍了以太网帧的结构,以及帧中各个字段的作用.参与以太网通讯的实体,由以太网地址唯一标识.以太网地址也叫做 MAC 地址,我们对它仍知之甚少. 以太网地址在不同场景,称谓也不一样,常用叫法包括 ...

  4. Linux常用命令(df&dh)

    在Linux下查看磁盘空间使用情况,最常使用的就是du和df了.然而两者还是有很大区别的,有时候其输出结果甚至非常悬殊. du的工作原理 du命令会对待统计文件逐个调用fstat这个系统调用,获取文件 ...

  5. 【MyBatis】MyBatis 延迟加载策略

    MyBatis 延迟加载策略 文章源码 什么是延迟加载 延迟加载,就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据,也被成为懒加载. 好处:先从单表查询,需要时再从关联表去关联查询,大大提 ...

  6. 【剑指 Offer】09.用两个栈实现队列

    题目描述 用两个栈实现一个队列.队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead , 分别完成在队列尾部插入整数和在队列头部删除整数的功能.(若队列中没有元素,del ...

  7. leetcode-242有效字母异位词

    题目 给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词. 示例 1: 输入: s = "anagram", t = "nagaram&quo ...

  8. URL重定向 - Pikachu

    概述: 不安全的url跳转问题可能发生在一切执行了url地址跳转的地方.如果后端采用了前端传进来的(可能是用户传参,或者之前预埋在前端页面的url地址)参数作为了跳转的目的地,而又没有做判断的话就可能 ...

  9. 攻防世界-crypto-easychallenge(.pyc反编译)

    进入题目后下载附件,发现是一个.pyc文件. pyc是一种二进制文件,是由py文件经过编译后,生成的文件,是一种byte code,py文件变成pyc文件后,运行加载的速度会有所提高:另一反面,把py ...

  10. 网络编程-I/O复用

    I/O模型 Unix下可用的I/O模型有五种: 阻塞式I/O 非阻塞式I/O I/O复用(select和poll.epoll) 信号驱动式I/O(SIGIO) 异步I/O(POSIX的aio_系列函数 ...