85 lines
1.7 KiB
Go
85 lines
1.7 KiB
Go
package entity
|
|
|
|
import (
|
|
"encoding/json"
|
|
"strings"
|
|
|
|
"github.com/montanaflynn/stats"
|
|
"github.com/photoprism/photoprism/pkg/clusters"
|
|
)
|
|
|
|
type Embedding = []float64
|
|
|
|
// Embeddings represents an embedding cluster.
|
|
type Embeddings = []Embedding
|
|
|
|
// EmbeddingsMidpoint returns the embeddings vector midpoint.
|
|
func EmbeddingsMidpoint(embeddings Embeddings) (result Embedding, radius float64, count int) {
|
|
count = len(embeddings)
|
|
|
|
// No embeddings?
|
|
if count == 0 {
|
|
return result, radius, count
|
|
} else if count == 1 {
|
|
return embeddings[0], 0.0, count
|
|
}
|
|
|
|
dim := len(embeddings[0])
|
|
|
|
// No embedding values?
|
|
if dim == 0 {
|
|
return Embedding{}, 0.0, count
|
|
}
|
|
|
|
result = make(Embedding, dim)
|
|
|
|
// The mean of a set of vectors is calculated component-wise.
|
|
for i := 0; i < dim; i++ {
|
|
values := make(stats.Float64Data, count)
|
|
|
|
for j := 0; j < count; j++ {
|
|
values[j] = embeddings[j][i]
|
|
}
|
|
|
|
if m, err := stats.Mean(values); err != nil {
|
|
log.Warnf("embeddings: %s", err)
|
|
} else {
|
|
result[i] = m
|
|
}
|
|
}
|
|
|
|
// Radius is the max embedding distance + 0.01 from result.
|
|
for _, emb := range embeddings {
|
|
if d := clusters.EuclideanDistance(result, emb); d > radius {
|
|
radius = d + 0.01
|
|
}
|
|
}
|
|
|
|
return result, radius, count
|
|
}
|
|
|
|
// UnmarshalEmbeddings parses face embedding JSON.
|
|
func UnmarshalEmbeddings(s string) (result Embeddings) {
|
|
if !strings.HasPrefix(s, "[[") {
|
|
return nil
|
|
}
|
|
|
|
if err := json.Unmarshal([]byte(s), &result); err != nil {
|
|
log.Errorf("faces: %s", err)
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// UnmarshalEmbedding parses a single face embedding JSON.
|
|
func UnmarshalEmbedding(s string) (result Embedding) {
|
|
if !strings.HasPrefix(s, "[") {
|
|
return nil
|
|
}
|
|
|
|
if err := json.Unmarshal([]byte(s), &result); err != nil {
|
|
log.Errorf("faces: %s", err)
|
|
}
|
|
|
|
return result
|
|
}
|