Skip to content

Commit 000735e

Browse files
authored
Merge pull request #26 from bionanoimaging/fractiona_fourier_transform
Fractiona fourier transform
2 parents 0c2de4f + 07cc78b commit 000735e

File tree

8 files changed

+520
-1
lines changed

8 files changed

+520
-1
lines changed

Project.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Reexport = "189a3867-3050-52da-a836-e630ba90ab69"
1515
ShiftedArrays = "1277b4bf-5013-50f5-be3d-901d8477a67a"
1616

1717
[compat]
18+
1819
ChainRulesCore = "1, 1.0, 1.1"
1920
FFTW = "1.5"
2021
ImageTransformations = "0.9"
@@ -28,10 +29,12 @@ Zygote = "0.6"
2829
julia = "1, 1.6, 1.7, 1.8"
2930

3031
[extras]
32+
FractionalTransforms = "e50ca838-b4f0-4a10-ad18-4b920bf1ae5c"
3133
ImageTransformations = "02fcd773-0e25-5acc-982a-7f6622650795"
3234
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
3335
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
36+
TestImages = "5e47fb64-e119-507b-a336-dd2b206d9990"
3437
Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f"
3538

3639
[targets]
37-
test = ["Test", "Random", "ImageTransformations", "Zygote"]
40+
test = ["Test", "TestImages", "FractionalTransforms", "Random", "ImageTransformations", "Zygote"]

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,15 @@ The main features are:
2929
* array/image shearing
3030
* convenient wrappers of [NFFT.jl](https://github.com/JuliaMath/NFFT.jl)
3131
* several tools like `ffts`, `ft`, `fftshift_view` etc. allowing simpler use with Fourier transforms
32+
* Chirp Z-Transform
33+
* Fractional Fourier Transform
3234
* reexports [FFTW.jl](https://github.com/JuliaMath/FFTW.jl)
3335

3436
Have a look in the [examples folder](examples/) for interactive examples. The [documentation](https://bionanoimaging.github.io/FourierTools.jl/dev/) offers a quick overview.
3537

38+
## FFTW Threading
39+
By default we set 4 Threads. Use `FFTW.set_num_threads(N)` to set `N` threads.
40+
3641

3742

3843
## Related Packages

examples/Project.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@
22
Colors = "5ae59095-9a9b-59fe-a467-6f913c188581"
33
FFTW = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341"
44
FourierTools = "b18b359b-aebc-45ac-a139-9c0ccbb2871e"
5+
FractionalTransforms = "e50ca838-b4f0-4a10-ad18-4b920bf1ae5c"
56
ImageShow = "4e3cecfd-b093-5904-9786-8bbb286a6a31"
67
Images = "916415d5-f1e6-5110-898d-aaa5f9f070e0"
8+
IndexFunArrays = "613c443e-d742-454e-bfc6-1d7f8dd76566"
9+
NDTools = "98581153-e998-4eef-8d0d-5ec2c052313d"
10+
Napari = "ed46c112-542a-4e7e-ab0f-e39321fab6f0"
711
Noise = "81d43f40-5267-43b7-ae1c-8b967f377efa"
812
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
913
Pluto = "c3e4b0f8-55cb-11ea-2926-15256bba5781"
Lines changed: 290 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,290 @@
1+
### A Pluto.jl notebook ###
2+
# v0.19.13
3+
4+
using Markdown
5+
using InteractiveUtils
6+
7+
# This Pluto notebook uses @bind for interactivity. When running this notebook outside of Pluto, the following 'mock version' of @bind gives bound variables a default value (instead of an error).
8+
macro bind(def, element)
9+
quote
10+
local iv = try Base.loaded_modules[Base.PkgId(Base.UUID("6e696c72-6542-2067-7265-42206c756150"), "AbstractPlutoDingetjes")].Bonds.initial_value catch; b -> missing; end
11+
local el = $(esc(element))
12+
global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : iv(el)
13+
el
14+
end
15+
end
16+
17+
# ╔═╡ a696290a-0122-11ed-01e5-a39256aed683
18+
begin
19+
using Pkg;
20+
Pkg.activate(".")
21+
using Revise
22+
end
23+
24+
# ╔═╡ 459649ed-ca70-426e-8273-97b146b5bcd5
25+
using FourierTools, FFTW, NDTools, TestImages, Colors, ImageShow, PlutoUI, IndexFunArrays, Plots
26+
27+
# ╔═╡ 55894157-a2d1-4567-99a8-a052d5335dd1
28+
begin
29+
30+
"""
31+
simshow(arr; set_one=false, set_zero=false,
32+
f=nothing, γ=1)
33+
Displays a real valued array . Brightness encodes magnitude.
34+
Works within Jupyter and Pluto.
35+
# Keyword args
36+
The transforms are applied in that order.
37+
* `set_zero=false` subtracts the minimum to set minimum to 1
38+
* `set_one=false` divides by the maximum to set maximum to 1
39+
* `f` applies an arbitrary function to the abs array
40+
* `γ` applies a gamma correction to the abs
41+
* `cmap=:gray` applies a colormap provided by ColorSchemes.jl. If `cmap=:gray` simply `Colors.Gray` is used
42+
and with different colormaps the result is an `Colors.RGB` element type
43+
"""
44+
function simshow(arr::AbstractArray{T};
45+
set_one=true, set_zero=false,
46+
f = nothing,
47+
γ = one(T),
48+
cmap=:gray) where {T<:Real}
49+
arr = set_zero ? arr .- minimum(arr) : arr
50+
51+
if set_one
52+
m = maximum(arr)
53+
if !iszero(m)
54+
arr = arr ./ maximum(arr)
55+
end
56+
end
57+
58+
arr = isnothing(f) ? arr : f(arr)
59+
60+
if !isone(γ)
61+
arr = arr .^ γ
62+
end
63+
64+
if cmap == :gray
65+
Gray.(arr)
66+
else
67+
get(colorschemes[cmap], arr)
68+
end
69+
end
70+
71+
72+
"""
73+
simshow(arr)
74+
Displays a complex array. Color encodes phase, brightness encodes magnitude.
75+
Works within Jupyter and Pluto.
76+
# Keyword args
77+
The transforms are applied in that order.
78+
* `f` applies a function `f` to the array.
79+
* `absf` applies a function `absf` to the absolute of the array
80+
* `absγ` applies a gamma correction to the abs
81+
"""
82+
function simshow(arr::AbstractArray{T};
83+
f=nothing,
84+
absγ=one(T),
85+
absf=nothing) where (T<:Complex)
86+
87+
if !isnothing(f)
88+
arr = f(arr)
89+
end
90+
91+
Tr = real(T)
92+
# scale abs to 1
93+
absarr = abs.(arr)
94+
absarr ./= maximum(absarr)
95+
96+
if !isnothing(absf)
97+
absarr .= absf(absarr)
98+
end
99+
100+
if !isone(absγ)
101+
absarr .= absarr .^ absγ
102+
end
103+
104+
angarr = angle.(arr) ./ Tr(2pi) * Tr(360)
105+
106+
HSV.(angarr, one(Tr), absarr)
107+
end
108+
109+
110+
end
111+
112+
# ╔═╡ 18b0700c-20fc-4e58-8950-ca09fe34ea19
113+
import FractionalTransforms
114+
115+
# ╔═╡ 4371cfbf-a3b3-45dc-847b-019994fbb234
116+
md"## Fractional Fourier Transform on a Image"
117+
118+
# ╔═╡ d90b7f67-4166-44fa-aab7-de2c4f38fc00
119+
img = Float32.(testimage("resolution_test_512"));
120+
121+
# ╔═╡ 24901666-4cc4-497f-a6ff-68c3e7ead629
122+
md"
123+
Fractional order
124+
125+
$(@bind s Slider(-3:0.001:3, show_value=true))
126+
"
127+
128+
# ╔═╡ 08d95a42-24fe-4995-98d6-1f415de71538
129+
function frft_1D(x, order)
130+
x_ft = similar(x, complex(eltype(x)), size(x))
131+
132+
133+
for i = 1:size(x, 1)
134+
x_ft[i, :] = FractionalTransforms.frft(x[i, :], order)
135+
end
136+
137+
for j = 1:size(x, 2)
138+
x_ft[:, j] = FractionalTransforms.frft(x_ft[:, j], order)
139+
end
140+
141+
return x_ft
142+
end
143+
144+
# ╔═╡ 7c445baa-d970-4954-a3dc-df828971bfd7
145+
[simshow(abs.(ft(img)), γ=0.2) simshow(sqrt(length(img)) .* abs.(frfft(img, s, shift=true)), γ=0.2) simshow(sqrt(length(img)) .* abs.(frft_1D(img, s)), γ=0.2)]
146+
147+
# ╔═╡ 1915c023-69cf-4d18-90cb-b47465dbef69
148+
begin
149+
plot(log1p.(abs.(ft(img)[(end+begin)÷2+1,:] ./ sqrt(length(img)))))
150+
plot!(log1p.(abs.(frfft(img, s)[(end+begin)÷2+1,:])))
151+
end
152+
153+
# ╔═╡ 3109fc21-50c6-46e6-850d-add6f54872d7
154+
begin
155+
plot((imag.(ft(img)[(end+begin)÷2+1,:] ./ sqrt(length(img)))))
156+
plot!((imag.(frfft(img, 0.99999999999)[(end+begin)÷2+1,:])))
157+
end
158+
159+
# ╔═╡ 284cd6f2-1ee3-4923-afa6-ea57e93b28a7
160+
begin
161+
plot((angle.(ft(img)[(end+begin)÷2+1,:] ./ sqrt(length(img)))))
162+
plot!((angle.(frfft(img, 0.99999999999)[(end+begin)÷2+1,:])))
163+
end
164+
165+
# ╔═╡ 227ae9a3-9387-4ac3-b391-e2a78ce40d49
166+
begin
167+
plot((real.(ft(img)[(end+begin)÷2+1,200:300] ./ sqrt(length(img)))))
168+
plot!((real.(frfft(img, s)[(end+begin)÷2+1,200:300])))
169+
end
170+
171+
# ╔═╡ abff911a-e10d-4311-955a-7afc4e0d344c
172+
md"## Fractional Fourier Transform on Vector
173+
Comparison with [FractionalTransforms.jl](https://github.com/SciFracX/FractionalTransforms.jl) roughly matches.
174+
"
175+
176+
# ╔═╡ bae3c5b7-8964-493b-9e7b-d343e092219c
177+
r = box(Float64, (301,), (201,))#.+ 0.4 .* randn((301,))
178+
179+
# ╔═╡ 5655dc10-f4e9-4765-9a89-ac9702864de1
180+
plot(abs.(ft(r)))
181+
182+
# ╔═╡ 07d2b3b6-3584-4c64-9c4a-138beb3d6b88
183+
@bind s2 Slider(-5:0.001:5, show_value=true)
184+
185+
# ╔═╡ 1839f03e-6add-4c85-b6fd-9035656ed86c
186+
begin
187+
plot(real.(frfft(r, s2, shift=true)), label="FourierTools")
188+
#plot!(imag.(frfft(frfft(r, s2/2, shift=true), s2/2, shift=true)), label="FourierTools 2 Step")
189+
190+
plot!(real.(FractionalTransforms.frft(r, s2)), label="FractionalTransforms")
191+
#plot!(imag.(FractionalTransforms.frft(ft(r) ./ sqrt(length(r)), -1+s2)), label="FractionalTransforms")
192+
193+
#plot!(imag.(FractionalTransforms.frft(r, s2)))
194+
195+
#plot!(real.(FractionalTransforms.frft(r, s2)))
196+
end
197+
198+
# ╔═╡ f3cb2153-a7b3-46ed-adbb-038a812b6a81
199+
begin
200+
201+
#plot(abs.(frfft(r, s2, shift=true, p_change=false)))
202+
plot(abs.(frfft(r, s2, shift=true, p_change=true)))
203+
204+
#plot!(imag.(FractionalTransforms.frft(r, s2)), label="FractionalTransforms")
205+
#plot!(imag.(FractionalTransforms.frft(ft(r) ./ sqrt(length(r)), -1+s2)), label="FractionalTransforms")
206+
plot!(abs.(FractionalTransforms.frft(r, s2)))
207+
208+
#plot!(real.(FractionalTransforms.frft(r, s2)))
209+
end
210+
211+
# ╔═╡ 37ebf4d8-28fa-4d0b-929c-5df4c9f418e0
212+
md"## Gaussian Propagation"
213+
214+
# ╔═╡ fab2b38f-7a93-438e-a1f9-9e58709aec2e
215+
x = -256:256
216+
217+
# ╔═╡ 02708a88-14ce-45cc-8d40-71a74bc5a56d
218+
amp = exp.(-(x.^2 .+ x'.^2) ./ 3000);
219+
220+
# ╔═╡ 77807bbe-a33a-4d65-8e06-446ad368784f
221+
phase_term = exp.(1im .* x .* 2π ./ 5 .+ 1im .* x'.^2);
222+
223+
# ╔═╡ 696a77b2-a904-4cf8-805e-b66621dbbb8f
224+
field = amp .* phase_term;
225+
226+
# ╔═╡ 4e53efc4-de25-4b97-8dc8-985d56b8bc67
227+
simshow(field)
228+
229+
# ╔═╡ 3fa82b96-e701-40d1-89c2-8f71038b6d05
230+
simshow(ft(field))
231+
232+
# ╔═╡ 4dcf3db5-6d37-4a09-a161-4af53ffc91ec
233+
@bind f2 Slider(-4:0.001:4, show_value=true)
234+
235+
# ╔═╡ e4db42df-cfe9-4ae0-91f6-5672707d87d5
236+
simshow(frfft(field, f2))
237+
238+
# ╔═╡ 67e0e7dc-4692-451c-97d0-742ab5df3853
239+
rev2(x) = ifftshift(reverse(fftshift(x)))
240+
241+
# ╔═╡ a52deb8f-64e6-46ab-b77e-13b35a20f17c
242+
rev2([simshow(frfft(field, f2));;; simshow(frfft(ift(field), f2-1))][:, :, 2])
243+
244+
# ╔═╡ ce65aa2c-e558-434b-aa8a-2268c47f5684
245+
md"### Comparison with two step FRFT with half the order"
246+
247+
# ╔═╡ e0529213-f2c9-49e4-b2fe-96bbd16a77b7
248+
@bind f3 Slider(-4:0.001:4, show_value=true)
249+
250+
# ╔═╡ 1fe0d80f-664b-4b9f-9ff3-95f0d00e32d5
251+
simshow(frfft(field, f3, p_change=false))
252+
253+
# ╔═╡ e5f32874-5f98-4825-824a-780764e8ef91
254+
simshow(frfft(frfft(field, f3/2),f3/2))
255+
256+
# ╔═╡ Cell order:
257+
# ╠═a696290a-0122-11ed-01e5-a39256aed683
258+
# ╟─55894157-a2d1-4567-99a8-a052d5335dd1
259+
# ╠═18b0700c-20fc-4e58-8950-ca09fe34ea19
260+
# ╠═459649ed-ca70-426e-8273-97b146b5bcd5
261+
# ╟─4371cfbf-a3b3-45dc-847b-019994fbb234
262+
# ╠═d90b7f67-4166-44fa-aab7-de2c4f38fc00
263+
# ╟─24901666-4cc4-497f-a6ff-68c3e7ead629
264+
# ╠═7c445baa-d970-4954-a3dc-df828971bfd7
265+
# ╠═08d95a42-24fe-4995-98d6-1f415de71538
266+
# ╠═1915c023-69cf-4d18-90cb-b47465dbef69
267+
# ╠═3109fc21-50c6-46e6-850d-add6f54872d7
268+
# ╠═284cd6f2-1ee3-4923-afa6-ea57e93b28a7
269+
# ╠═227ae9a3-9387-4ac3-b391-e2a78ce40d49
270+
# ╟─abff911a-e10d-4311-955a-7afc4e0d344c
271+
# ╠═bae3c5b7-8964-493b-9e7b-d343e092219c
272+
# ╠═5655dc10-f4e9-4765-9a89-ac9702864de1
273+
# ╠═1839f03e-6add-4c85-b6fd-9035656ed86c
274+
# ╠═07d2b3b6-3584-4c64-9c4a-138beb3d6b88
275+
# ╠═f3cb2153-a7b3-46ed-adbb-038a812b6a81
276+
# ╟─37ebf4d8-28fa-4d0b-929c-5df4c9f418e0
277+
# ╠═fab2b38f-7a93-438e-a1f9-9e58709aec2e
278+
# ╠═02708a88-14ce-45cc-8d40-71a74bc5a56d
279+
# ╠═77807bbe-a33a-4d65-8e06-446ad368784f
280+
# ╠═696a77b2-a904-4cf8-805e-b66621dbbb8f
281+
# ╠═4e53efc4-de25-4b97-8dc8-985d56b8bc67
282+
# ╠═3fa82b96-e701-40d1-89c2-8f71038b6d05
283+
# ╟─4dcf3db5-6d37-4a09-a161-4af53ffc91ec
284+
# ╠═e4db42df-cfe9-4ae0-91f6-5672707d87d5
285+
# ╠═67e0e7dc-4692-451c-97d0-742ab5df3853
286+
# ╠═a52deb8f-64e6-46ab-b77e-13b35a20f17c
287+
# ╟─ce65aa2c-e558-434b-aa8a-2268c47f5684
288+
# ╟─e0529213-f2c9-49e4-b2fe-96bbd16a77b7
289+
# ╠═1fe0d80f-664b-4b9f-9ff3-95f0d00e32d5
290+
# ╠═e5f32874-5f98-4825-824a-780764e8ef91

src/FourierTools.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,6 @@ include("convolutions.jl")
2929
include("correlations.jl")
3030
include("damping.jl")
3131
include("czt.jl")
32+
include("fractional_fourier_transform.jl")
3233

3334
end # module

0 commit comments

Comments
 (0)