OpenCV(一)人脸定位&人脸定位模型训练

您所在的位置:网站首页 opencv定位 OpenCV(一)人脸定位&人脸定位模型训练

OpenCV(一)人脸定位&人脸定位模型训练

2023-04-14 21:36| 来源: 网络整理| 查看: 265

OpenCV 学习目录:

OpenCV(一)人脸定位&人脸定位模型训练 OpenCV(二)应用车牌识别 OpenCV(三)车牌识别SVM训练与hsv定位 OpenCV(四)OpenCV车牌识别—字符分割与识别

简介

OpenCV是一个基于BSD许可开源发行的跨平台计算机视觉库。拥有C++,Python和Java接口,并且支持Windows, Linux, Mac OS, iOS 和 Android系统。实现了图像处理和计算机视觉方面的很多通用算法。

模块 功能 Core 核心基础模块,定义了被所有其他模块和基本数据结构(包括重要的多维数组Mat)使用的基本函数、底层数据结构和算法函数 Imgproc 图像处理模块,包括:滤波、高斯模糊、形态学处理、几何变换、颜色空间转换及直方图计算等 Highgui 高层用户交互模块,包括:GUI、图像与视频I\O等 Video 视频分析,,运动分析及目标跟踪。 Calib3d 3D模块,包括:摄像机标定、立体匹配、3D重建等 Features2d 二维特征检测与描述模块,包括:图像特征检测、描述、匹配等 Objdetect 目标检测模块,如:人脸检测等 MI 机器学习模块,包括:支持向量机、神经网络等 Flann 最近邻开源库。包含一系列查找算法,自动选取最快算法的机制。 Imgcodecs 图像编解码模块,图像文件的读写操作 Photo 图像计算(处理)模块,图像修复及去噪。 Shape 形状匹配算法模块。描述形状、比较形状 Stitching 图像拼接 Superres 超分辨率模块 Videoio 视频读写模块,视频文件包括摄像头的输入。 Videostab 解决拍摄的视频稳定 Dnn 深度神经网络 contrib 可以引入额外模块

优化补充-android 搭建和技巧 github 搜索opencv或者到官网,下载android sdk

例子: 如果你只需要图片处理的功能,又不想用其他的功能,由于库太大。你可以有选择的组合,使用静态库的方式。 但是core.a 相关的库必须有。然后组合Imgproc.a 相关的就可以了

开发环境 搭建

参见我的OpenCV文章demo mac 环境为例子。windows 稍微麻烦一些不网上有教程

测试环境

移动端比较麻烦,我们先用Clion环境测试 新建项目,配置CMakeLists.txt

cmake_minimum_required(VERSION 3.15) project(FaceTrain) set(CMAKE_CXX_STANDARD 14) add_executable(FaceTrain main.cpp) #修改为自己的路径 #set(OpenCV_DIR F:/xxx/OpenCV/mingw-build2) windows 环境 # Mac 环境 find_package(OpenCV REQUIRED) include_directories(${OpenCV_INCLUDE_DIRS}) message(STATUS "${OpenCV_INCLUDE_DIRS}") message(STATUS "${OpenCV_LIBS}") target_link_libraries(FaceTrain ${OpenCV_LIBS})

Hello World ,打开一张图片 main.cpp

#include #include using namespace cv; int test(){ Mat srcImage = imread("/Users/zcw/Downloads/WechatIMG12683.jpeg"); if (!srcImage.data) { std::cout run(); // android不能使用这个玩意 VideoCapture capture(0); Mat img; Mat gray; int i = 0; while (1) { capture >> img; // 预处理, 去噪 ,取出图片噪声 // img的 颜色空间是 BGR,不像现在,早期的计算机中主流是bgr,而不是rgb cvtColor(img, gray, COLOR_BGR2GRAY); //增强对比度 (直方图均衡) equalizeHist(gray, gray); std::vector faces; //定位人脸 N个 tracker->process(gray); tracker->getObjects(faces); //classifier->detectMultiScale(gray, faces); for (Rect face : faces) { //画矩形 //分别指定 bgra if (face.x < 0 || face.width < 0 || face.x + face.width > img.cols || face.y < 0 || face.height < 0 || face.y + face.height > img.rows) { continue; } rectangle(img, face, Scalar(255, 0, 255)); #if 0 /** * 制作训练正样本........ */ //使用opencv自带的模型 记录你的脸作为样本 //把找到的人脸扣出来 Mat m; //把img中的脸部位拷贝到m中 img(face).copyTo(m); //把人脸 重新设置为 24x24大小的图片 resize(m, m, Size(24, 24)); //转成灰度 cvtColor(m, m, COLOR_BGR2GRAY); char p[100]; sprintf(p, "F:/Lance/OpenCV/face/train/samples/lance/%d.jpg", i++); //把mat写出为jpg文件 imwrite(p, m); m.release(); #endif } imshow("摄像头", img); //延迟30ms 按Esc退出 ,27 =Esc if (waitKey(30) == 27) { break; } } if (!img.empty()) img.release(); if (!gray.empty()) gray.release(); capture.release(); tracker->stop(); return 0; } 级联分类器

从一堆弱分类器里面,挑出一个最符合要求的弱分类器,用着这个弱分类器把不想要的数据剔除,保留想要的数据 然后再从剩下的弱分类器里,再挑出一个最符合要求的弱分类器,对上一级保留的数据,把不想要的数据剔除,保 留想要的数据。最后,通过不断串联几个弱分类器,进过数据层层筛选,最后得到我们想要的数据。这就是级联分 类器。弱分类器分类正确率较低,但是较容易获得,强分类器分类正确率较高,但是较难获得。只要样本充足,弱 学习可以通过一定的组合获得任意精度的强学习。级联分类器就是 N个弱分类器 以级联的方式,从简单到复杂逐 步串联而成。 可以用决策树来构建一个简单的弱分类器, 将提取到的特征与分类器的特征进行逐个比较,从而判断该特征是否属 于人脸:

算法.png

而强分类器相当于先让各个弱分类器进行投票,然后让投票结果根据各弱分类器的错误率进行加权相加,最后与平 均的投票结果进行比较得到最终结果。

我们将使用OpenCV中提供的LBP特征提取与Adaboost算法(机器学习算法)训练人脸定位级联分类器。

训练

http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/user_guide/ug_traincascade.html

正样本:包含人脸的图片,灰度图。 正样本大小:统一大小并且不能小于负样本 负样本:不包含人脸的图片 负样本大小:无所谓 正、负样本个数比列大约为 1: 3

制作正样本

正样本目录为:xxx,内容为100张大小为24x24的人脸 假设目录结构如下:

/xxx 0.jpg 1.jpg

制作xxx.data文件,文件内容如下:

#分别表示 1张人脸 ;人脸从 0,0坐标开始;大小为24x24 xxx/0.jpg 1 0 0 24 24 #================================================================== #假设为2个人脸; 则数据为人脸分别为 100,200处的50x50 和 50,30处的25x25为人脸 xxx/1.jpg 2 100 200 50 50 50 30 25 25

data文件内容可以使用java 程序来制作

public class GeneateFile{ public static void main(String[] args) throws Exception{ String content = String.format("xxx/%d.jpg 1 0 0 24 24\n",i); fos.write(content.getBytes()); } fos.close(); } }

data目录执行: opencv_createsamples

opencv_createsamples -info xxx.data -vec xxx.vec -num 100 -w 24 -h 24 -info: 正样本描述 -vec : 输出的正样本文件 -num : 正样本数量 -w -h: 输出样本的大小 #输出:Done. Created 100 samples 表示成功生成100个样本 制作负样本

负样本大小无所谓,个数为300。假如目录结构如下:

/bg 0.jpg 1.jpg bg.data

则bg.data文件中的内容将如下所示:

bg/0.jpg bg/1.jpg 训练data

创建一个data 目录,执行:

opencv_traincascade -data data -vec xxx.vec -bg bg.data -numPos 100 -numNeg 300 -numStages 15 -featureType LBP -w 24 -h 24 -data : 目录,需要手动创建,生成的结果 训练的模型会输出到这个目录 -vec : 正样本 -bg : 负样本 -numPos :每级分类器训练时所用到的正样本数目 -numNeg :每级分类器训练时所用到的负样本数目,可以大于-bg数目 -numStages:训练分类器的级数,如果层数多,分类器的误差就更小,但是检测速度慢。(15-20) -featureType: LBP -w -h 输出: Training until now has taken 0 days 0 hours 0 minutes 10 seconds. 表示成功 输出: Required leaf false alarm rate achieved. Branch training terminated. 表示成功,但是误检率已经达标。(样本太少了,生成的模型质量不行) 输出: Bad argument < Can not get new positive sample. The most possible reason is insufficient count of samples in given vec-file. 则意味着错误。 #参数:(未使用) minHitRate:分类器的每一级希望得到的最小检测率。当设置为0.995(默认)时,如果numPos个数为1000个,那么第一 级分类器其中的5个就很可能不被检测,第二级选择的时候必须多选择后面的5个,按照这种规律我们为后面的每级多增 加numPos*minHitRate,5个正样本. 实际准备的正样本数量应该(读入vec的正样本数) >= numPos + (numStage - 1) * numPos * (1 - minHitRate) 按照此公式计算, numPos+14* numPos * 0.005 = 1.07*numPos ,也就是正样本数量要大于等于 1.07*numPos。 即:numPos:100,正样本数则为 107。 而我们正样本是100,所以numPos应该传:100/1.07=93。 因为实际设置numPos时可以将其设置的稍微再大些,最终的目的是要尽量让所有的正样本都参与到训练中。但是,过大 就会出错。

由于此处我只拿了自己的脸来训练,所以模型只能定位xxx的脸......

采集样本 for (Rect face : faces) { //画矩形 #if 0 //把人脸 重新设置为 24x24大小的图片 resize(m, m, Size(24, 24)); //转成灰度 cvtColor(m, m, COLOR_BGR2GRAY); char p[100]; sprintf(p, "D:/Lance/ndk/lsn27_opencv_face/资料/img/info/%d.jpg",i++); //把mat写出为jpg文件 imwrite(p,m); } LBP

LBP(Local Binary Pattern,局部二值模式)是一种用来描述图像局部纹理特征的算子,具有多分辨率、灰度 尺度不变、旋转不变等特性。主要用于特征提取中的纹理提取。 使用LBP作为人脸检测的特征提取方式具有:计算量小;存储空间小;计算过程简单,没有复杂的除法和特 殊运算,便于硬件实现;检测的时间短,检测的实时性好。

LBP的核心思想就是:以中心像素的灰度值作为阈值,与他的领域相比较得到相对应的二进制码来表示局部纹理特 征。

LBP 核心原理.png 基本LBP

原始的LBP算子定义为在3*3的窗口内,处理83这个像素点的lbp值: 将83与包围83的8个位置进行比较。如果大于83则取值为1,否则为0,然后将这些数据顺时针组合在一起,这样的 到一个01111100,即:0x7C(124)。这就是83位置的lbp值。顺序并无硬性要求,只要在同一处理中保持相同的顺序 即可。提取的LBP算子在每个像素点都可以得到一个LBP值,对一幅图像提取其原始的LBP算子之后,得到的原始 LBP特征依然是“一幅图片”(记录的是每个像素点的LBP值)这种图片称之为lbp图谱。

/** * 原始lbp:应该是3x3的src(先不管3x3) * src: 原图 * dst: 计算出的lbp图谱 * */ void processLBP(Mat src, Mat &dst) { // 循环处理图像数据 for (int i = 1; i < src.rows - 1; i++) { for (int j = 1; j < src.cols - 1; j++) { uchar lbp = 0; uchar center = src.at(i, j); //取出对应 高、宽位置的像素 与 中心点位置进行比较 if (src.at(i - 1, j - 1) > center) { lbp += 1 center) { lbp += 1 center) { lbp += 1 center) { lbp += 1 center) { lbp += 1 center) { lbp += 1 center) { lbp += 1 center) { lbp += 1


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3