This repository has been archived by the owner on Nov 12, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.go
116 lines (91 loc) · 2.64 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
114
115
116
package simian
import (
"fmt"
"image"
"math"
"os"
"sort"
)
const rootFingerprintSize = 1
type Index struct {
Store IndexStore
maxFingerprintSize int
maxEntryDifference float64
}
func (i *Index) Add(image image.Image, metadata map[string]interface{}) (key string, err error) {
entry, err := NewIndexEntry(image, i.maxFingerprintSize, metadata)
if err != nil {
return "", nil
}
root, err := i.Store.GetRoot()
if err != nil {
return "", err
}
var rootFingerprint Fingerprint
_, err = root.Add(entry, rootFingerprint, rootFingerprintSize+1, i)
if err != nil {
return "", err
}
fmt.Printf("Root node has %d children and %d entries\n", len(root.childFingerprints), len(root.entries))
return "", nil
}
func (i *Index) Close() error {
return i.Store.Close()
}
func (i *Index) FindNearest(image image.Image, maxResults int, maxDifference float64) ([]*IndexEntry, error) {
var dummy map[string]interface{}
entry, err := NewIndexEntry(image, i.maxFingerprintSize, dummy)
if err != nil {
return nil, nil
}
root, err := i.Store.GetRoot()
if err != nil {
return nil, err
}
results, err := root.FindNearest(entry, rootFingerprintSize+1, i, maxResults, math.Max(maxDifference, i.maxEntryDifference))
if err != nil {
return nil, err
}
sort.Sort(entriesByDifferenceToEntryWith(results, entry))
return results, err
}
func NewIndex(path string, maxFingerprintSize int, maxEntryDifference float64) (*Index, error) {
err := os.MkdirAll(path, 0700)
if err != nil {
return nil, err
}
indexStore, err := NewDiskIndexStore(path)
if err != nil {
return nil, err
}
return &Index{
Store: indexStore,
maxFingerprintSize: maxFingerprintSize,
maxEntryDifference: maxEntryDifference,
}, err
}
type entriesByDifferenceToEntry struct {
entries []*IndexEntry
differences []float64
}
func (sorter *entriesByDifferenceToEntry) Len() int {
return len(sorter.entries)
}
func (sorter *entriesByDifferenceToEntry) Less(i, j int) bool {
return sorter.differences[i] < sorter.differences[j]
}
func (sorter *entriesByDifferenceToEntry) Swap(i, j int) {
tmpEntry := sorter.entries[i]
sorter.entries[i] = sorter.entries[j]
sorter.entries[j] = tmpEntry
tmpDiff := sorter.differences[i]
sorter.differences[i] = sorter.differences[j]
sorter.differences[j] = tmpDiff
}
func entriesByDifferenceToEntryWith(entries []*IndexEntry, target *IndexEntry) *entriesByDifferenceToEntry {
differences := make([]float64, len(entries), len(entries))
for i, entry := range entries {
differences[i] = entry.MaxFingerprint.Difference(target.MaxFingerprint)
}
return &entriesByDifferenceToEntry{entries: entries, differences: differences}
}