opencv自学笔记之Haar训练自己的人脸分类器

目录

  • 前言
  • 准备数据
    • 正样本
    • 负样本
  • 训练
  • 测试

前言

本文介绍如何使用Haar训练自己的人脸分类器。
参考blog:
https://www.cnblogs.com/tornadomeet/archive/2012/03/28/2420936.html
https://www.cnblogs.com/tornadomeet/archive/2012/03/27/2420088.html
https://blog.csdn.net/yangleo1987/article/details/52883864
https://blog.csdn.net/qq_32502511/article/details/79010509

准备数据

训练数据包含正样本和负样本,比例设为1:3为好。另外将图片都resize成20x20。

正样本

正样本采用我之前一篇blog(https://blog.csdn.net/qq_35290955/article/details/99291496 )提到的
ORL人脸数据集。我只用了其中333张图片,样本少,训练快,只做演示效果,也为了达到1:3。建立一个VS2017工程resize_pic,将上面我那篇blog提到的labels.txt复制到自己的工作目录下,并改名为origin_ORL_datapath.txt。
resize_pic代码如下:

#include "pch.h"
#include 
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include    //ifstream用到
#include 
using namespace std;
using namespace cv;


#define IMG_WIDTH 20        //需要调整图片后的尺寸宽度
#define IMG_HEIGH 20        //需要调整图片后的尺寸高度



int main()
{
	Mat src_img;
	string path;
	//neg_pic转换
	/*
	string src_img_txt = "origin_neg.txt";//包含所有原始图片路径的txt文件
	int convert_num=1000;//3:1  neg:pos
	*/
	//pos_pic转换
	string src_img_txt = "origin_ORL_datapath.txt";//包含所有原始图片路径的txt文件
	int convert_num = 333 ;
	ifstream file(src_img_txt,ifstream::in);
	for (int i = 0; i < convert_num; i++)
	{
		//string dst_img_name = "D:\\yanxue\\openCV\\项目\\人脸识别\\haar_face_train\\20x20_neg\\";//neg目的文件夹路径
		string dst_img_name = "D:\\yanxue\\openCV\\项目\\人脸识别\\haar_face_train\\20x20_ORL_data\\";//pos目的文件夹路径
		getline(file, path);
		if (!path.empty())//如果读取成功,则将图片和对应标签压入对应容器中
		{
			src_img=imread(path);//图像读取
			Mat dst_img_rsize(IMG_WIDTH, IMG_HEIGH, src_img.type());//resize
			resize(src_img, dst_img_rsize, dst_img_rsize.size(), 0, 0, INTER_LINEAR);
			char name_num[5];//  千位数的4+\0的1
			_itoa_s(i, name_num,10);//10进制    _itoa()--->integer  to  ascii
			dst_img_name += name_num;
			dst_img_name += ".jpg";
			imwrite(dst_img_name,dst_img_rsize);
			printf("%d张图片已完成转换。\n", i + 1);
		}
	}
	printf("Finished!");
	
}

运行后在20x20_ORL_data文件夹下得到resize后的图片。然后在该文件下像生成labels.txt一样生成pos.txt。然后记事本打开它—>点击编辑—>点击替换---->.jpg全部替换为.jpg 1 0 0 20 20,1代表一张,0 0 20 20代表图片人脸区域。然后需要将其转化为.vec文件,需要从自己的opencv下(我的在
D:\study software\opencv\build\bin\Debug )copy 文件opencv_createsamplesd.exe到自己的工作目录下,打开cmd.exe,进入到工作目录下,执行以下命令:opencv_createsamplesd.exe -info pos.txt -vec pos.vec -num 333 -w 20 -h 20。这样就得到了pos.vec。

负样本

负样本要求是:不能包含人脸,且负样本一定不能重复,且尽可能增大负样本的差异性。开始我只从cifar10中的一个类抽取若干图片做负样本,导致负样本单一,且我选的样本量太少,导致训练失败。后来我在以前用过的道路交通数据集里抽取了1000张图片用来训练,效果尚可。其实自己训练可以按照要求在网上随便下载一个数据集使用即可。像上方正样本一样,得到origin_neg.txt放在resize_pic工作目录下,适当修改代码,即可在20x20_neg文件夹下得到图片。继而得到neg.txt,这里不需要修改操作。

训练

找到opencv_traincascaded.exe复制到工作目录,cmd执行命令:
opencv_traincascaded.exe –data xml –vec pos.vec –bg neg.txt –w 20 –h 20 –mode ALL -numPos 33 -numNeg 100

Usage: opencv_traincascaded.exe
  -data 
  -vec 
  -bg 
  [-numPos ]
  [-numNeg ]
  [-numStages ]
  [-precalcValBufSize ]
  [-precalcIdxBufSize ]
  [-baseFormatSave]
  [-numThreads ]
  [-acceptanceRatioBreakValue  = -1>]
--cascadeParams--
  [-stageType ]
  [-featureType <{HAAR(default), LBP, HOG}>]
  [-w ]
  [-h ]
--boostParams--
  [-bt <{DAB, RAB, LB, GAB(default)}>]
  [-minHitRate  = 0.995>]
  [-maxFalseAlarmRate ]
  [-weightTrimRate ]
  [-maxDepth ]
  [-maxWeakCount ]
--haarFeatureParams--
  [-mode 

训练则在xml文件夹下最终得到分类器cascade.xml。
补充:
若训练中途中止,看一下是否生成了cascade.xml,生成了就是训练好了。
否则可能是由于FA值已经达到0,没有负样本能够进入下一层进行训练了。
解决方案之一是增加负样本的数量;解决方案之二是用convert_cascade.exe生成xml文件。因为此时各层的训练信息已经有了,FA值达到0也说明训练结果可用。同样适用于FA值已经很低,而下一层的训练时间过长不想等待的情况。(参考 https://blog.csdn.net/yangleo1987/article/details/52883864 )

测试

将自己训练的cascade.xml文件用于 https://blog.csdn.net/qq_35290955/article/details/99291496 中人脸检测部分,测试结果如图:opencv自学笔记之Haar训练自己的人脸分类器_第1张图片可以看到是有效果的,但因训练样本少,效果不好。

你可能感兴趣的:(opencv)