/
faces_stats.go
115 lines (87 loc) Β· 2.27 KB
/
faces_stats.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
package photoprism
import (
"github.com/montanaflynn/stats"
"github.com/photoprism/photoprism/internal/query"
)
// Stats shows statistics on face embeddings.
func (w *Faces) Stats() (err error) {
if embeddings, err := query.Embeddings(true, false, 0, 0); err != nil {
return err
} else if samples := len(embeddings); samples == 0 {
log.Infof("faces: found no samples")
} else {
log.Infof("faces: computing distance of %d samples", samples)
distMin := make([]float64, samples)
distMax := make([]float64, samples)
for i := 0; i < samples; i++ {
min := -1.0
max := -1.0
for j := 0; j < samples; j++ {
if i == j {
continue
}
d := embeddings[i].Dist(embeddings[j])
if min < 0 || d < min {
min = d
}
if max < 0 || d > max {
max = d
}
}
distMin[i] = min
distMax[i] = max
}
minMedian, _ := stats.Median(distMin)
minMin, _ := stats.Min(distMin)
minMax, _ := stats.Max(distMin)
log.Infof("faces: min Γ %f < median %f < %f", minMin, minMedian, minMax)
maxMedian, _ := stats.Median(distMax)
maxMin, _ := stats.Min(distMax)
maxMax, _ := stats.Max(distMax)
log.Infof("faces: max Γ %f < median %f < %f", maxMin, maxMedian, maxMax)
}
if faces, err := query.Faces(true, false, false, false); err != nil {
log.Errorf("faces: %s", err)
} else if samples := len(faces); samples > 0 {
log.Infof("faces: computing distance of faces matching to the same person")
dist := make(map[string][]float64)
for i := 0; i < samples; i++ {
f1 := faces[i]
e1 := f1.Embedding()
min := -1.0
max := -1.0
if k, ok := dist[f1.SubjUID]; ok {
min = k[0]
max = k[1]
}
for j := 0; j < samples; j++ {
if i == j {
continue
}
f2 := faces[j]
if f1.SubjUID != f2.SubjUID {
continue
}
d := e1.Dist(f2.Embedding())
if min < 0 || d < min {
min = d
}
if max < 0 || d > max {
max = d
}
}
if max > 0 {
dist[f1.SubjUID] = []float64{min, max}
}
}
if l := len(dist); l == 0 {
log.Infof("faces: analyzed %d clusters, found no matches", samples)
} else {
log.Infof("faces: %d faces match to the same person", l)
}
for subj, d := range dist {
log.Infof("faces: %s Γ min %f, max %f", subj, d[0], d[1])
}
}
return nil
}