现今,「机器学习」发展迅速,并有大量干系的文章,包括那些 Medium 上的博客,同时险些每位开拓职员都开始在事情任务和本地项目中利用机器学习,但是从何处开始以及利用什么方法总是令人困惑的。大多针对初学者的文章供应了一堆文献,在阅读中创造这些文章分开生活,或供应一些「价」的课程等。
常日在新揭橥的文章中描述理解决特定问题的新方法,你可以在 GitHub 上找到文章中方法的实现。由于更普遍利用的编程措辞是:C / C ++、Python 2/3、Lua 和 Matlab,以及框架:Caffe、TensorFlow、Torch。因此在编程措辞和框架上的大量细分选择使得找到你所须要的,并集成到项目中的过程变得更加繁芜。
OpenCV 中添加的一个 DNN 模块以某种办法减少了这些混乱,它使得你可以直策应用一个在基本框架中演习过的模型。我会向你展示如何在 PHP 中利用这个模块。

DNN 模块:https://github.com/opencv/opencv/wiki/ChangeLog#version341
Jeremy Howard(免费的实践课程「machine learning for coders」的创建者)认为现如今在学习机器学习和实际运用之间存在一个很大的界线。
Howard 认为开始学习机器学习一年的编程履历就足够了。我完备赞许他的不雅观点,并且我希望我的文章可以帮助那些对机器学习不熟习,以及还不清楚是否乐意从事机器学习的 PHP 开拓职员降落 OpenCV 的利用门槛,同时我会尽力阐述我花了大量韶光得到的不雅观点,以是你们乃至都不须要很长的韶光就可以理解它。
php-opencv 项目的 logo
我曾考虑利用 SWIG 写一个 php-opencv 模块,并花费了大量韶光在上面,但是并没有取得任何成果。统统都由于我不懂 C / C++ 并且没有为 PHP 7 编写过扩展文件而变得繁芜。不幸的是,网上大多数材料都是基于 PHP 5 而写的 PHP 扩展,因此我不得不一点点网络信息并自己办理问题。
然后,我在 GitHub 上找到了 php-opencv 库,它是一个用于调用 OpenCV 方法的 PHP 7 模块。我花了几个晚上来编译、安装和运行示例。我开始考试测验这个模块的不同功能,但这个库还短缺一些方法,因此我就自己添加了它们并创建了一个 pull request,且该库的作者接管了它们。之后,我添加了更多的功能。
php-opencv:https://github.com/hihozhou/php-opencv
这是图像加载的方法:
$image = cv\imread(“images/faces.jpg”);
比较之下,在 python 下图像加载是这样的:
image = cv2.imread(“images/faces.jpg”)
当在 PHP(以及在 C++中)中读取一张图像时,信息就存储在 Mat 工具(矩阵)中。在 PHP 中,类似的是一个多维数组,但又与多维数组有所不同,该工具可以进行多种快速操作,例如,所有元素同时除以一个数。在 Python 中,当加载图像时,会返回「NumPy」工具。
小心原有的默认操作!
它会发生这样的情形,imread(在 php、c ++ 和 python 中)不因此 RGB 格式加载图像,而是 BGR 格式。因此,在 OpenCV 的示例中,你常常可以看到转换 BGR 到 RGB 的过程,反之亦然。
我第一次考试测验的是这个功能。为此,在 OpenCV 中有一个「CascadeClassifier」类,它可以加载 xml 格式的预演习模型。在找到人脸之前,该类建议将图像转换为黑白格式。
$src = imread(“images/faces.jpg”);
$gray = cvtColor($src, COLOR_BGR2GRAY);
$faceClassifier = new CascadeClassifier();
$faceClassifier->load(‘models/lbpcascades/lbpcascade_frontalface.xml’);
$faceClassifier->detectMultiScale($gray, $faces);
完全测示例代码:
https://github.com/php-opencv/php-opencv-examples/blob/master/detect_face_by_cascade_classifier.php
结果:
从这个示例中可以看出,纵然在僵尸妆容的照片上也可以找到一张人脸。特色点不会滋扰人脸的定位。
人脸识别对付人脸识别,OpenCV 拥有「LBPHFaceRecognizer」类和「train / predict」方法。
如果我们想要知道照片中是谁,首先我们须要利用 train 方法演习模型,它须要两个参数:对付这些图像的一个人脸图像的数组和一个数值标签的数组。然后你可以在测试图像(人脸)上调用 predict 方法并得到相匹配的数值标签。
$faceRecognizer = LBPHFaceRecognizer :: create ();
$faceRecognizer-> train ($myFaces, $myLabels = [1,1,1,1]); // 4 my faces
$faceRecognizer-> update ($angelinaFaces, $angelinaLabels = [2,2,2,2]); // 4 faces of Angelina
$label = $faceRecognizer-> predict ($faceImage, $confidence);
// get label (1 or 2) and confidence
完全的示例代码:
https://github.com/php-opencv/php-opencv-examples/blob/master/recognize_face_by_lbph.php
数据集:
结果:
当我开始调用 LBPHFaceRecognizer 类时,它无法保存/加载/更新演习好的模型。事实上,我的第一个 pull request 添加了这些方法:写入/读取/更新。
人脸标记/特色点当我开始熟习 OpenCV 时,我常常看到一些人的照片,这些照片上的点标记着眼睛、鼻子、嘴唇等。我想自己重复这个实验,但在 OpenCV 的 Python 版本中并没有实现。我花了一个晚上为 PHP 添加了 FacematkLBF 支持并返回一个工具。统统都是大略易行的,我们加载预演习的模型,输入关于人脸的一个数组,然后得到关于每个人的特色点的一个数组。
$facemark = FacemarkLBF::create();
$facemark->loadModel(‘models/opencv-facemark-lbf/lbfmodel.yaml’);
$facemark->fit($image, $faces, $landmarks);
完全的示例代码:
https://github.com/php-opencv/php-opencv-examples/blob/master/detect_facemarks_by_lbf.php
结果:
从这个示例中可以看出,僵尸妆容使得找到人脸上的特色点变得更难。特色点也会滋扰人脸的定位。光照也有影响,在这个实例中,嘴里的异物(草莓、喷鼻香烟等)可能不会有滋扰。
在我第一次拉拽要求之后,我受到了启示同时开始理解 opencv 可以做些什么,有时创造了一篇文章《Deep Learning,now in OpenCV》(OpenCV 中的深度学习)。我急速决定在 php-opencv 中利用预演习模型,这些模型在互联网上有很多。只管后来我花了很多韶光学习如何利用多维矩阵并在不该用 OpenCV 的情形下利用 Caffe / Torch / TensorFlow 模型,但事实证明加载 Caffe 模型并不困难。
Deep Learning,now in OpenCV:https://github.com/opencv/opencv/wiki/ChangeLog#version341
利用 DNN 模型进行人脸检测因此,OpenCV 许可你利用 readNetFromCaffe 函数在 Caffe 中加载预演习模型。它须要两个参数:指向 .prototxt 和 .caffemodel 文件的路径。prototxt 文件中有模型的描述,而在 caffemodel 中有模型演习期间打算的权重。
以下是一个 prototxt 文件开头的示例:
input:“data”
input_shape {
dim: 1
dim: 3
dim: 300
dim: 300
}
这段文件描述了输入一个 1x3x300x300 的 4 维矩阵。在对模型的描述中,常日会解释以这种格式输入的意义是什么,但在大多数情形下,这意味着将输入尺寸为 300x300 的 RGB 图像(3 通道)。
通过利用 imread 函数加载一张 300x300 的 RGB 图像,我们得到一个 300x300x3 的矩阵。
OpenCV 中有一个 blobFromImage 函数能将 300x300x3 的矩阵转换为 1x3x300x300 的格式。
之后,我们可以仅通过利用 setInput 方法将 blob 运用于网络输入并调用 forward 方法,其可以返回终极的结果给我们。
$src = imread(“images/faces.jpg”);
$net = \CV\DNN\readNetFromCaffe(‘models/ssd/res10_300x300_ssd_deploy.prototxt’, ‘models/ssd/res10_300x300_ssd_iter_140000.caffemodel’);
$blob = \CV\DNN\blobFromImage($src, $scalefactor = 1.0, $size = new Size(300, 300), $mean = new Scalar(104, 177, 123), $swapRB = true, $crop = false);
$net->setInput($blob,“”);
$result = $net->forward();
在这个实例中,结果是一个 1×1×200×7 的矩阵,即每张图像有 7 个元素的 200 个数组。在一张有 4 张脸的照片中,网络探求到 200 个候选工具。个中每一个工具的形式为 [,, $confidence, $startX, $startY, $endX, $endY]。元素 $confidence 代表「置信度」,即预测概率有多好,比如 0.75 是好的。之后的元素代表人脸矩形框的坐标。在这个示例中,只有 3 张人脸以超过 50% 的置信度被找到,而剩下的 197 个候选工具的置信度小于 15%。
完全的示例代码:
https://github.com/php-opencv/php-opencv-examples/blob/master/detect_face_by_dnn_ssd.php
结果:
从这个示例中可以看出,神经网络「在额头上「利用时并不总是产生良好的结果。没有找到第四张脸,但是如果将第四张照片单独拿出来并导着迷经网络,人脸就会被找到。
利用神经网络提升图像质量良久之前,我听说过 waifu2x 库,它可以肃清噪声并增加图标/照片的大小。该库利用 lua 编写,在底层利用几种 Torch 中演习好的模型(为了增加图标大小,肃清照片噪声等)。该库的作者将这些模型导出为 Caffe 并帮助我在 OpenCV 中利用它们。因此,一个示例便是在 PHP 中编写的用于增加图标的分辨率。
waifu2x 库:https://github.com/nagadomi/waifu2x
示例的完全代码:
https://github.com/php-opencv/php-opencv-examples/blob/master/upscale_image_x2_by_dnn_waifu2x.php
不该用神经网络放大图片
图像分类在 ImageNet 上演习的 MobileNet 神经网络可以分类图像。总的来说,它可以区分 1000 个种别,这对我来说还不足。
示例的完全代码:
https://github.com/php-opencv/php-opencv-examples/blob/master/classify_image_by_dnn_mobilenet.php
结果: 87% - 埃及猫,4% - 斑猫,2% - 虎猫
Tensorflow 目标检测 API在 COCO 数据集上利用 Tensorflow 演习的 MobileNet SSD(Single Shot MultiBox Detector)网络不仅可以对图像进行分类,还可以返回目标区域,只管只能检测 182 个种别。
示例的完全代码:
ttps://github.com/php-opencv/php-opencv-examples/blob/master/detect_objects_by_dnn_mobilenet.php
原图
语法高亮和代码补全
我还添加了 phpdoc.php 文件到版本库中并作为示例。多亏了它,Phpstorm 突出了函数的语法、类和它们的方法,并且还可以用于代码补全。这个文件不须要包含在你的代码中(否则会涌现缺点),将其放到你的项目中就足够了。就个人而言,它使得我的编程更轻松。这个文件描述了 OpenCV 中的大多数函数,但不是所有,因此欢迎发送拉拽要求。
phpdoc.php:https://github.com/php-opencv/php-opencv-examples/blob/master/phpdoc.php
安装「dnn」模块仅在 OpenCV 3.4 中涌现(对付之前的版本它是在 contrib 中)。
Ubuntu 18.04 最新的 OpenCV 版本是 3.2。从源码搭建 OpenCV 大约须要 半个小时,以是我在 Ubuntu 18.04 下编译了这个包(也适用于 17.10 版本,大小 25 MB),同时为 PHP 7.2(Ubuntu 18.04)和 PHP 7.1(Ubuntu 17.10)(大小 100 KB)编译了 php-opencv 包。注册 ppa:php-opencv,但还没上传完,同时没有创造比在 GitHub 上传包更好的。我还创建了一个在 pecl 中申请一个账户的要求,但几个月都没得到回答。
在 GitHub 上传包:https://github.com/php-opencv/php-opencv-packages
因此现在在 Ubuntu 18.04 下的安装看起来是这样的:
apt update && apt install -y wget && \
wget https://raw.githubusercontent.com/php-opencv/php-opencv-packages/master/opencv_3.4_amd64.deb && dpkg -i opencv_3.4_amd64.deb && rm opencv_3.4_amd64.deb && \
wget https://raw.githubusercontent.com/php-opencv/php-opencv-packages/master/php-opencv_7.2-3.4_amd64.deb && dpkg -i php-opencv_7.2–3.4_amd64.deb && rm php-opencv_7.2–3.4_amd64.deb && \
echo“extension=opencv.so”> /etc/php/7.2/cli/conf.d/opencv.ini
安装这个选项大约须要 1 分钟,所有安装选项在 Ubuntu 上进行:https://github.com/php-opencv/php-opencv-examples/wiki/Installation-on-ubuntu
我同时编译了 168 MB 的 docker 映像。
利用示例
下载:
git clone https://github.com/php-opencv/php-opencv-examples.git && cd php-opencv-examples
运行:
php detect_face_by_dnn_ssd.php
生活不但有面前的苟且还有诗和远方,想要学习PHP的请按照下图所示加群学习。