【QT中实现摄像头播放、以及视频录制】

1、效果图

在这里插入图片描述

2、camerathread.h

#ifndef CAMERATHREAD_H
#define CAMERATHREAD_H

#include <QObject>
#include <QThread>
#include <QDebug>
#include <QImage>
#include <unistd.h>
#include <iostream>
#include <QDateTime>
#include <opencv2/opencv.hpp>
using namespace  std;
using namespace  cv;
class CameraThread :public QThread
{
    Q_OBJECT
public:
    static CameraThread *camerathread;
    static CameraThread *getInstance();
    void run();
    bool getIsRun() const;
    void setIsRun(bool value);
    int getFrame_width() const;
    int getFrame_height() const;
    void detecCarDaw(Mat &frame,CascadeClassifier &cascade,double scale);
    bool getIsStop() const;
    void setIsStop(bool value);
    bool getIsRecord() const;
    void setIsRecord(bool value);
    VideoWriter getWriter() const;
    bool getIsPersistent() const;
    void setIsPersistent(bool value);
    bool getIsRun_s() const;
    void setIsRun_s(bool value);
signals:
    void sendQImage(Mat frame);
private:
    CameraThread();
    CascadeClassifier cascade;//级联分类器的过滤器
    VideoCapture cap;
    Mat frame;
    VideoWriter writer;//OpenCV视频录制类
    bool isRun;//控制线程是否运行
    int frame_width;
    int frame_height;
    int recordNum; //录制帧率,设定为300帧
    bool isRun_s; //控制线程是否运行
    bool isStop; //控制线程结束
    bool isRecord; //控制线程是否开始录制
    bool isPersistent;
};

#endif // CAMERATHREAD_H

3、camerathread.cpp

#include "camerathread.h"

CameraThread * CameraThread::camerathread =nullptr;
CameraThread * CameraThread::getInstance()
{
    if(CameraThread::camerathread ==nullptr)
    {
        CameraThread::camerathread =new CameraThread ();
    }
    return CameraThread::camerathread;
}
CameraThread::CameraThread()
{

    this->isRun =true;
    cap.open(0);
    // 获取摄像头的宽度和高度
    this->frame_width = static_cast<int>(cap.get(CAP_PROP_FRAME_WIDTH));
    this->frame_height = static_cast<int>(cap.get(CAP_PROP_FRAME_HEIGHT));

    // 定义视频编码格式、帧率和画面尺寸
     int fourcc = VideoWriter::fourcc('X', 'V', 'I', 'D');
     Size frameSize(frame_width, frame_height);
     this->isRun_s=false;
     this->isStop=false;
     this->isRecord=false;
     this->isPersistent=false;
     this->recordNum=0;

}


bool CameraThread::getIsStop() const
{
    return isStop;
}

void CameraThread::setIsStop(bool value)
{
    isStop = value;
}



bool CameraThread::getIsRecord() const
{
    return isRecord;
}

void CameraThread::setIsRecord(bool value)
{
    isRecord = value;
    if(this->isRecord == false && writer.isOpened())
    {
        qDebug()<<"手动关闭"<<endl;
        writer.release();
        this->recordNum =0;
    }
}

VideoWriter CameraThread::getWriter() const
{
    return writer;
}

bool CameraThread::getIsPersistent() const
{
    return isPersistent;
}

void CameraThread::setIsPersistent(bool value)
{
    isPersistent = value;
}

bool CameraThread::getIsRun_s() const
{
    return isRun_s;
}

void CameraThread::setIsRun_s(bool value)
{
    isRun_s = value;
}
void CameraThread::detecCarDaw(Mat &frame, CascadeClassifier &cascade, double scale)
{
    //灰度处理
    Mat gray;
    cvtColor(frame,gray,CV_BGR2GRAY);
    //将灰度图缩小一半
    //cvRound()用于四舍五入       CV_8UC1:单通道
    Mat smalling(cvRound(frame.rows/scale),cvRound(frame.cols/scale),CV_8UC1);
    //resize()改变大小      INTER_LINEAR 等比例缩小
    resize(gray,smalling,smalling.size(),0,0,INTER_LINEAR);

    //直方图均衡化:利用直方图函数将图像黑白分明  (结果跟二值化类似)
    equalizeHist(smalling,smalling);
    //进行模型检测
    vector<Rect>cars;
    cascade.detectMultiScale(smalling,cars,1.1,2,0|CV_HAAR_SCALE_IMAGE,Size(30,30));

    //绘制边框
    vector<Rect>::const_iterator iter;//系统默认迭代器
    for(iter =cars.begin();iter!=cars.end();iter++)
    {
        rectangle(
                  frame,//原图
                  cvPoint(cvRound(iter->x*scale),cvRound(iter->y*scale)),//左上角坐标
                  cvPoint(cvRound((iter->x+iter->width)*scale),cvRound((iter->y+iter->height)*scale)),//右下角坐标
                  Scalar(0,255,0),//绿色
                  2,//像素大小
                  8//亮度
                  );
    }
}


int CameraThread::getFrame_height() const
{
    return frame_height;
}

int CameraThread::getFrame_width() const
{
    return frame_width;
}

bool CameraThread::getIsRun() const
{
    return isRun;
}

void CameraThread::setIsRun(bool value)
{
    isRun = value;
}
void CameraThread::run()
{
    cascade.load("D:/OpenCV/cars.xml");//识别级联分类器  车辆
    while(this->isRun ==true)
    {
        if(cap.read(frame))
        {
            cvtColor(frame,frame,CV_BGR2RGB);
            detecCarDaw(frame,cascade,2);
            emit sendQImage(frame);

            if(this->isStop ==false)//控制线程结束
            {
                if(this->isRun_s == true)//控制线程是否运行
                {
                    if(cap.read(frame))
                    {
                        if(this->isRecord==true)
                        {
                            if(this->recordNum ==0)
                            {
                                QDateTime current_date_time =QDateTime::currentDateTime();
                                QString current_date =current_date_time.toString("yyyy-MM-dd-hh-mm-ss");
                                //QString filename ="../data/"+current_date+".avi";
                                QString filename ="D:/Qtsoft/videoDemo/data/"+current_date+".avi";
                                qDebug()<<"filename="<<filename;
                                writer.open(filename.toStdString().c_str(),CV_FOURCC('M','J','P','G'),30.0,Size(frame.cols,frame.rows),true);
                            }
                            if(!writer.isOpened())
                            {
                                qDebug()<<"录制路径失败!!!"<<endl;
                            }
                            else
                            {
                                if(this->recordNum<300)
                                {
                                        //当前帧不等于总帧数,录制300帧还没有结束
                                        //qDebug()<<"录制中..."<<endl;
                                        writer<<frame;
                                        this->recordNum++;
                                }
                                else
                                {
                                    qDebug()<<"已经到300帧结束录制";
                                    writer.release();
                                    this->recordNum =0;
                                    if(this->isPersistent==true)
                                    {
                                         this->isRecord =true;
                                    }else if(this->isPersistent ==false)
                                    {
                                        this->isRecord =false;
                                    }

                                }
                            }
                        }
                        cvtColor(frame,frame,CV_BGR2RGB);
                    }
                    msleep(10);
                }
            }
        }
    }

}

4、mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "camerathread.h"
namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
    void paintEvent(QPaintEvent * Eevent);
private:
    Ui::MainWindow *ui;
    CameraThread *ct;
//    VideoThread *vt;
    QImage image;
    Mat frame;
private slots:
    void isChecked(Mat frame);
    void on_pushButton_clicked();
    void on_checkBox_clicked(bool checked);
};

#endif // MAINWINDOW_H

5、mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    this->ct =CameraThread::getInstance();
    connect(this->ct,SIGNAL(sendQImage(Mat)),this,SLOT(isChecked(Mat)),Qt::BlockingQueuedConnection);
    this->ct->start();
//    this->vt =new VideoThread(0);
//    this->vt->start();
    waitKey(40);
}

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

void MainWindow::paintEvent(QPaintEvent *Eevent)
{
    ui->label->setPixmap(QPixmap::fromImage(this->image));
    QImage q_image = QImage(frame.data,frame.cols,frame.rows,QImage::Format_RGB888);
    ui->label->setPixmap(QPixmap::fromImage(q_image));
    ui->label->setScaledContents(true);
}

void MainWindow::isChecked(Mat frame)
{
    this->image =QImage(frame.data,frame.cols,frame.rows,QImage::Format_RGB888);
    this->image = this->image.scaled(ui->label->width(),ui->label->height());//以UI中的界面大小进行等比例缩放
    this->frame = frame.clone();
    this->update();
}

void MainWindow::on_pushButton_clicked()
{

    if(this->ct->getWriter().isOpened())
    {
               qDebug()<<"已经有录制项目:请先结束录制,再操作";
               return;
     }


    this->ct->setIsRun_s(true);
    this->ct->setIsRecord(true);

}

void MainWindow::on_checkBox_clicked(bool checked)
{
    if(checked==true)
    {
         //qDebug()<<"true";
        this->ct->setIsRecord(true);
        this->ct->setIsPersistent(true);
    }else if(checked==false)
    {
         //qDebug()<<"false";
         this->ct->setIsPersistent(false);
    }
}

6、main.cpp

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();


    return a.exec();
}

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-10 08:32:03       4 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-10 08:32:03       5 阅读
  3. 在Django里面运行非项目文件

    2024-07-10 08:32:03       4 阅读
  4. Python语言-面向对象

    2024-07-10 08:32:03       4 阅读

热门阅读

  1. adb 常用的命令总结

    2024-07-10 08:32:03       12 阅读
  2. gcc: options: -specs

    2024-07-10 08:32:03       10 阅读
  3. Python题解Leetcode Hot 100之栈和堆

    2024-07-10 08:32:03       7 阅读
  4. docker容器如何与本地配置文件关联

    2024-07-10 08:32:03       11 阅读
  5. SQL 字段类型-上

    2024-07-10 08:32:03       15 阅读
  6. C++ 入门04:数组与字符串

    2024-07-10 08:32:03       7 阅读
  7. 简谈设计模式之原型模式

    2024-07-10 08:32:03       11 阅读
  8. GPT带我学-设计模式-13策略模式

    2024-07-10 08:32:03       13 阅读
  9. 写一个字符设备的驱动步骤

    2024-07-10 08:32:03       10 阅读
  10. Transformer和Bert的原理是什么

    2024-07-10 08:32:03       9 阅读
  11. 使用tkinter 制作工作流ui

    2024-07-10 08:32:03       10 阅读