前言

本文主要讲述了在Qt下集成OpenCV进行一些基本的图像处理及实现人脸和眼睛的检测,并结合相应的示例进行讲解,以便大家学习,如有错误之处,欢迎大家批评指正。

项目效果
请添加图片描述


提示:以下是本篇文章正文内容,下面案例可供参考

一、OpenCV配置

将包含头文件和库文件的OpenCV文件夹放到项目路径处,在项目pro中添加代码让如下:

#OpenCV
INCLUDEPATH += $$PWD/OpenCV/Includes
DEPENDPATH += $$PWD/OpenCV/Includes
LIBS += -L$$PWD/OpenCV/Lib/ -lopencv_world452

二、实现人脸检测

我的示例中实现了在摄像头功能中添加人脸识别,这里使用OpenCV自带的Haar级联分类器进行人脸检测。步骤如下:
1、在MainWindow类中添加成员变量用于加载人脸和眼睛检测分类器(cv::CascadeClassifier)
2、在构造函数中加载分类器模型文件(需要下载好模型文件 haarcascade_frontalface_default.xml(人脸检测模型)和 haarcascade_eye.xml(眼睛检测模型))
3、在摄像头帧更新函数(onUpdateCameraFrame)中,对每一帧进行人脸检测,并在检测到的人脸及眼睛周围绘制矩形

下面是我的人脸检测函数的代码展示:

//执行人脸检测
void MainWindow::detectFaces(cv::Mat &image)
{
    //检查人脸检测器是否加载成功
    if(m_faceCascade.empty())
    {
        qWarning()<<"人脸检测器未加载!";
        ui->statusLabel->setText("错误: 人脸检测器未加载");
        return;
    }

    //转换为灰度图像
    cv::Mat gray;
    cv::cvtColor(image, gray, cv::COLOR_RGB2GRAY);

    //保存原始图像尺寸
    int originalWidth = gray.cols;
    int originalHeight = gray.rows;

    //缩小图像以提高检测性能
    double scale = 0.5;   //缩小为原始尺寸的一半
    cv::Mat smallGray;
    cv::resize(gray, smallGray, cv::Size(), scale, scale, cv::INTER_LINEAR);

    //直方图均衡化增强对比度
    cv::equalizeHist(smallGray, smallGray);

    //使用人脸检测器检测人脸
    std::vector<cv::Rect> faces;
    try{
        m_faceCascade.detectMultiScale(
                    smallGray,   //输入灰度图像
                    faces,       //输出检测到的人脸矩形
                    1.1,         //尺度缩放因子 (必须>1.0,典型值:1.01~1.5)
                    3,           //最小相邻人脸数 (减少误检测)
                    0|cv::CASCADE_SCALE_IMAGE,
                    cv::Size(30, 30),    //最小人脸尺寸
                    cv::Size(200, 200)   //最大人脸尺寸
                    );
    }
    catch (const cv::Exception& e)
    {
        qCritical()<<"人脸检测失败:"<<e.what();
        ui->statusLabel->setText("人脸检测出错");
        return;
    }

    //在原始图像上绘制检测结果
    for(const cv::Rect &face : faces)
    {
        //将检测结果映射回原始图像尺寸
        cv::Rect mappedFace(
                    static_cast<int>(face.x / scale),
                    static_cast<int>(face.y / scale),
                    static_cast<int>(face.width / scale),
                    static_cast<int>(face.height / scale)
                    );

        //确保映射后的人脸框在图像范围内
        if(mappedFace.x < 0)
            mappedFace.x = 0;
        if(mappedFace.y < 0)
            mappedFace.y = 0;
        if(mappedFace.x + mappedFace.width > originalWidth)
           mappedFace.width = originalWidth - mappedFace.x;
        if(mappedFace.y + mappedFace.height > originalHeight)
            mappedFace.height = originalHeight - mappedFace.y;

        //绘制人脸矩形(绿色)
        cv::rectangle(image, mappedFace, m_detectionColor, 2);

        //添加人脸标签
        cv::putText(image, "Face",
                    cv::Point(mappedFace.x, mappedFace.y - 5),
                    cv::FONT_HERSHEY_SIMPLEX, 0.5, m_detectionColor, 1);

        //在每张人脸中检测眼睛
        if(!m_eyesCascade.empty())
        {
            //在原始灰度图像上裁剪人脸区域
            cv::Mat faceROI = gray(mappedFace);

            //只检测人脸的上半部分(避免误检)
            int upperPartHeight = mappedFace.height * 2 / 3;
            cv::Rect upperFace(0, 0, mappedFace.width, upperPartHeight);
            cv::Mat upperFaceROI = faceROI(upperFace);

            //使用眼睛检测器检测眼睛
            std::vector<cv::Rect> eyes;
            try{
                m_eyesCascade.detectMultiScale(upperFaceROI, eyes,1.1, 4,0|cv::CASCADE_SCALE_IMAGE,cv::Size(10, 10),cv::Size(100, 100));
            }
            catch (const cv::Exception& e)
            {
                qCritical()<<"眼睛检测失败:"<<e.what();
                ui->statusLabel->setText("眼睛检测出错");
                return;
            }

            //过滤误检(可选)
            std::vector<cv::Rect> filteredEyes;
            for(const cv::Rect &eye : eyes)
            {
                //位置过滤
                if(eye.y < upperPartHeight * 0.8)
                {
                    //尺寸比例过滤(眼睛宽度应大于高度,实测这里为1)
                    //float aspectRatio = static_cast<float>(eye.width) / eye.height;
                    //if(aspectRatio > 1.2)
                    {
                        filteredEyes.push_back(eye);
                    }
                }
            }

            //确保检测到的是两个眼睛
            if(filteredEyes.size() >= 2)
            {
                //按x坐标排序
                std::sort(filteredEyes.begin(), filteredEyes.end(),
                          [](const cv::Rect &a, const cv::Rect &b)
                {
                    return a.x < b.x;
                });

                //只保留两个最可能的眼睛
                if(filteredEyes.size() > 2)
                {
                    filteredEyes.resize(2);
                }
            }

            //绘制眼睛
            for(const cv::Rect &eye : filteredEyes)
            {
                //计算眼睛在整幅图像中的位置
                cv::Point center(mappedFace.x + eye.x + eye.width/2,mappedFace.y + eye.y + eye.height/2);

                //绘制眼睛圆圈
                int radius = cvRound((eye.width + eye.height) * 0.25);
                cv::circle(image, center, radius, cv::Scalar(255, 0, 0), 2);
            }
        }
    }

    //在状态栏显示检测信息
    if(faces.size() > 0)
    {
        ui->statusLabel->setText(QString("检测到 %1 个人脸").arg(faces.size()));
    }
    else if(m_isCameraActive)
    {
        ui->statusLabel->setText("摄像头运行中 - 未检测到人脸");
    }
}

三、示例完整代码

其它的OpenCV基本功能实现见下文代码:
1.mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QTimer>
#include <QDebug>
#include <opencv2/opencv.hpp>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

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

    void updateImageView();
    void updateStatusBar();
    void detectFaces(cv::Mat &image);
    void processImage(const std::function<void(cv::Mat&)> &processor);

private slots:
    void onOpenImage();
    void onSaveImage();
    void onResetImage();
    void onGrayScale();
    void onGaussianBlur();
    void onCannyEdge();
    void onEqualizeHist();
    void onThreshold();
    void onRotate90();
    void onFlipHorizontal();
    void onFlipVertical();
    void onResizeHalf();
    void onCropCenter();
    void onCameraStart();
    void onFaceDetection();
    void onUpdateCameraFrame();

private:
    Ui::MainWindow *ui;
    cv::Mat m_currentImage;    //当前显示的图像
    cv::Mat m_originalImage;   //原始图像

    bool m_isCameraActive;         //标记摄像头是否处于活动状态
    QTimer *m_cameraTimer;         //定时从摄像头获取帧
    cv::VideoCapture m_videoCap;   //OpenCV视频捕获对象

    bool m_isFaceDetection;                //人脸检测开关
    cv::CascadeClassifier m_faceCascade;   //人脸检测器
    cv::CascadeClassifier m_eyesCascade;   //眼睛检测器
    cv::Scalar m_detectionColor;           //检测框颜色

};
#endif // MAINWINDOW_H

2.mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QFileDialog>
#include <QFileInfo>

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

    //设置初始状态
    m_isCameraActive = false;
    m_cameraTimer = nullptr;
    m_isFaceDetection = false;
    m_detectionColor = cv::Scalar(0, 255, 0);
    ui->statusLabel->setText("就绪");

    //加载人脸检测模型
    QString modelDir = QCoreApplication::applicationDirPath() + "/ModelFiles/";
    QString faceModelPath = modelDir + "haarcascade_frontalface_default.xml";
    if(QFile::exists(faceModelPath))
    {
        //尝试加载人脸检测模型
        if(m_faceCascade.load(faceModelPath.toStdString()))
        {
            qDebug() << "人脸检测模型加载成功:" << faceModelPath;
            ui->statusLabel->setText("就绪: 人脸检测可用");
        }
        else
        {
            qWarning() << "无法加载人脸检测模型:" << faceModelPath;
            ui->statusLabel->setText("警告: 人脸检测模型加载失败");
        }
    }

    //加载眼睛检测模型
    QString eyesModelPath = modelDir + "/haarcascade_eye.xml";
    if(QFile::exists(faceModelPath))
    {
        //尝试加载眼睛检测模型
        if(m_eyesCascade.load(eyesModelPath.toStdString()))
        {
            qDebug() << "眼睛检测模型加载成功:" << eyesModelPath;
            ui->statusLabel->setText("就绪: 眼睛检测可用");
        }
        else
        {
            qWarning() << "无法加载眼睛检测模型, 将仅使用人脸检测";
            ui->statusLabel->setText("警告: 眼睛检测模型加载失败");
        }
    }

    //连接信号槽
    connect(ui->btnOpen, &QPushButton::clicked, this, &MainWindow::onOpenImage);
    connect(ui->btnSave, &QPushButton::clicked, this, &MainWindow::onSaveImage);
    connect(ui->btnReset, &QPushButton::clicked, this, &MainWindow::onResetImage);
    connect(ui->btnCamera, &QPushButton::clicked, this, &MainWindow::onCameraStart);
    connect(ui->btnGray, &QPushButton::clicked, this, &MainWindow::onGrayScale);
    connect(ui->btnBlur, &QPushButton::clicked, this, &MainWindow::onGaussianBlur);
    connect(ui->btnCanny, &QPushButton::clicked, this, &MainWindow::onCannyEdge);
    connect(ui->btnEqualize, &QPushButton::clicked, this, &MainWindow::onEqualizeHist);
    connect(ui->btnThreshold, &QPushButton::clicked, this, &MainWindow::onThreshold);
    connect(ui->btnRotate, &QPushButton::clicked, this, &MainWindow::onRotate90);
    connect(ui->btnFlipH, &QPushButton::clicked, this, &MainWindow::onFlipHorizontal);
    connect(ui->btnFlipV, &QPushButton::clicked, this, &MainWindow::onFlipVertical);
    connect(ui->btnResize, &QPushButton::clicked, this, &MainWindow::onResizeHalf);
    connect(ui->btnCrop, &QPushButton::clicked, this, &MainWindow::onCropCenter);
    connect(ui->btnFaceDetection, &QPushButton::clicked, this, &MainWindow::onFaceDetection);

}

//清理资源
MainWindow::~MainWindow()
{
    if(m_isCameraActive)
    {
        m_cameraTimer->stop();
        m_videoCap.release();
    }
    delete m_cameraTimer;
    delete ui;
}


//更新图像显示
void MainWindow::updateImageView()
{
    if(!m_currentImage.empty())
    {
        //创建QImage (直接使用RGB888格式)
        QImage img(m_currentImage.data,m_currentImage.cols,m_currentImage.rows,m_currentImage.step,
                   QImage::Format_RGB888);

        //缩放适应Label大小
        QPixmap pix = QPixmap::fromImage(img);
        pix = pix.scaled(ui->imageLabel->width(),ui->imageLabel->height(),
                         Qt::KeepAspectRatio,Qt::SmoothTransformation);
        ui->imageLabel->setPixmap(pix);

        //更新状态栏信息
        if(!m_isCameraActive)
        {
            updateStatusBar();
        }
    }
}

//更新状态栏信息
void MainWindow::updateStatusBar()
{
    if(!m_currentImage.empty())
    {
        QString info = QString("尺寸: %1×%2 | 通道: %3 | 类型: %4")
            .arg(m_currentImage.cols)
            .arg(m_currentImage.rows)
            .arg(m_currentImage.channels())
            .arg(m_currentImage.type());

        ui->statusLabel->setText(info);
    }
    else
    {
        ui->statusLabel->setText("就绪");
    }
}

//执行人脸检测
void MainWindow::detectFaces(cv::Mat &image)
{
    //检查人脸检测器是否加载成功
    if(m_faceCascade.empty())
    {
        qWarning()<<"人脸检测器未加载!";
        ui->statusLabel->setText("错误: 人脸检测器未加载");
        return;
    }

    //转换为灰度图像
    cv::Mat gray;
    cv::cvtColor(image, gray, cv::COLOR_RGB2GRAY);

    //保存原始图像尺寸
    int originalWidth = gray.cols;
    int originalHeight = gray.rows;

    //缩小图像以提高检测性能
    double scale = 0.5;   //缩小为原始尺寸的一半
    cv::Mat smallGray;
    cv::resize(gray, smallGray, cv::Size(), scale, scale, cv::INTER_LINEAR);

    //直方图均衡化增强对比度
    cv::equalizeHist(smallGray, smallGray);

    //使用人脸检测器检测人脸
    std::vector<cv::Rect> faces;
    try{
        m_faceCascade.detectMultiScale(
                    smallGray,   //输入灰度图像
                    faces,       //输出检测到的人脸矩形
                    1.1,         //尺度缩放因子 (必须>1.0,典型值:1.01~1.5)
                    3,           //最小相邻人脸数 (减少误检测)
                    0|cv::CASCADE_SCALE_IMAGE,
                    cv::Size(30, 30),    //最小人脸尺寸
                    cv::Size(200, 200)   //最大人脸尺寸
                    );
    }
    catch (const cv::Exception& e)
    {
        qCritical()<<"人脸检测失败:"<<e.what();
        ui->statusLabel->setText("人脸检测出错");
        return;
    }

    //在原始图像上绘制检测结果
    for(const cv::Rect &face : faces)
    {
        //将检测结果映射回原始图像尺寸
        cv::Rect mappedFace(
                    static_cast<int>(face.x / scale),
                    static_cast<int>(face.y / scale),
                    static_cast<int>(face.width / scale),
                    static_cast<int>(face.height / scale)
                    );

        //确保映射后的人脸框在图像范围内
        if(mappedFace.x < 0)
            mappedFace.x = 0;
        if(mappedFace.y < 0)
            mappedFace.y = 0;
        if(mappedFace.x + mappedFace.width > originalWidth)
           mappedFace.width = originalWidth - mappedFace.x;
        if(mappedFace.y + mappedFace.height > originalHeight)
            mappedFace.height = originalHeight - mappedFace.y;

        //绘制人脸矩形(绿色)
        cv::rectangle(image, mappedFace, m_detectionColor, 2);

        //添加人脸标签
        cv::putText(image, "Face",
                    cv::Point(mappedFace.x, mappedFace.y - 5),
                    cv::FONT_HERSHEY_SIMPLEX, 0.5, m_detectionColor, 1);

        //在每张人脸中检测眼睛
        if(!m_eyesCascade.empty())
        {
            //在原始灰度图像上裁剪人脸区域
            cv::Mat faceROI = gray(mappedFace);

            //只检测人脸的上半部分(避免误检)
            int upperPartHeight = mappedFace.height * 2 / 3;
            cv::Rect upperFace(0, 0, mappedFace.width, upperPartHeight);
            cv::Mat upperFaceROI = faceROI(upperFace);

            //使用眼睛检测器检测眼睛
            std::vector<cv::Rect> eyes;
            try{
                m_eyesCascade.detectMultiScale(upperFaceROI, eyes,1.1, 4,0|cv::CASCADE_SCALE_IMAGE,cv::Size(10, 10),cv::Size(100, 100));
            }
            catch (const cv::Exception& e)
            {
                qCritical()<<"眼睛检测失败:"<<e.what();
                ui->statusLabel->setText("眼睛检测出错");
                return;
            }

            //过滤误检(可选)
            std::vector<cv::Rect> filteredEyes;
            for(const cv::Rect &eye : eyes)
            {
                //位置过滤
                if(eye.y < upperPartHeight * 0.8)
                {
                    //尺寸比例过滤(眼睛宽度应大于高度,实测这里为1)
                    //float aspectRatio = static_cast<float>(eye.width) / eye.height;
                    //if(aspectRatio > 1.2)
                    {
                        filteredEyes.push_back(eye);
                    }
                }
            }

            //确保检测到的是两个眼睛
            if(filteredEyes.size() >= 2)
            {
                //按x坐标排序
                std::sort(filteredEyes.begin(), filteredEyes.end(),
                          [](const cv::Rect &a, const cv::Rect &b)
                {
                    return a.x < b.x;
                });

                //只保留两个最可能的眼睛
                if(filteredEyes.size() > 2)
                {
                    filteredEyes.resize(2);
                }
            }

            //绘制眼睛
            for(const cv::Rect &eye : filteredEyes)
            {
                //计算眼睛在整幅图像中的位置
                cv::Point center(mappedFace.x + eye.x + eye.width/2,mappedFace.y + eye.y + eye.height/2);

                //绘制眼睛圆圈
                int radius = cvRound((eye.width + eye.height) * 0.25);
                cv::circle(image, center, radius, cv::Scalar(255, 0, 0), 2);
            }
        }
    }

    //在状态栏显示检测信息
    if(faces.size() > 0)
    {
        ui->statusLabel->setText(QString("检测到 %1 个人脸").arg(faces.size()));
    }
    else if(m_isCameraActive)
    {
        ui->statusLabel->setText("摄像头运行中 - 未检测到人脸");
    }
}

//图像处理模板函数
void MainWindow::processImage(const std::function<void(cv::Mat&)> &processor)
{
    //确保当前存在图像
    if(!m_currentImage.empty())
    {
        //克隆当前图像
        cv::Mat result = m_currentImage.clone();

        //应用处理函数
        processor(result);

        //更新当前图像显示
        m_currentImage = result;
        updateImageView();
    }
}

//打开图像文件
void MainWindow::onOpenImage()
{
    QString path = QFileDialog::getOpenFileName(this, "选择图像", QDir::homePath(),
                                                "图像文件 (*.png *.jpg *.jpeg *.bmp)");

    if(!path.isEmpty())
    {
        cv::Mat img = cv::imread(path.toStdString(), cv::IMREAD_COLOR);
        if(!img.empty())
        {
            //转换为RGB格式存储和显示
            cv::cvtColor(img, m_originalImage, cv::COLOR_BGR2RGB);
            m_currentImage = m_originalImage.clone();
            updateImageView();
            ui->statusLabel->setText("已加载: " + QFileInfo(path).fileName());
        }
    }
}

//保存当前图像
void MainWindow::onSaveImage()
{
    if(!m_currentImage.empty())
    {
        QString path = QFileDialog::getSaveFileName(this, "保存图像",QDir::homePath() + "/processed_image.png",
                                                    "PNG (*.png);;JPEG (*.jpg *.jpeg);;BMP (*.bmp)");

        if(!path.isEmpty())
        {
            //转换回BGR格式保存
            cv::Mat saveImg;
            cv::cvtColor(m_currentImage, saveImg, cv::COLOR_RGB2BGR);

            if(cv::imwrite(path.toStdString(), saveImg))
            {
                ui->statusLabel->setText("图像已保存: " + QFileInfo(path).fileName());
            }
            else
            {
                ui->statusLabel->setText("保存失败");
            }
        }
    }
}

//重置图像到原始状态
void MainWindow::onResetImage()
{
    if(!m_originalImage.empty())
    {
        m_currentImage = m_originalImage.clone();
        updateImageView();
        ui->statusLabel->setText("已重置图像");
    }
}

//转换为灰度图像
void MainWindow::onGrayScale()
{
    processImage([](cv::Mat &img)
    {
        cv::cvtColor(img, img, cv::COLOR_RGB2GRAY);
        cv::cvtColor(img, img, cv::COLOR_GRAY2RGB);   //保持RGB格式
    });
}

//高斯模糊处理
void MainWindow::onGaussianBlur()
{
    processImage([](cv::Mat &img)
    {
        cv::GaussianBlur(img, img, cv::Size(15, 15), 0);
    });
}

//Canny边缘检测
void MainWindow::onCannyEdge()
{
    processImage([](cv::Mat &img)
    {
        if(img.channels() > 1)
        {
            cv::cvtColor(img, img, cv::COLOR_RGB2GRAY);
        }
        cv::Canny(img, img, 50, 150);
        cv::cvtColor(img, img, cv::COLOR_GRAY2RGB);
    });
}

//直方图均衡化(支持彩色和灰度图像)
void MainWindow::onEqualizeHist()
{
    processImage([](cv::Mat &img)
    {
        if(img.channels() == 1)
        {
            cv::equalizeHist(img, img);
        }
        else
        {
            cv::Mat ycrcb;
            cv::cvtColor(img, ycrcb, cv::COLOR_RGB2YCrCb);
            std::vector<cv::Mat> channels;
            cv::split(ycrcb, channels);
            cv::equalizeHist(channels[0], channels[0]);
            cv::merge(channels, ycrcb);
            cv::cvtColor(ycrcb, img, cv::COLOR_YCrCb2RGB);
        }
    });
}

//二值化处理(使用大津法自动阈值)
void MainWindow::onThreshold()
{
    processImage([](cv::Mat &img)
    {
        if(img.channels() > 1)
        {
            cv::cvtColor(img, img, cv::COLOR_RGB2GRAY);
        }
        cv::threshold(img, img, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
        cv::cvtColor(img, img, cv::COLOR_GRAY2RGB);
    });
}

//顺时针旋转90度
void MainWindow::onRotate90()
{
    processImage([](cv::Mat &img)
    {
        cv::rotate(img, img, cv::ROTATE_90_CLOCKWISE);
    });
}

//水平翻转(镜像)
void MainWindow::onFlipHorizontal()
{
    processImage([](cv::Mat &img)
    {
        cv::flip(img, img, 1);
    });
}

//垂直翻转
void MainWindow::onFlipVertical()
{
    processImage([](cv::Mat &img)
    {
        cv::flip(img, img, 0);
    });
}

//缩小图像到原来的一半
void MainWindow::onResizeHalf()
{
    processImage([](cv::Mat &img)
    {
        cv::resize(img, img, cv::Size(), 0.5, 0.5, cv::INTER_LINEAR);
    });
}

//裁剪中心区域
void MainWindow::onCropCenter()
{
    processImage([](cv::Mat &img)
    {
        int width = img.cols;
        int height = img.rows;

        //取尺寸的50%作为裁剪区域
        int cropSize = std::min(width, height) * 0.5;
        int x = (width - cropSize) / 2;
        int y = (height - cropSize) / 2;

        //确保裁剪区域有效
        if (cropSize > 0 && x >= 0 && y >= 0 &&
            (x + cropSize) <= width && (y + cropSize) <= height)
        {
            cv::Rect roi(x, y, cropSize, cropSize);
            img = img(roi).clone();
        }
    });
}

//启动/停止摄像头
void MainWindow::onCameraStart()
{
    if(!m_isCameraActive)
    {
        //尝试打开摄像头
        if(!m_videoCap.open(0))
        {
            ui->statusLabel->setText("摄像头打开失败");
            return;
        }

        //配置摄像头分辨率
        m_videoCap.set(cv::CAP_PROP_FRAME_WIDTH, 640);
        m_videoCap.set(cv::CAP_PROP_FRAME_HEIGHT, 480);

        //创建并启动定时器
        m_cameraTimer = new QTimer(this);
        connect(m_cameraTimer, &QTimer::timeout, this, &MainWindow::onUpdateCameraFrame);
        m_cameraTimer->start(33); // 约30fps
        ui->btnCamera->setText("停止摄像头");
        m_isCameraActive = true;
        ui->statusLabel->setText("摄像头运行中...");
    }
    else
    {
        //停止摄像头
        m_cameraTimer->stop();
        m_videoCap.release();
        delete m_cameraTimer;
        m_cameraTimer = nullptr;

        ui->btnCamera->setText("开启摄像头");
        m_isCameraActive = false;

        //保持最后一帧作为当前图像
        if(!m_currentImage.empty())
        {
            m_originalImage = m_currentImage.clone();
            ui->statusLabel->setText("摄像头已停止");
        }
    }
}

//开启/关闭人脸检测
void MainWindow::onFaceDetection()
{
    //切换检测状态
    m_isFaceDetection = !m_isFaceDetection;

    //更新文本
    ui->btnFaceDetection->setText(m_isFaceDetection ? "关闭人脸检测" : "开启人脸检测");
    ui->statusLabel->setText(m_isFaceDetection ? "人脸检测已启用" : "人脸检测已禁用");
}

//更新摄像头帧
void MainWindow::onUpdateCameraFrame()
{
    cv::Mat frame;
    if(m_videoCap.read(frame))
    {
        //转换颜色空间: BGR -> RGB
        cv::cvtColor(frame, m_currentImage, cv::COLOR_BGR2RGB);

        //如果启用了人脸检测,执行人脸检测
        if(m_isFaceDetection)
        {
            detectFaces(m_currentImage);
        }

        //更新原始图像
        m_originalImage = m_currentImage.clone();
        updateImageView();
    }
}

3.mainwindow.ui
请添加图片描述


总结

本文使用Qt+OpenCV实现的图像处理应用包含基本图像处理算法(灰度化、模糊、边缘检测等),几何变换(旋转、翻转、缩放、裁剪),实时摄像头处理(人脸和眼睛检测),注意运行时需要连接摄像头才能进行人脸眼睛的检测哦~


hello:
共同学习,共同进步,如果还有相关问题,可在评论区留言进行讨论。

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐