-
-
Notifications
You must be signed in to change notification settings - Fork 112
/
Copy pathface.go
125 lines (101 loc) · 2.3 KB
/
face.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
// +build !ci
package gocv
import (
"fmt"
"image"
"os"
"gocv.io/x/gocv"
sclogger "github.com/muesli/smartcrop/logger"
)
type FaceDetector struct {
FaceDetectionHaarCascadeFilepath string
Logger *sclogger.Logger
}
func (d *FaceDetector) Name() string {
return "face"
}
func (d *FaceDetector) Bias() float64 {
return 0.9
}
func (d *FaceDetector) Weight() float64 {
return 1.8
}
func (d *FaceDetector) Detect(img *image.RGBA) ([][]uint8, error) {
res := make([][]uint8, img.Bounds().Dx())
for x := range res {
res[x] = make([]uint8, img.Bounds().Dy())
}
if img == nil {
return res, fmt.Errorf("img can't be nil")
}
if d.FaceDetectionHaarCascadeFilepath == "" {
return res, fmt.Errorf("FaceDetector's FaceDetectionHaarCascadeFilepath not specified")
}
_, err := os.Stat(d.FaceDetectionHaarCascadeFilepath)
if err != nil {
return res, err
}
classifier := gocv.NewCascadeClassifier()
defer classifier.Close()
if !classifier.Load(d.FaceDetectionHaarCascadeFilepath) {
return res, fmt.Errorf("FaceDetector failed loading cascade file")
}
// image.NRGBA-compatible params
cvMat, err := gocv.NewMatFromBytes(img.Rect.Dy(), img.Rect.Dx(), gocv.MatTypeCV8UC4, img.Pix)
defer cvMat.Close()
if err != nil {
return res, err
}
faces := classifier.DetectMultiScale(cvMat)
if d.Logger.DebugMode == true {
d.Logger.Log.Printf("Number of faces detected: %d\n", len(faces))
}
for _, face := range faces {
// Upper left corner of detected face-rectangle
x := face.Min.X
y := face.Min.Y
width := face.Dx()
height := face.Dy()
if d.Logger.DebugMode == true {
d.Logger.Log.Printf("Face: x: %d y: %d w: %d h: %d\n", x, y, width, height)
}
drawAFilledCircle(res, x+(width/2), y+(height/2), width/2)
}
return res, nil
}
func drawAFilledCircle(pix [][]uint8, x0, y0, r int) {
x := r - 1
y := 0
dx := 1
dy := 1
err := dx - (r << 1)
for {
if x < y {
return
}
for i := -x; i <= x; i++ {
putPixel(pix, x0+i, y0+y)
putPixel(pix, x0+i, y0-y)
putPixel(pix, x0+y, y0+i)
putPixel(pix, x0-y, y0+i)
}
if err <= 0 {
y++
err += dy
dy += 2
} else {
x--
dx += 2
err += dx - (r << 1)
}
}
}
func putPixel(pix [][]uint8, x, y int) {
if x >= len(pix) {
return
}
if y >= len(pix[x]) {
return
}
pix[x][y] = uint8(255)
}