Greyscale ℓ2-TV Denoising

This example demonstrates the use of class tvl2.TVL2Deconv for removing Gaussian white noise from a greyscale image using Total Variation regularization with an ℓ2 data fidelity term (ℓ2-TV denoising). (This class is primarily intended for deconvolution problems, but can be applied to denoising problems by choosing an impulse filter as the blurring kernel.)

from __future__ import print_function
from builtins import input

import numpy as np

from sporco.admm import tvl2
from sporco import util
from sporco import metric
from sporco import plot
plot.config_notebook_plotting()

Load reference image.

img = util.ExampleImages().image('monarch.png', scaled=True,
                                 idxexp=np.s_[:,160:672], gray=True)

Construct test image corrupted Gaussian white noise with a 0.05 standard deviation.

np.random.seed(12345)
imgn = img + np.random.normal(0.0, 0.05, img.shape)

Set regularization parameter and options for ℓ2-TV deconvolution solver. The regularization parameter used here has been manually selected for good performance.

lmbda = 0.04
opt = tvl2.TVL2Deconv.Options({'Verbose': True, 'MaxMainIter': 200,
                               'gEvalY': False})

Create solver object and solve, returning the the denoised image imgr.

b = tvl2.TVL2Deconv(np.ones((1,1)), imgn, lmbda, opt)
imgr = b.solve()
Itn   Fnc       DFid      RegTV     r         s         ρ
----------------------------------------------------------------
   0  7.70e+02  8.17e+01  1.72e+04  6.82e-01  4.34e-01  1.80e-01
   1  6.20e+02  2.30e+02  9.75e+03  2.99e-01  1.44e-01  1.80e-01
   2  5.99e+02  2.52e+02  8.66e+03  1.71e-01  9.59e-02  2.59e-01
   3  5.90e+02  2.66e+02  8.10e+03  1.07e-01  6.85e-02  3.46e-01
   4  5.85e+02  2.68e+02  7.93e+03  7.23e-02  5.39e-02  4.33e-01
   5  5.82e+02  2.69e+02  7.82e+03  5.11e-02  4.33e-02  5.01e-01
   6  5.80e+02  2.68e+02  7.78e+03  3.77e-02  3.18e-02  5.01e-01
   7  5.78e+02  2.68e+02  7.75e+03  2.89e-02  2.27e-02  5.01e-01
   8  5.77e+02  2.68e+02  7.73e+03  2.26e-02  1.86e-02  5.66e-01
   9  5.77e+02  2.68e+02  7.72e+03  1.80e-02  1.65e-02  6.24e-01
  10  5.76e+02  2.68e+02  7.71e+03  1.46e-02  1.38e-02  6.24e-01
  11  5.76e+02  2.68e+02  7.70e+03  1.20e-02  1.10e-02  6.24e-01
  12  5.76e+02  2.68e+02  7.70e+03  1.00e-02  8.88e-03  6.24e-01
  13  5.75e+02  2.67e+02  7.70e+03  8.52e-03  7.26e-03  6.24e-01
  14  5.75e+02  2.67e+02  7.70e+03  7.32e-03  6.05e-03  6.24e-01
  15  5.75e+02  2.67e+02  7.69e+03  6.35e-03  5.48e-03  6.86e-01
  16  5.75e+02  2.67e+02  7.69e+03  5.56e-03  4.98e-03  6.86e-01
  17  5.75e+02  2.67e+02  7.69e+03  4.91e-03  4.32e-03  6.86e-01
  18  5.75e+02  2.67e+02  7.69e+03  4.37e-03  3.75e-03  6.86e-01
  19  5.75e+02  2.67e+02  7.69e+03  3.92e-03  3.22e-03  6.86e-01
  20  5.75e+02  2.67e+02  7.69e+03  3.54e-03  3.01e-03  7.57e-01
  21  5.75e+02  2.67e+02  7.69e+03  3.21e-03  2.85e-03  7.57e-01
  22  5.75e+02  2.67e+02  7.69e+03  2.92e-03  2.57e-03  7.57e-01
  23  5.75e+02  2.67e+02  7.69e+03  2.67e-03  2.29e-03  7.57e-01
  24  5.75e+02  2.67e+02  7.69e+03  2.46e-03  2.04e-03  7.57e-01
  25  5.75e+02  2.67e+02  7.69e+03  2.26e-03  1.97e-03  8.32e-01
  26  5.74e+02  2.67e+02  7.69e+03  2.09e-03  1.91e-03  8.32e-01
  27  5.74e+02  2.67e+02  7.69e+03  1.94e-03  1.71e-03  8.32e-01
  28  5.74e+02  2.67e+02  7.69e+03  1.80e-03  1.54e-03  8.32e-01
  29  5.74e+02  2.67e+02  7.69e+03  1.68e-03  1.44e-03  8.32e-01
  30  5.74e+02  2.67e+02  7.69e+03  1.57e-03  1.31e-03  8.32e-01
  31  5.74e+02  2.67e+02  7.69e+03  1.46e-03  1.28e-03  9.11e-01
  32  5.74e+02  2.67e+02  7.68e+03  1.37e-03  1.24e-03  9.11e-01
  33  5.74e+02  2.67e+02  7.68e+03  1.29e-03  1.13e-03  9.11e-01
  34  5.74e+02  2.67e+02  7.68e+03  1.21e-03  1.06e-03  9.11e-01
  35  5.74e+02  2.67e+02  7.68e+03  1.14e-03  9.87e-04  9.11e-01
  36  5.74e+02  2.67e+02  7.68e+03  1.08e-03  9.18e-04  9.11e-01
  37  5.74e+02  2.67e+02  7.68e+03  1.02e-03  8.45e-04  9.11e-01
  38  5.74e+02  2.67e+02  7.68e+03  9.62e-04  8.25e-04  1.00e+00
----------------------------------------------------------------

Display solve time and denoising performance.

print("TVL2Deconv solve time: %5.2f s" % b.timer.elapsed('solve'))
print("Noisy image PSNR:    %5.2f dB" % metric.psnr(img, imgn))
print("Denoised image PSNR: %5.2f dB" % metric.psnr(img, imgr))
TVL2Deconv solve time:  6.24 s
Noisy image PSNR:    25.04 dB
Denoised image PSNR: 32.45 dB

Display reference, corrupted, and denoised images.

fig = plot.figure(figsize=(20, 5))
plot.subplot(1, 3, 1)
plot.imview(img, title='Reference', fig=fig)
plot.subplot(1, 3, 2)
plot.imview(imgn, title='Corrupted', fig=fig)
plot.subplot(1, 3, 3)
plot.imview(imgr, title=r'Restored ($\ell_2$-TV)', fig=fig)
fig.show()
../../_images/tvl2dcn_den_13_0.png

Get iterations statistics from solver object and plot functional value, ADMM primary and dual residuals, and automatically adjusted ADMM penalty parameter against the iteration number.

its = b.getitstat()
fig = plot.figure(figsize=(20, 5))
plot.subplot(1, 3, 1)
plot.plot(its.ObjFun, xlbl='Iterations', ylbl='Functional', fig=fig)
plot.subplot(1, 3, 2)
plot.plot(np.vstack((its.PrimalRsdl, its.DualRsdl)).T,
          ptyp='semilogy', xlbl='Iterations', ylbl='Residual',
          lgnd=['Primal', 'Dual'], fig=fig)
plot.subplot(1, 3, 3)
plot.plot(its.Rho, xlbl='Iterations', ylbl='Penalty Parameter', fig=fig)
fig.show()
../../_images/tvl2dcn_den_15_0.png