本编利用Qt实现一个网络摄像头功能,包含一个服务端和一个客户端,服务端用于将USB摄像头转换为一个IP摄像头,当有客户端连接时,将其捕获到的图像通过TCP发送出去;客户端运行在Linux板子上,用于查看摄像头的实时画面。

1 必备基础知识

本篇需要编写一个服务器和客户端,关于TCP服务器/客户端的基础知识,可参考这篇:Linux进程间通信详解(七) socket套接字基础

注意,Qt中对Socket的操作进行了进一步的封装,其基本思想还是一样的。

下面就来看一下Qt中如何实现TCP Socket通信。

1.1 QTcpSocket与QTcpServer

  • QTcpSocket,在Qt中,Socket被封装成了QTcpSocket,可以用它实现TCP客户端的功能,以及服务端接收到客户端后,对客户端的处理。

  • QTcpServer,对于TCP服务端的功能,可以使用QTcpServer来完成。

这里整理Qt中TCP Socket的使用方法,配合Qt的信号与槽机制,即可实现服务端/客户端数据的收发处理。

1.2 QCamera相关

  • QCamer,获取当前系统可用的摄像头 类似获取串口

  • QCamerInfo,获取当前系统可用的摄像头 类似获取串口

  • QCameraViewfinder,取景框类,摄像头的实时画面显示到这个里面

  • QCameraImageCapture,图像录制类,与QCamer 配合使用可进行拍照

2 Win平台上测试

首先在Windows平台上用Qt Creator编写服务端和客户端程序,并运行测试。

2.1 服务器端

先来看下服务器端的最终效果:

  • 左侧是摄像头的显示界面
  • 可以切换不同的摄像头作为视频源(笔记本自带的摄像头与USB外接的摄像头)
  • 可以切换摄像头的显示分辨率
  • 可以选择开启或关闭摄像头的IP服务

2.1.1 摄像头画面显示

Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget)
{ui->setupUi(this);QComboBox *pCamType = new QComboBox();m_pComboBox = ui->cbBox_resolution;pCamType = ui->cbBox_cameras;pCamType->clear();cameraList = QCameraInfo::availableCameras();foreach(const QCameraInfo &cameraInfo, cameraList){qDebug() << "CameraInfo:" << cameraInfo;pCamType->addItem(cameraInfo.description());}m_pCamViewFind = new QCameraViewfinder(this);m_pCamViewFind->setGeometry(10, 10, W, H);m_pCamViewFind->show();m_pCam = new QCamera(this);m_pCam->setViewfinder(m_pCamViewFind);m_pCam->start();
}

2.1.2 创建Socket服务

void Widget::on_btn_IPServer_toggled(bool checked)
{if (checked){m_pServer = new QTcpServer(this);if (!m_pServer->listen(QHostAddress::Any, 12345)){QMessageBox::critical(this, "error", "listen port failed");exit(0);}qDebug() << "start IP server";m_pTimer = new QTimer(this);connect(m_pServer, SIGNAL(newConnection()), this, SLOT(new_client()));connect(m_pTimer, SIGNAL(timeout()), this, SLOT(timer_slot()));m_pTimer->start(100);ui->btn_IPServer->setText("关闭IP服务");}else{qDebug() << "stop IP server";m_pServer->close();delete m_pServer;ui->btn_IPServer->setText("开启IP服务");}
}

2.1.3 读取图像并发送给客户端

先定义一下图像传送结构体和传送状态:

enum TransStatus{TS_IDLE,       //空闲(图像数据可以更新)TS_RUNNING,    //图像数据传输中(还不可以更新图像数据)TS_FIRST_DATA, //需要发出图像数据的第一部分
};class ImgData {
public:char data[LEN] = {0}; //图像数据int  totalLen = 0; //图像大小int  hasSentLen = 0; //已发出的数据长度TransStatus  stats = TS_IDLE; //工作状态
};

具体的实现过程:

void Widget::read_data()
{QString str = m_pClient->readAll();ImgData *pData = (ImgData*)m_pClient->userData(0);QString s("newImage:%1");if (str == "new_request"){qDebug() << "read_data, new_request, d->len:" << pData->totalLen << "d->stats:" << pData->stats;if ((pData->totalLen > 0) && (pData->stats==TS_IDLE)) //图像大小不为0,表示已更新图像数据了{pData->stats = TS_RUNNING;m_pClient->write(s.arg(pData->totalLen).toUtf8());pData->hasSentLen = 0;}else //图像数据还没有更新{pData->stats = TS_FIRST_DATA; //在定时器的槽函数里发出"newImage..."}}else if (str == "ack"){int len_send = P_LEN; //本次需要发送的长度if (pData->hasSentLen >= pData->totalLen) //如果图像已传输完毕{qDebug() << "read_data, send done! lenSent:" << pData->hasSentLen << "len" << pData->totalLen;return;}// 最后1包数据(不满P_LEN)if ((pData->hasSentLen + P_LEN) > pData->totalLen){len_send = pData->totalLen - pData->hasSentLen;}qDebug() << "read_data, ack, write len:" << len_send;// 发送数据pData->hasSentLen += m_pClient->write(pData->data + pData->hasSentLen, len_send);if (pData->hasSentLen >= pData->totalLen){pData->stats = TS_IDLE; //传输完毕后,把状态改为可更新pData->totalLen = 0;}}
}

需要注意的是,图像是需要分包传送的,最后一包一般都不是设定的最大长度,需要计算一下最后一包的数据长度。

2.2 客户端

先来看下客户端的最终效果:

  • 右侧是摄像头画面的显示框
  • 可以修改要连接的服务端的IP地址
  • 可以选择开启或关闭网络摄像头

2.2.1 创建Socket连接

void Widget::on_pushButton_toggled(bool checked)
{if (checked){QString ip = ui->lineEdit->text();m_pSocket->connectToHost(ip, 12345);if (!m_pSocket->waitForConnected(1000)){QMessageBox::critical(this, "error", "server connection failed");return;}ui->pushButton->setText("关闭");m_iRecvLen = 0;m_pSocket->write("new_request");qDebug("on_bnt_connect_clicked, new_request");}else{m_pSocket->close();ui->pushButton->setText("打开");}
}

2.3.2 接收服务端的图像

void Widget::read_data()
{int ret;QTime qTime;static int i = 0;ret = m_pSocket->read(m_pData + m_iRecvLen, P_LEN);if (0 == strncmp("newImage", m_pData + m_iRecvLen, 8)){m_iImgLen = atoi(m_pData + m_iRecvLen + 9);i++;}else{m_iRecvLen += ret;if (m_iRecvLen >= m_iImgLen){QString timestamp = QString::number(QDateTime::currentMSecsSinceEpoch());update();return;}}//图像传输完毕m_pSocket->write("ack");
}

2.3.3 将图像显示出来

void Widget::paintEvent(QPaintEvent *event)
{QPixmap map;if ((m_iRecvLen >= m_iImgLen) && (m_iImgLen > 0)){map.loadFromData((uchar *)m_pData, m_iImgLen);QPainter p(this);p.drawPixmap(140, 0, 640, 480, map);m_pSocket->write("new_request");m_iRecvLen = 0;}
}

3 嵌入式Linux平台上测试

3.1 交叉编译

将客户端程序的源代码拷贝到Ubunu中进行交叉编译,具体编译过程可参考之前的文章:

嵌入式Qt-动手编写并运行自己的第1个ARM-Qt程序

本篇的实验环境,继续使用的是烧录了野火i.MX6ULL自带的系统固件Linux板子,需要通过SSH的方式将编译的程序再发送到板子中,SSH传输文件的操作可参考上篇文章:

嵌入式Qt-控制硬件:滑动条控制RGB灯

3.2 实验演示

https://www.bilibili.com/video/BV12G4y1a7za

4 总结

本篇介绍了如何用Qt实现一个网络摄像头功能,通过服务端将USB摄像头转换为一个IP摄像头,Linux板子中的客户端来连接服务器,将摄像头的实时画面显示出来。

嵌入式Qt-简易网络监控摄像头相关推荐

  1. Win10 Bash搭建嵌入式Qt开发平台

    在Windows下利用mingw进行一些简单程序的编译还行,但是路径问题以及工具链的制作问题,总是会遇到麻烦,不如安装个虚拟机好用.曾试着在windows下编译下qt,后来坑太多果断放弃.自Win10 ...

  2. 树莓派Raspberry Pi的嵌入式QT平台

    在树莓派上设计桌面应用一般情况会依赖于X11环境,如果是Windows平台,就目前而言,我们也可以选择Windows 10 IoT环境进行开发.UWP目前也支持在树莓派2上进行部署.至于常见的Linu ...

  3. 基于QT的网络视频会议系统---KNVM

    本文来自http://blog.csdn.net/slientman原创,引用必须注明出处! KNVM网络视频会议系统V1.0 经过2年艰苦细致的开发,终于完成了基于QT的网络视频会议系统,特此记录, ...

  4. 嵌入式QT精品视频教程:开发RFID智能仓储指纹管理系统

    嵌入式QT精品视频教程:开发RFID智能仓储指纹管理系统 本文主要给大家分享了一个嵌入式QT精品视频教程,使用了多种流行技术(RFID.指纹识别.Qt软件编程,数据库与网络等)UI基础编程之实现用户登 ...

  5. [NUAA]数据库课设-基于OpenGauss的简易网络小说平台

    文章目录 前言 一.课设题目要求及分析 二.小说平台实现效果 1.合理的角色功能划分 2. 表结构的设计 3.Python如何与服务器进行连接 4.flask框架的应用 4.1 前端页面如何传递信息给 ...

  6. python嵌入式开发实战_嵌入式Qt实战教程 PDF 高清版

    给大家带来的一篇关于嵌入式相关的电子书资源,介绍了关于嵌入式.Qt实战方面的内容,本书是由电子工业出版社出版,格式为PDF,资源大小43.4 MB,陈志发,王苑增编写,目前豆瓣.亚马逊.当当.京东等电 ...

  7. Ubuntu下嵌入式Qt开发环境配置全攻略

    本文以友善之臂的Mini6410嵌入式开发板为目标板,介绍ubuntu 12.04系统下,配置嵌入式Qt开发工具的过程.本文中介绍的工具.大部分步骤和脚本来自开发板附带资料光盘,但其默认配置环境为老旧 ...

  8. 64位Ubuntu 12.04下搭建嵌入式Qt(4.8.6)、QtCreator、qvfb过程全记录

    最新公司搞一个新项目,需要在Linux下进行UI界面设计.选来选去,最后选择采用Qt平台来做,于是要开始研究一下Qt. Qt作为业内最著名的UI开发工具之一,是一套完整的跨平台C++图形用户界面应用程 ...

  9. 摄像头分辨率怎么调整_网络监控摄像头怎么选择 网络监控摄像头选择方法【介绍】...

    网络监控摄像头是我们生活中非常重要的一种安防产品,在我们的公共场所.小区.道路交通等等方面都发挥着非常重要的作用.目前市面上这类产品也是非常多的,但是想要选择一款好的.符合自己需求的产品,还需要我们掌 ...

最新文章

  1. DRV8301的使用
  2. Spark详解(十二):Spark Streaming原理和实现
  3. html弹窗中的layer,ModalLayer弹窗控件(原创)
  4. 浣溪沙·过杜甫草堂有感
  5. Centos7.x 安装 CDH 6.x
  6. 云原生数据库崛起,阿里云POLARDB当选世界互联网领先科技成果
  7. 怎么去掉ECSHOP的Powered by ECShop版权信息
  8. 修改kubelet启动参数
  9. php 为什么ctrl加 没用,电脑ctrl+c不能用怎么办
  10. 12.2 新特性:RMAN 自动恢复到 REDO 终点的步骤简化
  11. oracle成本模块培训,Oracle App 培训笔记(5) -- 成本管理模块表结构整理 续
  12. 单循环比赛的贝格尔编排法
  13. SNMP弱口令导致的网络入侵
  14. 【分享】Gitee如何下载单个文件
  15. SICP读书笔记2---if和cond的区别
  16. 雷电网络:前景,挑战,路线
  17. 张量分解浅谈(四 Tucker 分解)
  18. [libgdx游戏开发教程]使用Libgdx进行游戏开发(10)-音乐音效不求人,程序员也可以DIY
  19. 锐捷网络 Java开发工程师校招 一面面经
  20. 使用AlarmManager设置闹钟

热门文章

  1. JAVA面向对象三大特征:
  2. 无参考图像质量评价指标
  3. 青岛谱悦 半球形高保真拾音器 吸顶耳安装 MTK-070公检法审讯室 投标中心 安检通道降噪拾音器...
  4. 极狐场景化造车理念受热捧,北汽蓝谷构建未来5年核心竞争力
  5. linux 命令之 ufw(Uncomplicated Firewall)
  6. 【QT】float double的范围与精度及Qt中的qfloat16
  7. 【Linux】ss命令详解
  8. 查新报告包括什么内容?
  9. 怎么拥有36小时的一天
  10. 下午一口气睡了五个小时