Skip to content

Commit 83596e3

Browse files
authored
Add files via upload
1 parent 74b7080 commit 83596e3

File tree

2 files changed

+230
-0
lines changed

2 files changed

+230
-0
lines changed

expose_stack_denoise.py

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# -*- coding: utf-8 -*-
2+
"""
3+
Created on Tue Jul 20 02:27:11 2021
4+
5+
@author: cosmi
6+
"""
7+
8+
import os, numpy
9+
from PIL import Image
10+
import rof
11+
from matplotlib import pyplot as plt # For image viewing
12+
13+
14+
files = os.listdir(os.getcwd())
15+
images = [name for name in files if name[-4:] in [".jpg", ".JPG"]]
16+
width, height = Image.open(images[0]).size
17+
18+
19+
stack = numpy.zeros((height, width, 3), numpy.float)
20+
counter = 1
21+
22+
#denoise source images
23+
24+
for image in images:
25+
26+
outfile = image[:-3] + "png"
27+
print( "new filename : " + outfile)
28+
29+
print ("Denoising image " + str(counter))
30+
im = numpy.array(Image.open(image).convert('L'))
31+
U,T = rof.denoise(im,im)
32+
33+
fig, ax = plt.subplots()
34+
35+
image = ax.imshow(U, cmap='gray')
36+
plt.axis('off')
37+
#Lock or Unlock Key Bar Here for Mapping/Sampling/Showcasing:
38+
#create_colorbar(fig, image)
39+
extent = ax.get_window_extent().transformed(fig.dpi_scale_trans.inverted())
40+
#imageio.imsave(outfile, ndvi)
41+
fig.savefig(outfile, dpi=600, transparent=True, bbox_inches=extent, pad_inches=0)
42+
43+
counter += 1
44+
45+
46+
47+
#stacking denoised images
48+
49+
imlist = [name for name in files if name[-4:] in [".png", ".PNG"]]
50+
width2, height2 = Image.open(imlist[0]).size
51+
52+
stack = numpy.zeros((height2, width2, 3), numpy.float)
53+
counter = 1
54+
55+
for pngimage in imlist:
56+
print ("Processing image " + str(counter))
57+
58+
image_new = numpy.array(Image.open(pngimage), dtype = numpy.float)
59+
stack = numpy.maximum(stack, image_new)
60+
counter += 1
61+
62+
stack = numpy.array(numpy.round(stack), dtype = numpy.uint8)
63+
64+
output = Image.fromarray(stack, mode = "RGB")
65+
66+
output.save("exposure_stacked_denoised_image.jpg", "JPEG")
67+
68+
69+
70+
#convert from greyscale to colour
71+
72+
#color_img = cv2.cvtColor(output, cv.CV_GRAY2RGB)

rof.py

+158
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
# -*- coding: utf-8 -*-
2+
"""
3+
Created on Wed Aug 18 00:56:27 2021
4+
5+
@author: cosmi
6+
"""
7+
import numpy as np
8+
9+
10+
def denoise(im,U_init,tolerance=0.1,tau=0.125,tv_weight=100):
11+
12+
13+
14+
"""
15+
Removing noise from images is important for many applications, from making
16+
your personal photos look better to improving the quality of satellite and increasingly
17+
drone images.
18+
19+
In image processing denoising functionally looks like we are smoothing out the image.
20+
but just what is it we are smoothing out to remove the noise?
21+
22+
The ROF model has the interesting property that it finds a smoother version
23+
of the image while preserving edges and structures.
24+
25+
The underlying mathematics of the ROF model and the solution techniques are
26+
quite advanced and are showcased fully in the paper:
27+
28+
Nonlinear total variation based noise removal algorithms*
29+
Leonid I. Rudin 1, Stanley Osher and Emad Fatemi
30+
Cognitech Inc., 2800, 28th Street, Suite 101, Santa Monica, CA 90405, USA. circa 1992.
31+
32+
Its interesting to note that the authors base their work on work done previously
33+
by Geman and Reynolds in which they propse to minimisae the non-linear functionals
34+
asscoaited with noise in the total varience by use of simulated annealing, a
35+
metaheursitics technique, which would have been very slow to do using the computers
36+
available in the late 1980s something
37+
which drove the development of the ROF denoising model in the first place.
38+
The authors wanted a fast solver that could find a reasonably good local minima
39+
rather tha the ideal global minima.
40+
41+
Here I'll give a brief,
42+
simplified introduction before showing how to implement a ROF solver based
43+
on an algorithm by Chambolle.
44+
45+
The solver used in this code is a modified version that uses grdient descent/
46+
reprojection method to achieve total variance (TV) minimization/regularization
47+
The integral of the gradient across an image, any image, will produce the total varience
48+
in tha image. now, for noisy images the total varience will be higher. knowing this,
49+
denoising techniques have been developed that essentially minimise the total varience
50+
in the matrix element of an image and then reproject that image onto the original by substracting
51+
the imaginary form of the original image matrix element which contains the residiual texture
52+
of the image. so textures are effectively removed when we want to do TV minimization/regularization.
53+
54+
55+
56+
To minimise the total varience in the matrix element different algorithms can be used
57+
but one of the most popular is gradient descent, which is simular to the simulated annealing
58+
technique originally proposed but more computationally tractable.
59+
60+
61+
in gradient descent the image matrix containing the greyscale pixel values are
62+
essentially represented as an energy surface, whereby
63+
we want to descend into the global minima. the different values in the matrix represent
64+
the interaction energies of the nearest neighbour in this 2D energy surface.
65+
different algorithms can use
66+
different equations to represent the interaction energies, depending on the rate at which
67+
the interaction energies converge to a global minima in a certain steplength of
68+
iteration of the algorithm.
69+
70+
71+
72+
Interesting Note: When implented using periodic boundary conditions the TV minimization using
73+
an iteractive gradient descent on an image performs 2 transformations on that
74+
images rectangular image domain where the greyscale pixel values exist. 2 transformations
75+
on a rectangle result in the formation of a torus in a transformation which
76+
preserves the images pixel data but changes the domain topology.
77+
78+
79+
80+
81+
An implementation of the Rudin-Osher-Fatemi (ROF) denoising model
82+
using the numerical procedure presented in equation 11 on pg 15 of
83+
A. Chambolle (2005)
84+
http://www.cmap.polytechnique.fr/preprint/repository/578.pdf
85+
86+
87+
Input:
88+
im - noisy input image (grayscale)
89+
U_init - initial guess for U
90+
tv_weight - weight of the TV-regularizing term
91+
tau - steplength in the Chambolle algorithm
92+
tolerance - tolerance for determining the stop criterion
93+
94+
Output:
95+
U - denoised and detextured image (also the primal variable)
96+
T - texture residual
97+
98+
99+
100+
101+
102+
Input: noisy input image (grayscale), initial guess for U, weight of
103+
the TV-regularizing term, steplength, tolerance for stop criterion.
104+
105+
Output: denoised and detextured image, texture residual. """
106+
107+
m,n = im.shape # size of noisy image
108+
109+
# initialize
110+
U = U_init
111+
Px = im # x-component to the dual field
112+
Py = im # y-component of the dual field
113+
error = 1
114+
iteration = 0
115+
116+
117+
118+
while (error > tolerance):
119+
Uold = U
120+
121+
# gradient of primal variable
122+
GradUx = np.roll(U,-1,axis=1)-U # x-component of U's gradient
123+
GradUy = np.roll(U,-1,axis=0)-U # y-component of U's gradient
124+
125+
# update the dual varible
126+
PxNew = Px + (tau/tv_weight)*GradUx
127+
PyNew = Py + (tau/tv_weight)*GradUy
128+
NormNew = np.maximum(1,np.sqrt(PxNew**2+PyNew**2))
129+
130+
Px = PxNew/NormNew # update of x-component (dual)
131+
Py = PyNew/NormNew # update of y-component (dual)
132+
"""
133+
the function roll(), which, as the name suggests, “rolls” the values of an array
134+
cyclically around an axis. This is very convenient for computing neighbor differences,
135+
in this case for derivatives. We also used linalg.norm(), which measures the difference
136+
between two arrays (in this case, the image matrices U and Uold).
137+
"""
138+
# update the primal variable
139+
RxPx = np.roll(Px,1,axis=1) # right x-translation of x-component
140+
RyPy = np.roll(Py,1,axis=0) # right y-translation of y-component
141+
142+
DivP = (Px-RxPx)+(Py-RyPy) # divergence of the dual field.
143+
U = im + tv_weight*DivP # update of the primal variable
144+
145+
# update of error
146+
error = np.linalg.norm(U-Uold)/np.sqrt(n*m);
147+
148+
iteration += 1;
149+
150+
#The texture residual
151+
T = im - U
152+
#print: 'Number of ROF iterations: ', iteration
153+
154+
return U,T # denoised image and texture residual
155+
156+
157+
158+

0 commit comments

Comments
 (0)