C# 使用OpenCV在一张图片里寻找人脸

先上个效果图

9161b8dd4ed73de06c37dab0d41a6a7c.png

相关库的下载

例程中用到一个库叫做emgucv,是opencv\的net封装
编译打包好的稳定版,在这:https://sourceforge.net/projects/emgucv/files/emgucv/
如果要最新代码,在这里获取:https://github.com/emgucv/emgucv

 做个opencv人脸识别的小伙伴们可能会遇到这样的一个问题,如何下载haarcascade_frontalface_default.xml和haarcascade_frontalface_alt2.xml呢?
  OpenCV有已经自带了人脸的Haar特征分类器,有了那些IT大牛帮我们创建的这个分类器,我们便可的实现人脸的检查功能了,你只需要将他们下载到opencv的目录下。
  首先,进入网站
  https://github.com/opencv/opencv/tree/master/data/haarcascades
  点击这个文件。

haarcascade_frontalface_alt.xml
路径:

https://github.com/opencv/opencv/edit/master/data/haarcascades_cuda/haarcascade_frontalface_alt.xml

这里还有其他的模型:

https://github.com/opencv/opencv/tree/master/data/haarcascades

https://github.com/opencv/opencv/tree/master/data/haarcascades_cuda

建立工程

首先建立一个C#工程.nuget上安装引用

787a0e75d4ded8a627d6247475f3adfc.png

另外准备一张要识别的图片,放到编译输出目录.
接下来就是编辑代码了,后面所有代码都在main里

配置OpenCV使用显卡运算(如果支持的话)

使用显卡处理图像数据效率会很多,如果你的设备支持,最好打开,使用CvInvoke.HaveOpenCLCompatibleGpuDevice能返回是否支持.
配置CvInvoke.UseOpenCL能让OpenCV 启用或者停用 GPU运算

CvInvoke.UseOpenCL = CvInvoke.HaveOpenCLCompatibleGpuDevice;

构建级联分类器对象

emgu包里已经有训练好的数据了,文件名叫做"haarcascade_frontalface_alt.xml",就是上面添加的文件之一

var face = new CascadeClassifier("haarcascade_frontalface_alt.xml");

加载图像并作简单处理

在OpenCV中,大部分函数是处理灰度图的,包括这个识别物体,所以需要转成灰度图,然后再调整下亮度

//加载要识别的图片
var img = new Image<Bgr, byte>("0.png");
var img2 = new Image<Gray, byte>(img.ToBitmap());
//把图片从彩色转灰度
CvInvoke.CvtColor(img, img2, Emgu.CV.CvEnum.ColorConversion.Bgr2Gray);
//亮度增强
CvInvoke.EqualizeHist(img2, img2);

检测人脸

进行目标区域检测:
如果进行级联级联分类器创建之后, 便可以对图片进行目标区域的检测。
public Rectangle[] DetectMultiScale(IInputArray image, double scaleFactor =
1.1, int minNeighbors = 3, Size minSize = null, Size maxSize = null);//通过多次扫描
不同尺度, 寻找图像中可能包含级联分类器训练的样本, 返回这些样本的区域。
参数解析:
IInputArray image:被检测的图像。
double scaleFactor = 1.1:在随后的扫描中缩放比例。例如 double
scaleFactor = 1.1, 意味着增加 10%的窗口。
int minNeighbors = 3:最小值(- 1)的邻居矩形组成一个对象。所有的组
比 min_neighbors=-1 数量较小的矩形会被略去。如果 min_neighbors 是 0,
这个函数没有任何分组并返回所有检测到的候选矩形。这对于用户自定义
分组过程是很有用的。默认值为 3;
Size minSize = null:最小检测出来的窗口大小。
Size maxSize = null:最大检测出来的窗口大小

其实这一步反而最简单,返回的是rectangle[]格式,因为图中可能有多个人脸,所以返回的是数组.

//在这一步就已经识别出来了,返回的是人脸所在的位置和大小
var facesDetected = face.DetectMultiScale(img2, 1.1, 10, new Size(50, 50));

剪切并保存

因为是多个人脸所以需要循环剪切并保存,(→_→)这一块的代码量竟然反而比上面那堆多

//循环把人脸部分切出来并保存
int count = 0;
var b = img.ToBitmap();
foreach (var item in facesDetected)
{
  count++;
  var bmpOut = new Bitmap(item.Width, item.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
  var g = Graphics.FromImage(bmpOut);
  g.DrawImage(b, new Rectangle(0, 0, item.Width, item.Height), new Rectangle(item.X, item.Y, item.Width, item.Height), GraphicsUnit.Pixel);
  g.Dispose();
  bmpOut.Save($"{count}.png", System.Drawing.Imaging.ImageFormat.Png);
  bmpOut.Dispose();
}

释放资源退出

//释放资源退出
b.Dispose();
img.Dispose();
img2.Dispose();
face.Dispose();

全代码和测试图片:

static void Main(string[] args)
{
	//如果支持用显卡,则用显卡运算
	CvInvoke.UseOpenCL = CvInvoke.HaveOpenCLCompatibleGpuDevice;

	//构建级联分类器,利用已经训练好的数据,识别人脸
	var face = new CascadeClassifier("haarcascade_frontalface_alt.xml");

	//加载要识别的图片
	var img = new Image<Bgr, byte>("0.png");
	var img2 = new Image<Gray, byte>(img.ToBitmap());

	//把图片从彩色转灰度
	CvInvoke.CvtColor(img, img2, Emgu.CV.CvEnum.ColorConversion.Bgr2Gray);

	//亮度增强
	CvInvoke.EqualizeHist(img2, img2);

	//在这一步就已经识别出来了,返回的是人脸所在的位置和大小
	var facesDetected = face.DetectMultiScale(img2, 1.1, 10, new Size(50, 50));

	//循环把人脸部分切出来并保存
	int count = 0;
	var b = img.ToBitmap();
	foreach (var item in facesDetected)
	{
		count++;
		var bmpOut = new Bitmap(item.Width, item.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
		var g = Graphics.FromImage(bmpOut);
		g.DrawImage(b, new Rectangle(0, 0, item.Width, item.Height), new Rectangle(item.X, item.Y, item.Width, item.Height), GraphicsUnit.Pixel);
		g.Dispose();
		bmpOut.Save($"{count}.png", System.Drawing.Imaging.ImageFormat.Png);
		bmpOut.Dispose();
	}

	//释放资源退出
	b.Dispose();
	img.Dispose();
	img2.Dispose();
	face.Dispose();

	return;

}

运行效果

编译后运行可以看到目录多了两个图片文件:
8b6d00d2288b29af7c8b89ab462b8f54.png
打开看看:
07b17d2183bb686e3145c777b72fa28e.png

耗时测算:

private void button1_Click(object sender, EventArgs e)
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            //如果支持用显卡,则用显卡运算
            CvInvoke.UseOpenCL = CvInvoke.HaveOpenCLCompatibleGpuDevice;


            //构建级联分类器,利用已经训练好的数据,识别人脸
            var face = new CascadeClassifier("haarcascade_frontalface_alt.xml");


            //加载要识别的图片
            var img = new Image<Bgr, byte>("0.png");
            var img2 = new Image<Gray, byte>(img.ToBitmap());


            //把图片从彩色转灰度
            CvInvoke.CvtColor(img, img2, Emgu.CV.CvEnum.ColorConversion.Bgr2Gray);


            //亮度增强
            CvInvoke.EqualizeHist(img2, img2);


            //在这一步就已经识别出来了,返回的是人脸所在的位置和大小
            var facesDetected = face.DetectMultiScale(img2, 1.1, 10, new Size(50, 50));


            //循环把人脸部分切出来并保存
            int count = 0;
            var b = img.ToBitmap();
            foreach (var item in facesDetected)
            {
                count++;
                var bmpOut = new Bitmap(item.Width, item.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
                var g = Graphics.FromImage(bmpOut);
                g.DrawImage(b, new Rectangle(0, 0, item.Width, item.Height), new Rectangle(item.X, item.Y, item.Width, item.Height), GraphicsUnit.Pixel);
                g.Dispose();
                bmpOut.Save($"{count}.png", System.Drawing.Imaging.ImageFormat.Png);
                bmpOut.Dispose();
            }


            //释放资源退出
            b.Dispose();
            img.Dispose();
            img2.Dispose();
            face.Dispose();
            sw.Stop();
            MessageBox.Show(sw.ElapsedMilliseconds.ToString());
            
        }

015c202287159ed0736f5a8b42b0a8f8.png

标注人脸:

using Emgu.CV;
using Emgu.CV.Structure;
using System;
using System.Diagnostics;
using System.Drawing;
using System.Windows.Forms;


namespace WindowsFormsApp18
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }


        private void button1_Click(object sender, EventArgs e)
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            //如果支持用显卡,则用显卡运算
            CvInvoke.UseOpenCL = CvInvoke.HaveOpenCLCompatibleGpuDevice;


            //构建级联分类器,利用已经训练好的数据,识别人脸
            var face = new CascadeClassifier("haarcascade_frontalface_alt.xml");


            //加载要识别的图片
            var img = new Image<Bgr, byte>("0.png");
            var img2 = new Image<Gray, byte>(img.ToBitmap());


            //把图片从彩色转灰度
            CvInvoke.CvtColor(img, img2, Emgu.CV.CvEnum.ColorConversion.Bgr2Gray);


            //亮度增强
            CvInvoke.EqualizeHist(img2, img2);


            //在这一步就已经识别出来了,返回的是人脸所在的位置和大小
            var facesDetected = face.DetectMultiScale(img2, 1.1, 10, new Size(50, 50));


            //循环把人脸部分切出来并保存
            int count = 0;
            var b = img.ToBitmap();
            foreach (var item in facesDetected)
            {
                count++;
                var bmpOut = new Bitmap(item.Width, item.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
                var g = Graphics.FromImage(bmpOut);
                g.DrawImage(b, new Rectangle(0, 0, item.Width, item.Height), new Rectangle(item.X, item.Y, item.Width, item.Height), GraphicsUnit.Pixel);
                g.Dispose();
                bmpOut.Save($"{count}.png", System.Drawing.Imaging.ImageFormat.Png);
                bmpOut.Dispose();
            }


            //释放资源退出
            b.Dispose();
            img.Dispose();
            img2.Dispose();
            face.Dispose();
            sw.Stop();
           // MessageBox.Show(sw.ElapsedMilliseconds.ToString());
            label1.Text = "取出人脸耗时:" + sw.ElapsedMilliseconds.ToString() + "ms";




        }


        private void button2_Click(object sender, EventArgs e)
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            CascadeClassifier face_detect = new CascadeClassifier(@"haarcascade_frontalface_alt.xml");//创建一个人脸检测级联分类器。
            Mat face_image = new Mat("0.png", Emgu.CV.CvEnum.LoadImageType.AnyColor);//打开指定目录下的图片。
            Rectangle[] rects = face_detect.DetectMultiScale(face_image);//对人脸进行检测, 放回数据在 rects 数组中。
            foreach (Rectangle rect in rects)//遍历每个矩形区域。
            {
                CvInvoke.Rectangle(face_image, rect, new MCvScalar(0, 0, 255), 2);//绘制检测出的人脸的区域。
            }
            imageBox1.Image = face_image;//显示图片
            sw.Stop();
            label2.Text = "标注人脸耗时:" + sw.ElapsedMilliseconds.ToString()+"ms";
        }
    }
}

6d02961d3aa3071cc5a7e83de5974cd5.png

6c237a91393f812f69e16340b9ab88e2.png

注:人脸稍微小点测试效果就不好了

参考链接:

https://www.cnblogs.com/DragonStart/p/7751993.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zls365365

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值