Qt下使用OpenCV基本函数及实现人脸检测
·
前言
本文主要讲述了在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:
共同学习,共同进步,如果还有相关问题,可在评论区留言进行讨论。
更多推荐


所有评论(0)