File size: 1,815 Bytes
ca7217f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
package detector

import (
	"image"

	pigo "github.com/esimov/pigo/core"

	"github.com/metatube-community/metatube-sdk-go/common/cluster"
	"github.com/metatube-community/metatube-sdk-go/detector/internal/position"
)

const (
	// tolerance defines the max distance between
	// two vectors to be considered as the same.
	tolerance = 0.05
)

func computeFaceWeight(face pigo.Detection) float64 {
	// face size (scale) * quality factor.
	return float64(face.Scale) * float64(face.Q)
}

func extractFaceVector(img image.Image, face pigo.Detection) position.Vector {
	var (
		width  = img.Bounds().Dx()
		height = img.Bounds().Dy()
	)
	return position.NewVector(
		position.Position(float64(face.Col)/float64(width)),  // X
		position.Position(float64(face.Row)/float64(height)), // Y
	)
}

func dominantAxisByRatio(img image.Image, ratio float64) int {
	var (
		width  = img.Bounds().Dx()
		height = img.Bounds().Dy()
	)
	if int(float64(height)*ratio) < width {
		return 0 // X
	} else {
		return 1 // Y
	}
}

func clusterFaceVectors(img image.Image, faces []pigo.Detection, dims ...int) []cluster.Group[position.WeightedVector, float64] {
	vecs := make([]position.WeightedVector, len(faces))
	for i, face := range faces {
		vec := extractFaceVector(img, face)
		vecs[i] = position.NewWeightedVector(
			// select vector dimensions:
			// X:(0), Y:(1), XY:(0,1).
			vec.Select(dims...),
			computeFaceWeight(face),
		)
	}
	return cluster.GroupByDistance(vecs, tolerance)
}

func getDominantVector(groups []cluster.Group[position.WeightedVector, float64]) (position.Vector, bool) {
	if len(groups) == 0 {
		return position.Vector{}, false
	}
	// sort weighted vector groups.
	cluster.SortGroupsByWeight(groups)
	// calculate the average vector.
	vec := position.WeightedAverageVector(groups[0].Items)
	return vec, true
}