-
Notifications
You must be signed in to change notification settings - Fork 29
/
Copy pathcore.jl
143 lines (119 loc) · 4.04 KB
/
core.jl
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
abstract type Params end
"""
```
keypoint = Keypoint(y, x)
keypoint = Keypoint(feature)
```
A `Keypoint` may be created by passing the coordinates of the point or from a feature.
"""
const Keypoint = CartesianIndex{2}
"""
```
keypoints = Keypoints(boolean_img)
keypoints = Keypoints(features)
```
Creates a `Vector{Keypoint}` of the `true` values in a boolean image or from a list of features.
"""
const Keypoints = Vector{CartesianIndex{2}}
"""
```
feature = Feature(keypoint, orientation = 0.0, scale = 0.0)
```
The `Feature` type has the keypoint, its orientation and its scale.
"""
struct Feature
keypoint::Keypoint
orientation::Float64
scale::Float64
end
"""
```
features = Features(boolean_img)
features = Features(keypoints)
```
Returns a `Vector{Feature}` of features generated from the `true` values in a boolean image or from a
list of keypoints.
"""
const Features = Vector{Feature}
Feature(k::Keypoint) = Feature(k, 0.0, 0.0)
Feature(k::Keypoint, ori::Number) = Feature(k, ori, 0.0)
Features(keypoints::Keypoints) = map(k -> Feature(k), keypoints)
Features(img::AbstractArray) = Features(Keypoints(img))
Keypoint(feature::Feature) = feature.keypoint
function Keypoints(img::AbstractArray)
I = findall(!iszero, img)
r = getindex.(I, 1)
c = getindex.(I, 2)
map((ri, ci) -> Keypoint(ri, ci), r, c)
end
Keypoints(features::Features) = map(f -> f.keypoint, features)
const OrientationPair = Tuple{Int16, Int16}
const OrientationWeights = Tuple{Float16, Float16}
const SamplePair = Tuple{Float16, Float16}
"""
```
distance = hamming_distance(desc_1, desc_2)
```
Calculates the hamming distance between two descriptors.
"""
hamming_distance(desc_1, desc_2) = sum(xor.(desc_1, desc_2)) / length(desc_1)
"""
```
matches = match_keypoints(keypoints_1, keypoints_2, desc_1, desc_2, threshold = 0.1)
```
Finds matched keypoints using the [`hamming_distance`](@ref) function having distance value less than `threshold`.
"""
function match_keypoints(keypoints_1::Keypoints, keypoints_2::Keypoints, desc_1, desc_2, threshold::Float64 = 0.1)
smaller = desc_1
larger = desc_2
s_key = keypoints_1
l_key = keypoints_2
order = false
if length(desc_1) > length(desc_2)
smaller = desc_2
larger = desc_1
s_key = keypoints_2
l_key = keypoints_1
order = true
end
hamming_distances = [hamming_distance(s, l) for s in smaller, l in larger]
matches = Keypoints[]
for i in 1:length(smaller)
if any(hamming_distances[i, :] .< threshold)
id_min = argmin(hamming_distances[i, :])
push!(matches, order ? [l_key[id_min], s_key[i]] : [s_key[i], l_key[id_min]])
hamming_distances[:, id_min] .= 1.0
end
end
matches
end
"""
```
grade = grade_matches(keypoints_1, keypoints_2, limit, difference_method)
```
Returns the fraction of keypoint pairs which have
`difference_method(keypoint_1,keypoint_2)` less than `limit`.
"""
function grade_matches(keypoints_1::Keypoints, keypoints_2::Keypoints, limit::Real, diff::Function = (i,j) -> (sqrt( (i[1]-j[1])^2 + (i[2]-j[2])^2 )))
@assert length(keypoints_1)==length(keypoints_2) "Keypoint lists are of different lengths."
@assert length(keypoints_1)!=0 "Keypoint list is of size zero."
mean(map((keypoint_1,keypoint_2)->((diff(keypoint_1,keypoint_2) < limit) ? 1.0 : 0.0), keypoints_1, keypoints_2))
end
function bilinear_interpolator(img::AbstractMatrix{T}, padding::Tuple{UnitRange,UnitRange}) where T
pad_ax = map(axes(img), padding) do ax, x
first(ax)+first(x):last(ax)+last(x)
end
padded_img = PaddedView(zero(T), img, pad_ax)
return interpolate(padded_img, BSpline(Linear()))
end
bilinear_interpolator(img::AbstractMatrix, offsets) = bilinear_interpolator(img, padding_from_offsets(offsets))
function padding_from_offsets(offsets)
padding = [0:0 for _ in first(offsets)]
for o in offsets
for (i, p) in enumerate(o)
pd = padding[i]
padding[i] = min(pd.start, floor(Int, p)) : max(pd.stop, ceil(Int, p))
end
end
return (padding...,)
end