#!/usr/bin/env python # coding: utf-8 # Rank Filters for Image Processing # ================================= # # *Important:* Please read the [installation page](http://gpeyre.github.io/numerical-tours/installation_python/) for details about how to install the toolboxes. # $\newcommand{\dotp}[2]{\langle #1, #2 \rangle}$ # $\newcommand{\enscond}[2]{\lbrace #1, #2 \rbrace}$ # $\newcommand{\pd}[2]{ \frac{ \partial #1}{\partial #2} }$ # $\newcommand{\umin}[1]{\underset{#1}{\min}\;}$ # $\newcommand{\umax}[1]{\underset{#1}{\max}\;}$ # $\newcommand{\umin}[1]{\underset{#1}{\min}\;}$ # $\newcommand{\uargmin}[1]{\underset{#1}{argmin}\;}$ # $\newcommand{\norm}[1]{\|#1\|}$ # $\newcommand{\abs}[1]{\left|#1\right|}$ # $\newcommand{\choice}[1]{ \left\{ \begin{array}{l} #1 \end{array} \right. }$ # $\newcommand{\pa}[1]{\left(#1\right)}$ # $\newcommand{\diag}[1]{{diag}\left( #1 \right)}$ # $\newcommand{\qandq}{\quad\text{and}\quad}$ # $\newcommand{\qwhereq}{\quad\text{where}\quad}$ # $\newcommand{\qifq}{ \quad \text{if} \quad }$ # $\newcommand{\qarrq}{ \quad \Longrightarrow \quad }$ # $\newcommand{\ZZ}{\mathbb{Z}}$ # $\newcommand{\CC}{\mathbb{C}}$ # $\newcommand{\RR}{\mathbb{R}}$ # $\newcommand{\EE}{\mathbb{E}}$ # $\newcommand{\Zz}{\mathcal{Z}}$ # $\newcommand{\Ww}{\mathcal{W}}$ # $\newcommand{\Vv}{\mathcal{V}}$ # $\newcommand{\Nn}{\mathcal{N}}$ # $\newcommand{\NN}{\mathcal{N}}$ # $\newcommand{\Hh}{\mathcal{H}}$ # $\newcommand{\Bb}{\mathcal{B}}$ # $\newcommand{\Ee}{\mathcal{E}}$ # $\newcommand{\Cc}{\mathcal{C}}$ # $\newcommand{\Gg}{\mathcal{G}}$ # $\newcommand{\Ss}{\mathcal{S}}$ # $\newcommand{\Pp}{\mathcal{P}}$ # $\newcommand{\Ff}{\mathcal{F}}$ # $\newcommand{\Xx}{\mathcal{X}}$ # $\newcommand{\Mm}{\mathcal{M}}$ # $\newcommand{\Ii}{\mathcal{I}}$ # $\newcommand{\Dd}{\mathcal{D}}$ # $\newcommand{\Ll}{\mathcal{L}}$ # $\newcommand{\Tt}{\mathcal{T}}$ # $\newcommand{\si}{\sigma}$ # $\newcommand{\al}{\alpha}$ # $\newcommand{\la}{\lambda}$ # $\newcommand{\ga}{\gamma}$ # $\newcommand{\Ga}{\Gamma}$ # $\newcommand{\La}{\Lambda}$ # $\newcommand{\si}{\sigma}$ # $\newcommand{\Si}{\Sigma}$ # $\newcommand{\be}{\beta}$ # $\newcommand{\de}{\delta}$ # $\newcommand{\De}{\Delta}$ # $\newcommand{\phi}{\varphi}$ # $\newcommand{\th}{\theta}$ # $\newcommand{\om}{\omega}$ # $\newcommand{\Om}{\Omega}$ # This numerical tour explores non-linear local filters that proceeds by # ordering the pixels in a neighboorhood and selecting a given ranked # entry. # In[1]: from __future__ import division import numpy as np import scipy as scp import pylab as pyl import matplotlib.pyplot as plt from nt_toolbox.general import * from nt_toolbox.signal import * import warnings warnings.filterwarnings('ignore') get_ipython().run_line_magic('matplotlib', 'inline') get_ipython().run_line_magic('load_ext', 'autoreload') get_ipython().run_line_magic('autoreload', '2') # Continuous Rank Filtering # ------------------------- # We consider an image $f : [0,1]^2 \rightarrow \RR$. # # # For any $\beta \in [0,1]$, we define the rank filter # $\phi_\be^B$ of order $\beta$ associated to a set $B$ to be # $$ g = \phi_\beta^B(f) # \qwhereq # g(x) = \inf \: \enscond{t \in \RR}{ # \mu( f^{-1}(]-\infty,t]) \cap x+B ) \geq \mu(B)/2 }. $$ # where $\mu$ is the Lebesgue measure on $\RR$. # # # One usually assumes that $B$ is the ball of radius $\epsilon>0$ # $$ B = B_\epsilon = \enscond{x}{\norm{x} \leq \epsilon}. $$ # # # When $\be=0$ (resp. $\be=1$, resp. # $\be=1/2$), then $g(x)$ is the miniminimum # (resp. maximum, resp. median) value of $f$ in a small neighboorhood of # radius $\epsilon$ # $$ \phi_0^{B_\epsilon}(f)(x) = \umin{\norm{y-x} \leq \epsilon} f(y), $$ # $$ \phi_{1/2}^{B_\epsilon}(f)(x) = \umax{\norm{y-x} \leq \epsilon} f(y), $$ # $$ \phi_{1}^{B_\epsilon}(f)(x) = \underset{\norm{y-x} \leq \epsilon}{\text{median}} f(y). $$ # # # The operator $\phi_\beta^B$ is contrast-invariant, meaning that it # computes with increasing functions $ \psi : \RR \rightarrow \RR $ # $$ \phi_\beta^B \circ \psi = \psi \circ \phi_\beta^B. $$ # The axiomatic study of contrast invariant operator was initiated in the # comunity of mathematical morphology, see [Matheron75](#biblio), [Tukey77](#biblio), [Serra82](#biblio). # # # Note also that there exist generalization of rank filters (and in # particular the median filter) to vector valued images # $ f : [0,1]^2 \rightarrow \RR^d$. Since the notion of rank does not # exists anymore, one has to rely on variational caracteriation of the # median, see for instance [CasSapChu00](#biblio). # # # The medial filtering is the most popular rank filter. # It is particularly efficient to remove impulse noise, # see for instance [Piterbarg84](#biblio), [FanHall94](#biblio). # See also [AriasDon99](#biblio) for a theoritical analysis of median # filtering and of a two-stage iterated version. # # Patches in Images # ----------------- # We apply rank filters to discretized images by interpreting them as # piecewise constant functions. # # # Size $N = n \times n$ of the image. # In[2]: n = 256 # We load an image $f_0 \in \RR^N$. # In[3]: f0 = load_image("nt_toolbox/data/hibiscus.bmp",n) # Display $f_0$. # In[4]: plt.figure(figsize = (5,5)) imageplot(f0) # Noise level $\si$. # In[5]: sigma = .04 # Generate a noisy image $f=f_0+\epsilon$ where $\epsilon \times # \Nn(0,\si^2\text{Id}_N)$. # In[6]: from numpy import random f = f0 + sigma*random.standard_normal((n,n)) # Display $f$. # In[7]: plt.figure(figsize = (5,5)) imageplot(clamp(f)) # For simplicity, we consider the case where # the set $B$ is a square of $w_1 \times w_2$ pixels. # where we denote $w$ to be the half width of the patches, # and $w_1=2w+1$ the full width. # In[8]: w = 3 w1 = 2*w + 1 # We define the patch extraction operator # $$ p = p_x(f) \in \RR^{w_1 \times w_1} # \qwhereq \forall -w \leq s_1,s_2 \leq w, \quad p(s) = f(x+s). $$ # # # We now define the function $\Pi(f) = (p_x(f))_x $ # that extracts all possible patches. # # # We set up large $(n,n,w_1,w_1)$ matrices to index the the X and Y # position of the pixel to extract. # In[9]: [X,Y,dX,dY] = np.meshgrid(np.arange(1,n+1),np.arange(1,n+1),np.arange(-w,w+1),np.arange(-w,w+1)) X = X + dX Y = Y + dY # We handle boundary condition by reflexion. # In[10]: X[X < 1] = 2-X[X < 1] Y[Y < 1] = 2-Y[Y < 1] X[X > n] = 2*n-X[X > n] Y[Y > n] = 2*n-Y[Y > n] # Patch extractor operator $\Pi$. # In[11]: I = (X-1) + (Y-1)*n for i in range(n//w): for j in range(n//w): I[i,j] = np.transpose(I[i,j]) Pi = lambda f: np.reshape(np.ravel(f)[I],(n,n,w1*w1)) # We store the patches $\Pi(f)$ as a $n \times n \times w_1^2$ matrix $P$ # such that, for each pixel $x$, $P(x)$ is a vector of size $w_1^2$ # storing the entries of $p_x(f)$. # In[12]: P = Pi(f) # Display some example of patches. # In[13]: from numpy import random plt.figure(figsize = (5,5)) for i in range(16): x = random.randint(n) y = random.randint(n) imageplot(np.reshape(P[x, y],(w1,w1)), '', [4, 4, i+1]) # Linear Filter # ------------- # A linear filter (convolution) can be computed using this patch # representation as # $$ g(x) = \sum_{i} \la_i p_x(f)_i. $$ # # # In the case where $\la_i=1/w_1^2$, this # defines the mean value inside the patch: # $$ g(x) = \frac{1}{w_1^2} \sum_{i} p_x(f)_i. $$ # In[14]: Pmean = lambda f: np.mean(Pi(f), 2) # Display it. # In[15]: plt.figure(figsize = (5,5)) imageplot(Pmean(f)) # Note that this is not a rank filter (this a linear filter) and that it is # not contrast invariant. This is shown by displaying # $$ \phi_\beta^B(f) - \psi^{-1} \circ \phi_\beta^B \circ \psi(f) $$ # which is non-zero. # In[16]: p = 100 psi = lambda f: f**(1/p) ipsi = lambda f: f**p plt.figure(figsize = (5,5)) imageplot(Pmean(abs(f)) - ipsi(Pmean(psi(abs(f))))) # Opening and Closing Rank Filters # -------------------------------- # We now come back to the discrete computation of a rank filter $\phi_\be^B$ # for $B$ a square of width $w_1 \times w_1$ pixels. # # # It is defined as $g=\phi_\beta^B(f)$ where # $$ g(x) = \text{rank}_{r(\beta)}( p_x(f) ) $$ # where $\text{rank}_r(v)$ extracted the element of order $k$ in the # sorted value of $v \in \RR^Q$ (here $Q=w_1^2$). More precisely, we denote # $$ v_{\si(1)} \leq v_{\si(2)} \leq \ldots \leq v_{\si(Q)} $$ # where $\si \in \Sigma_Q$ is an ordering permutation, which can be # computed in $ O(N \log(N)) $ operations with the QuickSort algorithm. # Then the ranked valued is # $$ \text{rank}_r(v) = v_{\si(r)}. $$ # # # In order to be consistent with the continuous definition of the # rank filter, one should define the rank as # $$ r=r(\beta) = \lfloor Q r \rfloor. $$ # In[17]: r = lambda beta: min(np.ceil(beta*w1*w1), w1*w1-1) # Shortcut for the rank filter. # In[18]: subsample = lambda x,s : x[: , : , s] phi = lambda f, beta: subsample(np.sort(Pi(f), 2), r(beta)) # __Exercise 1__ # # Compute the rank filter for several values of $\beta$. # In[19]: run -i nt_solutions/denoisingadv_7_rankfilters/exo1 # In[20]: ## Insert your code here. # The case $\beta=0$ corresponds to the closing operator from # mathematical morphology (min filter). # In[21]: closing = lambda f: phi(f, 0) plt.figure(figsize = (5,5)) imageplot(closing(f)) # The case $\beta=1$ corresponds to the opening operator from # mathematical morphology (max filter). # In[22]: opening = lambda f: phi(f, 1) plt.figure(figsize = (5,5)) imageplot(opening(f)) # __Exercise 2__ # # Compute a closing followed by an opening. # In[23]: run -i nt_solutions/denoisingadv_7_rankfilters/exo2 # In[24]: ## Insert your code here. # __Exercise 3__ # # Compute an opening followed by a closing. # In[25]: run -i nt_solutions/denoisingadv_7_rankfilters/exo3 # In[26]: ## Insert your code here. # __Exercise 4__ # # Perform iterated opening and closing. # In[27]: run -i nt_solutions/denoisingadv_7_rankfilters/exo4 # In[28]: ## Insert your code here. # Median Filter # ------------- # The median filter corresponds to the case where $\be=1/2$. # In[29]: medfilt = lambda f: phi(f, 1/2) # Display the result. # In[30]: plt.figure(figsize = (5,5)) imageplot(medfilt(f)) # Iterated median filtering computes # $$ f^{(\ell+1)} = \phi_{1/2}^B( f^{(\ell)} ). $$ # # In the case where $f$ is of class $C^3$ and $\nabla f(x) \neq 0$, # one has the following Taylor expansion # $$ \phi_{1/2}^{B_\epsilon}(x) = # f(x) + \frac{\epsilon^2}{6} \norm{\nabla f(x)} # \text{Curv}(f)(x) + O(\epsilon^{7/3}) $$ # where the curvature operator is # $$ \text{Curv}(f) = \text{div}\pa{ # \frac{\nabla f}{\norm{\nabla f}} # }. $$ # # # Intuitively, it means that if one iterates the operator # $ \phi_{1/2}^{B_\epsilon} $ with a proper re-scaling $\ell \leftrightarrow t$ # and when # $\epsilon \rightarrow 0$, then $f^{(\ell)}$ tends to the solution to the # famous mean-curvature motion PDE # $$ \pd{f}{t} = \norm{\nabla f} \text{Curv}(f). $$ # # # This conjecture was initially mentionned in [BeMerOsh92](#biblio). # This was rigorously proved in [Ishii95](#biblio), [BarGeorg](#biblio), # [Evans93](#biblio) using the machinery of viscosity solutions. # # # Similar result holds for other class of contrast invariant operator, see # for instance [Cao98](#biblio) for affine invariant operators, and [GuiMoRy04](#biblio) # for an axiomatic and general framework. # __Exercise 5__ # # Perform iterated median filtering, and store the output in $f_1$. # In[31]: run -i nt_solutions/denoisingadv_7_rankfilters/exo5 # In[32]: ## Insert your code here. # Display. # In[33]: plt.figure(figsize = (5,5)) imageplot(f1) # Bibliography # ------------ # # # # * [Matheron75] G. Matheron, [Random Sets and Integral Geometry][1], Wiley, New York, 1975 # * [Serra82] J. Serra, [Image Analysis and Mathematical Morphology][2], Academic Press, London, 1982 # * [Tukey77] J. W. Tukey, [Exploratory Data Analysis][3]. Addison-Wesley, Reading, MA, 1977 # * [BeMerOsh92] J. Bence, B. Merriman, S. Osher, [Diffusionn generated motion by mean curvature][4], Selected Lectures in Math. Amer. Math. Soc., Providence, 1992 # * [Cao98] F. Cao, [Partial differential equations and mathematical morphology][5]. J.Math. Pures Appl. 77 909?941, 1998 # * [Ishii95] H. Ishii, _A generalization of the Bence, Merriman and Osher algorithm for motion by mean curvature_, 1995 # * [BarGeorg] G. Barles and C. Georgelin, [A Simple Proof of Convergence for an Approximation Scheme for Computing Motions by Mean Curvature][6], SIAM J. Numer. Anal., 32(2), 484?500, 1995. # * [Evans93] L. C. Evans, [Convergence of an algorithm for mean curvature motion][7], Indiana Univ. Math. J., 42, pp. 533?557, 1993. # * [GuiMoRy04] F. Guichard, J-M. Morel and Robert Ryan, _Contrast invariant image analysis and PDE's_, 2004. # * [CasSapChu00] V. Caselles, G. Sapiro and D. H. Chung, [Vector median filters, inf-sup operations, and coupled PDEs: Theoretical connections][8]. J. Math. Imaging Vision 12 109?119, 2000 # * [Piterbarg84] L. I. Piterbarg, [Median filtering of random processes][9], Problemy Peredachi Informatsii, 20, 65?73, 1984. # * [FanHall94] J. Fan and P. Hall, [On curve estimation by minimizing mean absolute deviation and its implications][10]. Ann. Statist. 22 867?885, 1994. # * [AriasDon99] E. Arias-Castro and D. L. Donoho, [Does the median filter truly preserve edges better than linear filtering?][11], The Annals of Statistics, Vol. 37, No. 3, 1172-1206, 2009. # # # # [1]:http://books.google.fr/books/about/Random_sets_and_integral_geometry.html?hl=fr&id=bgzvAAAAMAAJ # [2]:http://dl.acm.org/citation.cfm?id=1098652 # [3]:http://books.google.fr/books/about/Exploratory_Data_Analysis.html?hl=fr&id=UT9dAAAAIAAJ # [4]:http://books.google.fr/books/about/Diffusion_Generated_Motion_by_Mean_Curva.html?id=DYi-GwAACAAJ&redir_esc=y # [5]:http://dx.doi.org/10.1016/S0021-7824(01)80003-9 # [6]:http://dx.doi.org/10.1137/0732020 # [7]:http://cat.inist.fr/?aModele=afficheN&cpsidt=3899933 # [8]:http://dx.doi.org/10.1023/A:1008310305351 # [9]:http://www.mathnet.ru/php/archive.phtml?wshow=paper&jrnid=ppi&paperid=1122&option_lang=eng # [10]:http://dx.doi.org/10.1214/aos/1176325499 # [11]:http://dx.doi.org/10.1214/08-AOS604