定义
核心定义:OpenCV是一个开源的计算机视觉和机器学习软件库。
作用:就类似于给计算机装上眼睛和大脑,让计算机能够看懂图像/视频/并进行只能分析。帮助开发人员构建复杂的视觉应用。
框架
关键类Mat
概念:用于保存图像的数据结构,该数据结构是所有OpenCV和函数的核心。
- 图形存储的容器,像智能的像素矩阵
- 自动内存管理:引用计数的方式实现
- 支持多通道
- 支持多种数据类型
关键属性:
| 属性 | 描述 |
|---|---|
dims |
矩阵的维度(如 2D 图像为 2 维) |
rows, cols |
2D 矩阵的行数和列数(仅当 dims=2 时有效) |
data |
指向实际数据的指针(uchar* 类型) |
type() |
数据类型和通道数(如 CV_8UC3 表示 8 位无符号 3 通道) |
depth() |
位数(8 位,32位等等) |
channels() |
通道数(如灰度图=1,RGB=3) |
构造函数
默认构造函数:生成一个矩阵并由 OpenCV 提供的函数(一是 Mat::create() 和 cv::imread())来分配储存空间。
常用构造函数:
cv::Mat::Mat(int rows,int cols,int type)
//提供矩阵的大小(rows,行数;cols ,列数),以及存储类型(type)
//提供矩阵的大小(rows,行数;cols ,列数),以及存储类型(type)
cv::Mat::Mat(Size size,int type )
// Size 为分别率,比如屏幕分别率 1440*900,其中 cols=1440,rows=900;
cv::Mat::Mat(int ndims,const int * sizes,int type,const Scalar& s)
//生成图像背景颜色
cv::Mat::Mat(const Mat & m)
成员函数
- at 函数的功能是访问矩阵元素:Mat::at(int i0,int i1)
- Mat cv::Mat::clone() const // 深拷贝(独立内存)
- void cv::Mat::copyTo(OutputArray m) const //从 m 矩阵复制 data 数据单元,与 clone 函数的作用类似
- void cv::Mat::create(int rows,int cols,int type) //分配矩阵的存储单元,一般和默认构造函数配合使用
- void Mat::release()//在必要的情况下,递减引用计数并释放该矩阵
常用函数
imshow显示图像函数
imshow("OpenCV测试程序", myjpg);
imwrite保存图像函数
Mat myjpg = imread("image.jpg");
imwrite("newjpg.jpg", myjpg);
filename
mat 待写入的图像
params 用来设置图片格式的参数
waitKey接受按键事件函
delay按下后返回的延时时间
截取图像当中某一个区域方法,通过Rect进行处理
使用rect确定选定图像区域
Rect recta(45, 45, 100, 100);//x,y,width,height,图片截取的大小
Rect rectb(130,130, 100, 100);//存放的画框
Mat rtest1;
myjpg(recta).copyTo(rtest1);
rtest1.copyTo(myjpg(rectb));//将rtest1放到myjpg内部的rectb区域,并且这个区域大小要与图片大小一致
交集区域:两个rect区域进行&就是交集
Mat rtest3 = rtest1 & rtest2;
copyto拷贝图像
将截取的图像放入到原始图像
-
OpenCV要求:复制的源图像大小必须和目标区域大小 完全相等
myjpg(rectb).copyTo(rtest2);
选择视频文件,抓取帧,放入mat中
VideoCapture vcapture;
Mat mpic;
vcapture.open(0);
if (!vcapture.isOpened())
{
return -1;
}
while (1)
{
vcapture >> mpic;
imshow("读取摄像头", mpic);
if (waitKey(20) == 32)
{
Mat mpic2;
mpic2 = mpic.clone();
imshow("读取摄像头2", mpic2);
waitKey(20);
}
}
opencv 图像滤波技术
概念:为图像识别抽取图像特征;消除图像中混入的噪声。要求图像视觉效果更好,不能损坏图像
滤波器函数。图像滤波就像给照片做后期处理。
均值滤波
语法:
void cv::blur(
InputArray src, // 输入图像
OutputArray dst, // 输出图像
Size ksize, // 滤波核大小,如Size(5,5)
Point anchor = Point(-1,-1), // 锚点,默认中心
int borderType = BORDER_DEFAULT // 边界处理
);
工作原理:
每个像素的新值=周围邻居的算数平均值
特点: 简单快速,消除细小噪声,边缘模糊严重,像毛玻璃,ksize越大,模糊越强。
Mat blurDst;
blur(NewSrc, blurDst, Size(5, 5));
//Size(5, 5):这是唯一且最重要的参数,表示一个 5像素×5像素的正方形窗口
//这个窗口会在图像上滑动,对每个5×5区域内的25个像素求平均值,值越大,模糊效果越强
//常用值:Size(3,3)(轻微模糊)、Size(5,5)(中等模糊)、Size(7,7)(强烈模糊)
imshow("原始图像", NewSrc);
waitKey(0);
imshow("均值滤波图像", blurDst);
waitKey(0);
高斯滤波
语法:
void cv::GaussianBlur(
InputArray src,
OutputArray dst,
Size ksize, // 核大小,必须为正奇数
double sigmaX, // X方向标准差
double sigmaY = 0, // Y方向标准差(0表示与sigmaX相同)
int borderType = BORDER_DEFAULT
);
工作原理:离得越近的邻居,说话越重(权重越高),离得越远,分量越轻。计算:给每个邻居的值乘以一个不同的权重,再加起来。
特点:效果:过渡非常自然,像隔着毛玻璃看东西。既平滑了噪点 ,又比均值滤波更好地保留了整体边缘。在去除噪声 和保留边缘 之间取得了最好的平衡,符合人眼的视觉感受。sigma - 控制"钟"的胖瘦。sigma 越大,考虑越远的邻居,越模糊。
GaussianBlur(NewSrc, Gablur, Size(5, 5), 2, 0);//5x5窗口,sigma=2
Size(5, 5):
必须是奇数(3,5,7,...)
决定参与计算的像素范围
1.5(sigmaX,最重要的参数):
控制权重分布的形状
值越小 → 权重集中在中心 → 轻微模糊
值越大 → 权重分布广 → 严重模糊
经验值:
0.5-1.0:轻微模糊,保留细节
1.0-2.0:自然模糊(最常用)
2.0-3.0:强烈模糊
0(sigmaY):
如果为0,OpenCV会自动设成与sigmaX相同
如果指定不同值,可以在X和Y方向有不同的模糊程度(椭圆模糊)
中值滤波
语法:
void cv::medianBlur(
InputArray src,
OutputArray dst,
int ksize // 孔径大小,必须为大于1的奇数
);
工作原理
将所有邻居的亮度值排序 ,取中位数,像选举中排除极端票
特点
有效去除椒盐噪声, 边缘保持良好,计算量较大,ksize通常为3、5、7
medianBlur(NewSrc, Medblur, 3);
必须是奇数(3,5,7,...)
表示取 3×3区域 内的9个像素
将这些像素的值排序,取中间值
值越大,去噪能力越强,但细节损失也越大
特殊之处:
核大小不是Size()而是单个整数
因为中值滤波窗口必须是正方形
双边滤波
语法
void cv::bilateralFilter(
InputArray src,
OutputArray dst,
int d, // 邻域直径,-1表示由sigmaSpace计算
double sigmaColor, // 颜色空间标准差
double sigmaSpace, // 坐标空间标准差
int borderType = BORDER_DEFAULT
);
特点:
优秀的边缘保持能力 ,纹理平滑自然,计算最慢,sigmaColor:值越大,颜色差异容忍度越高
适用场景:人像美颜、细节增强、HDR色调映射
bilateralFilter(
NewSrc, // 📤 输入图像
Bilblur,// 📥 输出图像
5, // 📏 直径:邻域范围
1.2, // 🎨 sigmaColor:颜色相似度容忍度
1.5 // 📍 sigmaSpace:空间距离权重
);
5(d:直径):
邻域像素的范围直径
如果≤0,则从sigmaSpace计算
决定要考虑多远距离的邻居
1.2(sigmaColor:最重要的参数):
颜色相似度的容忍度
值小 → 只和颜色非常相似的像素混合 → 边缘保留好
值大 → 能和颜色差异大的像素混合 → 平滑效果好
比喻:交朋友的"颜色门槛"。门槛低(值小)只交相似的朋友,门槛高(值大)什么朋友都交。
1.5(sigmaSpace):
空间距离的权重
值小 → 只考虑很近的邻居
值大 → 考虑较远的邻居
通常和sigmaColor设为相似值
对比
录制摄像头设备视频
int main(int argc, char* argv[])
{
VideoCapture vcapture;
Mat mpic;
vcapture.open(0);
if (!vcapture.isOpened())
{
return -1;
}
//读取视频帧的宽度和高度
int fvwidth = vcapture.get(CAP_PROP_FRAME_WIDTH);
int fvheight = vcapture.get(CAP_PROP_FRAME_HEIGHT);
//获取帧数
double fvfps = 30.0;//防止帧数为0
VideoWriter vw("record.mp4", vcapture.get(CAP_PROP_FOURCC), fvfps, Size(fvwidth, fvheight), true);
bool record = false;
while (1)
{
// 捕获一帧
bool success = vcapture.read(mpic);
if (!success)
{
cout << "⚠️ 无法从摄像头读取帧!" << endl;
break;
}
imshow("读取摄像头", mpic);
int key = waitKey(20);
if (key == 13)//退出
{
record = true;
/*Mat mpic2;
mpic2 = mpic.clone();
imshow("读取摄像头2", mpic2);
waitKey(20);*/
}
if (key == 32)//空格
{
record = false;
}
if (key == 27)
{
break;
}
if (record == true)
{
vw.write(mpic);
}
}
vw.release();
vcapture.release();
return 0;
}
图像翻转
| 翻转类型 | 比喻 | 应用场景 | 代码参数 |
|---|---|---|---|
| 水平翻转 | 照镜子 | 人脸识别数据增强、照片修复 | 1 |
| 垂直翻转 | 倒影效果 | 水波特效、倒立视图 | 0 |
| 双向翻转 | 180°旋转+镜像 | 特殊视觉效果、图像校正 | -1 |
// 📝 flip函数原型解析
void cv::flip(
InputArray src, // 🔍 输入图像矩阵(源图像)
OutputArray dst, // 🔍 输出图像矩阵(翻转后的图像)
int flipCode // 🔍 翻转代码:0=垂直,1=水平,-1=双向
);
Mat image = cv::imread("newjpg.jpg");
Mat image2;
Mat image3;
Mat image4;
flip(image,image2, 1);//水平 原始图片 目标存放图片对象
flip(image, image3, -1);
flip(image, image4, 0);
imshow("原始显示", image);
waitKey(0);
imshow("水平显示", image2);
waitKey(0);
imshow("双向翻转显示", image3);
waitKey(0);
imshow("翻转显示", image4);
waitKey(0);
图像旋转
指定角度旋转
// 🚀 仅支持90°倍数旋转(最快)
void cv::rotate(
InputArray src, // 🔍 输入图像
OutputArray dst, // 🔍 输出图像
int rotateCode // 🔍 旋转代码枚举
);
// 🎯 旋转代码枚举值
enum RotateFlags {
ROTATE_90_CLOCKWISE = 0, // 🔄 顺时针90°
ROTATE_180 = 1, // 🔄 旋转180°
ROTATE_90_COUNTERCLOCKWISE = 2 // 🔄 逆时针90°
};
任意角度旋转:cv::warpAffine() + getRotationMatrix2D()
// 📐 获取旋转矩阵
cv::Mat cv::getRotationMatrix2D(
Point2f center, // 🎯 旋转中心
double angle, // 🔄 角度(度,正=逆时针)
double scale // 📏 缩放比例
);
// 🎨 应用仿射变换
void cv::warpAffine(
InputArray src, // 🔍 输入图像
OutputArray dst, // 🔍 输出图像
InputArray M, // 🔍 2x3变换矩阵
Size dsize, // 🔍 输出尺寸
int flags = INTER_LINEAR, // 🔧 插值方法
int borderMode = BORDER_CONSTANT, // 🎨 边界模式
const Scalar& borderValue = Scalar() // 🖌️ 边界颜色
);
窗口句柄
概念:cvGetWindowHandle 是 OpenCV 早期 C 接口 中的一个函数,用于获取由 cvNamedWindow 创建的窗口的底层操作系统句柄。这个函数能将 OpenCV 窗口与原生系统的 GUI 操作联系起来
作用:根据窗口名称,返回底层系统的原生窗口句柄,让你能够调用系统原生 API 对这个窗口进行深度控制。这在 OpenCV 自身提供的窗口功能(如移动、调整大小)不够用时很关键。
边缘检测技术
检测物体边缘的时候,首先对轮廓进行粗略检测,再通过链接规则将原来检测的轮廓点链接起来。同时也检测和连接漏掉的边界点及去除虚假边界
图像滤波-》图像增强-》图像检测-》图像定位
sobel
核心思想:边缘的图像中像素值剧烈变化的地方,Sobel算子通过计算水平和垂直方向的梯度(变化率),找到这些变化剧烈的位置,从而检测出边缘。
原理:
想象你在爬山⛰️:
- X方向梯度:测量东西方向的坡度(水平变化)
- Y方向梯度:测量南北方向的坡度(垂直变化)
- 陡峭的地方(梯度大)就是边缘,平缓的地方(梯度小)不是边缘
参数详解
void Sobel(InputArray src, OutputArray dst, int ddepth,
int dx, int dy, int ksize = 3,
double scale = 1, double delta = 0,
int borderType = BORDER_DEFAULT);
src:需要进行处理的图像,通常为Mat对象
det:存储计算结果的容器,即输出图像
ddepth:指定输出图像的数据类型,输出图像深度
dx:在x方向(水平方向)求导的阶数
dy:在Y方向(垂直方向)导数阶数
ksize:sobel算子的大小。
实际工作原理:
想象用一个3×3的"放大镜"在图像上滑动:
[-1 0 1]
[-2 0 2]
[-1 0 1]
计算中心像素的梯度 =
(左上×(-1) + 上中×0 + 右上×1) +
(左中×(-2) + 中心×0 + 右中×2) +
(左下×(-1) + 下中×0 + 右下×1)
scale:缩放因子
delta:偏移量
borderType :处理图像边缘的像素
应用场景
-
文档识别
-
人脸检测
-
工业零件检测
-
根据噪音类型调节:高噪音图/老照片/医学影像
//读取图像 Mat mSrc = imread("R-C .jpg"); //输出原图像 imshow("测试:原图像", mSrc); waitKey(0); //设置目标图像 Mat mSox, mAbsx, mSoy, mAbsy, mResult; Sobel(mSrc, mSox, CV_16S, 1, 0, 3, 1, 1, BORDER_DEFAULT); //因为梯度值会有负数,但是图像显示需要0-255的正数 convertScaleAbs(mSox, mAbsx); imshow("测试2:x方向梯度", mAbsx); waitKey(0); Sobel(mSrc, mSoy, CV_16S, 0, 1, 3, 1, 1, BORDER_DEFAULT); //因为梯度值会有负数,但是图像显示需要0-255的正数 convertScaleAbs(mSox, mAbsy); imshow("测试2:y方向梯度", mAbsy); waitKey(0); addWeighted(mAbsx, 0.6, mAbsy, 0.6, 0, mResult); // 参数详解: // 1. mAbsx:第一个输入图像 // 2. 0.6:第一个图像的权重 // 3. mAbsy:第二个输入图像 // 4. 0.6:第二个图像的权重 // 5. 0:添加到每个和的标量值 // 6. mResult:输出图像 imshow("测试4:XY方向梯度相加", mResult); waitKey(0);
四种图像阈值分割法
举例说明
就像用不同方式"筛选豆子":
1. 常规阈值:大于100的豆子放左边,小于100的放右边
2. 截断阈值:大于80的豆子都变成80,其他的不变
3. 零化阈值:小于100的豆子扔掉(变0),大于100的保留
4. 三角法:自动找一个最佳分界点来分豆子
Mat mSrc= imread("girl.png",0);
//创建存储器
cv::Mat mBinary, mTrunc, mZero, mTrangle;
//常规阈值分割法
threshold(mSrc, mBinary, 50, 150, THRESH_BINARY);
imshow("常规阈值分割法", mBinary);//像素值大于50,设为150,
waitKey(0);
//截断阈值分割法
threshold(mSrc, mTrunc, 100, 120, THRESH_TRUNC);//如果 像素值 > 80:设为80(截断)否则:保持不变
imshow("截断阈值分割法", mTrunc);//像素值大于50,设为150,
waitKey(0);
//零化阈值分隔法
threshold(mSrc, mZero, 180, 255, THRESH_TOZERO);//如果 像素值 > 180:保持不变否则:设为0(变黑)
imshow("零化阈值分割法", mZero);//像素值大于50,设为150,
waitKey(0);
//三角法(自动阈值)
threshold(mSrc, mTrangle, 0, 255, THRESH_TRIANGLE);//算法自动找到一个最佳分割点就像让电脑自己决定哪里该分界
imshow("三角阈值分割法", mTrangle);//像素值大于50,设为150,
waitKey(0);
向上采样和向下采样
向下采样:对图像进行降低尺寸,降低尺寸之后进行显示
输入图像尺寸:W × H
输出图像尺寸:(W+1)/2 × (H+1)/2
大约为:原图的一半大小
语法
void pyrDown(InputArray src, OutputArray dst,
const Size& dstsize = Size(),
int borderType = BORDER_DEFAULT);//size目标尺寸,默认为Size(0,0),自动计算
边界类型枚举
enum BorderTypes {
BORDER_CONSTANT = 0, // 常量填充
BORDER_REPLICATE = 1, // 复制边缘
BORDER_REFLECT = 2, // 反射(不包括边缘)
BORDER_WRAP = 3, // 包装
BORDER_REFLECT_101 = 4, // 反射(包括边缘,默认值)
// ... 其他值
};
向上采样:对图形进行扩大尺寸,放大尺寸之后进行显示
语法:
void pyrUp(InputArray src, OutputArray dst,
const Size& dstsize = Size(),
int borderType = BORDER_DEFAULT);
borderType与向下枚举的一样,不能用2
#include <iostream>
#include <D:/vsopencv/opencv/opencv/sources/include/opencv2/opencv.hpp>
using namespace cv;
int main(int argc, char* argv[])
{
Mat image1, image2, image3;
image1 = imread("2022-05-15.png");
pyrDown(image1, image2, Size(0, 0), 2);
pyrUp(image2, image3, Size(0, 0));
imshow("原本图像", image1);
waitKey(0);
imshow("缩小图像", image2);
waitKey(0);
imshow("还原图像", image3);
waitKey(0);
return 0;
}
图像形态学膨胀
概念:让图像中的亮色区域变胖
膨胀 vs 腐蚀(Erosion):
与腐蚀的对比
膨胀:让白色区域"长胖"
效果:白色区域变大,黑色区域变小
类比:用白色画笔在白色图案外描边
腐蚀:让白色区域"变瘦"
效果:白色区域变小,黑色区域变大
类比:用橡皮擦掉白色图案的边缘
两者是相反的操作,通常配合使用。
案例:用空间拖拉框控制模糊度
int radius = 1;//结构体半径
int maxradius = 22;//最大班级
Mat mSrc, mDst;
void CallBackFunc(int, void*)
{
// 创建垂直方向的矩形结构元
Mat ms = getStructuringElement(MORPH_RECT, Size(1, 2 * radius + 1));
// 调用膨胀操作
dilate(mSrc, mDst, ms);
imshow("测试2:图像", mDst);
}
int main(int argc, char* argv[])
{
// 输入图像
mSrc = imread("R-C.png");
// 创建调节radius进度条
// 输出源图像
imshow("测试1:源图像", mSrc);
// 创建调节窗口
namedWindow("dilatetest", WINDOW_AUTOSIZE);
createTrackbar("半径参数:", "dilatetest", &radius, maxradius, CallBackFunc);//拖拉空间连接模糊调节函数
// 输出膨胀之后的图像
CallBackFunc(0, 0);
waitKey(0);
return 0;
}
浮雕效果图像
概念:浮雕效果是一种将二维图转换为具有三维立体感的图像处理技术啊。它模拟关系从特定角度照射物体时产生的阴影和高光,让图像看起来像雕刻在平面上的浮雕艺术品。
原理:
浮雕效果 = 像素差值计算 + 亮度偏移
具体公式:
新像素值 = (像素A - 像素B) + 128
其中:
• 像素A、像素B:原始图像中两个特定位置的像素
• 128:中性灰色值(RGB三通道都是128)
详细步骤:
第一步:确定图像的类型:彩色/灰度
第二步:确定差值,来决定浮雕的显示强度
选择方向:根据想要的立体效果选择光照方向
设定强度:
弱浮雕:差值乘以0.5-0.8的系数
中浮雕:差值乘以1.0(标准)
强浮雕:差值乘以1.5-2.0
边界处理:
保留原图边界
填充灰色(128)
镜像扩展
第三步逐像素处理流程
彩色图像
1. 从第1行第1列开始(避开图像最外一圈边缘)
2. 对于当前像素(i,j):
a. 获取参考像素A:根据选择的方向,如左上方向则取(i-1, j-1)
b. 获取参考像素B:根据选择的方向,如右下方向则取(i+1, j+1)
c. 分别计算三个通道的差值:
红差值 = A的红色值 - B的红色值
绿差值 = A的绿色值 - B的绿色值
蓝差值 = A的蓝色值 - B的蓝色值
d. 每个差值乘以强度系数
e. 每个结果加上128
f. 限制每个值在0-255之间:
- 小于0 → 设为0(纯黑)
- 大于255 → 设为255(纯白)
g. 将计算结果赋给输出图像的(i,j)位置
3. 移动到下一个像素,重复步骤2
4. 处理完所有内部像素
灰度图像
1. 同样从第1行第1列开始
2. 对于当前像素(i,j):
a. 获取两个参考像素的亮度值
b. 计算差值 = 像素A亮度 - 像素B亮度
c. 差值 × 强度系数 + 128
d. 限制在0-255之间
e. 赋给输出图像
3. 遍历所有像素
彩色图像案例:
#include <iostream>
#include <D:/vsopencv/opencv/opencv/sources/include/opencv2/opencv.hpp>
using namespace std;
using namespace cv;
void ReliefFunc(Mat mSrc, Mat& mDes, int cols, int rows)
{
CV_Assert(mSrc.channels() == 3); // 确保是3通道彩色图像
for (int i = 1; i < rows - 1; i++)
{
uchar* s1 = mSrc.ptr<uchar>(i - 1);//上一行的指针
uchar* s2 = mSrc.ptr<uchar>(i + 1);//下一行的指针
uchar* ut = mDes.ptr<uchar>(i);//当前行的指针
//循环处理每一列
for (int j = 1; j < cols - 1; j++)
{
//循环处理三个颜色通道
for (int k = 0; k < 3; k++)
{
//核心浮雕计算
int RGB = (s1[3 * (j - 1) + k] - s2[3 * (j + 1) + k])*2 + 128;
//限制值在0-255范围内
if (RGB < 0)
RGB = 128;
if (RGB > 255)
RGB = 255;
ut[j * 3 + k] = (uchar)RGB;
}
}
}
}
int main(int argc, char* argv[])
{
Mat image = imread("R-C.jfif");
Mat image2 = image.clone();
int cols = image.cols;
int rows = image.rows;
ReliefFunc(image,image2, cols, rows);
imshow("浮雕图像:", image2);
waitKey(0);
return 0;
}
人脸识别
概念:opencv会自带开发团队训练好的模型文件,因此可以直接将文件接入代码中进行识别。
多种人脸检测模型
haarcascade_frontalface_default.xml # 基础正面人脸检测
haarcascade_frontalface_alt.xml # 改进版(你使用的这个)
haarcascade_frontalface_alt2.xml # 另一种改进版
haarcascade_frontalface_alt_tree.xml # 更准确但稍慢
haarcascade_profileface.xml # 侧面人脸检测
第一步加载人脸模型
// 读取训练器haar
CascadeClassifier clsface;
string strFileFace = "D:\\vsopencv\\opencv\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_default.xml ";
// 判断加载xml文件是否成功
if (!clsface.load(strFileFace))
{
cout << "系统加载haarcascade_frontalface_alt.xml文件失败,请重新检查?" << endl;
return -1;
}
第二步加载需要识别的图片
Mat mGrayImage;
cvtColor(mSrcImage, mGrayImage, COLOR_BGR2GRAY); // 正确转换
Mat mSrcImage = imread("people.jpg"); // 读取图像文件
Mat mDstImage = mSrcImage.clone(); // 克隆原图用于绘制结果
第三步转换为灰度图,更加好识别
// 交图像生成灰度,目的提高检测效率
cvtColor(mSrcImage, mGrayImage, COLOR_BGR2GRAY);
第四步执行人脸检测,获取结果
vector<Rect> vFaceRect; // 存储检测结果的容器,存放是人脸的矩形点
clsface.detectMultiScale(mGrayImage, vFaceRect, 1.1, 3, 0);
参数详解
clsface.detectMultiScale(
输入图像, // mGrayImage:灰度图像
输出矩形, // vFaceRect:存储找到的人脸位置
1.1, // scaleFactor:每次搜索窗口扩大10%
3, // minNeighbors:至少被检测到3次才确认是人脸
0, // flags:旧参数,通常为0
Size(30,30) // minSize:忽略比30×30更小的检测
);
第五步:绘制边框和获取人脸的图片
if (vFaceRect.size())
{
for (int i = 0; i < vFaceRect.size(); i++)
{
// 在图像人脸上面:标注矩形
cv::rectangle(mDstImage, vFaceRect[i], Scalar(0, 0, 255), 1);
// 可选:添加标签
string label = "Face " + to_string(i + 1)+" x:"+to_string(vFaceRect[i].x) + " y:"+to_string(vFaceRect[i].y);
putText(mDstImage, label, Point(vFaceRect[i].x, vFaceRect[i].y - 10),
FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 255), 1);
//获取图像人脸矩形图像
Mat mFaceImg = mDstImage(vFaceRect[i]);
imshow("测试:人脸", mFaceImg);
waitKey(0);
}
}