opencv

定义

核心定义:OpenCV是一个开源的计算机视觉和机器学习软件库。

作用:就类似于给计算机装上眼睛和大脑,让计算机能够看懂图像/视频/并进行只能分析。帮助开发人员构建复杂的视觉应用。

框架

关键类Mat

概念:用于保存图像的数据结构,该数据结构是所有OpenCV和函数的核心。

  1. 图形存储的容器,像智能的像素矩阵
  2. 自动内存管理:引用计数的方式实现
  3. 支持多通道
  4. 支持多种数据类型

关键属性:

属性 描述
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)

成员函数

  1. at 函数的功能是访问矩阵元素:Mat::at(int i0,int i1)
  2. Mat cv::Mat::clone() const // 深拷贝(独立内存)
  3. void cv::Mat::copyTo(OutputArray m) const //从 m 矩阵复制 data 数据单元,与 clone 函数的作用类似
  4. void cv::Mat::create(int rows,int cols,int type) //分配矩阵的存储单元,一般和默认构造函数配合使用
  5. 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 :处理图像边缘的像素

应用场景

  1. 文档识别

  2. 人脸检测

  3. 工业零件检测

  4. 根据噪音类型调节:高噪音图/老照片/医学影像

    复制代码
     //读取图像
     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);
	}

}
相关推荐
王莽v26 小时前
FlexRound:基于逐元素除法的可学习舍入后训练量化方法
人工智能
爱思德学术7 小时前
【IEEE会议】第三届智能计算与机器人国际会议(ICICR 2026)
人工智能·机器学习·机器人
楚来客7 小时前
AI基础概念之七:一个AI应用的基本架构
人工智能·架构
沛沛老爹7 小时前
用 Web 开发思维理解 Agent 的三大支柱——Tools + Memory + LLM
java·人工智能·llm·llama·rag
光羽隹衡7 小时前
深度学习----PyTorch框架(手写数字识别案例)
人工智能·pytorch·深度学习
GeminiJM7 小时前
我的 MCP 学习之旅:从困惑到理解
人工智能·mcp
Hubianji_097 小时前
2026第7届人工智能与计算机应用国际会议
人工智能·能源·国际会议
Jerryhut7 小时前
opencv总结9——答题卡识别
人工智能·opencv·计算机视觉
DB!!!7 小时前
cube-studio手动部署label_studio至“标注平台”(启动企业版的功能)
人工智能·机器学习·rancher·mlops
掘金酱7 小时前
TRAE 2025 年度报告分享活动|获奖名单公示🎊
前端·人工智能·后端