在Visual Studio上,使用OpenCV实现人脸识别

这篇具有很好参考价值的文章主要介绍了在Visual Studio上,使用OpenCV实现人脸识别。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1. 环境与说明

本文介绍了如何在Visual Studio上,使用OpenCV来实现人脸识别的功能

环境说明 :

  • 操作系统 : windows 10 64位
  • Visual Studio版本 : Visual Studio Community 2022 (社区版)
  • OpenCV版本 : OpenCV-4.8.0 (2023年7月最新版)

实现效果如图所示,识别到的人脸会用红框框出来 :

在Visual Studio上,使用OpenCV实现人脸识别,visual studio,opencv,人脸识别,级联分类器,图像识别

2. 配置Visual Studio环境

这部分详见我的另一篇博客 : Visual Studio 2022 cmake配置opencv开发环境

最终配置好后,能够在Visual Studio中正常调用OpenCV,运行CMake项目(C++程序)
在Visual Studio上,使用OpenCV实现人脸识别,visual studio,opencv,人脸识别,级联分类器,图像识别

3. 实现摄像头预览

这部分要用到VideoCapture这个类,VideoCapture既支持从视频文件读取,也支持直接从摄像机等监控器中读取,还可以读取 IP 视频流,要想获取视频需要先创建一个 VideoCapture 对象来打开相机,然后就可以来操作视频帧了。

我们将项目代码修改为如下内容

#include "OpenCVTest.h"
#include "opencv2/opencv.hpp"

using namespace std;
using namespace cv;

int main()
{
	VideoCapture capture;
	//打开相机,这个传入的相机ID为0
	capture.open(0);
	if (!capture.isOpened())
	{
		cout << "opencv打开摄像头失败!\n" << endl;
		return -1;
	}
	//Mat矩阵,用来存一张图片
	Mat frame;
	while (true)
	{
		//从capture中取数据,将画面输出到frame矩阵里面
		capture >> frame; 
		if (frame.empty())
		{
			cout << "读取摄像头数据失败\n" << endl;
		}
		imshow("摄像头", frame); //显示图像

		if (waitKey(30) == 27) //按下ESC键退出程序
		{
			break;
		}
	}
	return 0;
}

运行程序,效果如下所示

在Visual Studio上,使用OpenCV实现人脸识别,visual studio,opencv,人脸识别,级联分类器,图像识别

4. 转化为灰度图像

接下来我们需要将图片转化为灰度图,为什么要进行灰度化处理呢 ? 主要有以下几个作用,提高人脸识别的准确性和可靠性

  • 简化图像处理:灰度化可以将彩色图像转化为黑白图像,使得处理更加简单。彩色图像包含三个通道(红、绿、蓝),而灰度图像只有一个通道,使得处理更加快速和高效。
  • 消除颜色信息:人脸识别对于颜色信息并不是非常敏感,而更关注形状和轮廓等特征。因此,通过灰度化处理,可以消除颜色信息对于后续处理的影响。
  • 提高处理性能:灰度化处理可以减少计算量,提高处理性能。在人脸识别过程中,对每个像素进行颜色计算会消耗大量计算资源,而灰度化处理只需要对每个像素的亮度进行计算,减少了计算量。
  • 突出图像特征:灰度化处理可以突出图像中的边缘和纹理等特征。这些特征对于人脸识别非常关键,可以帮助算法更好地识别人脸。

进行灰度化处理我们需要调用void cvtColor( InputArray src, OutputArray dst, int code, int dstCn = 0 );,这里src是我们输入的图像,dst是我们要输出的图像,code需要传COLOR_BGR2GRAY,表示将BGR转化为灰度图。

要注意,在OpenCV中,是BGR排列方式,而不是RGB排列。

具体完整代码如下

#include "OpenCVTest.h"
#include "opencv2/opencv.hpp"

using namespace std;
using namespace cv;

int main()
{
	VideoCapture capture;
	capture.open(0);
	if (!capture.isOpened())
	{
		cout << "opencv打开摄像头失败!\n" << endl;
		return -1;
	}
	Mat frame; //摄像头彩色图像
	Mat grayFrame; //摄像头灰度图像
	while (true)
	{
		//从capture中取数据,将画面输出到frame矩阵里面
		capture >> frame; 
		if (frame.empty())
		{
			cout << "读取摄像头数据失败!\n" << endl;
			return -1;
		}
		imshow("摄像头", frame); //显示彩色图像
		//灰度化处理
		cvtColor(frame, grayFrame, COLOR_BGR2GRAY); //注意 : OpenCV中是BRG
		imshow("灰度化", grayFrame); //显示灰色图像


		if (waitKey(30) == 27) //ESC键
		{
			break;
		}
	}
	return 0;
}

运行程序,效果如下所示,左边的是彩色画面,右边的是黑白画面

在Visual Studio上,使用OpenCV实现人脸识别,visual studio,opencv,人脸识别,级联分类器,图像识别

5. 直方图均衡化处理

接着,要进行直方图均衡化处理,为什么要进行这一步操作呢 ? 主要有以下几个作用,提高人脸识别的准确性和可靠性

  • 提高对比度:直方图均衡化通过重新分布图像像素的灰度级,将原始图像中的灰度级分布变得更加均匀。这样做可以增强图像的对比度,使得人脸的特征更加清晰可见。
  • 消除光照变化:人脸识别中的一个挑战是光照变化对人脸图像的影响。直方图均衡化可以消除光照变化,使得人脸图像在不同光照条件下具有一致的亮度和对比度。
  • 提高图像质量:直方图均衡化可以改善图像的质量,去除图像中的噪声和伪影。这对于后续的人脸特征提取和匹配非常重要,可以提高人脸识别的准确性和鲁棒性。
  • 增强细节信息:直方图均衡化可以增强图像的细节信息,使得人脸图像中的纹理和特征更加明显。这对于人脸识别算法的性能至关重要,可以提高人脸识别的准确率和鲁棒性。

直方图均衡化处理需要调用void equalizeHist( InputArray src, OutputArray dst);src是输入的图像,需要是单通道的灰度图,dst是我们输出的图像。

具体完整代码如下

#include "OpenCVTest.h"
#include "opencv2/opencv.hpp"

using namespace std;
using namespace cv;

int main()
{
	VideoCapture capture;
	capture.open(0);
	if (!capture.isOpened())
	{
		cout << "opencv打开摄像头失败!\n" << endl;
		return -1;
	}
	Mat frame; //摄像头彩色图像
	Mat grayFrame; //摄像头灰度图像
	Mat equalizeFrame; //直方图
	while (true)
	{
		capture >> frame; //从capture中取数据,将画面输出到frame矩阵里面
		if (frame.empty())
		{
			cout << "读取摄像头数据失败!\n" << endl;
			return -1;
		}
		imshow("摄像头", frame); //显示图像
		//灰度化处理
		cvtColor(frame, grayFrame, COLOR_BGR2GRAY); //注意 : OpenCV中是BRG
		imshow("灰度化", grayFrame); //显示图像
		//直方图均衡化,用来增强图像对比度,从而让轮廓更加明显
		equalizeHist(grayFrame, equalizeFrame);
		imshow("直方图", equalizeFrame);


		if (waitKey(30) == 27) //ESC键
		{
			break;
		}
	}
	return 0;
}

运行程序,效果如下所示,最右边的是经过直方图均衡化处理后的
在Visual Studio上,使用OpenCV实现人脸识别,visual studio,opencv,人脸识别,级联分类器,图像识别

6. 加载级联分类器

级联分类器CascadeClassifier的作用是进行目标检测。它是一种基于机器学习的分类器,通过训练多个弱分类器来识别目标物体。这些弱分类器层层级联,形成一个级联分类器,能够快速准确地检测出图像中的目标物体。

级联分类器通常用于人脸检测,可以通过训练来识别人的面部特征,如眼睛、鼻子、嘴巴等,从而识别人脸并定位人脸的位置。在OpenCV中,CascadeClassifier类提供了一个方便的接口,可以加载预训练的级联分类器,并进行目标检测操作。

首先我们要去加载级联分类器文件(xml文件),这些文件位于D:\Developer\opencv4.8.0\opencv\build\etc目录下,这里我们用的是haarcascade这种基于梯度提升决策树的分类器 (另一种lbpcascade是一种基于局部二值模式LBP的分类器)

haarcascade目录下,我们可以看到haarcascade_frontalface_alt.xml这个文件,就是我们需要的,用于人脸识别的级联分类器了。
在Visual Studio上,使用OpenCV实现人脸识别,visual studio,opencv,人脸识别,级联分类器,图像识别
所以,我们加载级联分类器的时候,去指定这个路径D:\Developer\opencv4.8.0\opencv\build\etc\haarcascades\haarcascade_frontalface_alt.xml,需要注意的是,放到代码里,这里的要将\改为/ (或者改为\\也行)。如果不改,那么路径不对,级联分类器会读取出错。

具体代码如下

int main()
{
	CascadeClassifier face_CascadeClassifier;
	if (!face_CascadeClassifier.load("D:/Developer/opencv4.8.0/opencv/build/etc/haarcascades/haarcascade_frontalface_alt.xml")) {
		cout << "级联分类器加载失败!\n" << endl;
		return -1;
	}

	//这里省略了原本其他的代码 ...
}

7. 进行人脸检测

接下来我们就要进行人脸检测了,人脸检测需要调用detectMultiScale方法,第一个参数 image 需要传入我们刚才处理后的直方图,第二个参数objects会返回所有检测出来的人脸的坐标。

void detectMultiScale( InputArray image,
				CV_OUT std::vector<Rect>& objects,
				double scaleFactor = 1.1,
				int minNeighbors = 3, int flags = 0,
				Size minSize = Size(),
				Size maxSize = Size() );

还有一个rectangle方法,用来在得到人脸坐标之后,进行画框。第一个参数img代表要在哪个图像上画框,第二个参数rec表示框的坐标,第三个参数color表示画框的颜色。

void rectangle(InputOutputArray img, Rect rec,
				const Scalar& color, int thickness = 1,
				int lineType = LINE_8, int shift = 0);

主要代码如下所示

std::vector<Rect> faces;
face_CascadeClassifier.detectMultiScale(grayFrame, faces);  //检测人脸

for (size_t i = 0; i < faces.size(); i++)
{
	rectangle(frame,faces[i],Scalar(0,0,255)); //在人脸的位置画红色的框
}

来看一下完整代码

#include "OpenCVTest.h"
#include "opencv2/opencv.hpp"

using namespace std;
using namespace cv;

int main()
{
	//加载级联分类器
	CascadeClassifier face_CascadeClassifier;
	if (!face_CascadeClassifier.load("D:/Developer/opencv4.8.0/opencv/build/etc/haarcascades/haarcascade_frontalface_alt.xml")) {
		cout << "级联分类器加载失败!\n" << endl;
		return -1;
	}

	VideoCapture capture;
	capture.open(0);
	if (!capture.isOpened())
	{
		cout << "opencv打开摄像头失败!\n" << endl;
		return -1;
	}
	Mat frame; //摄像头彩色图像
	Mat grayFrame; //摄像头灰度图像
	Mat equalizeFrame; //直方图
	while (true)
	{
		capture >> frame; //从capture中取数据,将画面输出到frame矩阵里面
		if (frame.empty())
		{
			cout << "读取摄像头数据失败!\n" << endl;
		}
		//imshow("摄像头", frame); //显示图像
		//灰度化处理
		cvtColor(frame, grayFrame, COLOR_BGR2GRAY); //注意 : OpenCV中是BRG
		//imshow("灰度化", grayFrame); //显示图像
		//直方图均衡化,用来增强图像对比度,从而让轮廓更加明显
		equalizeHist(grayFrame, equalizeFrame);
		//imshow("直方图", equalizeFrame);

		std::vector<Rect> faces;
		face_CascadeClassifier.detectMultiScale(grayFrame, faces);  //检测人脸

		for (size_t i = 0; i < faces.size(); i++)
		{
			rectangle(frame,faces[i],Scalar(0,0,255));
		}
		imshow("摄像头", frame); //显示图像


		if (waitKey(30) == 27) //ESC键
		{
			break;
		}
	}
	return 0;
}

运行程序,来看一下效果

可以看到,人脸已经检测出来了,并对人脸进行了画框。但是可以画面非常的卡顿,因为人脸检测是非常耗时的,可能需要500毫秒甚至1-2秒时间,这里每一帧都去检测人脸,导致了异常卡顿。所以这种方式只适合用来检测静态图像,并不适合用作实时的摄像头人脸跟踪检测。

8. 实现实时人脸跟踪检测

8.1 OpenCV Android Demo

那我们需要来怎么做呢 ? 其实我们可以来看一下官方的示例,我们要去下载官方的Android包,里面有Android的官方示例。

在Visual Studio上,使用OpenCV实现人脸识别,visual studio,opencv,人脸识别,级联分类器,图像识别

8.2 DetectionBasedTracker_jni.cpp

我们下载解压后,可以在OpenCV-android-sdk\samples\face-detection\jni目录下找到DetectionBasedTracker_jni.cpp这个文件
在Visual Studio上,使用OpenCV实现人脸识别,visual studio,opencv,人脸识别,级联分类器,图像识别
在里面的nativeCreateObject方法里,我们可以发现其调用了这几句代码
在Visual Studio上,使用OpenCV实现人脸识别,visual studio,opencv,人脸识别,级联分类器,图像识别

8.3 CascadeDetectorAdapter

CascadeDetectorAdapter是一个适配器类,用于将CascadeClassifierDetector接口适配起来,从而用于检测人脸。

再来看一下CascadeDetectorAdapter这个类,里面的detect方法就是用来检测人脸的
在Visual Studio上,使用OpenCV实现人脸识别,visual studio,opencv,人脸识别,级联分类器,图像识别

8.4 DetectorAgregator

然后来看一下第三行代码中的DetectorAgregator,这里面有tracker = makePtr<DetectionBasedTracker>(mainDetector, trackingDetector, DetectorParams);这行代码是我们需要的,用来传入mainDetectortrackingDetector,生成一个tracker对象。
在Visual Studio上,使用OpenCV实现人脸识别,visual studio,opencv,人脸识别,级联分类器,图像识别

8.5 开始重新编写代码

这里我们将原来写的人脸检测的代码删除了,代码恢复到了刚配置好OpenCV的初始状态,然后将CascadeDetectorAdapter这个类的代码复制到我们的项目中

class CascadeDetectorAdapter: public DetectionBasedTracker::IDetector
{
public:
    CascadeDetectorAdapter(cv::Ptr<cv::CascadeClassifier> detector):
            IDetector(),
            Detector(detector)
    {
        CV_Assert(detector);
    }

    void detect(const cv::Mat &Image, std::vector<cv::Rect> &objects)
    {
        Detector->detectMultiScale(Image, objects, scaleFactor, minNeighbours, 0, minObjSize, maxObjSize);
    }

    virtual ~CascadeDetectorAdapter(){}

private:
    CascadeDetectorAdapter();
    cv::Ptr<cv::CascadeClassifier> Detector;
};

声明 tracker这个对象。

cv::Ptr<DetectionBasedTracker> tracker;

然后创建tracker,并调用run()方法,会启动一个异步线程,后面的人脸检测会在这个异步线程进行检测了。

string stdFileName = "D:/Developer/opencv4.8.0/opencv/build/etc/haarcascades/haarcascade_frontalface_alt.xml";
//创建一个主检测适配器
cv::Ptr<CascadeDetectorAdapter> mainDetector = makePtr<CascadeDetectorAdapter>(
	makePtr<CascadeClassifier>(stdFileName));
//创建一个跟踪检测适配器
cv::Ptr<CascadeDetectorAdapter> trackingDetector = makePtr<CascadeDetectorAdapter>(
	makePtr<CascadeClassifier>(stdFileName));
//创建跟踪器
DetectionBasedTracker::Parameters DetectorParams;
tracker = makePtr<DetectionBasedTracker>(mainDetector, trackingDetector, DetectorParams);
tracker->run();

然后在人脸检测的使用调用tracker->process(grayFrame);进行人脸检测,并调用tracker->getObjects(faces);获得识别出来的人脸。

tracker->process(grayFrame);
tracker->getObjects(faces);

核心代码就是如上所示,接下来我们再来看一下完整的代码

#include "OpenCVTest.h"
#include "opencv2/opencv.hpp"

using namespace std;
using namespace cv;

class CascadeDetectorAdapter : public DetectionBasedTracker::IDetector
{
public:
	CascadeDetectorAdapter(cv::Ptr<cv::CascadeClassifier> detector) :
		IDetector(),
		Detector(detector)
	{
		CV_Assert(detector);
	}

	void detect(const cv::Mat& Image, std::vector<cv::Rect>& objects)
	{
		Detector->detectMultiScale(Image, objects, scaleFactor, minNeighbours, 0, minObjSize, maxObjSize);
	}

	virtual ~CascadeDetectorAdapter()
	{
	}

private:
	CascadeDetectorAdapter();
	cv::Ptr<cv::CascadeClassifier> Detector;
};

cv::Ptr<DetectionBasedTracker> tracker;

int main()
{
	string stdFileName = "D:/Developer/opencv4.8.0/opencv/build/etc/haarcascades/haarcascade_frontalface_alt.xml";
	//创建一个主检测适配器
	cv::Ptr<CascadeDetectorAdapter> mainDetector = makePtr<CascadeDetectorAdapter>(
		makePtr<CascadeClassifier>(stdFileName));
	//创建一个跟踪检测适配器
	cv::Ptr<CascadeDetectorAdapter> trackingDetector = makePtr<CascadeDetectorAdapter>(
		makePtr<CascadeClassifier>(stdFileName));
	//创建跟踪器
	DetectionBasedTracker::Parameters DetectorParams;
	tracker = makePtr<DetectionBasedTracker>(mainDetector, trackingDetector, DetectorParams);
	tracker->run();

	VideoCapture capture;
	capture.open(0);
	if (!capture.isOpened())
	{
		cout << "opencv打开摄像头失败!\n" << endl;
		return -1;
	}
	Mat frame; //摄像头彩色图像
	Mat grayFrame; //摄像头灰度图像
	Mat equalizeFrame; //直方图
	while (true)
	{
		capture >> frame; //从capture中取数据,将画面输出到frame矩阵里面
		if (frame.empty())
		{
			cout << "读取摄像头数据失败!\n" << endl;
			return -1;
		}
		//imshow("摄像头", frame); //显示图像
		//灰度化处理
		cvtColor(frame, grayFrame, COLOR_BGR2GRAY); //注意 : OpenCV中是BRG
		//imshow("灰度化", grayFrame); //显示图像
		//直方图均衡化,用来增强图像对比度,从而让轮廓更加明显
		equalizeHist(grayFrame, equalizeFrame);
		//imshow("直方图", equalizeFrame);

		std::vector<Rect>  faces;

		tracker->process(grayFrame);
		tracker->getObjects(faces);

		for (size_t i = 0; i < faces.size(); i++)
		{
			rectangle(frame, faces[i], Scalar(0, 0, 255));
		}

		imshow("摄像头", frame); //显示图像


		if (waitKey(30) == 27) //ESC键
		{
			break;
		}
	}
	tracker->stop();
	return 0;
}

8.6 运行效果

运行程序,我们就可以看到本文开头给出的效果了

在Visual Studio上,使用OpenCV实现人脸识别,visual studio,opencv,人脸识别,级联分类器,图像识别
至此,我们就使用OpenCV完成实时人脸跟踪识别了。

9. 本文源码下载

使用OpenCV实现人脸识别示例Demo文章来源地址https://www.toymoban.com/news/detail-650410.html

到了这里,关于在Visual Studio上,使用OpenCV实现人脸识别的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【配置环境】Visual Studio 配置 OpenCV

    目录 一,环境 二,下载和配置 OpenCV 三,创建一个 Visual Studio 项目 四,配置 Visual Studio 项目 五,编写并编译 OpenCV 程序 六,解决CMake编译OpenCV报的错误 七,本人编译好的库 Windows 11 家庭中文版 Microsoft Visual Studio Community 2022 (64 位) - Current版本 17.5.3 CMake – 3.24.1 OpenCV – 4.8.0

    2024年02月08日
    浏览(55)
  • Visual Studio下2022Opencv的配置

    先从官网下载opencv : opencv releases 下载 ​ 我这里的开发环境是window版本,我们选择Windows版本进行下载 点开下载的文件,输入需要保存的路径 记住你保存的路径(我这里安装再F:) 安装需要时间静等安装。 创建一个项目 我们对其进行opencv的配置 在创建的项目中找到解决方案资

    2024年02月13日
    浏览(55)
  • 安装visual studio2022以及配置opencv

    目录 1下载visual studio 1.1进入网站点击 下载visual studio,选择Community 2022 1.2打开安装包,进入界面 1.3等待安装完成  2下载opencv 2.2下载完成后自定义解压路径 3.3win10系统配置环境变量 3配置visual studio 3.1打开软件 3.2配置 4测试 Visual Studio: 面向软件开发人员和 Teams 的 IDE 和代码编

    2024年02月12日
    浏览(70)
  • 一文搞定 Visual Studio 配置 OpenCV环境

    在 Visual Studio 上配置 OpenCV 环境是极其恼人的事情,尤其是对于初学者,经常几个小时过去了都配不好,将我们对代码的热爱扼杀在摇篮之中。 本文根据本人的无数次环境配置经历,总结了一套完整的 OpenCV 环境配置流程,包教包会,百分百成功。 要在 Visual Studio 上配置 Op

    2024年02月16日
    浏览(54)
  • Visual Studio 2022 cmake配置opencv开发环境

    这里我用的是 widnows 10 64位 , Visual Studio 用的 Visual Studio Community 2022 (社区版) 对于 Android 开发工程师来说,为什么要使用 Visual Studio 呢 ? 因为在 Visual Studio 中开发调试 OpenCV 方便,可以开发调试好后,再移植到 Android 中。 官方地址在这里 : 官方下载地址 不过官方下载地址可能

    2024年02月07日
    浏览(92)
  • Visual Studio部署C++环境下OpenCV库

      本文介绍在 Visual Studio 2022 中配置、编译 C++ 计算机视觉库 OpenCV 的方法。   首先,我们进行 OpenCV 库的下载与安装。作为一个开源的库,我们直接在其官方下载网站中进行下载即可;如下图所示,我们首先选择需要下载的操作系统。   随后,即可在弹出的新界面中自

    2024年03月09日
    浏览(62)
  • 如何在Visual Studio 2022中配置OpenCV环境

    Visual Studio下载链接 Open CV下载链接 注意:环境配置所有流程中使用到的路径均为个人下载安装软件对应路径!! 【高级系统配置】——【环境变量】——【系统变量-Path】               双击【Path】,进入后点击【新建】,输入红框中所示路径(路径请注意修改为自己

    2024年02月08日
    浏览(60)
  • 在Visual Studio 2019中使用Qt5.14.2并配置相关路径(含opencv/halcon)联合编程配置

    (1)Qt下载安装 参考链接:https://blog.csdn.net/weixin_41977337/article/details/106859728 1、QT下载 推荐下载Qt5.12.3版本(5.12为LTS长期支持版本),官方下载链接: http://download.qt.io/archive/qt/. 清华源连接: https://mirrors.tuna.tsinghua.edu.cn/qt/archive/qt/5.14/5.14.2/ 版本5.14.2下载: 断网即可跳过注册账

    2024年02月04日
    浏览(45)
  • visual studio配置调用c++ dll opencv为例

    1,配置VC++目录,包含目录和库目录。 2,链接器-输入-包含目录 3,生成目录下包含对应的dll文件 4,需注意对应的Debug,Release及X86,X64选项

    2024年02月17日
    浏览(52)
  • [超级无敌详细系列]Visual Studio/c++配置opencv环境

    写在前面:如果这篇文章对大家有帮助的话,欢迎关注Franpper的公众号: Franpper的知识铺 , 回复“进群”,即可进入讨论群 ,有什么问题大家可以一起讨论呀! 目录 1、下载opencv安装包 2、 添加环境变量 3、 导入.dll(动态库)文件 4、 Visual Studio项目属性配置 5、验证安装结

    2024年02月07日
    浏览(57)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包