-
Notifications
You must be signed in to change notification settings - Fork 143
/
algorithms.jl
122 lines (109 loc) · 4.5 KB
/
algorithms.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
# Simple image difference testing
macro test_approx_eq_sigma_eps(A, B, sigma, eps)
quote
if size($(esc(A))) != size($(esc(B)))
error("Sizes ", size($(esc(A))), " and ",
size($(esc(B))), " do not match")
end
kern = KernelFactors.IIRGaussian($(esc(sigma)))
Af = imfilter($(esc(A)), kern, NA())
Bf = imfilter($(esc(B)), kern, NA())
diffscale = max(_abs(maximum_finite(abs, $(esc(A)))), _abs(maximum_finite(abs, $(esc(B)))))
d = sad(Af, Bf)
if d > length(Af)*diffscale*($(esc(eps)))
error("Arrays A and B differ")
end
end
end
# image difference testing (@tbreloff's, based on the macro)
# A/B: images/arrays to compare
# sigma: tuple of ints... how many pixels to blur
# eps: error allowance
# returns: percentage difference on match, error otherwise
function test_approx_eq_sigma_eps(A::AbstractArray, B::AbstractArray,
sigma::AbstractVector{T} = ones(ndims(A)),
eps::AbstractFloat = 1e-2,
expand_arrays::Bool = true) where T<:Real
if size(A) != size(B)
if expand_arrays
newsize = map(max, size(A), size(B))
if size(A) != newsize
A = copyto!(zeros(eltype(A), newsize...), A)
end
if size(B) != newsize
B = copyto!(zeros(eltype(B), newsize...), B)
end
else
error("Arrays differ: size(A): $(size(A)) size(B): $(size(B))")
end
end
if length(sigma) != ndims(A)
error("Invalid sigma in test_approx_eq_sigma_eps. Should be ndims(A)-length vector of the number of pixels to blur. Got: $sigma")
end
kern = KernelFactors.IIRGaussian(sigma)
Af = imfilter(A, kern, NA())
Bf = imfilter(B, kern, NA())
diffscale = max(_abs(maximum_finite(abs, A)), _abs(maximum_finite(abs, B)))
d = sad(Af, Bf)
diffpct = d / (length(Af) * diffscale)
if diffpct > eps
error("Arrays differ. Difference: $diffpct eps: $eps")
end
diffpct
end
# This should be removed when upstream ImageBase is updated
# In ImageBase v0.1.3: `maxabsfinite` returns a RGB instead of a Number
_abs(c::CT) where CT<:Color = mapreducec(abs, +, zero(eltype(CT)), c)
_abs(c::Number) = abs(c)
@inline function _clippedinds(Router,rstp)
CartesianIndices(map((f,l)->f:l,
(first(Router)+rstp).I,(last(Router)-rstp).I))
end
function imgaussiannoise(img::AbstractArray{T}, variance::Number, mean::Number) where T
return img + sqrt(variance)*randn(size(img)) + mean
end
imgaussiannoise(img::AbstractArray{T}, variance::Number) where {T} = imgaussiannoise(img, variance, 0)
imgaussiannoise(img::AbstractArray{T}) where {T} = imgaussiannoise(img, 0.01, 0)
"""
```
pyramid = gaussian_pyramid(img, n_scales, downsample, sigma)
```
Returns a gaussian pyramid of scales `n_scales`, each downsampled
by a factor `downsample` > 1 and `sigma` for the gaussian kernel.
"""
function gaussian_pyramid(img::AbstractArray{T,N}, n_scales::Int, downsample::Real, sigma::Real) where {T,N}
kerng = KernelFactors.IIRGaussian(sigma)
kern = ntuple(d->kerng, Val(N))
gaussian_pyramid(img, n_scales, downsample, kern)
end
function gaussian_pyramid(img::AbstractArray{T,N}, n_scales::Int, downsample::Real, kern::NTuple{N,Any}) where {T,N}
downsample > 1 || @warn("downsample factor should be greater than one")
# To guarantee inferability, we make sure that we do at least one
# round of smoothing and resizing
img_smoothed_main = imfilter(img, kern, NA())
img_scaled = pyramid_scale(img_smoothed_main, downsample)
prev = convert(typeof(img_scaled), img)
pyramid = typeof(img_scaled)[prev]
if n_scales ≥ 1
# Take advantage of the work we've already done
push!(pyramid, img_scaled)
prev = img_scaled
end
for i in 2:n_scales
img_smoothed = imfilter(prev, kern, NA())
img_scaled = pyramid_scale(img_smoothed, downsample)
push!(pyramid, img_scaled)
prev = img_scaled
end
pyramid
end
function pyramid_scale(img, downsample)
sz_next = map(s->ceil(Int, s/downsample), size(img))
imresize(img, sz_next)
end
function pyramid_scale(img::OffsetArray, downsample)
sz_next = map(s->ceil(Int, s/downsample), length.(axes(img)))
# off = (.-ceil.(Int,(.-iterate.(axes(img).-(1,1))[1])./downsample))
off = (.-ceil.(Int,(.-iterate.(map(x->UnitRange(x).-1,axes(img)))[1])./downsample))
OffsetArray(imresize(img, sz_next), off)
end