2021-08-13 20:31:41 +02:00
|
|
|
package entity
|
|
|
|
|
|
|
|
import (
|
2021-08-26 11:58:52 +02:00
|
|
|
"testing"
|
2021-08-28 13:55:37 +02:00
|
|
|
|
2021-09-30 13:44:23 +02:00
|
|
|
"github.com/photoprism/photoprism/internal/face"
|
|
|
|
|
2021-08-28 13:55:37 +02:00
|
|
|
"github.com/stretchr/testify/assert"
|
2021-08-13 20:31:41 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestFace_TableName(t *testing.T) {
|
|
|
|
m := &Face{}
|
|
|
|
assert.Contains(t, m.TableName(), "faces")
|
|
|
|
}
|
2021-08-21 16:36:00 +02:00
|
|
|
|
|
|
|
func TestFace_Match(t *testing.T) {
|
|
|
|
t.Run("1000003-4", func(t *testing.T) {
|
|
|
|
m := FaceFixtures.Get("joe-biden")
|
|
|
|
match, dist := m.Match(MarkerFixtures.Pointer("1000003-4").Embeddings())
|
|
|
|
|
|
|
|
assert.True(t, match)
|
|
|
|
assert.Greater(t, dist, 1.31)
|
|
|
|
assert.Less(t, dist, 1.32)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("1000003-6", func(t *testing.T) {
|
|
|
|
m := FaceFixtures.Get("joe-biden")
|
|
|
|
match, dist := m.Match(MarkerFixtures.Pointer("1000003-6").Embeddings())
|
|
|
|
|
|
|
|
assert.True(t, match)
|
|
|
|
assert.Greater(t, dist, 1.27)
|
|
|
|
assert.Less(t, dist, 1.28)
|
|
|
|
})
|
2021-08-26 11:58:52 +02:00
|
|
|
|
|
|
|
t.Run("len(embeddings) == 0", func(t *testing.T) {
|
|
|
|
m := FaceFixtures.Get("joe-biden")
|
2021-09-30 13:44:23 +02:00
|
|
|
match, dist := m.Match(face.Embeddings{})
|
2021-08-26 11:58:52 +02:00
|
|
|
|
|
|
|
assert.False(t, match)
|
|
|
|
assert.Equal(t, dist, float64(-1))
|
|
|
|
})
|
|
|
|
t.Run("len(efacEmbeddings) == 0", func(t *testing.T) {
|
2021-09-30 13:44:23 +02:00
|
|
|
m := NewFace("12345", SrcAuto, face.Embeddings{})
|
2021-08-26 11:58:52 +02:00
|
|
|
match, dist := m.Match(MarkerFixtures.Pointer("1000003-6").Embeddings())
|
|
|
|
|
|
|
|
assert.False(t, match)
|
|
|
|
assert.Equal(t, dist, float64(-1))
|
|
|
|
})
|
|
|
|
t.Run("jane doe- no match", func(t *testing.T) {
|
|
|
|
m := FaceFixtures.Get("jane-doe")
|
|
|
|
match, _ := m.Match(MarkerFixtures.Pointer("1000003-5").Embeddings())
|
|
|
|
|
|
|
|
assert.False(t, match)
|
|
|
|
})
|
2021-08-21 16:36:00 +02:00
|
|
|
}
|
|
|
|
|
2021-09-01 12:48:17 +02:00
|
|
|
func TestFace_ResolveCollision(t *testing.T) {
|
2021-08-26 15:51:21 +02:00
|
|
|
t.Run("collision", func(t *testing.T) {
|
|
|
|
m := FaceFixtures.Get("joe-biden")
|
2021-08-21 16:36:00 +02:00
|
|
|
|
2021-08-26 15:51:21 +02:00
|
|
|
assert.Zero(t, m.Collisions)
|
|
|
|
assert.Zero(t, m.CollisionRadius)
|
2021-08-21 16:36:00 +02:00
|
|
|
|
2021-09-01 12:48:17 +02:00
|
|
|
if reported, err := m.ResolveCollision(MarkerFixtures.Pointer("1000003-4").Embeddings()); err != nil {
|
2021-08-26 15:51:21 +02:00
|
|
|
t.Fatal(err)
|
|
|
|
} else {
|
|
|
|
assert.True(t, reported)
|
|
|
|
}
|
2021-08-21 16:36:00 +02:00
|
|
|
|
2021-08-26 15:51:21 +02:00
|
|
|
// Number of collisions must have increased by one.
|
|
|
|
assert.Equal(t, 1, m.Collisions)
|
2021-08-21 16:36:00 +02:00
|
|
|
|
2021-08-26 15:51:21 +02:00
|
|
|
// Actual distance is ~1.314040
|
|
|
|
assert.Greater(t, m.CollisionRadius, 1.2)
|
|
|
|
assert.Less(t, m.CollisionRadius, 1.314)
|
2021-08-21 16:36:00 +02:00
|
|
|
|
2021-09-01 12:48:17 +02:00
|
|
|
if reported, err := m.ResolveCollision(MarkerFixtures.Pointer("1000003-6").Embeddings()); err != nil {
|
2021-08-26 15:51:21 +02:00
|
|
|
t.Fatal(err)
|
|
|
|
} else {
|
2021-09-01 12:48:17 +02:00
|
|
|
assert.True(t, reported)
|
2021-08-26 15:51:21 +02:00
|
|
|
}
|
2021-08-21 16:36:00 +02:00
|
|
|
|
2021-08-26 15:51:21 +02:00
|
|
|
// Number of collisions must not have increased.
|
2021-09-01 12:48:17 +02:00
|
|
|
assert.Equal(t, 2, m.Collisions)
|
2021-08-21 16:36:00 +02:00
|
|
|
|
2021-08-26 15:51:21 +02:00
|
|
|
// Actual distance is ~1.272604
|
|
|
|
assert.Greater(t, m.CollisionRadius, 1.1)
|
|
|
|
assert.Less(t, m.CollisionRadius, 1.272)
|
|
|
|
})
|
|
|
|
t.Run("subject id empty", func(t *testing.T) {
|
2021-09-30 13:44:23 +02:00
|
|
|
m := NewFace("", SrcAuto, face.Embeddings{})
|
2021-09-01 12:48:17 +02:00
|
|
|
if reported, err := m.ResolveCollision(MarkerFixtures.Pointer("1000003-4").Embeddings()); err != nil {
|
2021-08-26 15:51:21 +02:00
|
|
|
t.Fatal(err)
|
|
|
|
} else {
|
|
|
|
assert.False(t, reported)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
t.Run("invalid face id", func(t *testing.T) {
|
2021-09-30 13:44:23 +02:00
|
|
|
m := NewFace("123", SrcAuto, face.Embeddings{})
|
2021-08-26 15:51:21 +02:00
|
|
|
m.ID = ""
|
2021-09-01 12:48:17 +02:00
|
|
|
if reported, err := m.ResolveCollision(MarkerFixtures.Pointer("1000003-4").Embeddings()); err == nil {
|
2021-08-26 15:51:21 +02:00
|
|
|
t.Fatal(err)
|
|
|
|
} else {
|
|
|
|
assert.False(t, reported)
|
|
|
|
assert.Equal(t, "invalid face id", err.Error())
|
|
|
|
}
|
|
|
|
})
|
2021-08-26 16:00:11 +02:00
|
|
|
t.Run("embedding empty", func(t *testing.T) {
|
2021-09-30 13:44:23 +02:00
|
|
|
m := NewFace("123", SrcAuto, face.Embeddings{})
|
2021-08-26 16:00:11 +02:00
|
|
|
m.EmbeddingJSON = []byte("")
|
2021-09-01 12:48:17 +02:00
|
|
|
if reported, err := m.ResolveCollision(MarkerFixtures.Pointer("1000003-4").Embeddings()); err == nil {
|
2021-08-26 16:00:11 +02:00
|
|
|
t.Fatal(err)
|
|
|
|
} else {
|
|
|
|
assert.False(t, reported)
|
|
|
|
assert.Equal(t, "embedding must not be empty", err.Error())
|
|
|
|
}
|
|
|
|
})
|
2021-08-21 16:36:00 +02:00
|
|
|
}
|
2021-08-22 21:06:44 +02:00
|
|
|
|
|
|
|
func TestFace_ReviseMatches(t *testing.T) {
|
|
|
|
m := FaceFixtures.Get("joe-biden")
|
|
|
|
removed, err := m.ReviseMatches()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
assert.Empty(t, removed)
|
|
|
|
}
|
2021-08-26 11:58:52 +02:00
|
|
|
|
|
|
|
func TestNewFace(t *testing.T) {
|
|
|
|
t.Run("success", func(t *testing.T) {
|
|
|
|
marker := MarkerFixtures.Get("1000003-4")
|
|
|
|
e := marker.Embeddings()
|
|
|
|
|
|
|
|
r := NewFace("123", SrcAuto, e)
|
|
|
|
assert.Equal(t, "", r.FaceSrc)
|
2021-09-17 14:26:12 +02:00
|
|
|
assert.Equal(t, "123", r.SubjUID)
|
2021-08-26 11:58:52 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-10-07 09:32:17 +02:00
|
|
|
func TestFace_Unsuitable(t *testing.T) {
|
|
|
|
t.Run("True", func(t *testing.T) {
|
|
|
|
m := FaceFixtures.Get("joe-biden")
|
|
|
|
assert.False(t, m.Unsuitable())
|
|
|
|
})
|
|
|
|
t.Run("False", func(t *testing.T) {
|
|
|
|
m := NewFace("", SrcImage, face.Embeddings{{-0.00959064718335867, 0.03787063807249069, -0.0030881548300385475, 0.02789853885769844, 0.017454572021961212, 0.0396987721323967, -0.03091704286634922, 0.005318029318004847, 0.021617550402879715, -0.08214963972568512, -0.003952134400606155, 0.0269720908254385, 0.048880551010370255, -0.03537372127175331, -0.042236171662807465, 0.021553633734583855, 0.03937383368611336, 0.01815507560968399, 0.08373168110847473, -0.11838400363922119, -0.038254253566265106, -0.04993032291531563, 0.07148619741201401, 0.006384310312569141, 0.05344310402870178, -0.027579499408602715, 0.021648988127708435, -0.07013172656297684, -0.06400937587022781, 0.10622639954090118, -0.01507984846830368, -0.02844894863665104, -0.013048898428678513, -0.03571505844593048, -0.022063886746764183, 0.022826166823506355, 0.01703103445470333, 0.00679031852632761, -0.09583312273025513, 0.03446732088923454, -0.045221585780382156, 0.03292521834373474, -0.012820744886994362, 0.06122862547636032, 0.01973198726773262, -0.013975882902741432, 0.027514882385730743, 0.12478502094745636, -0.09630053490400314, -0.008597812615334988, -0.019534612074494362, 0.03927983343601227, 0.04311678186058998, 0.025297729298472404, -0.035719674080610275, 0.05421024188399315, 0.07541341334581375, 0.040334682911634445, -0.0632546916604042, -0.004164006095379591, 0.027950556948781013, 0.017827920615673065, 0.02774866297841072, -0.025094853714108467, 0.00012262807285878807, 0.04165732488036156, -0.03155842795968056, 0.03801475837826729, 0.0031508952379226685, -0.011753040365874767, 0.06262513995170593, 0.05895991623401642, -0.02384188584983349, -0.025149181485176086, -0.016906173899769783, -0.03138834610581398, -0.06759334355592728, 0.018074069172143936, 0.028748946264386177, 0.03350280225276947, 0.001738330232910812, -0.035873714834451675, 0.0050230612978339195, -0.005394259933382273, -0.035111431032419205, 0.005703517701476812, -0.060869812965393066, 0.044046416878700256, 0.05451945215463638, -0.0012109529925510287, 0.04929054155945778, 0.03312966600060463, -0.02503111958503723, -0.0699458047747612, 0.09152142703533173, -0.035196661949157715, -0.02000804804265499, 0.003603762947022915, -0.0549810416996479, 0.041149843484163284, 0.019640415906906128, -0.06913350522518158, -0.08494774252176285, 0.047828249633312225, 0.011485084891319275, 0.11441357433795929, 0.012079037725925446, 0.026444999501109123, 0.008605830371379852, -0.014796323142945766, 0.042191699147224426, 0.0360623262822628, -0.01067506056278944, -0.02117612026631832, -0.0003311904729343951, 0.020912105217576027, 0.02051572874188423, 0.04119933396577835, 0.011461400426924229, 0.02468070574104786, -0.030830683186650276, -0.024522947147488594, 0.07760800421237946, -0.044838037341833115, 0.007875975221395493, 0.03662760183215141, -0.031315844506025314, 0.028968002647161484, -0.007360775955021381, -0.052097514271736145, 0.004892056342214346, 0.0051552411168813705, 0.058972474187612534, -0.05307154729962349, -0.02330617979168892, 0.0560041144490242, -0.06173492223024368, 0.00004632262425730005, 0.007912986911833286, 0.0031768144108355045, -0.08211413770914078, -0.02641596458852291, -0.07240095734596252, -0.04998013749718666, 0.016048355028033257, -0.023686233907938004, 0.08416120707988739, 0.002466161735355854, 0.0017551603959873319, 0.000651281327009201, 0.018105899915099144, -0.05974912270903587, -0.03980677202343941, 0.019075721502304077, 0.0014616637490689754, 0.06682229787111282, 0.02257758192718029, 0.04021807014942169, 0.09144134074449539, 0.020396307110786438, 0.055604636669158936, 0.026022544130682945, -0.03050902672111988, 0.011569516733288765, -0.014519683085381985, 0.0038184933364391327, -0.03115340694785118, 0.029596896842122078, -0.055038318037986755, -0.005584381986409426, -0.015937503427267075, -0.01591162569820881, 0.034234486520290375, 0.010233158245682716, 0.0364360548555851, 0.02957785315811634, 0.038372594863176346, -0.04782934859395027, -0.03462134674191475, -0.0432763509452343, -0.041607096791267395, 0.019871780648827553, -0.026665959507226944, 0.046689242124557495, 0.0
|
|
|
|
assert.True(t, m.Unsuitable())
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-08-26 11:58:52 +02:00
|
|
|
func TestFace_SetEmbeddings(t *testing.T) {
|
|
|
|
t.Run("success", func(t *testing.T) {
|
|
|
|
marker := MarkerFixtures.Get("1000003-4")
|
|
|
|
e := marker.Embeddings()
|
2021-08-26 15:51:21 +02:00
|
|
|
m := FaceFixtures.Get("joe-biden")
|
|
|
|
assert.NotEqual(t, e[0][0], m.Embedding()[0])
|
2021-08-26 11:58:52 +02:00
|
|
|
|
2021-08-26 15:51:21 +02:00
|
|
|
err := m.SetEmbeddings(e)
|
2021-08-26 11:58:52 +02:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2021-08-26 15:51:21 +02:00
|
|
|
assert.Equal(t, e[0][0], m.Embedding()[0])
|
2021-08-26 11:58:52 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestFace_Embedding(t *testing.T) {
|
|
|
|
t.Run("success", func(t *testing.T) {
|
2021-08-26 15:51:21 +02:00
|
|
|
m := FaceFixtures.Get("joe-biden")
|
2021-08-26 11:58:52 +02:00
|
|
|
|
2021-08-26 15:51:21 +02:00
|
|
|
assert.Equal(t, 0.10730543085474682, m.Embedding()[0])
|
2021-08-26 11:58:52 +02:00
|
|
|
})
|
|
|
|
t.Run("empty embedding", func(t *testing.T) {
|
2021-09-30 13:44:23 +02:00
|
|
|
m := NewFace("12345", SrcAuto, face.Embeddings{})
|
2021-08-26 15:51:21 +02:00
|
|
|
m.EmbeddingJSON = []byte("")
|
2021-08-26 11:58:52 +02:00
|
|
|
|
2021-08-26 15:51:21 +02:00
|
|
|
assert.Empty(t, m.Embedding())
|
2021-08-26 11:58:52 +02:00
|
|
|
})
|
|
|
|
t.Run("invalid embedding json", func(t *testing.T) {
|
2021-09-30 13:44:23 +02:00
|
|
|
m := NewFace("12345", SrcAuto, face.Embeddings{})
|
2021-08-26 15:51:21 +02:00
|
|
|
m.EmbeddingJSON = []byte("[false]")
|
2021-08-26 11:58:52 +02:00
|
|
|
|
2021-08-26 15:51:21 +02:00
|
|
|
assert.Equal(t, float64(0), m.Embedding()[0])
|
2021-08-26 11:58:52 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestFace_UpdateMatchTime(t *testing.T) {
|
2021-09-30 13:44:23 +02:00
|
|
|
m := NewFace("12345", SrcAuto, face.Embeddings{})
|
2021-08-26 15:51:21 +02:00
|
|
|
initialMatchTime := m.MatchedAt
|
|
|
|
assert.Equal(t, initialMatchTime, m.MatchedAt)
|
2021-08-29 13:26:05 +02:00
|
|
|
m.Matched()
|
2021-08-26 15:51:21 +02:00
|
|
|
assert.NotEqual(t, initialMatchTime, m.MatchedAt)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestFace_Save(t *testing.T) {
|
2021-09-30 13:44:23 +02:00
|
|
|
m := NewFace("12345fde", SrcAuto, face.Embeddings{face.Embedding{1}, face.Embedding{2}})
|
2021-08-26 15:51:21 +02:00
|
|
|
assert.Nil(t, FindFace(m.ID))
|
|
|
|
m.Save()
|
|
|
|
assert.NotNil(t, FindFace(m.ID))
|
2021-09-17 14:26:12 +02:00
|
|
|
assert.Equal(t, "12345fde", FindFace(m.ID).SubjUID)
|
2021-08-26 15:51:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestFace_Update(t *testing.T) {
|
2021-09-30 13:44:23 +02:00
|
|
|
m := NewFace("12345fdef", SrcAuto, face.Embeddings{face.Embedding{8}, face.Embedding{16}})
|
2021-08-26 15:51:21 +02:00
|
|
|
assert.Nil(t, FindFace(m.ID))
|
|
|
|
m.Save()
|
|
|
|
assert.NotNil(t, FindFace(m.ID))
|
2021-09-17 14:26:12 +02:00
|
|
|
assert.Equal(t, "12345fdef", FindFace(m.ID).SubjUID)
|
2021-08-26 15:51:21 +02:00
|
|
|
|
|
|
|
m2 := FindFace(m.ID)
|
2021-09-17 14:26:12 +02:00
|
|
|
m2.Update("SubjUID", "new")
|
|
|
|
assert.Equal(t, "new", FindFace(m.ID).SubjUID)
|
2021-08-26 15:51:21 +02:00
|
|
|
}
|
|
|
|
|
2021-09-06 00:52:10 +02:00
|
|
|
func TestFace_RefreshPhotos(t *testing.T) {
|
|
|
|
f := FaceFixtures.Get("joe-biden")
|
|
|
|
|
|
|
|
if err := f.RefreshPhotos(); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-26 15:51:21 +02:00
|
|
|
func TestFirstOrCreateFace(t *testing.T) {
|
|
|
|
t.Run("create new face", func(t *testing.T) {
|
2021-09-30 13:44:23 +02:00
|
|
|
m := NewFace("12345unique", SrcAuto, face.Embeddings{face.Embedding{99}, face.Embedding{2}})
|
2021-08-26 15:51:21 +02:00
|
|
|
r := FirstOrCreateFace(m)
|
2021-09-17 14:26:12 +02:00
|
|
|
assert.Equal(t, "12345unique", r.SubjUID)
|
2021-08-26 15:51:21 +02:00
|
|
|
})
|
|
|
|
t.Run("return existing entity", func(t *testing.T) {
|
|
|
|
m := FaceFixtures.Pointer("joe-biden")
|
|
|
|
r := FirstOrCreateFace(m)
|
2021-09-17 14:26:12 +02:00
|
|
|
assert.Equal(t, "jqy3y652h8njw0sx", r.SubjUID)
|
2021-08-26 15:51:21 +02:00
|
|
|
assert.Equal(t, 33, r.Samples)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestFindFace(t *testing.T) {
|
|
|
|
t.Run("existing face", func(t *testing.T) {
|
2021-09-01 14:05:15 +02:00
|
|
|
assert.NotNil(t, FindFace("VF7ANLDET2BKZNT4VQWJMMC6HBEFDOG7"))
|
2021-08-26 15:51:21 +02:00
|
|
|
assert.Equal(t, 3, FindFace("VF7ANLDET2BKZNT4VQWJMMC6HBEFDOG7").Samples)
|
|
|
|
})
|
|
|
|
t.Run("empty id", func(t *testing.T) {
|
|
|
|
assert.Nil(t, FindFace(""))
|
|
|
|
})
|
2021-08-26 11:58:52 +02:00
|
|
|
}
|
2021-09-18 20:41:30 +02:00
|
|
|
|
|
|
|
func TestFace_HideAndShow(t *testing.T) {
|
|
|
|
f := FaceFixtures.Get("joe-biden")
|
|
|
|
|
|
|
|
if err := f.Hide(); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
} else if err = f.Show(); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|