#### 1.1 简介

​		OpenCV是一个基于BSD许可开源发行的跨平台计算机视觉库。拥有C++，Python和Java接口，并且支持Windows, Linux, Mac OS, iOS 和 Android系统。实现了图像处理和计算机视觉方面的很多通用算法。

  		**Opencv（Open Source Computer Vision Library）**是一个基于开源发行的跨平台计算机视觉库，它实现了图像处理和计算机视觉方面的很多通用算法，已成为计算机视觉领域最有力的研究工具。在这里我们要区分两个概念：图像处理和计算机视觉的区别：图像处理侧重于“处理”图像--如增强，还原，去噪，分割等等；而计算机视觉重点在于使用计算机来模拟人的视觉，因此模拟才是计算机视觉领域的最终目标。



​		**Opencv由一系列C函数和C++类构成**，拥有包括500多个C函数的跨平台的中高层API。它不依赖与外部库，但需要也可以使用外部库。因为计算机视觉和机器学习密切相关，所以Opencv还提供了MLL（Machine Learning Library）机器学习库，该学习库主要用于统计方面的模式识别和聚类。

Opencv官方主页点击打开链接

Opencv Github主页点击打开链接

首先了解一下Opencv的整体模块架构，在重点学习和突破自己感兴趣的部分，就会有得心应手，一览众山小的学习体验。进入到Opencv安装的目录，本人是在Ubuntu下面的，默认的目录是/usr/local/include，可以看到有opencv和opencv2这两个文件夹。opencv这个文件夹里面包含旧版本的头文件，而opencv2 这个文件夹里面包含新版本的头文件。opencv文件夹下面主要包含下面文件

 



#### 1.2 人脸定位

​		人脸定位是人脸检测、识别等一系列后续功能的基础。比如，美颜相机的贴纸、大眼等功能都需要先定位到人脸才
能进行后续的处理，否则你放大的就不是眼睛，可能是一些什么不可描述的部位了。另外在人脸识别方面，比如支
付宝刷脸支付、张学友演唱会抓逃犯都运用到了人脸定位然后识别的功能。



#### 1.3 训练

> http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/user_guide/ug_traincascade.html

1. 正样本：包含人脸的图片,灰度图。 正样本大小：统一大小并且不能小于负样本 负样本：不包含人脸的图片
2. 负样本大小：无所谓

正、负样本个数比列大约为 1： 3

制作正样本正样本目录为：maniu，内容为100张大小为24x24的人脸
假设目录结构如下：

> /david
>
> ​	 0.jpg
>
> ​	1.jpg
>
> ​	2.jpg

制作david.data文件，文件内容如下：

> **#分别表示 1张人脸 ；人脸从 0,0坐标开始；大小为24x24**
> david /0.jpg 1 0 0 24 24
> **#==================================================================**
> #假设为2个人脸； 则数据为人脸分别为 100,200处的50x50 和 50,30处的25x25为人脸
> david /1.jpg 2 100 200 50 50 50 30 25 25

**david.data文件内容可以使用java 程序来制作**

```
public class GeneateFile{
	public static void main(String[] args) throws Exception{
		FileOutputStream fos = new
		FileOutputStream("C:\Users\Administrator\Desktop\opencv\david.data");
		for(int i =0 ;i<100;i++){
			String content = String.format("david/%d.jpg 1 0 0 24 24\n",i);
			fos.write(content.getBytes());
		}
		fos.close();
	}
}

```





在lance.data目录执行：

> opencv_createsamples.exe 见附录一

```
opencv_createsamples -info lance.data -vec lance.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/0.jpg
> bg/1.jpg

#### 训练

创建一个data 目录，执行：

 

```
opencv_traincascade -data data -vec david.vec -bg bg.txt -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时可以将其设置的稍微再大些，最终的目的是要尽量让所有的正样本都参与到训练中。但是，过大
就会出错。

由于此处我只拿了自己的脸来训练，所以模型只能定位David的脸......





问题

> ​    java.lang.UnsatisfiedLinkError: dlopen failed: library "libc++_shared.so" not found

【特意去NDK官网查了下，默认情况下，NDK 构建系统为Android 系统提供的最小 C++ 运行时库 (system/lib/libstdc++.so) 提供 C++ 标头。此外，它随附您可以在自己的应用中使用或链接的替代 C++ 实现。请使用 APP_STL 选择其中一个。 】
————————————————







　没有看LBP之前觉得它很神秘，看完了之后也就那么回事，不过提出LBP的人确实很伟大！！

　　LBP（Local Binary Pattern，局部二值模式）是一种用来描述图像局部纹理特征的算子；它具有旋转不变性和灰度不变性等显著的优点。它是首先由T. Ojala, M.Pietikäinen, 和D. Harwood 在1994年提出，用于纹理特征提取。而且，提取的特征是图像的局部的纹理特征；

# 1、LBP特征的描述

　　原始的LBP算子定义为在3*3的窗口内，以窗口中心像素为阈值，将相邻的8个像素的灰度值与其进行比较，若周围像素值大于中心像素值，则该像素点的位置被标记为1，否则为0。这样，3*3邻域内的8个点经比较可产生8位二进制数（通常转换为十进制数即LBP码，共256种），即得到该窗口中心像素点的LBP值，并用这个值来反映该区域的纹理信息。如下图所示：
![这里写图片描述](资料.assets/20180130113413656)

## LBP的改进版本：

　　原始的LBP提出后，研究人员不断对其提出了各种改进和优化。

### （1）圆形LBP算子：

　　基本的 LBP 算子的最大缺陷在于它只覆盖了一个固定半径范围内的小区域，这显然不能满足不同尺寸和频率纹理的需要。为了适应不同尺度的纹理特征，并达到灰度和旋转不变性的要求，Ojala 等对 LBP 算子进行了改进，将 3×3 邻域扩展到任意邻域，并用圆形邻域代替了正方形邻域，改进后的 LBP 算子允许在半径为 R 的圆形邻域内有任意多个像素点。从而得到了诸如半径为R的圆形区域内含有P个采样点的LBP算子；
![这里写图片描述](资料.assets/20180130113742101)

### （2）LBP旋转不变模式

　　从 LBP 的定义可以看出，LBP 算子是灰度不变的，但却不是旋转不变的。图像的旋转就会得到不同的 LBP值。
　　Maenpaa等人又将 LBP 算子进行了扩展，提出了具有旋转不变性的 LBP 算子，即不断旋转圆形邻域得到一系列初始定义的 LBP 值，取其最小值作为该邻域的 LBP 值。
　　图 2.5 给出了求取旋转不变的 LBP 的过程示意图，图中算子下方的数字表示该算子对应的 LBP 值，图中所示的 8 种 LBP模式，经过旋转不变的处理，最终得到的具有旋转不变性的 LBP 值为 15。也就是说，图中的 8 种 LBP 模式对应的旋转不变的 LBP 模式都是00001111。
![这里写图片描述](资料.assets/20180130113806268)

### （3）LBP等价模式

　　一个LBP算子可以产生不同的二进制模式，对于半径为R的圆形区域内含有P个采样点的LBP算子将会产生2P2P种模式。很显然，随着邻域集内采样点数的增加，二进制模式的种类是急剧增加的。例如：5×5邻域内20个采样点，有220220＝1,048,576种二进制模式。如此多的二值模式无论对于纹理的提取还是对于纹理的识别、分类及信息的存取都是不利的。同时，过多的模式种类对于纹理的表达是不利的。例如，将LBP算子用于纹理分类或人脸识别时，常采用LBP模式的统计直方图来表达图像的信息，而较多的模式种类将使得数据量过大，且直方图过于稀疏。因此，需要对原始的LBP模式进行降维，使得数据量减少的情况下能最好的代表图像的信息。
　　为了解决二进制模式过多的问题，提高统计性，Ojala提出了采用一种“等价模式”（Uniform Pattern）来对LBP算子的模式种类进行降维。Ojala等认为，在实际图像中，绝大多数LBP模式最多只包含两次从1到0或从0到1的跳变。因此，Ojala将“等价模式”定义为：当某个LBP所对应的循环二进制数从0到1或从1到0最多有两次跳变时，该LBP所对应的二进制就称为一个等价模式类。如00000000（0次跳变），00000111（只含一次从0到1的跳变），10001111（先由1跳到0，再由0跳到1，共两次跳变）都是等价模式类。除等价模式类以外的模式都归为另一类，称为混合模式类，例如10010111（共四次跳变）（这是我的个人理解，不知道对不对）。
　　通过这样的改进，二进制模式的种类大大减少，而不会丢失任何信息。模式数量由原来的2P2P种减少为 P ( P-1)+2种，其中P表示邻域集内的采样点数。对于3×3邻域内8个采样点来说，二进制模式由原始的256种减少为58种，这使得特征向量的维数更少，并且可以减少高频噪声带来的影响。

# 2、LBP特征用于检测的原理

　　显而易见的是，上述提取的LBP算子在每个像素点都可以得到一个LBP“编码”，那么，对一幅图像（记录的是每个像素点的灰度值）提取其原始的LBP算子之后，得到的原始LBP特征依然是“一幅图片”（记录的是每个像素点的LBP值）。
![这里写图片描述](资料.assets/20180130114114113)
　　从上图可以看出LBP对光照具有很强的鲁棒性
　　LBP的应用中，如纹理分类、人脸分析等，一般都不将LBP图谱作为特征向量用于分类识别，而是采用LBP特征谱的统计直方图作为特征向量用于分类识别。
　　因为，从上面的分析我们可以看出，这个“特征”跟位置信息是紧密相关的。直接对两幅图片提取这种“特征”，并进行判别分析的话，会因为“位置没有对准”而产生很大的误差。后来，研究人员发现，可以将一幅图片划分为若干的子区域，对每个子区域内的每个像素点都提取LBP特征，然后，在每个子区域内建立LBP特征的统计直方图。如此一来，每个子区域，就可以用一个统计直方图来进行描述；整个图片就由若干个统计直方图组成；
　　例如：一幅100*100像素大小的图片，划分为10*10=100个子区域（可以通过多种方式来划分区域），每个子区域的大小为10*10像素；在每个子区域内的每个像素点，提取其LBP特征，然后，建立统计直方图；这样，这幅图片就有10*10个子区域，也就有了10*10个统计直方图，利用这10*10个统计直方图，就可以描述这幅图片了。之后，我们利用各种相似性度量函数，就可以判断两幅图像之间的相似性了；

# 3、对LBP特征向量进行提取的步骤

　　（1）首先将检测窗口划分为16×16的小区域（cell）；
　　（2）对于每个cell中的一个像素，将相邻的8个像素的灰度值与其进行比较，若周围像素值大于中心像素值，则该像素点的位置被标记为1，否则为0。这样，3*3邻域内的8个点经比较可产生8位二进制数，即得到该窗口中心像素点的LBP值；
　　（3）然后计算每个cell的直方图，即每个数字（假定是十进制数LBP值）出现的频率；然后对该直方图进行归一化处理。
　　（4）最后将得到的每个cell的统计直方图进行连接成为一个特征向量，也就是整幅图的LBP纹理特征向量；
　　然后便可利用SVM或者其他机器学习算法进行分类了。