/
index.go
113 lines (90 loc) · 1.88 KB
/
index.go
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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
package pkg
import (
"errors"
"fmt"
)
var ErrAlreadyAdded = errors.New("image does already exist")
type Image struct {
Id string
Guid int
Path string
Name string
Features []float64
}
type ImageProvider interface {
Images() ([]*Image, error)
Get(string) *Image
Persist(*Image) error
}
type ImageIndex struct {
provider ImageProvider
images []*Image
imageMap map[string]*Image
}
func (i *ImageIndex) Add(image *Image) error {
if image == nil {
return nil
}
if i.Has(image.Id) {
return ErrAlreadyAdded
}
if image.Features == nil {
feature, err := FeatureVector(*image)
if err != nil {
return err
}
image.Features = feature
err = i.provider.Persist(image)
if err != nil {
return err
}
}
i.imageMap[image.Id] = image
i.images = append(i.images, image)
return nil
}
func (i ImageIndex) Has(id string) bool {
_, ok := i.imageMap[id]
return ok
}
func (i ImageIndex) Load(id string) *Image {
return i.provider.Get(id)
}
func (i ImageIndex) Images() []*Image {
return i.images
}
func (i ImageIndex) Search(referenceImage Image, distanceThreshold float64, limit int) ([]ImageDistance, error) {
distances, err := CalculateDistances(referenceImage, i.images)
if err != nil {
return nil, err
}
var results []ImageDistance
for i, distance := range distances {
if distance.Distance > distanceThreshold || i >= limit {
break
}
results = append(results, distance)
}
return results, nil
}
func NewIndex(p ImageProvider) (*ImageIndex, error) {
images, err := p.Images()
if err != nil {
return nil, err
}
var imageDescriptors []*Image
imageMap := make(map[string]*Image, len(images))
imageIndex := &ImageIndex{
provider: p,
images: imageDescriptors,
imageMap: imageMap,
}
for i := range images {
err := imageIndex.Add(images[i])
if err != nil {
fmt.Println(err)
continue
}
}
return imageIndex, nil
}