MetaTube / detector /compute.go
henry99a's picture
Clean commit for Hugging Face Spaces without binary files
ca7217f
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
}