src/ImGenerate.jl

changeset 0
a55e35d20336
child 5
843e7611b068
equal deleted inserted replaced
-1:000000000000 0:a55e35d20336
1 ###################
2 # Image generation
3 ###################
4
5 module ImGenerate
6
7 using ColorTypes: Gray
8 import TestImages
9 # We don't really *directly* depend on QuartzImageIO. The import here is
10 # merely a workaround to suppress warnings when loading TestImages.
11 # Something is broken in those packages.
12 import QuartzImageIO
13
14 using AlgTools.Util
15 using AlgTools.Comms
16 using ImageTools.Translate
17
18 using ..OpticalFlow: Image, DisplacementConstant, DisplacementFull
19
20 ##############
21 # Our exports
22 ##############
23
24 export ImGen,
25 OnlineData,
26 imgen_square,
27 imgen_shake
28
29 ##################
30 # Data structures
31 ##################
32
33 struct ImGen
34 f :: Function
35 dim :: Tuple{Int64,Int64}
36 Λ :: Float64
37 dynrange :: Float64
38 name :: String
39 end
40
41 struct OnlineData{DisplacementT}
42 b_true :: Image
43 b_noisy :: Image
44 v :: DisplacementT
45 v_true :: DisplacementT
46 v_cumul_true :: DisplacementT
47 end
48
49 ###################
50 # Shake generation
51 ###################
52
53 function make_const_v(displ, sz)
54 v = zeros(2, sz...)
55 v[1, :, :] .= displ[1]
56 v[2, :, :] .= displ[2]
57 return v
58 end
59
60 function shake(params)
61 if !haskey(params, :shaketype) || params.shaketype == :gaussian
62 return () -> params.shake.*randn(2)
63 elseif params.shaketype == :disk
64 return () -> begin
65 θ = 2π*rand(Float64)
66 r = params.shake*√(rand(Float64))
67 return [r*cos(θ), r*sin(θ)]
68 end
69 elseif params.shaketype == :circle
70 return () -> begin
71 θ = 2π*rand(Float64)
72 r = params.shake
73 return [r*cos(θ), r*sin(θ)]
74 end
75 else
76 error("Unknown shaketype $(params.shaketype)")
77 end
78 end
79
80 pixelwise = (shakefn, sz) -> () -> make_const_u(shakefn(), sz)
81
82 ################
83 # Moving square
84 ################
85
86 function generate_square(sz,
87 :: Type{DisplacementT},
88 datachannel :: Channel{OnlineData{DisplacementT}},
89 params) where DisplacementT
90
91 if false
92 v₀ = make_const_v(0.1.*(-1, 1), sz)
93 nextv = () -> v₀
94 elseif DisplacementT == DisplacementFull
95 nextv = pixelwise(shake(params), sz)
96 elseif DisplacementT == DisplacementConstant
97 nextv = shake(params)
98 else
99 @error "Invalid DisplacementT"
100 end
101
102 # Constant linear displacement everywhere has Jacobian determinant one
103 # (modulo the boundaries which we ignore here)
104 m = round(Int, sz[1]/5)
105 b_orig = zeros(sz...)
106 b_orig[sz[1].-(2*m:3*m), 2*m:3*m] .= 1
107
108 v_true = nextv()
109 v_cumul = copy(v_true)
110
111 while true
112 # Flow original data and add noise
113 b_true = zeros(sz...)
114 translate_image!(b_true, b_orig, v_cumul; threads=true)
115 b = b_true .+ params.noise_level.*randn(sz...)
116 v = v_true.*(1.0 .+ params.shake_noise_level.*randn(size(v_true)...))
117 # Pass true data to iteration routine
118 data = OnlineData{DisplacementT}(b_true, b, v, v_true, v_cumul)
119 if !put_unless_closed!(datachannel, data)
120 return
121 end
122 # Next step shake
123 v_true = nextv()
124 v_cumul .+= v_true
125 end
126 end
127
128 function imgen_square(sz)
129 return ImGen(curry(generate_square, sz), sz, 1, 1, "square$(sz[1])x$(sz[2])")
130 end
131
132 ################
133 # Shake a photo
134 ################
135
136 function generate_shake_image(im, sz,
137 :: Type{DisplacementConstant},
138 datachannel :: Channel{OnlineData{DisplacementConstant}},
139 params :: NamedTuple)
140
141 nextv = shake(params)
142 v_true = nextv()
143 v_cumul = copy(v_true)
144
145 while true
146 # Extract subwindow of original image and add noise
147 b_true = zeros(sz...)
148 extract_subimage!(b_true, im, v_cumul; threads=true)
149 b = b_true .+ params.noise_level.*randn(sz...)
150 v = v_true.*(1.0 .+ params.shake_noise_level.*randn(size(v_true)...))
151 # Pass data to iteration routine
152 data = OnlineData{DisplacementConstant}(b_true, b, v, v_true, v_cumul)
153 if !put_unless_closed!(datachannel, data)
154 return
155 end
156 # Next step shake
157 v_true = nextv()
158 v_cumul .+= v_true
159 end
160 end
161
162 function imgen_shake(imname, sz)
163 im = Float64.(Gray.(TestImages.testimage(imname)))
164 dynrange = maximum(im)
165 return ImGen(curry(generate_shake_image, im, sz), sz, 1, dynrange,
166 "$(imname)$(sz[1])x$(sz[2])")
167 end
168
169 end # Module

mercurial