Qt-openCV实现简单的人脸检测

Qt-openCV实现简单的人脸检测

知识总结:

1.将Mat对象显示到QLabel中,需要类转换(Mat->QImage->QPixmap)

Mat在转换成QImage对象时
QImage((const uchar*)(mat->data),mat->cols,mat->rows,mat->cols*3,QImage::Format_RGB888);
第四参数要传进去,不传QT不会报错显示图片会出现乱图

2.QMessageBox的应用
3.connect函数(lambda表达式)
4.灰度图的图像通道为1
5.画的线在图片中有时候显示不出来是因为在QLabel中缩放的原因,加粗该线或者扩大显示尺寸
6.rectangle绘图函数
这篇文章有介绍这个函数的使用:https://blog.csdn.net/jiangjiao4726/article/details/75220479

widget.cpp:

#include "widget.h"
#include 
#include 
#include 
#include 
#include 
#include 
#include
#include 
#include 
#include 
#include 



using namespace std;
using namespace cv;
Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    Mat *src = new Mat;
    Mat *mat = new Mat;
   // namedWindow("Demo");
   // imshow("Dome",src);
   // waitKey(0);
   QImage image;
   QPixmap qPixmap;
   //设置窗口大小
   this->setFixedSize(700,600);


   //布置一个label显示图片
   QLabel *qLabel = new QLabel(this);
  //qLabel->setFixedSize(200,200);
   //qLabel->setText("Qlabel");
   //布置三个按钮
   QPushButton *but1 = new QPushButton("打开显示文件",this);
   but1->setGeometry(50,550,100,30);
   QPushButton *but2 = new QPushButton("转换灰度图",this);
   but2->setGeometry(200,550,100,30);
   QPushButton *but3 = new QPushButton("识别",this);
   but3->setGeometry(350,550,100,30);

   //显示检测到人的数量的label
   QTextEdit *people=new QTextEdit(this);
   people->setGeometry(610,550,70,30);
   QLabel *text = new QLabel(this);
   text->setGeometry(520,550,90,30);
   text->setText("检测出人数:");


   //连接按钮点击事件
   //按钮1
   connect(but1,&QPushButton::clicked,[=]()mutable{
      qDebug() << "but1鼠标单击" << endl;
      //QFileDialog qFileDialog(this);
      //qFileDialog.setWindowTitle("打开文件");
      QString str = QFileDialog::getOpenFileName();//打开文件
      if(str.isEmpty())
      {
          qDebug() << "文件打开失败" << endl;
          QMessageBox::information(this,"information","文件打开失败",QMessageBox::Ok,QMessageBox::Ok);
          return;
      }
      qDebug() << str << endl;
      *src = imread(str.toStdString(),-1); //第二个参数小于0返回原图带alpha通道
      if(!src->data)
      {
          qDebug() << "图片加载失败" << endl;
          QMessageBox::information(this,"information","图片加载失败",QMessageBox::Ok,QMessageBox::Ok);
          //qLabel->setText("打开图片失败");
          return;
      }


      //下面代码是将Mat对象显示在QLabel上面
      Img2RGB(*src,*mat); //修改图像API BGR->RGB
      //imshow("show", *mat);
      //rows行数量  cols列数量  uchar* data指向的数据

      Mat2QPixmap(mat, qPixmap);

      //qLabel->resize(qLabel->pixmap()->size());
      qLabel->resize(700,550); //重置QLabel
      QSize picSize(700,550);//要缩放的大小
      QPixmap scalePixmap = qPixmap.scaled(picSize,Qt::KeepAspectRatio); //后面一个宏是按比例缩放
      qLabel->setPixmap(scalePixmap);
      qLabel->show();
   });

   //按钮2
   connect(but2,&QPushButton::clicked,this,[=]()mutable{
      if(!src->data)
      {
          qDebug() << "src为空" << endl;
          QMessageBox::information(this,"information","没有打开图片",QMessageBox::Ok,QMessageBox::Ok);
          return;
      }
      if(!mat->data)
      {
          qDebug() << "mat为空" << endl;
          QMessageBox::information(this,"information","没有打开图片",QMessageBox::Ok,QMessageBox::Ok);
      }
      Img2Gray(*src,*mat); //转换为灰度图
      Mat temp;
      cvtColor(*mat,temp,CV_GRAY2RGB);
      //rows行数量  cols列数量  uchar* data指向的数据

      Mat2QPixmap(&temp, qPixmap);

      //下面代码是将Mat对象显示在QLabel上面
      //qLabel->resize(qLabel->pixmap()->size());
      qLabel->resize(700,550); //重置QLabel
      QSize picSize(700,550);//要缩放的大小
      //另一种方式按比例缩放
      //qLabel.setScaledContens(true);
      QPixmap scalePixmap = qPixmap.scaled(picSize,Qt::KeepAspectRatio); //后面一个宏是按比例缩放
      qLabel->setPixmap(scalePixmap);
      qDebug() << "but2鼠标单击" << endl;
   });
   //按钮3
   connect(but3,&QPushButton::clicked,this,[=]()mutable{

      if(src->data == nullptr || mat->data == nullptr)
      {
          qDebug() << "src 和 mat 为空" << endl;
          QMessageBox::information(this,"information","没有文件",QMessageBox::Ok,QMessageBox::Ok);
          return;
      }
      //没有转换为灰度图单击按钮软件会奔溃
      if(mat->channels() !=1)
      {
          qDebug() << "没有转换为灰度图" << endl;
          QMessageBox::information(this,"information","没有转换灰度图",QMessageBox::Ok,QMessageBox::Ok);
          return;
      }

      FancMain(*src, *mat, people);
      //imshow("show", *src);
      Mat temp;
      Img2RGB(*src, temp);
      //imshow("show1",temp);
      Mat2QPixmap(&temp, qPixmap);
      QSize picSize(700,550);//要缩放的大小
      //另一种按比例缩放
      //qLabel.setScaledContens(true);
      QPixmap scalePixmap = qPixmap.scaled(picSize,Qt::KeepAspectRatio); //后面一个宏是按比例缩放
      qLabel->setPixmap(scalePixmap);
      //imshow("success", *src);
      qDebug() << "but3鼠标单击" << endl;
   });

}

Widget::~Widget()
{
}
//判断图片的通道,然后转换为灰度图
void Widget::Img2Gray(Mat image, Mat &gray)
{
    if(image.channels() == 3)
    {
        cvtColor(image,gray,CV_BGR2GRAY);
    }
    else if(image.channels() == 4)
    {
        cvtColor(image,gray,CV_BGRA2GRAY);
    }
    else
    {
        gray = image;
    }
}
//转换为RGB
void Widget::Img2RGB(Mat& image, Mat &rgb)
{
    if(image.channels() == 3)
    {
        qDebug() << "图片通道为3" << endl;
        cvtColor(image,rgb,CV_BGR2RGB);
    }
    else if(image.channels() == 4)
    {
        qDebug() << "图片通道为4" << endl;
        cvtColor(image,rgb,CV_BGRA2RGB);
    }
    else
    {
        qDebug() << image.channels() << endl;
        rgb = image;
    }
}
//人脸检测
void Widget::FancMain(Mat &image, Mat &gray, QTextEdit *people)  //src已经打开文原图 mat是储存rgb格式 按钮2后mat边为gray
{
    CascadeClassifier faceDetetor;
    faceDetetor.load("F:/QT/Demo/haarcascade_frontalface_alt2.xml");

    if(faceDetetor.empty())
    {
        QMessageBox::information(this,"information","加载分类器失败",QMessageBox::Ok,QMessageBox::Ok);
        qDebug() << "加载检测器失败!" << endl;
        return;
    }

    //直方图均匀化(改善图像的对比度和亮度)
    Mat equalizedImg;
    equalizeHist(gray,equalizedImg);
    int flags = CASCADE_SCALE_IMAGE; //检测多个人

    Size minFeatureSize(30,30);
    float searchScaleFactor = 1.1f; //默认1.1倍
    int minNeighbors = 4;
    //QVector faces;
    vector<Rect> faces;
    faceDetetor.detectMultiScale(equalizedImg,faces,searchScaleFactor,minNeighbors,flags,minFeatureSize);
    qDebug() << "检测到人脸的个数:" << faces.size() << endl;
    QString str;
    str.setNum(faces.size());
    qDebug() << str << endl;

    people->setText(str);

    //画矩形框
    Mat face;
    Point text_lb;

    for(int i = 0; i < faces.size(); i++)
    {
        if(faces[i].height > 0 && faces[i].width >0 )
        {
            face = gray(faces[i]);
            text_lb = Point(faces[i].x,faces[i].y);
            //rectangle(equalizedImg, faces[i],Scalar(255,0,0),1,8,0);
            //rectangle(gray,faces[i],Scalar(255,0,0),1,8,0);
            //rectangle
            //第一个参数:输入的图像,
            //第二个参数:
            //第三个参数:
            //第四个参数:
            rectangle(image, faces[i], Scalar(50, 50, 150), 2, 8, 0); //线太细了会导致在QLabel上面丢失线框
        }
    }
    //imshow("lllll",gray);
}
//将cv::Mat转换QPixmap
void Widget::Mat2QPixmap(Mat *mat, QPixmap &qPixmap)
{
    QImage qImage;
    //rows行数量  cols列数量  uchar* data指向的数据
    qImage = QImage((const uchar*)(mat->data),mat->cols,mat->rows,mat->cols*3,QImage::Format_RGB888); //转换成image对象
    qPixmap = QPixmap();
    qPixmap = QPixmap::fromImage(qImage);//QImage转换为QPixmap
}


widget.h:

#ifndef WIDGET_H
#define WIDGET_H

#include 
#include "opencv2/opencv.hpp"   //opnecv用到的头文件
#include "opencv2/imgproc/types_c.h"  //解决CV_BGR2RGB找不到
#include "opencv2/objdetect.hpp"   //级联分类器CascadeClassifier头文件
#include "opencv2/highgui.hpp"
#include "opencv2/core/core.hpp"
//#include "opencv2/imgproc.hpp"
#include 


class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
public:
    //判断图片的通道,然后转换为灰度图
    void Img2Gray(cv::Mat image, cv::Mat& gray);
    void Img2RGB(cv::Mat& image, cv::Mat& rgb);
    //人脸检测
    void FancMain(cv::Mat& image,cv::Mat& gray,QTextEdit *people);
    //将cv::Mat转换QPixmap
    void Mat2QPixmap(cv::Mat* mat,QPixmap& qPixmap);

};
#endif // WIDGET_H

会出现漏检情况,只要脸稍微侧点检测不出,使用的是官方提供的分类器
Qt-openCV实现简单的人脸检测_第1张图片

你可能感兴趣的:(openCV学习,人脸识别,opencv,qt,图像识别,计算机视觉)