Merge pull request #9 from goodspb/master

refresh
This commit is contained in:
Branko Kokanovic 2018-08-30 21:19:36 +02:00 committed by GitHub
commit 54f3b75139
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 489 additions and 32 deletions

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 pdlib contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,16 +1,15 @@
# PDlib - A PHP extension for Dlib
A PHP extension
## Requirements
- Dlib 19.13+
- PHP 7.0+
- C++11
## Dependence
## Dependencies
### Dlib
Install Dlib as share library
Install Dlib as shared library
```bash
git clone git@github.com:davisking/dlib.git
@ -33,23 +32,62 @@ make
sudo make install
```
## Configure
### Configure PHP installation
```
```bash
vim youpath/php.ini
```
Write the below content into `php.ini`
Append the content below into `php.ini`
```
[pdlib]
extension="pdlib.so"
```
## Tests
For tests, you will need to have bz2 extension installed. On Ubuntu, it boils to:
```bash
sudo apt-get install php-bz2
```
After you successfully compiled everything, just run:
```bash
make test
```
## Usage
### General Usage
Good starting point can be `tests/integration_face_recognition.phpt`. Check that first.
Basically, if you just quickly want to get from your image to 128D descriptor of faces in image,
here is really minimal example how:
```php
<?php
$img_path = "image.jpg";
$fd = new CnnFaceDetection("detection_cnn_model.dat");
$detected_faces = $fd->detect($img_path);
foreach($detected_faces as $detected_face) {
$fld = new FaceLandmarkDetection("landmark_model.dat");
$landmarks = $fld->detect($img_path, $detected_face);
$fr = new FaceRecognition("recognition_model.dat");
$descriptor = $fr->computeDescriptor($img_path, $landmarks);
// Optionally use descriptor later in `dlib_chinese_whispers` function
}
```
Location from where to get these models can be found on DLib website, as well as in `tests/integration_face_recognition.phpt` test.
### Specific use cases
#### face detection
If you want to use HOG based approach:
```php
<?php
@ -57,9 +95,19 @@ extension="pdlib.so"
$faceCount = dlib_face_detection("~/a.jpg");
// how mary face in the picture.
var_dump($faceCount);
```
If you want to use CNN approach (and CNN model):
```php
<?php
$fd = new CnnFaceDetection("detection_cnn_model.dat");
$detected_faces = $fd->detect("image.jpg");
// $detected_face is indexed array, where values are assoc arrays with "top", "bottom", "left" and "right" values
```
CNN model can get you slightly better results, but is much, much more demanding (CPU and memory, GPU is also preferred).
#### face landmark detection
```php
@ -68,7 +116,6 @@ var_dump($faceCount);
// face landmark detection
$landmarks = dlib_face_landmark_detection("~/a.jpg");
var_dump($landmarks);
```
Additionally, you can also use class-based approach:
@ -83,6 +130,19 @@ $parts = $fld->detect("path/to/image.jpg", $rect);
Note that, if you use class-based approach, you need to feed bounding box rectangle with values obtained from `dlib_face_detection`. If you use `dlib_face_landmark_detection`, everything is already done for you (and you are using HOG face detection model).
#### face recognition (aka getting face descriptor)
```php
<?php
$fr = new FaceRecognition($model_path);
$landmarks = array(
"rect" => $rect_of_faces_obtained_with_CnnFaceDetection,
"parts" => $parts_obtained_with_FaceLandmarkDetection);
$descriptor = $fr->computeDescriptor($img_path, $landmarks);
// $descriptor is 128D array
```
#### chinese whispers
Provides raw access to dlib's `chinese_whispers` function.
@ -98,13 +158,12 @@ Returned value is also numeric array, containing obtained labels.
// $labels will look like [0,0,1].
$edges = [[0,0], [0,1], [1,1], [2,2]];
$labels = dlib_chinese_whispers($edges);
```
## Features
- [x] 1.Face Detection
- [x] 2.Face Landmark Detection
- [ ] 3.Deep Face Recognition
- [x] 3.Deep Face Recognition
- [x] 4.Deep Learning Face Detection
- [x] 5. Raw chinese_whispers

View File

@ -28,6 +28,7 @@ if test "$PHP_PDLIB" != "no"; then
src/chinese_whispers.cc \
src/face_detection.cc \
src/face_landmark_detection.cc \
src/face_recognition.cc \
src/cnn_face_detection.cc "
AC_MSG_CHECKING(for pkg-config)

View File

@ -30,6 +30,7 @@ extern "C" {
#include "php_pdlib.h"
#include "src/chinese_whispers.h"
#include "src/face_detection.h"
#include "src/face_recognition.h"
#include "src/cnn_face_detection.h"
#include "src/face_landmark_detection.h"
@ -46,6 +47,9 @@ static zend_object_handlers cnn_face_detection_obj_handlers;
static zend_class_entry *face_landmark_detection_ce = nullptr;
static zend_object_handlers face_landmark_detection_obj_handlers;
static zend_class_entry *face_recognition_ce = nullptr;
static zend_object_handlers face_recognition_obj_handlers;
/* {{{ PHP_INI
*/
/* Remove comments and fill if you need to have entries in php.ini
@ -142,6 +146,29 @@ static void php_face_landmark_detection_free(zend_object *object)
zend_object_std_dtor(object);
}
const zend_function_entry face_recognition_class_methods[] = {
PHP_ME(FaceRecognition, __construct, face_recognition_ctor_arginfo, ZEND_ACC_PUBLIC)
PHP_ME(FaceRecognition, computeDescriptor, face_recognition_compute_descriptor_arginfo, ZEND_ACC_PUBLIC)
PHP_FE_END
};
zend_object* php_face_recognition_new(zend_class_entry *class_type TSRMLS_DC)
{
face_recognition *fr = (face_recognition*)ecalloc(1, sizeof(face_recognition));
zend_object_std_init(&fr->std, class_type TSRMLS_CC);
object_properties_init(&fr->std, class_type);
fr->std.handlers = &face_recognition_obj_handlers;
return &fr->std;
}
static void php_face_recognition_free(zend_object *object)
{
face_recognition *fr = (face_recognition*)((char*)object - XtOffsetOf(face_recognition, std));
delete fr->net;
zend_object_std_dtor(object);
}
/* {{{ PHP_MINIT_FUNCTION
*/
PHP_MINIT_FUNCTION(pdlib)
@ -165,6 +192,15 @@ PHP_MINIT_FUNCTION(pdlib)
face_landmark_detection_obj_handlers.offset = XtOffsetOf(face_landmark_detection, std);
face_landmark_detection_obj_handlers.free_obj = php_face_landmark_detection_free;
// FaceRecognition class definition
//
INIT_CLASS_ENTRY(ce, "FaceRecognition", face_recognition_class_methods);
face_recognition_ce = zend_register_internal_class(&ce TSRMLS_CC);
face_recognition_ce->create_object = php_face_recognition_new;
memcpy(&face_recognition_obj_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
face_recognition_obj_handlers.offset = XtOffsetOf(face_recognition, std);
face_recognition_obj_handlers.free_obj = php_face_recognition_free;
/* If you have INI entries, uncomment these lines
REGISTER_INI_ENTRIES();
*/

View File

@ -61,6 +61,22 @@ ZEND_END_MODULE_GLOBALS(pdlib)
ZEND_TSRMLS_CACHE_EXTERN()
#endif
#define PARSE_LONG_FROM_ARRAY(hashtable, key, error_key_missing, error_key_not_long) \
zval* data##key; \
/* Tries to find given key in array */ \
data##key = zend_hash_str_find(hashtable, #key, sizeof(#key)-1); \
if (data##key == nullptr) { \
zend_throw_exception_ex(zend_ce_exception, 0 TSRMLS_CC, #error_key_missing); \
return; \
} \
\
/* We also need to check proper type of value in associative array */ \
if (Z_TYPE_P(data##key) != IS_LONG) { \
zend_throw_exception_ex(zend_ce_exception, 0 TSRMLS_CC, #error_key_not_long); \
return; \
} \
zend_long key = Z_LVAL_P(data##key); \
#endif /* PHP_PDLIB_H */

View File

@ -85,7 +85,7 @@ PHP_METHOD(CnnFaceDetection, detect)
//
for (auto&& d: dets) {
d.rect = pyr.rect_down(d.rect, upsample_num);
// Create new assoc array with dimensions of found rectt and confidence
// Create new assoc array with dimensions of found rect and confidence
//
zval rect_arr;
array_init(&rect_arr);

View File

@ -102,20 +102,8 @@ PHP_METHOD(FaceLandmarkDetection, __construct)
// Helper macro to automatically have parsing of "top"/"bottom"/"left"/"right"
#define PARSE_BOUNDING_BOX_EDGE(side) \
zval* data##side; \
/* Tries to find given key in array */ \
data##side = zend_hash_str_find(bounding_box_hash, #side, sizeof(#side)-1); \
if (data##side == nullptr) { \
zend_throw_exception_ex(zend_ce_exception, 0 TSRMLS_CC, "Bounding box (second argument) is missing " #side "key"); \
return; \
} \
\
/* We also need to check proper type of value in associative array */ \
if (Z_TYPE_P(data##side) != IS_LONG) { \
zend_throw_exception_ex(zend_ce_exception, 0 TSRMLS_CC, "Value of bounding box's (second argument) " #side " key is not long type"); \
return; \
} \
zend_long side = Z_LVAL_P(data##side); \
PARSE_LONG_FROM_ARRAY(bounding_box_hash, side, \
"Bounding box (second argument) is missing " #side "key", "Value of bounding box's (second argument) " #side " key is not long type")
PHP_METHOD(FaceLandmarkDetection, detect)
{
@ -134,8 +122,8 @@ PHP_METHOD(FaceLandmarkDetection, detect)
// Check that bounding box have exactly 4 elements
HashTable *bounding_box_hash = Z_ARRVAL_P(bounding_box);
uint32_t bounding_box_num_elements = zend_hash_num_elements(bounding_box_hash);
if (bounding_box_num_elements != 4) {
zend_throw_exception_ex(zend_ce_exception, 0 TSRMLS_CC, "Bounding box (second argument) needs to have exactly 4 elements");
if (bounding_box_num_elements < 4) {
zend_throw_exception_ex(zend_ce_exception, 0 TSRMLS_CC, "Bounding box (second argument) needs to have at least 4 elements");
return;
}
@ -158,14 +146,28 @@ PHP_METHOD(FaceLandmarkDetection, detect)
// Each key is one part from shape. Value of each part is associative array of keys "x" and "y".
//
array_init(return_value);
zval rect_arr, parts_arr;
array_init(&rect_arr);
array_init(&parts_arr);
for (int i = 0; i < shape.num_parts(); i++) {
zval part;
array_init(&part);
dlib::point p = shape.part(i);
add_assoc_long(&part, "x", p.x());
add_assoc_long(&part, "y", p.y());
add_next_index_zval(return_value, &part);
add_next_index_zval(&parts_arr, &part);
}
const rectangle& r = shape.get_rect();
add_assoc_long(&rect_arr, "left", r.left());
add_assoc_long(&rect_arr, "top", r.top());
add_assoc_long(&rect_arr, "right", r.right());
add_assoc_long(&rect_arr, "bottom", r.bottom());
add_assoc_zval(return_value, "rect", &rect_arr);
add_assoc_zval(return_value, "parts", &parts_arr);
} catch (exception& e) {
zend_throw_exception_ex(zend_ce_exception, 0 TSRMLS_CC, e.what());
return;

189
src/face_recognition.cc Normal file
View File

@ -0,0 +1,189 @@
#include "../php_pdlib.h"
#include "face_recognition.h"
#include <zend_exceptions.h>
#include <dlib/image_io.h>
using namespace std;
using namespace dlib;
static inline face_recognition *php_face_recognition_from_obj(zend_object *obj) {
return (face_recognition*)((char*)(obj) - XtOffsetOf(face_recognition, std));
}
#define Z_FACE_RECOGNITION_P(zv) php_face_recognition_from_obj(Z_OBJ_P((zv)))
PHP_METHOD(FaceRecognition, __construct)
{
char *sz_face_recognition_model_path;
size_t face_recognition_model_path_len;
face_recognition *fr = Z_FACE_RECOGNITION_P(getThis());
if (NULL == fr) {
php_error_docref(NULL TSRMLS_CC, E_ERROR, "Unable to find obj in FaceRecognition::__construct()");
return;
}
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
&sz_face_recognition_model_path, &face_recognition_model_path_len) == FAILURE){
zend_throw_exception_ex(zend_ce_exception, 0 TSRMLS_CC, "Unable to parse face_recognition_model_path");
return;
}
try {
string face_recognition_model_path(sz_face_recognition_model_path, face_recognition_model_path_len);
fr->net = new anet_type;
deserialize(face_recognition_model_path) >> *(fr->net);
} catch (exception& e) {
zend_throw_exception_ex(zend_ce_exception, 0 TSRMLS_CC, e.what());
return;
}
}
std::vector<matrix<rgb_pixel>> pdlib_jitter_image(
const matrix<rgb_pixel>& img,
const int num_jitters,
dlib::rand& rnd) {
std::vector<matrix<rgb_pixel>> crops;
for (int i = 0; i < num_jitters; ++i)
crops.push_back(dlib::jitter_image(img,rnd));
return crops;
}
// Helper macro to automatically have parsing of "top"/"bottom"/"left"/"right"
//
#define PARSE_BOUNDING_BOX_EDGE(side) \
PARSE_LONG_FROM_ARRAY(rect_hash, side, \
"Shape's rect array is missing " #side "key", "Shape's rect array's " #side " key is not long type")
// Helper macro to parse "x"/"y"
//
#define PARSE_POINT(coord) \
PARSE_LONG_FROM_ARRAY(part_hash, coord, \
#coord " coordinate key is missing in parts array", #coord " coordinate key is not of long type")
PHP_METHOD(FaceRecognition, computeDescriptor)
{
char *img_path;
size_t img_path_len;
zval *shape;
long num_jitters = 1;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sa|l", &img_path, &img_path_len, &shape, &num_jitters) == FAILURE){
zend_throw_exception_ex(zend_ce_exception, 0 TSRMLS_CC, "Unable to parse computeDescriptor arguments");
return;
}
HashTable *shape_hash = Z_ARRVAL_P(shape);
uint32_t shape_hash_num_elements = zend_hash_num_elements(shape_hash);
if (shape_hash_num_elements != 2) {
zend_throw_exception_ex(zend_ce_exception, 0 TSRMLS_CC, "Shape (second argument) needs to have exactly 2 elements - keys \"rect\" and \"parts\"");
return;
}
zval *rect_zval = zend_hash_str_find(shape_hash, "rect", sizeof("rect")-1);
if (rect_zval == nullptr) {
zend_throw_exception_ex(zend_ce_exception, 0 TSRMLS_CC, "Shape (second argument) array needs to have \"rect\" key"); \
return;
}
if (Z_TYPE_P(rect_zval) != IS_ARRAY) {
zend_throw_exception_ex(zend_ce_exception, 0 TSRMLS_CC, "Value of shape's key \"rect\" must be array");
return;
}
HashTable *rect_hash = Z_ARRVAL_P(rect_zval);
PARSE_BOUNDING_BOX_EDGE(top)
PARSE_BOUNDING_BOX_EDGE(bottom)
PARSE_BOUNDING_BOX_EDGE(left)
PARSE_BOUNDING_BOX_EDGE(right)
rectangle rect(left, top, right, bottom);
zval *parts_zval = zend_hash_str_find(shape_hash, "parts", sizeof("parts")-1);
if (parts_zval == nullptr) {
zend_throw_exception_ex(zend_ce_exception, 0 TSRMLS_CC, "Shape (second argument) array needs to have \"parts\" key"); \
return;
}
if (Z_TYPE_P(parts_zval) != IS_ARRAY) {
zend_throw_exception_ex(zend_ce_exception, 0 TSRMLS_CC, "Value of shape's key \"parts\" must be array");
return;
}
HashTable *parts_hash = Z_ARRVAL_P(parts_zval);
HashPosition parts_pos;
uint32_t parts_count = zend_hash_num_elements(parts_hash);
point parts_points[parts_count];
if ((parts_count != 5) && (parts_count != 68)) {
zend_throw_exception_ex(zend_ce_exception, 0 TSRMLS_CC,
"The full_object_detection must use the iBUG 300W 68 point face landmark style or dlib's 5 point style");
return;
}
for (zend_hash_internal_pointer_reset_ex(parts_hash, &parts_pos);
zend_hash_has_more_elements_ex(parts_hash, &parts_pos) == SUCCESS;
zend_hash_move_forward_ex(parts_hash, &parts_pos)
) {
zend_string* str_index = {0};
zend_ulong num_index;
zval *part_zval = zend_hash_get_current_data_ex(parts_hash, &parts_pos);
switch (zend_hash_get_current_key_ex(parts_hash, &str_index, &num_index, &parts_pos)) {
case HASH_KEY_IS_LONG:
if (Z_TYPE_P(part_zval) == IS_ARRAY)
{
HashTable *part_hash = Z_ARRVAL_P(part_zval);
PARSE_POINT(x)
PARSE_POINT(y)
if (num_index > parts_count) {
zend_throw_exception_ex(zend_ce_exception, 0 TSRMLS_CC, "Internal error, bad parsing of parts array");
return;
}
parts_points[num_index] = point(x, y);
} else {
zend_throw_exception_ex(zend_ce_exception, 0 TSRMLS_CC, "Values from parts array must be arrays with \"x\" and \"y\" keys");
return;
}
break;
case HASH_KEY_IS_STRING:
zend_throw_exception_ex(zend_ce_exception, 0 TSRMLS_CC, "Parts array must be indexed and it contains string keys");
return;
break;
}
}
std::vector<point> parts;
for (unsigned int i = 0; i < parts_count; i++) {
parts.push_back(parts_points[i]);
}
try {
face_recognition *fr = Z_FACE_RECOGNITION_P(getThis());
full_object_detection fod(rect, parts);
matrix<rgb_pixel> img;
load_image(img, img_path);
std::vector<chip_details> dets;
dets.push_back(get_face_chip_details(fod, 150, 0.25));
dlib::array<matrix<rgb_pixel>> face_chips;
extract_image_chips(img, dets, face_chips);
array_init(return_value);
matrix<float,0,1> face_descriptor;
if (num_jitters <= 1) {
std::vector<matrix<float,0,1>> face_descriptors = fr->net->operator()(face_chips, 16);
face_descriptor = face_descriptors[0];
} else {
matrix<rgb_pixel>& face_chip = face_chips[0];
face_descriptor = mean(mat(fr->net->operator()(pdlib_jitter_image(face_chip, num_jitters, fr->rnd), 16)));
}
for (auto& d : face_descriptor) {
add_next_index_double(return_value, d);
}
} catch (exception& e) {
zend_throw_exception_ex(zend_ce_exception, 0 TSRMLS_CC, e.what());
return;
}
}

58
src/face_recognition.h Normal file
View File

@ -0,0 +1,58 @@
//
// Created by branko at kokanovic dot org on 2018/8/26.
//
#ifndef PHP_DLIB_FACE_RECOGNITION_H
#define PHP_DLIB_FACE_RECOGNITION_H
#include <dlib/dnn.h>
using namespace dlib;
template <template <int,template<typename>class,int,typename> class block, int N, template<typename>class BN, typename SUBNET>
using residual = add_prev1<block<N,BN,1,tag1<SUBNET>>>;
template <template <int,template<typename>class,int,typename> class block, int N, template<typename>class BN, typename SUBNET>
using residual_down = add_prev2<avg_pool<2,2,2,2,skip1<tag2<block<N,BN,2,tag1<SUBNET>>>>>>;
template <int N, template <typename> class BN, int stride, typename SUBNET>
using block = BN<con<N,3,3,1,1,relu<BN<con<N,3,3,stride,stride,SUBNET>>>>>;
template <int N, typename SUBNET> using ares = relu<residual<block,N,affine,SUBNET>>;
template <int N, typename SUBNET> using ares_down = relu<residual_down<block,N,affine,SUBNET>>;
template <typename SUBNET> using alevel0 = ares_down<256,SUBNET>;
template <typename SUBNET> using alevel1 = ares<256,ares<256,ares_down<256,SUBNET>>>;
template <typename SUBNET> using alevel2 = ares<128,ares<128,ares_down<128,SUBNET>>>;
template <typename SUBNET> using alevel3 = ares<64,ares<64,ares<64,ares_down<64,SUBNET>>>>;
template <typename SUBNET> using alevel4 = ares<32,ares<32,ares<32,SUBNET>>>;
using anet_type = loss_metric<fc_no_bias<128,avg_pool_everything<
alevel0<
alevel1<
alevel2<
alevel3<
alevel4<
max_pool<3,3,2,2,relu<affine<con<32,7,7,2,2,
input_rgb_image_sized<150>
>>>>>>>>>>>>;
typedef struct _face_recognition {
anet_type *net;
zend_object std;
dlib::rand rnd;
} face_recognition;
ZEND_BEGIN_ARG_INFO_EX(face_recognition_ctor_arginfo, 0, 0, 1)
ZEND_ARG_INFO(0, face_recognition_model_path)
ZEND_END_ARG_INFO()
PHP_METHOD(FaceRecognition, __construct);
ZEND_BEGIN_ARG_INFO_EX(face_recognition_compute_descriptor_arginfo, 0, 0, 3)
ZEND_ARG_INFO(0, img_path)
ZEND_ARG_INFO(0, landmarks)
ZEND_ARG_INFO(0, num_jitters)
ZEND_END_ARG_INFO()
PHP_METHOD(FaceRecognition, computeDescriptor);
#endif //PHP_DLIB_FACE_RECOGNITION_H

View File

@ -0,0 +1,15 @@
--TEST--
Testing FaceRecognition constructor without arguments
--SKIPIF--
<?php if (!extension_loaded("pdlib")) print "skip"; ?>
--FILE--
<?php
try {
new FaceRecognition();
} catch (Exception $e) {
var_dump($e->getMessage());
}
?>
--EXPECT--
Warning: FaceRecognition::__construct() expects exactly 1 parameter, 0 given in /home/branko/pdlib/tests/face_recognition_ctor_error.php on line 3
string(43) "Unable to parse face_recognition_model_path"

View File

@ -0,0 +1,60 @@
--TEST--
Full test for face recognition - download models, detect faces, landmark detection and face recognition.
--SKIPIF--
<?php if (!extension_loaded("pdlib") || (function_exists("bzopen"))) print "skip"; ?>
--FILE--
<?php
$models = array(
"detection" => array("uri"=>"http://dlib.net/files/mmod_human_face_detector.dat.bz2"),
"prediction" => array("uri"=>"http://dlib.net/files/shape_predictor_5_face_landmarks.dat.bz2"),
"recognition" => array("uri"=>"http://dlib.net/files/dlib_face_recognition_resnet_model_v1.dat.bz2")
);
// Check if there are models in local tmp. Download them if not (lazy caching).
//
foreach ($models as $modelName => $modelBag) {
printf("Processing %s model\n", $modelName);
$bz2_filename = array_values(array_slice(explode("/", $modelBag["uri"]), -1))[0];
$temp_bz2_file = sys_get_temp_dir() . "/" . $bz2_filename;
$dat_filename = array_values(array_slice(explode(".", $bz2_filename), 0))[0] . ".dat";
$temp_dat_file = sys_get_temp_dir() . "/" . $dat_filename;
$models[$modelName]["local_path"] = $temp_dat_file;
if (file_exists($temp_dat_file)) {
continue;
}
file_put_contents($temp_bz2_file, fopen($modelBag["uri"], 'r'));
$bz = bzopen($temp_bz2_file, "r");
$decompressed_file = "";
while (!feof($bz)) {
$decompressed_file .= bzread($bz, 4096);
}
bzclose($bz);
file_put_contents($temp_dat_file, $decompressed_file);
}
printf("Detection\n");
$fd = new CnnFaceDetection($models["detection"]["local_path"]);
$detected_faces = $fd->detect(__DIR__ . "/lenna.jpg");
printf("Faces found = %d\n", count($detected_faces));
foreach($detected_faces as $index => $detected_face) {
printf("Face[%d] in bounding box (left=%d, top=%d, right=%d, bottom=%d)\n", $index,
$detected_face["left"], $detected_face["top"], $detected_face["right"], $detected_face["bottom"]);
$fld = new FaceLandmarkDetection($models["prediction"]["local_path"]);
$landmarks = $fld->detect(__DIR__ . "/lenna.jpg", $detected_face);
printf("Since we used model with 5 shape predictions, we found %d landmark parts\n", count($landmarks["parts"]));
$fr = new FaceRecognition($models["recognition"]["local_path"]);
$descriptor = $fr->computeDescriptor(__DIR__ . "/lenna.jpg", $landmarks);
printf("Descriptor is vector of %d dimensions\n", count($descriptor));
}
?>
--EXPECT--
Processing detection model
Processing prediction model
Processing recognition model
Detection
Faces found = 1
Face[0] in bounding box (left=187, top=186, right=357, bottom=355)
Since we used model with 5 shape predictions, we found 5 landmark parts
Descriptor is vector of 128 dimensions

BIN
tests/lenna.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 460 KiB