Convolutional Sparse Coding (CSC)
CSC is defined by the optimization problem
where
\(\{ h^{(l)} \}\) is the set of convolutional dictionaries,
\(\mathbf{b}\) is the input image, and
\(\{ \mathbf{u}^{(l)} \}\) is the corresponding set of coefficient maps that encodes image \(\mathbf{b}\) via \(\{ H_l \}\).
Problem (1) is a particular case of composite unconstrained convex programming (see Section 5.2 [BCG11]), which in general can be written as
and be solved via several numerical algorithms, e.g. Douglas-Rachford splitting [EB92], forward-backward splitting [CW05], ADMM [BPC+11], FISTA [BT09], etc.
Solving (1) using the F2O's framework in the frequency domain
The corresponding code snippets for FISTA and ADMM are access via the corresponding tabs.
for k in range(nIter):
grad = computeGrad(y, args.Bf, x_sptl) # compute the gradient
# Depends on the definition of f()
alpha, grad = computeSS(k, grad, y, x_sptl) # compute step-size
x0 = x1.copy()
x_sptl = prox(irfft2( y - alpha*grad, axes=(0,1) ), alpha*lmbda)
x1 = rfft2( x_sptl, axes=(0,1) ).ravel()
t1 = iseq(k, t0) # compute inertial sequence
gamma = (t0-1)/t1
y = x1 + gamma*(x1-x0) # extrapolation step
t0 = t1
ToDo
Simulation
The collapsible items below sets up a simulation to test diferent algorithms that target the solution of (1).
Simulation setup
1. Load F2O
# Generic F2O imports
import F2O.F2O_utils as F2O
import F2O.fwOp.fwOperator as fwOp
# F2O 'utils' for reading / ploting images
from F2O.imgUtils.image_utils import ImgPlot, ImgRead
# F2O 'utils' for (i) adding noise, (ii) collecting image metrics and (iii) applying the forward model
from F2O.imgUtils.image_utils import ImgMetrics, ImgApplyFwNoise
from F2O.noise.noiseModels import noiseModels
# Other packages
import matplotlib.pylab as PLT
import numpy as np
# If you get an error while loading the F2O, then
#
# * Exit Jupyter
# * Go to the F2O root dir, and execute
# export PYTHONPATH=$PYTHONPATH:`pwd`
# * Relaunch Jupyter
---------------------------------------------------------------------------
ModuleNotFoundError Traceback (most recent call last)
/tmp/ipykernel_251/1396103323.py in <module>
1 # Generic F2O imports
----> 2 import F2O.F2O_utils as F2O
3 import F2O.fwOp.fwOperator as fwOp
4
5 # F2O 'utils' for reading / ploting images
ModuleNotFoundError: No module named 'F2O'
2. Load test images (SIPI Image database)
# Imports needed to read images from an URL address
import requests
from io import BytesIO
# Define an 'F2O-image' object
testImgs = ImgRead()
# Test images from the SIPI image database
fname = {0: requests.get('http://sipi.usc.edu/database/misc/5.2.10.tiff'), # bridge (grayscale)
1: requests.get('http://sipi.usc.edu/database/misc/boat.512.tiff'), # boat (grayscale)
2: requests.get('http://sipi.usc.edu/database/misc/4.2.03.tiff'), # mandrill (color)
}
testImgs.list.append([BytesIO(fname.get(1).content),'g'])
testImgs.list.append([BytesIO(fname.get(2).content),'c'])
u = testImgs.readListImgs() # read list of images, normalize them between 0 and 1
pltImg = ImgPlot()
pltImg.plotNImgs(u, len(u), None, 5)
3. Compute low / high pass filtered image; if any, add noise.
# Noise model
noise = noiseModels(model=F2O.f2oDef.noise_Gaussian, sigma=0.0)
addNoise = noise.sel_NoiseModel()
# Select one image from list
uObs = addNoise(u[0])
uLP, uHP = testImgs.computeLPHP( uObs , padFlag=True)
pltImg = ImgPlot()
pltImg.plotNImgs(uHP, len(uHP), None, 5)
4. Load convolutional dictionary.
# Load library to read .mat files
import scipy.io as sio
# Load pre-computed dictionary
Dict = sio.loadmat('../data/nsp_36x36x12.mat')
H = Dict['FB']
FISTA-based simulation
1. Define optimization variable; set properties for FISTA
# Load F2O specific modules
from F2O.fwOp.fwOperator import fwOp_f
from F2O.PG_freq import apg as fAPG
# Create an 'optimization variable' in freq.; set generic properties
argsF = F2O.argsF2O()
argsF.verbose = False
argsF.fCostClass = argsF.f2oDef.cost_L2L1_lin # F(x) = 0.5|| Op(x) - b ||_2^2 + \lambda||x||_1,
# where Op(.) is linear
argsF.padFlag = True
argsF.padMode = 'symmetric'
# Set Op(.) -- in this particular case, the convolutional dictionary
freqOp = fwOp_f(linOp=argsF.f2oDef.fAx_FB2D, A=H)
freqOp.label = "nsp_36x36x12"
freqOp.vecFlag = True # input / output data are asumed / force to be vectorized
1. Execute FISTA
# Set particular FISTA properties
argsF.ssPolicy = argsF.f2oDef.ss_CauchyLagged # step-size policy
argsF.ISeqPolicy = argsF.f2oDef.iseq_ntrv # inertial sequence
lmbda = 0.1
nIter = 40
x, Stats = fAPG(freqOp, uHP, lmbda, nIter, argsF)
fig = PLT.figure(figsize=(24, 16))
ax1 = fig.add_subplot(2, 1, 1)
PLT.plot(Stats[:,2], Stats[:,0], label=r'$\alpha_k$ : {0}'.format(argsF.f2oDef.ss_list[argsF.ssPolicy]) )
PLT.legend(loc='upper right',fontsize=20)
PLT.ylabel(r'$f(x) = \frac{1}{2} \|\|$Op$(\mathbf{u}) - \mathbf{b} \|\|_2^2$',fontsize=20)
PLT.xlabel('Time',fontsize=20);
imgs = []
uRec = freqOp.fRec(x, uLP, getROI=argsF.getROI )
imgs.append(uRec)
imgs.append(uRec[:,:,0]-uObs)
txt = []
txt.append('Reconstructed')
txt.append('Difference {:1.2f}'.format(np.linalg.norm(uRec.ravel() - uObs.ravel()) ) )
pltImg = ImgPlot()
pltImg.plotNImgs(imgs, len(imgs), txt, 5)