Face::getBaseDimension()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
rs 9.9332
c 0
b 0
f 0
cc 3
nc 3
nop 1
1
<?php
2
3
namespace Imagecow\Crops;
4
5
use Imagick;
6
use Imagecow\ImageException;
7
8
/**
9
 * This class is adapted from Stig Lindqvist's great Crop library:
10
 * https://github.com/stojg/crop
11
 * Copyright (c) 2013, Stig Lindqvist.
12
 *
13
 * CropFace
14
 *
15
 * This class will try to find the most interesting point in the image by trying to find a face and
16
 * center the crop on that
17
 *
18
 * @todo implement
19
 * @see https://github.com/mauricesvay/php-facedetection/blob/master/FaceDetector.php
20
 */
21
class Face extends Entropy
22
{
23
    const CLASSIFIER_FACE = '/classifier/haarcascade_frontalface_default.xml';
24
    const CLASSIFIER_PROFILE = '/classifier/haarcascade_profileface.xml';
25
26
    /**
27
     * safeZoneList
28
     *
29
     * @var array
30
     * @access protected
31
     */
32
    protected static $safeZoneList = array();
33
34
    /**
35
     * originalImage
36
     *
37
     * @var object
38
     * @access protected
39
     */
40
    protected static $originalImage;
41
42
    /**
43
     * baseDimension
44
     *
45
     * @var array
46
     * @access protected
47
     */
48
    protected static $baseDimension = array();
49
50
    /**
51
     * Returns the x,y values.
52
     *
53
     * @param Imagick $original
54
     * @param int     $targetWidth
55
     * @param int     $targetHeight
56
     *
57
     * @return array
58
     */
59
    public static function getOffsets(Imagick $original, $targetWidth, $targetHeight)
60
    {
61
        static::$originalImage = $original;
62
        static::$baseDimension = [
63
            'width' => $original->getImageWidth(),
64
            'height' => $original->getImageWidth(),
65
        ];
66
67
        return parent::getOffsets($original, $targetWidth, $targetHeight);
68
    }
69
70
    /**
71
     * getBaseDimension
72
     *
73
     * @param string $key width|height
74
     *
75
     * @access protected
76
     *
77
     * @return int
78
     */
79
    protected static function getBaseDimension($key)
80
    {
81
        if (isset(static::$baseDimension)) {
82
            return static::$baseDimension[$key];
83
        } elseif ($key === 'width') {
84
            return static::$originalImage->getImageWidth();
85
        }
86
87
        return static::$originalImage->getImageHeight();
88
    }
89
90
    /**
91
     * getFaceList get faces positions and sizes
92
     *
93
     * @access protected
94
     *
95
     * @return array
96
     */
97
    protected static function getFaceList()
98
    {
99
        if (!function_exists('face_detect')) {
100
            throw new ImageException('PHP Facedetect extension must be installed. See http://www.xarg.org/project/php-facedetect/ for more details');
101
        }
102
103
        $faceList = static::getFaceListFromClassifier(self::CLASSIFIER_FACE);
104
105
        if (!is_array($faceList)) {
106
            $faceList = [];
107
        }
108
109
        $profileList = static::getFaceListFromClassifier(self::CLASSIFIER_PROFILE);
110
111
        if (!is_array($profileList)) {
112
            $profileList = [];
113
        }
114
115
        return array_merge($faceList, $profileList);
116
    }
117
118
    /**
119
     * getFaceListFromClassifier
120
     *
121
     * @param string $classifier
122
     *
123
     * @access protected
124
     *
125
     * @return array
126
     */
127
    protected static function getFaceListFromClassifier($classifier)
128
    {
129
        $file = tmpfile();
130
131
        static::$originalImage->writeImageFile($file);
132
133
        $faceList = face_detect(stream_get_meta_data($file)['uri'], __DIR__.$classifier);
134
135
        fclose($file);
136
137
        return $faceList;
138
    }
139
140
    /**
141
     * getSafeZoneList
142
     *
143
     * @access protected
144
     *
145
     * @return array
146
     */
147
    protected static function getSafeZoneList()
148
    {
149
        // the local key is the current image width-height
150
        $key = static::$originalImage->getImageWidth().'-'.static::$originalImage->getImageHeight();
151
152
        if (isset(static::$safeZoneList[$key])) {
153
            return static::$safeZoneList[$key];
154
        }
155
156
        $faceList = static::getFaceList();
157
158
        // getFaceList works on the main image, so we use a ratio between main/current image
159
        $xRatio = static::getBaseDimension('width') / static::$originalImage->getImageWidth();
160
        $yRatio = static::getBaseDimension('height') / static::$originalImage->getImageHeight();
161
162
        $safeZoneList = array();
163
164
        foreach ($faceList as $face) {
165
            $hw = ceil($face['w'] / 2);
166
            $hh = ceil($face['h'] / 2);
167
168
            $safeZone = array(
169
                'left' => $face['x'] - $hw,
170
                'right' => $face['x'] + $face['w'] + $hw,
171
                'top' => $face['y'] - $hh,
172
                'bottom' => $face['y'] + $face['h'] + $hh
173
            );
174
175
            $safeZoneList[] = array(
176
                'left' => round($safeZone['left'] / $xRatio),
177
                'right' => round($safeZone['right'] / $xRatio),
178
                'top' => round($safeZone['top'] / $yRatio),
179
                'bottom' => round($safeZone['bottom'] / $yRatio),
180
            );
181
        }
182
183
        static::$safeZoneList[$key] = $safeZoneList;
184
185
        return static::$safeZoneList[$key];
186
    }
187
}
188