/
puploc.go
138 lines (116 loc) · 3.89 KB
/
puploc.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package main
import "C"
import (
"io/ioutil"
"log"
"runtime"
"unsafe"
pigo "github.com/esimov/pigo/core"
)
var (
cascade []byte
puplocCascade []byte
faceClassifier *pigo.Pigo
puplocClassifier *pigo.PuplocCascade
imageParams *pigo.ImageParams
err error
)
func main() {}
//export FindFaces
func FindFaces(pixels []uint8) uintptr {
pointCh := make(chan uintptr)
results := clusterDetection(pixels, 480, 640)
dets := make([][]int, len(results))
for i := 0; i < len(results); i++ {
dets[i] = append(dets[i], results[i].Row, results[i].Col, results[i].Scale, int(results[i].Q), 1)
// left eye
puploc := &pigo.Puploc{
Row: results[i].Row - int(0.085*float32(results[i].Scale)),
Col: results[i].Col - int(0.185*float32(results[i].Scale)),
Scale: float32(results[i].Scale) * 0.4,
Perturbs: 50,
}
det := puplocClassifier.RunDetector(*puploc, *imageParams, 0.0, false)
if det.Row > 0 && det.Col > 0 {
dets[i] = append(dets[i], det.Row, det.Col, int(det.Scale), int(results[i].Q), 0)
}
// right eye
puploc = &pigo.Puploc{
Row: results[i].Row - int(0.085*float32(results[i].Scale)),
Col: results[i].Col + int(0.185*float32(results[i].Scale)),
Scale: float32(results[i].Scale) * 0.4,
Perturbs: 50,
}
det = puplocClassifier.RunDetector(*puploc, *imageParams, 0.0, false)
if det.Row > 0 && det.Col > 0 {
dets[i] = append(dets[i], det.Row, det.Col, int(det.Scale), int(results[i].Q), 0)
}
}
coords := make([]int, 0, len(dets))
go func() {
// Since in Go we cannot transfer a 2d array trough an array pointer
// we have to transform it into 1d array.
for _, v := range dets {
coords = append(coords, v...)
}
// Include as a first slice element the number of detected faces.
// We need to transfer this value in order to define the Python array buffer length.
coords = append([]int{len(dets), 0, 0, 0, 0}, coords...)
// Convert the slice into an array pointer.
s := *(*[]uint8)(unsafe.Pointer(&coords))
p := uintptr(unsafe.Pointer(&s[0]))
// Ensure `det` is not freed up by GC prematurely.
runtime.KeepAlive(coords)
// return the pointer address
pointCh <- p
}()
return <-pointCh
}
// clusterDetection runs Pigo face detector core methods
// and returns a cluster with the detected faces coordinates.
func clusterDetection(pixels []uint8, rows, cols int) []pigo.Detection {
imageParams = &pigo.ImageParams{
Pixels: pixels,
Rows: rows,
Cols: cols,
Dim: cols,
}
cParams := pigo.CascadeParams{
MinSize: 60,
MaxSize: 600,
ShiftFactor: 0.1,
ScaleFactor: 1.1,
ImageParams: *imageParams,
}
// Ensure that the face detection classifier is loaded only once.
if len(cascade) == 0 {
cascade, err = ioutil.ReadFile("../../cascade/facefinder")
if err != nil {
log.Fatalf("Error reading the cascade file: %v", err)
}
p := pigo.NewPigo()
// Unpack the binary file. This will return the number of cascade trees,
// the tree depth, the threshold and the prediction from tree's leaf nodes.
faceClassifier, err = p.Unpack(cascade)
if err != nil {
log.Fatalf("Error unpacking the cascade file: %s", err)
}
}
// Ensure that we load the pupil localization cascade only once
if len(puplocCascade) == 0 {
puplocCascade, err := ioutil.ReadFile("../../cascade/puploc")
if err != nil {
log.Fatalf("Error reading the puploc cascade file: %s", err)
}
puplocClassifier, err = puplocClassifier.UnpackCascade(puplocCascade)
if err != nil {
log.Fatalf("Error unpacking the puploc cascade file: %s", err)
}
}
// Run the classifier over the obtained leaf nodes and return the detection results.
// The result contains quadruplets representing the row, column, scale and detection score.
dets := faceClassifier.RunCascade(cParams, 0.0)
// Calculate the intersection over union (IoU) of two clusters.
dets = faceClassifier.ClusterDetections(dets, 0.0)
return dets
}