Merge pull request #3 from stalker314314/cnn_face_detection

Adding support for cnn face detector
pull/1/head
goodspb 6 years ago committed by GitHub
commit b17cd7c945
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

3
.gitignore vendored

@ -15,6 +15,7 @@ config.status
config.sub
configure
configure.ac
configure.in
include
install-sh
libtool
@ -35,4 +36,4 @@ tests/*/*.log
tests/*/*.sh
.idea
cmake-build-debug
cmake-build-debug

@ -75,5 +75,5 @@ var_dump($landmarks);
- [x] 1.Face Detection
- [x] 2.Face Landmark Detection
- [ ] 3.Deep Face Recognition
- [ ] 4.Deep Learning Face Detection
- [x] 4.Deep Learning Face Detection

@ -26,7 +26,8 @@ if test "$PHP_PDLIB" != "no"; then
pdlib_src_files="pdlib.cc \
src/face_detection.cc \
src/face_landmark_detection.cc"
src/face_landmark_detection.cc \
src/cnn_face_detection.cc"
AC_MSG_CHECKING(for pkg-config)
if test ! -f "$PKG_CONFIG"; then
@ -49,4 +50,4 @@ if test "$PHP_PDLIB" != "no"; then
PHP_EVAL_INCLINE($LIBDLIB_CFLAGS)
PHP_NEW_EXTENSION(pdlib, $pdlib_src_files, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1)
fi
fi

@ -29,6 +29,7 @@ extern "C" {
}
#include "php_pdlib.h"
#include "src/face_detection.h"
#include "src/cnn_face_detection.h"
#include "src/face_landmark_detection.h"
/* If you declare any globals in php_pdlib.h uncomment this:
@ -38,6 +39,9 @@ ZEND_DECLARE_MODULE_GLOBALS(pdlib)
/* True global resources - no need for thread safety here */
static int le_pdlib;
static zend_class_entry *cnn_face_detection_ce = nullptr;
static zend_object_handlers cnn_face_detection_obj_handlers;
/* {{{ PHP_INI
*/
/* Remove comments and fill if you need to have entries in php.ini
@ -88,15 +92,47 @@ static void php_pdlib_init_globals(zend_pdlib_globals *pdlib_globals)
*/
/* }}} */
const zend_function_entry cnn_face_detection_class_methods[] = {
PHP_ME(CnnFaceDetection, __construct, cnn_face_detection_ctor_arginfo, ZEND_ACC_PUBLIC)
PHP_ME(CnnFaceDetection, detect, cnn_face_detection_detect_arginfo, ZEND_ACC_PUBLIC)
PHP_FE_END
};
zend_object* php_cnn_face_detection_new(zend_class_entry *class_type TSRMLS_DC)
{
cnn_face_detection *cfd = (cnn_face_detection*)ecalloc(1, sizeof(cnn_face_detection));
zend_object_std_init(&cfd->std, class_type TSRMLS_CC);
object_properties_init(&cfd->std, class_type);
cfd->std.handlers = &cnn_face_detection_obj_handlers; //zend_get_std_object_handlers();
return &cfd->std;
}
static void php_cnn_face_detection_free(zend_object *object)
{
cnn_face_detection *cfd = (cnn_face_detection*)((char*)object - XtOffsetOf(cnn_face_detection, std));
delete cfd->net;
zend_object_std_dtor(object);
}
/* {{{ PHP_MINIT_FUNCTION
*/
PHP_MINIT_FUNCTION(pdlib)
{
zend_class_entry ce;
INIT_CLASS_ENTRY(ce, "CnnFaceDetection", cnn_face_detection_class_methods);
cnn_face_detection_ce = zend_register_internal_class(&ce TSRMLS_CC);
cnn_face_detection_ce->create_object = php_cnn_face_detection_new;
memcpy(&cnn_face_detection_obj_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
cnn_face_detection_obj_handlers.offset = XtOffsetOf(cnn_face_detection, std);
cnn_face_detection_obj_handlers.free_obj = php_cnn_face_detection_free;
/* If you have INI entries, uncomment these lines
REGISTER_INI_ENTRIES();
*/
return SUCCESS;
}
/* }}} */
/* {{{ PHP_MSHUTDOWN_FUNCTION

@ -0,0 +1,108 @@
#include "../php_pdlib.h"
#include "cnn_face_detection.h"
#include <zend_exceptions.h>
#include <dlib/image_processing/frontal_face_detector.h>
#include <dlib/gui_widgets.h>
#include <dlib/image_io.h>
#include <dlib/dnn.h>
#include <iostream>
using namespace dlib;
using namespace std;
static inline cnn_face_detection *php_cnn_face_detection_from_obj(zend_object *obj) {
return (cnn_face_detection*)((char*)(obj) - XtOffsetOf(cnn_face_detection, std));
}
#define Z_CNN_FACE_DETECTION_P(zv) php_cnn_face_detection_from_obj(Z_OBJ_P((zv)))
PHP_METHOD(CnnFaceDetection, __construct)
{
char *sz_cnn_face_detection_model_path;
size_t cnn_face_detection_model_path_len;
cnn_face_detection *cfd = Z_CNN_FACE_DETECTION_P(getThis());
if (NULL == cfd) {
php_error_docref(NULL TSRMLS_CC, E_ERROR, "Unable to find obj in CnnFaceDetection::__construct()");
return;
}
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
&sz_cnn_face_detection_model_path, &cnn_face_detection_model_path_len) == FAILURE){
zend_throw_exception_ex(zend_ce_exception, 0 TSRMLS_CC, "Unable to parse face_detection_model_path");
return;
}
try {
string cnn_face_detection_model_path(
sz_cnn_face_detection_model_path, cnn_face_detection_model_path_len);
net_type *pnet = new net_type;
deserialize(cnn_face_detection_model_path) >> *pnet;
cfd->net = pnet;
} catch (exception& e) {
zend_throw_exception_ex(zend_ce_exception, 0 TSRMLS_CC, e.what());
return;
}
}
PHP_METHOD(CnnFaceDetection, detect)
{
char *img_path;
size_t img_path_len;
long upsample_num = 1;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &img_path, &img_path_len, &upsample_num) == FAILURE){
zend_throw_exception_ex(zend_ce_exception, 0 TSRMLS_CC, "Unable to parse detect arguments");
RETURN_FALSE;
}
try {
cnn_face_detection *cfd = Z_CNN_FACE_DETECTION_P(getThis());
pyramid_down<2> pyr;
matrix<rgb_pixel> img;
load_image(img, img_path);
// Upsampling the image will allow us to detect smaller faces but will cause the
// program to use more RAM and run longer.
//
unsigned int levels = upsample_num;
while (levels > 0)
{
levels--;
pyramid_up(img, pyr);
}
net_type *pnet = cfd->net;
auto dets = (*pnet)(img);
int rect_count = 0;
array_init(return_value);
// Scale the detection locations back to the original image size
// if the image was upscaled.
//
for (auto&& d: dets) {
d.rect = pyr.rect_down(d.rect, upsample_num);
// Create new assoc array with dimensions of found rectt and confidence
//
zval rect_arr;
array_init(&rect_arr);
add_assoc_long(&rect_arr, "left", d.rect.left());
add_assoc_long(&rect_arr, "top", d.rect.top());
add_assoc_long(&rect_arr, "right", d.rect.right());
add_assoc_long(&rect_arr, "bottom", d.rect.bottom());
add_assoc_double(&rect_arr, "detection_confidence", d.detection_confidence);
// Add this assoc array to returned array
//
add_next_index_zval(return_value, &rect_arr);
}
}
catch (exception& e)
{
zend_throw_exception_ex(zend_ce_exception, 0 TSRMLS_CC, e.what());
return;
}
}

@ -0,0 +1,36 @@
//
// Created by branko at kokanovic dot org on 2018/7/16.
//
#ifndef PHP_DLIB_CNN_FACE_DETECTION_H
#define PHP_DLIB_CNN_FACE_DETECTION_H
#include <dlib/dnn.h>
using namespace dlib;
template <long num_filters, typename SUBNET> using con5d = con<num_filters,5,5,2,2,SUBNET>;
template <long num_filters, typename SUBNET> using con5 = con<num_filters,5,5,1,1,SUBNET>;
template <typename SUBNET> using downsampler = relu<affine<con5d<32, relu<affine<con5d<32, relu<affine<con5d<16,SUBNET>>>>>>>>>;
template <typename SUBNET> using rcon5 = relu<affine<con5<45,SUBNET>>>;
using net_type = loss_mmod<con<1,9,9,1,1,rcon5<rcon5<rcon5<downsampler<input_rgb_image_pyramid<pyramid_down<6>>>>>>>>;
typedef struct _cnn_face_detection {
net_type *net;
zend_object std;
} cnn_face_detection;
ZEND_BEGIN_ARG_INFO_EX(cnn_face_detection_ctor_arginfo, 0, 0, 1)
ZEND_ARG_INFO(0, cnn_face_detection_model_path)
ZEND_END_ARG_INFO()
PHP_METHOD(CnnFaceDetection, __construct);
ZEND_BEGIN_ARG_INFO_EX(cnn_face_detection_detect_arginfo, 0, 0, 2)
ZEND_ARG_INFO(0, img_path)
ZEND_ARG_INFO(0, upsample_num)
ZEND_END_ARG_INFO()
PHP_METHOD(CnnFaceDetection, detect);
#endif //PHP_DLIB_CNN_FACE_DETECTION_H

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

@ -0,0 +1,14 @@
--TEST--
Testing CnnFaceDetection constructor with model that do not exist
--SKIPIF--
<?php if (!extension_loaded("pdlib")) print "skip"; ?>
--FILE--
<?php
try {
new CnnFaceDetection("foo");
} catch (Exception $e) {
var_dump($e->getMessage());
}
?>
--EXPECT--
string(31) "Unable to open foo for reading."
Loading…
Cancel
Save