嵌入式Qt-简易网络监控摄像头

本编利用qt实现一个网络摄像头功能,包含一个服务端和一个客户端,服务端用于将usb摄像头转换为一个ip摄像头,当有客户端连接时,将其捕获到的图像通过tcp发送出去;客户端运行在linux板子上,用于查看摄像头的实时画面。
1 必备基础知识 本篇需要编写一个服务器和客户端。
注意,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: 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() btn_ipserver->settext(关闭ip服务); } else { qdebug() 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() 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->totallen) { len_send = pdata->totallen - pdata->hassentlen; } qdebug() << read_data, ack, write len: 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板子中的客户端来连接服务器,将摄像头的实时画面显示出来。


matlab小波分析工具箱使用教程
飞利浦照明引领物联网时代照明创新
关于NTN研发测试的十个经典问答(建议收藏!)
TK选择是德科技5G设备测试解决方案验证5G NR特性
业务规模同比下降,英飞拓上半年预亏9500万元-1.2亿元
嵌入式Qt-简易网络监控摄像头
谷歌Pixel 3 Lite真机曝光造型与Pixel 3相似并没有采用刘海屏设计
面向污水处理行业的设备资产管理系统解决方案
继电器的工作原理、作用及分类
世界500强榜单上华为上升至49名 华为1万人正研发激光雷达技术
iPhone11系列的实际续航表现如何
资本热潮褪去后,才能看到哪个造车成为幸存者、颠覆者?
oracle修改表字段长度语句
嵌入式移动数据库的结构体系、特点和优化查询方法研究
用 Hercules 开发套件来控制 GaN 功率级——第 2 部分
PCB是不是必须清洗
我国人工智能市场在2018年已经达到千亿
灌胶机工作原理及保养步骤
MOS管在开关电路中的使用
影子物联网是什么?该怎样降低风险