0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

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

码农爱学习 来源:码农爱学习 作者:码农爱学习 2022-09-14 08:52 次阅读


本编利用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的信号与槽机制,即可实现服务端/客户端数据的收发处理。

pYYBAGMgke-AS-cqAABRBCZsiFA664.png

1.2 QCamera相关

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

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

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

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

2 Win平台上测试

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

2.1 服务器端

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

左侧是摄像头的显示界面

可以切换不同的摄像头作为视频源(笔记本自带的摄像头与USB外接的摄像头)

可以切换摄像头的显示分辨率

可以选择开启或关闭摄像头的IP服务

poYBAGMgkgCAchMbAAIIP9aGJfc341.png

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地址

可以选择开启或关闭网络摄像头

pYYBAGMgkmmAfG1cAACzHDLq1qM978.png

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

poYBAGMgkvKAGzXjAA2qetEAwRE119.png

4 总结

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

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 嵌入式
    +关注

    关注

    5082

    文章

    19117

    浏览量

    304961
  • 摄像头
    +关注

    关注

    59

    文章

    4840

    浏览量

    95645
  • Qt
    Qt
    +关注

    关注

    1

    文章

    302

    浏览量

    37903
收藏 人收藏

    评论

    相关推荐

    嵌入式Qt-表格使用测试

    本篇介绍了Qt中QTable Widget这个表格组件的使用,后续可增加SQLite数据库功能,利用表格可以直观的展示出嵌入式设备的数据库中的数据信息。
    的头像 发表于 05-14 12:27 1584次阅读
    <b class='flag-5'>嵌入式</b><b class='flag-5'>Qt-</b>表格使用测试

    监控摄像头的选型方法

    监控摄像头的选用原则做以下简单说明,希望对您的项目有所帮助:      1)根据安装方式选择。如固定安装,监控摄像头多选用普通枪
    发表于 02-05 16:23

    网络摄像头监控的系统优势

    软件系统即可;  可靠性:主要设备网络摄像头采用了嵌入式实时操作系统,所需设备简单,而图像的传输是通过综合布线网络实现的,系统可靠性相当高;  网络
    发表于 03-25 15:26

    【OK210申请】基于嵌入式LinuxQT开发的摄像头监控系统

    开发板提供的资料进行学习,然后自己移植一个全新的Linux内核,及移植基于QT5.0版本以上的文件系统来开发一个摄像头监控项目,项目的功能主要是能实现摄像头的拍照,及录像,达到
    发表于 06-25 12:01

    【OK210申请】简易摄像头监控系统

    ,之前用过一款,很喜欢。项目描述:项目就是做一个简易摄像头监控系统,其功能主要类似于小区摄像头监控的系统,在实现基本功能之后,希望能对小区的
    发表于 07-26 09:55

    【OK210申请】基于arm嵌入式监控智能小车的设计与实现

    经验目前正在做的项目是基于嵌入式arm平台的监控智能小车的设计与实现该项目的的功能是:1、手机app操作小车的运动2、手机app可观看到小车摄像头发回的视频手机app实现用到的是Qt
    发表于 08-03 09:40

    【AWorks280试用申请】u***监控摄像头

    申请理由:物联网的兴起,导致嵌入式设备需要更强大的采集和通信功能,普通单片机开发难度过高。本人想通过这次活动,尝试使用arm9+linux来实现摄像头驱动和一些网络应用。项目描述:使用这块280板子枚举u***
    发表于 10-23 10:09

    【NanoPi NEO Plus2开发板试用申请】u***摄像头远程监控

    项目名称:u***摄像头远程监控试用计划:最近工业自动化开发上有一个工业摄像头的远程wifi监控项目。该摄像头的驱动对于处理器有较大要求,需
    发表于 08-09 10:08

    教你做一个用嵌入式linux开发板和web端来实现的视频监控系统

    node.js html QT硬件:开发板:ARM开发板、树莓派、jetson nano...等跑linux系统的开发板,连接一个摄像头;电脑:Web前端,可查看监控画面;功能介绍:开发板与电脑通过
    发表于 11-05 07:38

    嵌入式视频监控的相关资料分享

    上利用USB 摄像头采集视频图像,通过视频图像压缩及结合网络进行视频图像传输,使远程监控成为可能。文章目录嵌入式视频监控1 系统介绍1.1
    发表于 11-08 07:10

    监控摄像头的种类

    监控摄像头的种类:监控摄像头一般有几种?有很多种,监控摄像头的效果,主要看他的芯片和线数。一般买
    发表于 03-17 12:04

    嵌入式工控板上接一个摄像头进行视频监控

    嵌入式工控板上接一个摄像头进行视频监控,看起来比较容易实现,但是往往是理想很丰满、现实很骨感历经千辛万苦效果却不是很理想,本文就给大家介绍各种解决方案。 这里给大家介绍的是既对外设有需求,又要连接
    发表于 10-15 12:13 0次下载

    如何使用ARM进行嵌入式监控系统的设计

    本文利用网络嵌入式设备实现远程视频监控的系统。摄像头采集模拟的视频信号转化为数字信号后,通过局域网传送到网内的任何一台计算机, 从而实现异地的监控
    发表于 03-13 18:07 7次下载
    如何使用ARM进行<b class='flag-5'>嵌入式</b><b class='flag-5'>监控</b>系统的设计

    嵌入式视频监控

    上利用USB 摄像头采集视频图像,通过视频图像压缩及结合网络进行视频图像传输,使远程监控成为可能。文章目录嵌入式视频监控1 系统介绍1.1
    发表于 11-02 21:06 31次下载
    <b class='flag-5'>嵌入式</b>视频<b class='flag-5'>监控</b>

    嵌入式Linux的摄像头驱动程序设计与实现

    电子发烧友网站提供《嵌入式Linux的摄像头驱动程序设计与实现.pdf》资料免费下载
    发表于 10-12 09:31 2次下载
    <b class='flag-5'>嵌入式</b>Linux的<b class='flag-5'>摄像头</b>驱动程序设计与实现