Merge pull request #3 from stalker314314/cnn_face_detection
Adding support for cnn face detectorpull/1/head
commit
b17cd7c945
@ -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…
Reference in new issue