-
Notifications
You must be signed in to change notification settings - Fork 7
Add Denoising Problem #43
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
102a972
25e9997
c2e4e7e
fbdf953
90a4e8a
048f892
27a1755
44635b9
f789684
5ce0805
2f62ffd
3770393
5b55407
4937015
72874a3
63e1c63
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
export generate_uniform_blur, generate_gaussian_blur | ||
|
||
""" | ||
Implementation of the denoising problem described in | ||
|
||
Stella, L., Themelis, A. & Patrinos, P. | ||
Forward–backward quasi-Newton methods for nonsmooth optimization problems. | ||
Comput Optim Appl 67, 443–487 (2017). https://doi.org/10.1007/s10589-017-9912-y | ||
|
||
and adapted from the original implementation in Python by the authors of the paper: | ||
|
||
Chouzenoux, E., Martin, S. & Pesquet, JC. | ||
A Local MM Subspace Method for Solving Constrained Variational Problems in Image Recovery. | ||
J Math Imaging Vis 65, 253–276 (2023). https://doi.org/10.1007/s10851-022-01112-z | ||
""" | ||
|
||
# Function to unpad an array | ||
function unpad(x, n_p, m_p, n) | ||
a = n_p - n + 1 | ||
x = reshape_array(x, (n_p, m_p)) | ||
unpadded_x = x[a:end, a:end] | ||
return unpadded_x | ||
end | ||
|
||
# Function to pad an array | ||
function pad(z, s1, s2) | ||
x = cat(zeros(size(z, 1), s1), z, dims = 2) | ||
x = cat(x, zeros(size(z, 1), s2), dims = 2) | ||
x = cat(x, zeros(s2, size(x, 2)), dims = 1) | ||
x = cat(zeros(s1, size(x, 2)), x, dims = 1) | ||
return x | ||
end | ||
|
||
# Function to pad a specific array to match suitable dimensions | ||
function pad_x(z, a) | ||
t = cat(zeros(size(z, 1), a), z, dims = 2) | ||
t = cat(zeros(a, size(z, 2) + a), t, dims = 1) | ||
return t | ||
end | ||
|
||
# Function to create a meshgrid for the gaussian kernel | ||
function meshgrid(x_range, y_range) | ||
m = length(x_range) | ||
n = length(y_range) | ||
x = repeat(x_range, inner = (1, n)) | ||
y = repeat(y_range', outer = (m, 1)) | ||
return x, y | ||
end | ||
|
||
# Function to generate a Gaussian kernel | ||
function my_gaussian_kernel(kernel_size, kernel_sigma) | ||
x, y = meshgrid((-kernel_size):kernel_size, (-kernel_size):kernel_size) | ||
normal = 1 / (2 * pi * kernel_sigma^2) | ||
kernel = exp.(-((x .^ 2 .+ y .^ 2) / (2.0 * kernel_sigma^2))) * normal | ||
kernel ./= sum(kernel) | ||
return kernel | ||
end | ||
|
||
# Function to generate a uniform kernel | ||
function uniform_kernel(kernel_size) | ||
kernel = ones(2 * kernel_size + 1, 2 * kernel_size + 1) | ||
kernel = kernel / sum(kernel) | ||
return kernel | ||
end | ||
|
||
# Main function to generate H, H_T, W, and W_T functions for gaussian kernel | ||
function generate_gaussian_blur(shape, shape_p, KERNEL_SIZE, KERNEL_SIGMA = 1.5) | ||
(n, m) = shape | ||
(n_p, m_p) = shape_p | ||
a = n_p - n | ||
|
||
kernel_h = my_gaussian_kernel(KERNEL_SIZE, KERNEL_SIGMA) | ||
|
||
sz = (n_p - (2 * KERNEL_SIZE + 1), m_p - (2 * KERNEL_SIZE + 1)) | ||
kernel_h = pad(kernel_h, div(sz[1], 2), div(sz[1], 2) + 1) | ||
kernel_h = FFTW.ifftshift(kernel_h) | ||
fft_h = FFTW.fft(kernel_h) | ||
|
||
# Function H: Applies a linear transformation H which models the blur to an input x | ||
function H(x) | ||
x = reshape_array(x, (n, m)) | ||
x = pad_x(x, a) | ||
fft_x = FFTW.fft(x) | ||
x_new = real(FFTW.ifft(fft_x .* fft_h)) | ||
return unpad(x_new, n_p, m_p, n)[:] | ||
end | ||
|
||
# Function H_T: Applies the transpose of the linear transformation H to an input x | ||
function H_T(x) | ||
x = reshape_array(x, (n, m)) | ||
x = pad_x(x, a) | ||
fft_x = FFTW.fft(x) | ||
x_new = real(FFTW.ifft(fft_x .* conj.(fft_h))) | ||
return unpad(x_new, n_p, m_p, n)[:] | ||
end | ||
|
||
wt = Wavelets.wavelet(Wavelets.WT.haar) | ||
|
||
# ----- Discrete Wavelet Transform (DWT) ----- | ||
|
||
# Function W: Applies the DWT to an input x | ||
function W(x) | ||
return Wavelets.dwt(reshape_array(x, (n, m)), wt, 4)[:] | ||
end | ||
|
||
# Function W_T: Applies the inverse DWT to an input x | ||
function W_T(x) | ||
return Wavelets.idwt(reshape_array(x, (n, m)), wt, 4)[:] | ||
end | ||
|
||
# Return the generated functions | ||
return H, H_T, W, W_T | ||
end | ||
|
||
# Main function to generate H, H_T, W, and W_T functions for gaussian kernel | ||
function generate_uniform_blur(shape, shape_p, KERNEL_SIZE) | ||
(n, m) = shape | ||
(n_p, m_p) = shape_p | ||
a = n_p - n | ||
|
||
kernel_h = uniform_kernel(KERNEL_SIZE) | ||
|
||
sz = (n_p - (2 * KERNEL_SIZE + 1), m_p - (2 * KERNEL_SIZE + 1)) | ||
kernel_h = pad(kernel_h, div(sz[1], 2), div(sz[1], 2) + 1) | ||
kernel_h = FFTW.ifftshift(kernel_h) | ||
fft_h = FFTW.fft(kernel_h) | ||
|
||
# Function H: Applies a linear transformation H which models the blur to an input x | ||
function H(x) | ||
x = reshape_array(x, (n, m)) | ||
x = pad_x(x, a) | ||
fft_x = FFTW.fft(x) | ||
x_new = real(FFTW.ifft(fft_x .* fft_h)) | ||
return unpad(x_new, n_p, m_p, n)[:] | ||
end | ||
|
||
# Function H_T: Applies the transpose of the linear transformation H to an input x | ||
function H_T(x) | ||
x = reshape_array(x, (n, m)) | ||
x = pad_x(x, a) | ||
fft_x = FFTW.fft(x) | ||
x_new = real(FFTW.ifft(fft_x .* conj.(fft_h))) | ||
return unpad(x_new, n_p, m_p, n)[:] | ||
end | ||
|
||
wt = Wavelets.wavelet(Wavelets.WT.haar) | ||
|
||
# ----- Discrete Wavelet Transform (DWT) ----- | ||
|
||
# Function W: Applies the DWT to an input x | ||
function W(x) | ||
return Wavelets.dwt(reshape_array(x, (n, m)), wt, 4)[:] | ||
end | ||
|
||
# Function W_T: Applies the inverse DWT to an input x | ||
function W_T(x) | ||
return Wavelets.idwt(reshape_array(x, (n, m)), wt, 4)[:] | ||
end | ||
|
||
# Return the generated functions | ||
return H, H_T, W, W_T | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
export denoising_model | ||
|
||
include("denoising_data.jl") | ||
|
||
function denoising_model(shape, shape_p, KERNEL_SIZE, KERNEL_SIGMA = 1.5) | ||
sigma = 10^-3 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this model only work in Float64? Could There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In the literature, no one seemed to be interested by this problem at lower precision. |
||
data_path = joinpath(@__DIR__, "..", "images/cameraman.png") | ||
cameraman_image = Images.load(data_path) | ||
x_t = vec(Float64.(cameraman_image)) | ||
dpo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
H, H_T, W, W_T = generate_gaussian_blur(shape, shape_p, KERNEL_SIZE, KERNEL_SIGMA) | ||
(n, m) = shape | ||
b = H(x_t) + randn(n * m) * sigma | ||
y = similar(b) | ||
z = similar(b) | ||
|
||
function obj(x) | ||
y .= W_T(x) | ||
y .= H(y) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are there in-place versions of |
||
z .= log.((y .- b) .^ 2 .+ 1) | ||
return sum(z) | ||
end | ||
|
||
function grad!(g, x) | ||
y .= H(W_T(x)) | ||
z .= 1 ./ ((y .- b) .^ 2 .+ 1) | ||
@. z = 2 * z * (y - b) | ||
g .= W(H_T(z)) | ||
return g | ||
end | ||
|
||
x0 = W(b) | ||
|
||
FirstOrderModel(obj, grad!, x0, name = "denoing_model"), x_t | ||
end |
Uh oh!
There was an error while loading. Please reload this page.