compareFaces static method
Compare two face embeddings using Euclidean distance (FaceNet standard) For normalized embeddings, Euclidean distance and cosine similarity are related: Euclidean distance = sqrt(2 * (1 - cosine_similarity))
Implementation
static FaceComparisonResult compareFaces(
Float64List embedding1,
Float64List embedding2,
) {
// Calculate Euclidean distance (standard for FaceNet)
double sumSquared = 0.0;
final len = min(embedding1.length, embedding2.length);
for (int i = 0; i < len; i++) {
final diff = embedding1[i] - embedding2[i];
sumSquared += diff * diff;
}
final euclideanDistance = sqrt(sumSquared);
// For L2-normalized embeddings, convert to cosine similarity
// cosine_similarity = 1 - (euclidean_distance^2 / 2)
// Convert to similarity percentage
// FaceNet thresholds (from original paper and common practice):
// - Euclidean distance < 0.6: same person (typically ~1.1 for 99% accuracy)
// - For normalized embeddings, distance < 1.1 is typically same person
// We use a more conservative threshold
double similarityPercentage;
// Using Euclidean distance for thresholding (more reliable for FaceNet)
// Typical thresholds: 0.6-1.1 for same person
if (euclideanDistance < 0.6) {
// Very high similarity (same person, very confident)
similarityPercentage = 100.0 - (euclideanDistance / 0.6) * 10.0; // 90-100%
} else if (euclideanDistance < 0.8) {
// High similarity (likely same person)
similarityPercentage = 90.0 - ((euclideanDistance - 0.6) / 0.2) * 15.0; // 75-90%
} else if (euclideanDistance < 1.0) {
// Good similarity (probably same person)
similarityPercentage = 75.0 - ((euclideanDistance - 0.8) / 0.2) * 20.0; // 55-75%
} else if (euclideanDistance < 1.1) {
// Moderate similarity (could be same person)
similarityPercentage = 55.0 - ((euclideanDistance - 1.0) / 0.1) * 15.0; // 40-55%
} else {
// Low similarity (likely different person)
// Distance > 1.1 typically means different person
final excess = euclideanDistance - 1.1;
similarityPercentage = max(0.0, 40.0 - (excess * 40.0));
}
// Determine match level
String matchLevel;
bool isMatch;
if (similarityPercentage >= 70) {
matchLevel = 'Strong Match';
isMatch = true;
} else if (similarityPercentage >= 55) {
matchLevel = 'Likely Match';
isMatch = true;
} else if (similarityPercentage >= 40) {
matchLevel = 'Possible Match';
isMatch = false; // Conservative: require higher threshold
} else {
matchLevel = 'No Match';
isMatch = false;
}
return FaceComparisonResult(
distance: euclideanDistance,
similarityPercentage: similarityPercentage,
isMatch: isMatch,
matchLevel: matchLevel,
);
}