服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C/C++ - Qt+OpenCV实现目标检测详解

Qt+OpenCV实现目标检测详解

2022-10-13 14:16SongpingWang C/C++

这篇文章主要介绍了如何利用Qt和OpenCV中自带xml文件实现目标检测,文中的实现过程讲解详细,感兴趣的小伙伴可以动手试一试

一、创建项目&UI设计

创建项目,UI设计如下

Qt+OpenCV实现目标检测详解

文件类型判断

简单的判断文件类型

QString file("sample.jpg");
if (file.contains(".jpg") || file.contains(".bmp") || file.contains(".png"))
  qDebug()<<"这是图片。";

推荐使用QMimeDatabase类

QMimeDatabase db;
QMimeType mime = db.mimeTypeForFile("sample.bmp");
if (mime.name().startsWith("image/")) 
  qDebug()<<"这是图片。";
类型 描述 示例
text 普通文本 text/plain,
text/html,
text/css,
text/javascript
image 图像文件(包含动态gif) image/gif,
image/png,
image/jpeg,
image/bmp,
image/webp
audio 音频文件 audio/wav,
audio/mpeg,
audio/midi,
audio/webm,
audio/ogg
video 视频文件 video/mp4,
video/x-flv,
video/webm,
video/ogg
application 二进制数据 application/xml,
application/pdf

 

二、代码与演示

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QFileDialog>
#include <QFile>
#include <opencv2/opencv.hpp>
#include <QMainWindow>
#include <QTimer>
#include <QImage>
#include <QPixmap>
#include <QDateTime>
#include <QMutex>
#include <QMutexLocker>
#include <QMimeDatabase>
#include <iostream>

QPixmap Mat2Image(cv::Mat src);

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
  Q_OBJECT

public:
  MainWindow(QWidget *parent = nullptr);
  void Init();
  ~MainWindow();

private slots:
  void readFrame(); //自定义信号处理函数

  void on_pushButton_OpenFile_clicked();

  void on_pushButton_StartDetect_clicked();

  void on_pushButton_StopDetect_clicked();

  void on_pushButton_FlushDevice_clicked();

private:
  Ui::MainWindow *ui;
  QTimer *timer;
  QImage *img;
  QString mp4_path = NULL;
  cv::VideoCapture *capture;
  cv::CascadeClassifier *classifier;
  std::vector<cv::Rect> bodys;
  int display_HeightWidth = 500;
  int IsDetect_ok = 0;     //用于判断是否加载了MP4和xml
};
#endif // MAINWINDOW_H

mainwindow.cpp

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


MainWindow::MainWindow(QWidget *parent)
  : QMainWindow(parent)
  , ui(new Ui::MainWindow)
{
  ui->setupUi(this);

  timer = new QTimer(this);
  timer->setInterval(33);
  connect(timer,SIGNAL(timeout()),this,SLOT(readFrame()));
  ui->pushButton_StartDetect->setEnabled(false);
  ui->pushButton_StopDetect->setEnabled(false);
  Init();
}

void MainWindow::Init()
{
  capture = new cv::VideoCapture();
  classifier = new cv::CascadeClassifier;
}

MainWindow::~MainWindow()
{
  capture->release();
  delete ui;
}


void MainWindow::readFrame()
{
  cv::Mat frame, hsv_img, mask_img, gray_src;
  capture->read(frame);
  if (frame.empty()) return;
//    int frame_width = capture->get(cv::CAP_PROP_FRAME_WIDTH);
//    int frame_height = capture->get(cv::CAP_PROP_FRAME_HEIGHT);
//    if (frame_width / frame_height >= 1){
//        cv::resize(frame, frame, cv::Size(display_HeightWidth, (int)(frame_height * display_HeightWidth / frame_width)));
//    }else{
//        cv::resize(frame, frame, cv::Size((int)(frame_width * display_HeightWidth / frame_height), display_HeightWidth));
//    }

  //算法一:行人检测
  cv::cvtColor(frame, gray_src, cv::COLOR_BGR2GRAY);
  cv::equalizeHist(gray_src, gray_src);
  classifier->detectMultiScale(gray_src, bodys, 1.1, 3, 0, cv::Size(30, 30));
  for (size_t i = 0; i < bodys.size(); i++){
      cv::rectangle(frame, bodys[i], cv::Scalar(0, 0, 255), 2, 8, 0);
  }

  //算法二:颜色跟踪
  cv::cvtColor(frame, hsv_img, cv::COLOR_BGR2HSV);
  cv::inRange(hsv_img, cv::Scalar(35, 43, 46), cv::Scalar(155, 255, 255), mask_img);
  cv::Mat kernel = getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3));
  morphologyEx(mask_img, mask_img, cv::MORPH_CLOSE, kernel);
  erode(mask_img, mask_img, kernel);
  GaussianBlur(mask_img, mask_img, cv::Size(3, 3), 0, 0);
  if (cv::waitKey(30) == 27) {
      ui->textEdit_log->setText("Exit...");
      ui->label_raw->clear();
      return;
  }
  cv::cvtColor(frame, frame, cv::COLOR_BGR2RGB);
  QImage rawImage = QImage((uchar*)(frame.data),frame.cols,frame.rows,frame.step,QImage::Format_RGB888);
  ui->label_raw->setPixmap(QPixmap::fromImage(rawImage));     //显示源图像
  QImage dstImage = QImage((uchar*)(mask_img.data),mask_img.cols,mask_img.rows,mask_img.step,QImage::Format_Grayscale8);
  ui->label_detect->setPixmap(QPixmap::fromImage(dstImage));  //显示图像
}


void MainWindow::on_pushButton_OpenFile_clicked()
{
  QString filename = QFileDialog::getOpenFileName(this,"打开文件",".","*.mp4 *.avi;;*.png *.jpg *.jpeg *.bmp");
  if(!QFile::exists(filename)){
      return;
  }
  ui->statusbar->showMessage(filename);
  IsDetect_ok +=1;
  if (IsDetect_ok ==2)
      ui->pushButton_StartDetect->setEnabled(true);
  QMimeDatabase db;
  QMimeType mime = db.mimeTypeForFile(filename);
  if (mime.name().startsWith("image/")) {
      cv::Mat src = cv::imread(filename.toLatin1().data());
      if(src.empty()){
          ui->statusbar->showMessage("图像不存在!");
          return;
      }
      cv::Mat temp;
      if(src.channels()==4)
          cv::cvtColor(src,temp,cv::COLOR_BGRA2RGB);
      else if (src.channels()==3)
          cv::cvtColor(src,temp,cv::COLOR_BGR2RGB);
      else
          cv::cvtColor(src,temp,cv::COLOR_GRAY2RGB);
      QImage img = QImage((uchar*)temp.data,temp.cols,temp.rows,temp.step,QImage::Format_RGB888);
      ui->label_raw->setPixmap(QPixmap::fromImage(img));
      ui->label_raw->resize(ui->label_raw->pixmap()->size());
      filename.clear();
  }else if (mime.name().startsWith("video/")) {
      capture->open(filename.toLatin1().data());
      if (!capture->isOpened()){
          ui->textEdit_log->append("fail to open MP4!");
          return;
      }
      ui->textEdit_log->append(QString::fromUtf8("Open video: %1 succesfully!").arg(filename));

      //获取整个帧数
      long totalFrameNumber = capture->get(CV_CAP_PROP_FRAME_COUNT);
      ui->textEdit_log->append(QString::fromUtf8("整个视频共 %1 帧").arg(totalFrameNumber));
      ui->label_raw->resize(QSize(capture->get(CV_CAP_PROP_FRAME_WIDTH), capture->get(CV_CAP_PROP_FRAME_HEIGHT)));

      //设置开始帧()
      long frameToStart = 0;
      capture->set(CV_CAP_PROP_POS_FRAMES, frameToStart);
      ui->textEdit_log->append(QString::fromUtf8("从第 %1 帧开始读").arg(frameToStart));

      //获取帧率
      double rate = capture->get(CV_CAP_PROP_FPS);
      ui->textEdit_log->append(QString::fromUtf8("帧率为: %1 ").arg(rate));
  }
}

void MainWindow::on_pushButton_StartDetect_clicked()
{
  timer->start();
  ui->pushButton_StartDetect->setEnabled(false);
  ui->pushButton_StopDetect->setEnabled(true);
}

void MainWindow::on_pushButton_StopDetect_clicked()
{
  ui->pushButton_StartDetect->setEnabled(true);
  ui->pushButton_StopDetect->setEnabled(false);
  timer->stop();
}

void MainWindow::on_pushButton_FlushDevice_clicked()
{

  QString xmlfilename = QFileDialog::getOpenFileName(this,"打开文件",".","*.xml");
  if(!QFile::exists(xmlfilename)){
      return;
  }
  ui->statusbar->showMessage(xmlfilename);
  if (!classifier->load(xmlfilename.toLatin1().data())) {
      ui->textEdit_log->append("fail to open classifier_path!");
      return;
  }
  IsDetect_ok +=1;
  ui->textEdit_log->append(QString::fromUtf8("Open xmlfile: %1 succesfully!").arg(xmlfilename));
  if (IsDetect_ok ==2)
      ui->pushButton_StartDetect->setEnabled(true);
}

 

演示效果

Qt+OpenCV实现目标检测详解

 

拓展阅读

直接在属性栏目搜索中设置(如下图),或者pushbutton设置icon和文字

Qt+OpenCV实现目标检测详解

下面是pushbutton设置icon和文字的四种方法详解

1.使用系统自带api

    ui->pushButton->setIconSize(QSize(32,32));
  ui->pushButton->setIcon(QIcon(":/images/Setting.png"));
  ui->pushButton->setText(QString::fromLocal8Bit("系统设置"));
  ui->pushButton->setStyleSheet("QPushButton{border:1px solid blue;background:white;}"
                                "QPushButton:hover{border:0px;background:blue;}"
                                "QPushButton:pressed{border:0px;background:red;}");

Qt+OpenCV实现目标检测详解

无法设置icon和文字之间的距离。

2.如果想让icon显示在文字上方可使用QToolButton

ui->toolButton->setIconSize(QSize(32,32));
  ui->toolButton->setIcon(QIcon(":/images/Setting.png"));
  ui->toolButton->setText(QString::fromLocal8Bit("系统设置"));
  ui->toolButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);

Qt+OpenCV实现目标检测详解

3.在pushbutton上面使用label进行布局

 QLabel *iconLabel = new QLabel;
  QLabel *textLabel = new QLabel;
  iconLabel->setFixedSize(32,32);
  iconLabel->setStyleSheet("border:1px solid red;");
  textLabel->setStyleSheet("border:1px solid red;");
  iconLabel->setPixmap(QPixmap(":/images/Setting.png"));
  textLabel->setText(QString::fromLocal8Bit("系统设置"));
  textLabel->setFixedWidth(60);
  QHBoxLayout *myLayout = new QHBoxLayout();
  myLayout->addSpacing(10);
  myLayout->addWidget(iconLabel);
  myLayout->addSpacing(30);
  myLayout->addWidget(textLabel);
  myLayout->addStretch();
  ui->pushButton_2->setLayout(myLayout);
  ui->pushButton_2->setStyleSheet("QPushButton{border:1px solid blue;background:white;}"
                                "QPushButton:hover{border:0px;background:blue;}"
                                "QPushButton:pressed{border:0px;background:red;}");

Qt+OpenCV实现目标检测详解

4.使用图片,设置stylesheet即可

以上三种方法,需要设置,比较麻烦,最好还是找UI设计按钮图片,这样软件的适配性也比较好。

到此这篇关于Qt+OpenCV实现目标检测详解的文章就介绍到这了,更多相关Qt OpenCV目标检测内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.csdn.net/wsp_1138886114/article/details/123066863

延伸 · 阅读

精彩推荐
  • C/C++c语言连接mysql数据库的实现方法

    c语言连接mysql数据库的实现方法

    C语言连接mysql数据库,需要相应的头文件和lib文件,如果你安装Mysql数据库,会在安装目录下找到这些库文件,如果没有安装,也可以在网上找到...

    脚本之家2232020-11-09
  • C/C++VC++ 使用 _access函数判断文件或文件夹是否存在

    VC++ 使用 _access函数判断文件或文件夹是否存在

    这篇文章主要介绍了VC++ 使用 _access函数判断文件或文件夹是否存在的相关资料,需要的朋友可以参考下...

    99re7872021-03-15
  • C/C++带你了解C++中vector的用法

    带你了解C++中vector的用法

    大家好,本篇文章主要讲的是带你了解C++中vector的用法,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下...

    小时师兄4762022-08-24
  • C/C++使用用C++做一颗会跳动的爱心实例代码

    使用用C++做一颗会跳动的爱心实例代码

    大家好,本篇文章主要讲的是使用用C++做一颗会跳动的爱心实例代码,感兴趣的同学赶快来看一看吧,欢迎借鉴学习C++做一颗会跳动的爱心实例代码...

    Flood_H9042022-07-19
  • C/C++C语言实现餐饮点餐管理系统

    C语言实现餐饮点餐管理系统

    这篇文章主要为大家详细介绍了C语言实现餐饮点餐管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    Sriven9602021-07-20
  • C/C++C/C++混合编程之extern “C”的使用示例

    C/C++混合编程之extern “C”的使用示例

    这篇文章主要给大家介绍了关于C/C++混合编程之extern “C”使用的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习...

    青儿哥哥9642021-06-01
  • C/C++C++(STL库)之顺序容器vector的使用

    C++(STL库)之顺序容器vector的使用

    这篇文章主要介绍了C++(STL库)之顺序容器vector的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们...

    江南、董少11722021-08-18
  • C/C++c语言随机数函数示例

    c语言随机数函数示例

    这篇文章主要介绍了c语言随机数函数示例,需要的朋友可以参考下...

    C语言程序设计5962021-01-18