1435: Augment tutorial slides and start to clean erosion.

https://svn.lrde.epita.fr/svn/oln/trunk/milena Index: ChangeLog from Thierry Geraud <thierry.geraud@lrde.epita.fr> Augment tutorial slides and start to clean erosion. * doc/tutorial/slides.tex: Augment. * mln/trait/ch_value.hh: Layout. * mln/border/resize.hh (infty): Update. * mln/border/adjust.hh: New. * mln/border/equalize.hh: New. * mln/border/all.hh: Update. * mln/win/rectangle2d.hh (area): New. * mln/win/octagon2d.hh (area): New. * mln/morpho/erosion.spe.hh: De-activate some code. Re-organize. * mln/morpho/includes.hh: Update. * mln/morpho/erosion.hh (erosion_on_set_): Fix. Add the case when the window is not centered. * tests/morpho_erosion.cc: Update. doc/tutorial/slides.tex | 1758 ++++++++++++++++++++++++++++++++++++++++++++-- mln/border/adjust.hh | 86 ++ mln/border/all.hh | 2 mln/border/equalize.hh | 117 +++ mln/border/resize.hh | 40 - mln/morpho/erosion.hh | 78 +- mln/morpho/erosion.spe.hh | 352 +++++---- mln/morpho/includes.hh | 3 mln/trait/ch_value.hh | 12 mln/win/octagon2d.hh | 10 mln/win/rectangle2d.hh | 9 tests/morpho_erosion.cc | 30 12 files changed, 2230 insertions(+), 267 deletions(-) Index: tests/morpho_erosion.cc --- tests/morpho_erosion.cc (revision 1434) +++ tests/morpho_erosion.cc (working copy) @@ -57,20 +57,36 @@ using namespace mln; using value::int_u8; - win::rectangle2d rec(21, 21); - border::thickness = 66; + unsigned + l_oct = 11, L_oct = 6 * l_oct + 1, + l_rec = 29, L_rec = 2 * l_rec + 1; + + // l_ + // oct rec err + // 0 0 3 + // 0 1 5 + // 1 2 15 + // 1 3 9 + // 2 5 11 + // 3 8 9 + // 5 13 15 + // 8 21 11 + // 11 29 1 + // 25 66 15 image2d<int_u8> lena = io::pgm::load("../img/lena.pgm"); + // trace::quiet = false; + { - image2d<int_u8> out(lena.domain()); - morpho::erosion(lena, rec, out); - io::pgm::save(out, "out1.pgm"); + win::rectangle2d rec(L_rec, L_rec); + io::pgm::save(morpho::erosion(lena, rec), + "out1.pgm"); } { - io::pgm::save(morpho::erosion(lena, - win::octagon2d(31)), + win::octagon2d oct(L_oct); + io::pgm::save(morpho::erosion(lena, oct), "out2.pgm"); } Index: doc/tutorial/slides.tex --- doc/tutorial/slides.tex (revision 1434) +++ doc/tutorial/slides.tex (working copy) @@ -85,7 +85,7 @@ \lstset{language=[ISO]C++, texcl=true, columns=fullflexible, - basicstyle={\small\sffamily}, % normal footnote small scriptsize tiny + basicstyle={\scriptsize\sffamily}, % normal footnote small scriptsize tiny commentstyle=\itshape, showstringspacesúlse, numberstyle=\tiny, @@ -120,8 +120,8 @@ -\title[Milena: A Tutorial] -{Milena: A Tutorial} +\title[Milena: A Tutorial---Part 1] +{Milena: A Tutorial---Part 1} \author[Milena Team]{Milena Team} @@ -147,6 +147,22 @@ \newcommand{\fal}{$\bullet$\xspace} \definecolor{darkgreen}{rgb}{0.1,0.7,0.1} + +\newcommand{\cpp}{{C++}\xspace} + +\newcommand{\kw}[1]{{\color{blue}{\texttt{#1}}}\xspace} +\newcommand{\code}[1]{{\scriptsize{\texttt{#1}}}\xspace} +\newcommand{\var}[1]{\texttt{#1}\xspace} + +\newcommand{\struct}{\kw{struct}} + +\newcommand{\pointIId}{\code{point2d}} + + +\newcommand{\oln}{\textsc{Olena}\xspace} +\newcommand{\mln}{\textsc{Milena}\xspace} + + %########################################################### % end of NEW! %########################################################### @@ -181,17 +197,9 @@ -% macros - -\newcommand{\oln}{\textsc{Olena}\xspace} -\newcommand{\mln}{\textsc{Milena}\xspace} - -% end of macros - - %############################################################ -\section{Part 1: Introduction} +\section{About \oln and \mln} @@ -268,13 +276,13 @@ \medskip - \textit{During 3 years we developed a prototype to experiment with + \textit{During those 3 years we developed a prototype to experiment with genericity and to try to meet our objectives.} \medskip \begin{itemize} - \item From June 2007 up to new: Re-writing of the library with a + \item From June 2007 up to now: Re-writing of the library with a programming paradigm that rocks. \end{itemize} @@ -284,12 +292,99 @@ +%........................................................................ +\begin{frame}[fragile] + \frametitle{Illustration of the Evolution} + + +\begin{minipage}{0.5\linewidth} +{\it Algorithm:}\\ +\smallskip +{\tiny +$\forall p \in \mathcal{D}(f), \;\; f(p) = \mathit{h}(f(p))$ +} + +\bigskip\medskip + +{\it In 2007:} +\smallskip +\begin{lstlisting}[basicstyle={\tiny\sffamily}] +template <typename I, typename H> +void oper(Image<I>& f_, const Function_v2v<H>& h_) +{ + I& f = exact(f); + const H& h = exact(h_); + mln_piter(I) p(f.domain()); + for_all(p) + f(p) = h(f(p)); +} + +\end{lstlisting} + +\end{minipage} + % + \hspace*{2mm} + % +\begin{minipage}{.45\linewidth} + +{\it The same code in 2000:} +\smallskip +\begin{lstlisting}[basicstyle={\tiny\sffamily}] +template< typename H, + template< class U > class get_A = get_value, + typename P = Pred_true > +struct oper +{ + template< typename I > static + void on( I& f, + P pred = P() ) + { + H h; + get_A< I::value_type > access; + I::iterator_type iter( f ); + for ( iter.first(); ! iter.isDone(); iter.next() ) + if ( pred( access( iter() ) ) ) + access( iter() ) = h( access( iter() ) ); + } +}; +\end{lstlisting} + +\end{minipage} + +\end{frame} + + + %============================== \subsection{Features of the \mln Library} + +%........................................................................ +\begin{frame}%[<+->] + \frametitle{What's In a Library} + + \begin{itemize} + \item algorithms:\\ + procedures dedicated to image processing and pattern recognition + \smallskip + % + \item data types for pixel values:\\ + e.g., gray level types, color types + \smallskip + % + \item data structures:\\ + image types or point set types for instance + \smallskip + % + \item auxiliary tools... + \end{itemize} + +\end{frame} + + %........................................................................ \begin{frame} - \frametitle{Feature List} + \frametitle{\mln as a Feature List} \begin{itemize} \item Generic... @@ -432,13 +527,13 @@ -%........................................................................ -\begin{frame} - \frametitle{\mln Documentation} +% %........................................................................ +% \begin{frame} +% \frametitle{\mln Documentation} -FIXME +% FIXME -\end{frame} +% \end{frame} @@ -494,64 +589,1602 @@ + +%........................................................................ +\begin{frame}%[<+->] + \frametitle{Why Choosing \mln?} + + \begin{itemize} + \item rather different... + \smallskip + % + \item a strong potential + \smallskip + % + \item you want to focus on what you do,\\ + not on implementation details about how to do it + \smallskip + % + \item you do not have found yet a library to easily process your + particular types of data + \end{itemize} + +\end{frame} + + + +%........................................................................ +\begin{frame}%[<+->] + \frametitle{Dev status} + + \begin{itemize} + \item alpha + \item some cleanings remain to be done + \item an intensive test phase is upcoming... + \item rough documentation (yet in progress) + \end{itemize} + +\end{frame} + + + +%############################################################" +\section{A Short Tour of \cpp} + +%........................................................................ +\begin{frame} + \frametitle{The Running Example} + + A class that represents: + \begin{itemize} + \item a discrete point of the 2D plane + \item a node of a square grid + \item a point of a ``classical'' 2D image + \item basically a couple of integer coordinates + \item namely \pointIId + \end{itemize} + +\end{frame} + + +%============================== +\subsection{Very Basic Notions} + +%........................................................................ +\begin{frame} + \frametitle{Class v. Object} + + \begin{block}{Class} + A class is a type that describes at the same time both data and behavior. + \smallskip + % + + \begin{itemize} + \item the data are described by attributes\\ + (equiv.) structure fields of a \struct + \smallskip + % + \item the behavior is described by methods\\ + (equiv.) procedures/functions attached to the class + \end{itemize} + + \end{block} + +\end{frame} + + +%........................................................................ +\begin{frame} + \frametitle{Object v. Class} + + \begin{block}{Object} + An object is an instance of a class. + \smallskip + % + + \begin{itemize} + \item the object data are a set of values: the state of the object + \smallskip + % + \item the object behavior is what happens at run-time when a + method is called on that particular object + \end{itemize} + \end{block} + +\end{frame} + + +%........................................................................ +\begin{frame} + \frametitle{Getting an Object} + + \begin{block}{Constructor} + A constructor is a special method to instantiate a class / to get + an object. + + \begin{itemize} + \item it allows for initializing the state of this object + \end{itemize} + \end{block} + +\end{frame} + + %........................................................................ \begin{frame}[fragile] - \frametitle{Illustration} + \frametitle{Example} + \begin{itemize} + \item \pointIId is a class + \item \var{p} is a variable that represents a point object + \item this variable designates one particular 2D point\\ + at a given couple of coordinates: row and column. + \end{itemize} -\begin{minipage}{0.5\linewidth} -{\it Algorithm:}\\ \smallskip -{\tiny -$\forall p \in \mathcal{D}(f), \;\; \mathit{oper}(f(p), \, c)$ -} -\bigskip\medskip +\begin{lstlisting} +point2d p(5,1); // construction of an object +std::cout << p << std::endl; // print this object on the std output +\end{lstlisting} % >> + +gives: \code{(5,1)} + +meaning that \var{p} represents the point of the 2D grid located at +row 5 and column 1. + +\end{frame} + + + +%........................................................................ +\begin{frame}[fragile] + \frametitle{Accessing the State of an Object} + + \begin{itemize} + \item data are usually protected / hidden from the user + \item reading and modifying them is performed through method calls + \end{itemize} -{\it Olena in 2007:} \smallskip -\begin{lstlisting}[basicstyle={\tiny\sffamily}] -template <typename O, typename I, typename T> -void op(Image<I>& f, T c) -{ - O oper; - oln_piter(I) p(f.domain()); - for_all(p) - oper(f(p), c); + +Here is a call to the method \code{row()} defined in the \pointIId class: + +\begin{lstlisting} +std::cout << p.row() << std::endl; // gives: 5 +\end{lstlisting} % >> + +\var{p} is the object targeted by the method call: we want to print +the row of this particular point. + +\end{frame} + + +%........................................................................ +\begin{frame}[fragile] + \frametitle{Methods are just like C functions!} + +The previous example is just the \cpp equivalent of this C code: + +\begin{lstlisting} +struct point2d { + int row, col; +}; + +int get_row(point2d p) { + return p.row; } +int main() { + point2d p; + printf("%d", get_row(p)); +} \end{lstlisting} -\end{minipage} - % - \hspace*{2mm} - % -\begin{minipage}{.45\linewidth} +\end{frame} + + + +%........................................................................ +\begin{frame}[fragile] + \frametitle{Modifying the State of an Object (1/2)} + +modifying an object is performed through method calls: + +\begin{lstlisting} +p.row() = 7; // method call +std::cout << p.row() << std::endl; // now give 7 +\end{lstlisting} % >> -{\it Olena in 2000:} \smallskip -\begin{lstlisting}[basicstyle={\tiny\sffamily}] -template< typename O, - template< class U > class get_A = get_value, - typename P = Pred_true > -struct op -{ - template< typename I > static - void on( I& f, - const get_A< I::value_type >::output_type& c, - P pred = P() ) - { - O oper; - get_A< I::value_type > access; - I::iterator_type iter( f ); - for ( iter.first(); ! iter.isDone(); iter.next() ) - if ( pred( access( iter() ) ) ) - oper( access( iter() ), c ); + +the C equivalent of this method would be: +\begin{lstlisting} +void set_row(point2d* p, int r) { + assert(p != 0); + p->row = r; +} + +int main() { + point2d p; + set_row(&p, 7); } -}; \end{lstlisting} -\end{minipage} +note that \code{p.row() = 7} looks more natural than \code{set\_row(\&p, 7)}. + +\end{frame} + + +%........................................................................ +\begin{frame}[fragile] + \frametitle{Modifying the State of an Object (2/2)} + + accessing and modifying through method calls allow for some controls: + \begin{itemize} + \item one cannot do everything with an object + \item especially putting it in an invalid state + \end{itemize} + + \smallskip + +imagine that \var{ima} is a 3$\times$3 image (starting from (0,0)) + +trying to access the image value at point \var{p}, like with: +\begin{lstlisting} +std::cout << ima(p) << std::endl; // remind that p is at a row 7... +\end{lstlisting} % >> +will hopefully produce an error at run-time! + +\end{frame} + + + +%........................................................................ +\begin{frame} + \frametitle{Operators} + + In \cpp some operators can be re-defined to get a high + expressiveness in client code. + + \begin{itemize} + \item ``\code{ima(p)}'' is a call to the parenthesis operator + defined as a method in every image class + \begin{itemize} + \item that's great, an image looks like a function from points to + values + \end{itemize} + \smallskip + % + \item \code{2 * p} calls a multiplication operator defined as a + procedure (function): + \begin{itemize} + \item this way one can easily use arithmetics over points + \item the result is a 2D point which coordinates are twice those of \var{p} + \end{itemize} + \end{itemize} + + Operators are very convenient! + +\end{frame} + + + +%============================== +\subsection{References} + + +%........................................................................ +\begin{frame} + \frametitle{Reference v. Pointer} + + A reference looks like a pointer, yet: + \begin{itemize} + \item without the pointer notations + \begin{itemize} + \item no need to take the address (with \&) of an object + \item no pointer arithmetics + \item no $->$ in use + \end{itemize} + \item it \emph{always} designates the same object + \begin{itemize} + \item one can reuse a pointer and make it points elsewhere, that's + not the case for a reference + \item it is like a ``constant pointer''\\ + ``\code{int*const}'', not ``\code{int*}'' + \item it has to be initialized + \end{itemize} + \end{itemize} + +\end{frame} + + +%........................................................................ +\begin{frame}[fragile] + \frametitle{Example (1/2)} + +This C program: + +\begin{lstlisting} +void set_row(point2d* p, int r) { + p->row = r; +} +// used with: +point2d p; +set_row(&p, 7); +\end{lstlisting} + +\smallskip + +can be re-written as: +\begin{lstlisting} +void set_row(point2d& p, int r) { + p.row = r; // no ``$->$'' here +} +// used with: +point2d p; +set_row(p, 7); +\end{lstlisting} + +\end{frame} + + +%........................................................................ +\begin{frame}[fragile] + \frametitle{Example (1/2)} + +and this one: +\begin{lstlisting} +int get_row(point2d p) { // copy of a point at procedure call + return p.row; +} +\end{lstlisting} + +\smallskip + +is better written as: +\begin{lstlisting} +int get_row(const point2d& p) { + return p.row; +} +// used with: +point2d p; +int i = get_row(p); +\end{lstlisting} +which avoids the copy of a point at function call. + +\end{frame} + + +%........................................................................ +\begin{frame}[fragile] + \frametitle{References rock!} + +Realize that with: +\begin{lstlisting} +class point2d { +public: + int& row() { return row_; } + // ... +private: + int row_, col_; +}; +\end{lstlisting} + +one can write: +\begin{lstlisting} +point2d p; +p.row() = 5; +\end{lstlisting} + +so it really performs \code{p.row\_ = 5} + +\end{frame} + + +%........................................................................ +\begin{frame}[fragile] + \frametitle{A few Remarks} + + \begin{itemize} + \item the attribute \code{row\_} of the class \code{point2d} is not + accessible from the user + \begin{itemize} + \item thanks to the keyword \kw{private} + \item writing \code{p.row\_} outside this class is not allowed (do + not compile) + \end{itemize} + \smallskip + % + \item the method \code{row()} is accessible (keyword \kw{public}) + \begin{itemize} + \item in the method body we have some room to add code + \item a simple access to data can performs some clever stuff that + you do not really have to know (neither want to)! + \end{itemize} + \end{itemize} + +\end{frame} + + + + +%============================== +\subsection{Inheritance} + + +%........................................................................ +\begin{frame}[fragile] + \frametitle{The ``Is-A'' Relationship} + + \begin{block}{Inheritance} + The inheritance between classes maps the ``is-a'' relationship. + \end{block} + +For instance, since we can say that a rabbit is an animal: +\begin{itemize} +\item it is safe to make the \code{rabbit} class inherits from the + \code{animal} one +\item we also say that: + \begin{itemize} + \item \code{rabbit} derives from \code{animal} + \item \code{animal} is a \emph{base} class for \code{rabbit} + \end{itemize} +\end{itemize} + +In \cpp we write: +\begin{lstlisting} +class animal { ... }; +class rabbit : public animal { ... }; +\end{lstlisting} + +\end{frame} + + + +%........................................................................ +\begin{frame}[fragile] + \frametitle{Using the ``Is-A'' Relationship} + + When one wants to have a procedure to feed an animal, one can write: + +\begin{lstlisting} +void feed(animal& a) { + ... +} +\end{lstlisting} + +then the following use is valid +\begin{lstlisting} +int main() { + rabbit r; + feed(r); // works fine since a rabbit ``is-an'' animal + ... +} +\end{lstlisting} + +\end{frame} + + + +%........................................................................ +\begin{frame}[fragile] + \frametitle{One Object but Several Variables and Types (1/2)} + +Considering \emph{only} the \code{feed} routine: +\begin{lstlisting} +void feed(animal& a) { + ... +} +\end{lstlisting} + +\smallskip + +we can say that: +\begin{itemize} +\item the variable \code{a} can represent an object being of any type + deriving from \code{animal} +\item it may be a \code{rabbit} + \begin{itemize} + \item yet we do not really know! + \item it might be a \code{sheep} instead... + \end{itemize} +\end{itemize} + +\smallskip + +\begin{center} + This routine is \emph{general} since it can work on objects of + different types. +\end{center} + +\end{frame} + + + +%........................................................................ +\begin{frame}[fragile] + \frametitle{One Object but Several Variables and Types (2/2)} + +Now considering the entire program, with: +\begin{lstlisting} +int main() { + rabbit r; + feed(r); // first call + sheep s; feed(s); // another call +} +\end{lstlisting} + +\begin{itemize} +\item the variable \code{r} represents an object which type is + precisely \code{rabbit} + \begin{center} + we say that it is the \emph{exact} type behind this variable + \end{center} + % +\item for the first call to \code{feed}, we know that \code{a} represents a rabbit + \begin{center} + during this execution, the \emph{exact} type of \code{a} is \code{rabbit} + \end{center} +\end{itemize} + +\end{frame} + + +%........................................................................ +\begin{frame} + \frametitle{Static type} + + \begin{block}{Static type} + \begin{itemize} + \item A variable is declared with one type. + \item This type can be read in the code; it is known at compile-time. + \item For instance, in ``\lstinline@animal& a@'': \code{a} is an animal. + \end{itemize} + + The variable type is said to be the \emph{static} type. + \end{block} + +\end{frame} + + + +%........................................................................ +\begin{frame} + \frametitle{Exact type} + + \begin{block}{Exact type} + \begin{itemize} + \item A variable represents an object. + \item Its static type can be a \textit{base} class (like in ``\lstinline@animal& a@'') + \item In that case + \begin{itemize} + \item at compile-time: there are many possible types of objects represented + \item at run-time: there is one object represented so just type. + \end{itemize} + \end{itemize} + + At run-time, the type of the object behind a variable is said to + be the \emph{exact} type. + \end{block} + +\end{frame} + + + +%........................................................................ +\begin{frame} + \frametitle{A Clue to Understand \mln} + + About ``classical'' object-orientation: + + \begin{itemize} + \item abstractions (like \code{animal}) leads to poor + performance at run-time when involved in intensive scientific code. + % + \item it is due to the fact that the exact type is lost\\ + (the \kw{virtual} keyword has an effective cost) + \end{itemize} + + \smallskip + + The clue: + + \begin{itemize} + \item genericity leads to dedicated code, thus it is efficient at run-time + % + \item though we really want abstractions! + \end{itemize} + + +\end{frame} + + + +%============================== +\subsection{What a Class Can Contain} + + + +%........................................................................ +\begin{frame}[fragile] + \frametitle{Methods and Attributes} + +\begin{lstlisting} +class point2d { +public: + point2d(int r, int c) { // constructor + row_ = r; col_ = col; + } + int& operator[](unsigned i) { + assert(i < 2); + return i = 0 ? row_ : col_; + } + int row() const { return row_; } + int& row() { return row_; } + // ... +private: + int row_, col_; +} +\end{lstlisting} + +Sample use: +\begin{lstlisting} +point2d p(5, 1); +assert(p[0] = p.row()); +\end{lstlisting} + +\end{frame} + + + +%........................................................................ +\begin{frame}[fragile] + \frametitle{Values and Typedefs} + + +\begin{lstlisting} +class point2d +{ +public: + enum { dim = 2 } + typedef int coord; + // ... +} +\end{lstlisting} + +Sample use: +\begin{lstlisting} +std:::cout << point2d::dim << std::endl; // gives 2 +point2d::coord c; // \code{c} is an \code{int} +\end{lstlisting} + +{\scriptsize +At first glance, that seems weird to equip this class with \code{dim} +and \code{coord} (but is is \emph{not}!) +} + +\end{frame} + + + +%........................................................................ +\begin{frame} + \frametitle{Associated Types} + +\begin{block}{Associated Type} + A typedef (type alias) defined in a class (e.g., \code{coord} in + \code{point2d}) is called an ``\emph{associated} type.'' +\end{block} + +\smallskip +We have defined macros to access those types: +\begin{itemize} +\item given a type T, \code{mln\_something(T)} gives the associated + type \code{something} defined in \code{T} +\item example of use: \code{mln\_coord(point2d)} +\item we can see \code{mln\_coord} like a function that takes a type and returns a type +\end{itemize} + +\smallskip + +\tiny{\code{mln\_something(T)} is for a \kw{template}d piece of + code,\\ whereas \code{mln\_something\_(T)} is for a + \emph{non}-\kw{template}d code} + +\end{frame} + + + +%############################################################" +\section{Genericity in \cpp} + + +%============================== +\subsection{Genericity for Routines} + + +%........................................................................ +\begin{frame} + \frametitle{About Naming} + + \begin{center} + \begin{tabular}{|c|c|} + \hline + we say & a C or \cpp user says \\ + \hline \hline + attribute & a field (C) or member (\cpp) \\ + procedure & function \\ + method & a member function \\ + \hline + \end{tabular} + \end{center} + +\smallskip + +In the following: +\begin{block}{routine} + A \emph{routine} designates either a procedure (function) or a + method (a member function). +\end{block} + +\end{frame} + + +%........................................................................ +\begin{frame}[fragile] + \frametitle{A rationale for Genericity} + +Suppose that you want a routine that computes twice the input: +\begin{lstlisting} +int twice(int i) { return 2 * i; } +\end{lstlisting} + +Suppose now that you want the ``\code{twice}'' operation to work also +with values of type \kw{float}. + +\begin{itemize} +\item you can rely on \emph{overloading} +\item that is the ability of defining several versions of a function + \begin{itemize} + \item having the \emph{same} name + \item but different signatures + \end{itemize} +\end{itemize} + +Precisely, you write: +\begin{lstlisting} +int twice(int i) { return 2 * i; } +float twice(float f) { return 2 * f; } +\end{lstlisting} + +\end{frame} + + +%........................................................................ +\begin{frame} + \frametitle{Overloading is Limited} + +This code is quite poor: + +\begin{itemize} +\item it is redundant + \begin{itemize} + \item tedious to write (copy-paste, many lines at end) + \item thus error-prone + \end{itemize} + \smallskip + % +\item it is still limited to \code{int} and \code{float} + \smallskip + % +\item so it is not re-usable! + \begin{itemize} + \item understand that ``\code{twice}'' should be able to work with + \pointIId too + \end{itemize} +\end{itemize} + +Though overload is great; think of \code{operator*}... + +\end{frame} + + +%........................................................................ +\begin{frame}[fragile] + \frametitle{We Want Genericity} + +Actually +\begin{center} + for every type \code{T}, \code{twice} a value \code{t} of type + \code{T} returns \code{2 * t} which is of type \code{T} +\end{center} + +So this procedure definition looks like +\begin{lstlisting} +// ... +T twice(T t) { + return t; +} +\end{lstlisting} +except that we have to say first what \code{T} is: +\begin{lstlisting} +template <typename T> +T twice(T t) { + return t; +} +\end{lstlisting} + +\end{frame} + + +%........................................................................ +\begin{frame}[fragile] + \frametitle{Syntax of Genericity} + +In \lstinline@template <typename T> T twice(T t)@ +% +\begin{itemize} +\item the declaration ``\code{<typename T>}'' is very similar to the + one of the procedure argument ``\code{(T t)}'' +% +\item the nature of \code{t} is \code{T}, the nature of \code{T} is + \code{typename} (so designates a type) +% +\item the \cpp keyword introducing a generic piece of code is + \kw{template} + \begin{itemize} + \item it can be read as ``for all'' (the universal quantifier $\forall$)\\ + so you read here: ``for all $<$type T$>$, we have...'' + \item the definition (symbolized by ``...'') follows a classical + \cpp syntax + \end{itemize} +% +\item yet the major difference is that: + \begin{center} + \code{t} is valued at \emph{run-time}, whereas \code{T} is valued at compile-time + \end{center} +\end{itemize} + +\end{frame} + + +%........................................................................ +\begin{frame}[fragile] + \frametitle{Use of a Generic Procedure} + +With +\begin{lstlisting} +int main() { + int i = 1, j; + j = twice(i); // Calls twice with \code{T} being \kw{int} + float pi = 3.14, two_pi; + two_pi = twice(pi); // Calls another ``version'' of twice with \code{T} being \kw{float} +} +\end{lstlisting} + + +Once this program is compiled +\begin{itemize} +\item two different versions of \code{twice} cohabits: + \begin{itemize} + \item \code{int twice(int t) { return 2 * t; }} and + \item \code{float twice(float t) { return 2 * t; }} + \end{itemize} +\item so it is not so different than with overloading +\end{itemize} + +except that: +\begin{center} + this generic definition of \code{twice} is \emph{reusable} +\end{center} + +\end{frame} + + +%........................................................................ +\begin{frame}[fragile] + \frametitle{Generic Procedures and Reusability} + +Precisely +\begin{itemize} +\item the generic definition of a procedure is written once +\item and is possibly usable in a large number of different versions +\end{itemize} + +If the client wants to write this kind of use: +\begin{lstlisting} +point2d p(2,3), pp; +pp = twice(p); +std::cout << pp << std::endl; // writes (4,6) +\end{lstlisting} % >> +it also works! + +\end{frame} + + +% HERE + + +%........................................................................ +\begin{frame} + \frametitle{Exercise} + +Consider this mathematical parameterized function: +$$ +\forall a \in \mathbb{Z}, \; +f_a: \left\{ + \begin{array}{lll} + \mathbb{R} &\rightarrow & \mathbb{R} \\ + x & \leadsto & \cos(a x) + \end{array} +\right. +$$ + +\begin{itemize} +\item how can it be translated in \cpp? +\item how can a call to such a function work? +\end{itemize} + +\end{frame} + + + +%============================== +\subsection{Genericity for Classes} + + +%........................................................................ +\begin{frame}[fragile] + \frametitle{A First Generic Class} + + We want to define a class to represent couples of values, whatever + their respective type is; it gives: + +\begin{lstlisting} +template <typename T1, typename T2> +struct pair { + T1 first; + T2 second; +}; +\end{lstlisting} + +\smallskip + +A sample use is: +\begin{lstlisting} +pair<float, int> c; +c.first = 3.14, c.second = 3; +\end{lstlisting} + +Another possible use is: +\begin{lstlisting} +pair<bool, point2d> c; +c.first = true, c.second = p; +\end{lstlisting} + +\end{frame} + + +%........................................................................ +\begin{frame}[fragile] + \frametitle{Exercise} + +Consider this: +\begin{lstlisting} +template <typename T1, typename T2> +struct pair +{ + template <typename S> + void operator*=(S scalar) + { + first *= scalar; + second *= scalar; + } + T1 first; + T2 second; +}; +\end{lstlisting} + +\smallskip + +\begin{itemize} +\item explain what you see +\item then write a program to use this class +\end{itemize} + +\end{frame} + + + + +%############################################################" +\section{Understanding \mln} + + +%........................................................................ +\begin{frame}[fragile] + \frametitle{Forewords (1/2)} + +We want some arithmetics over points: +\begin{itemize} +\item a ``delta-point'' is a difference between two points +\item a point + (plus) a delta-point gives a point +\item the addition (resp. subtraction) of a couple of delta-points gives a delta-point. +\end{itemize} + +\smallskip + +For instance +\begin{lstlisting} +point2d p(4, -1); +dpoint2d dp(1, 2); // \code{dpoint} is ``delta-point'' for short +std::cout << (p + dp) << std::endl; // gives (5, 1) +\end{lstlisting} + +\end{frame} + + +%........................................................................ +\begin{frame} + \frametitle{Forewords (2/2)} + +Our objectives: + +\begin{itemize} +\item write the \code{operator+} (resp. '-') routine corresponding to\\ + \begin{center} + ``a \code{point2d} ~+~ a \code{dpoint2d} $~\rightarrow~$ a \code{point2d}'' + \end{center} + % +\item understand that we actually want:\\ + \begin{center} + ``any \code{point P} ~+~ a compatible \code{dpoint D} $~\rightarrow~$ a \code{point P}'' + \end{center} + \scriptsize{for instance with \code{P} and \code{D} being + respectively \code{point3d} and \code{dpoint3d}} + % +\item make different versions of operators cohabit... +\end{itemize} + +\end{frame} + + + +%============================== +\subsection{First Attempts} + + +%........................................................................ +\begin{frame}[fragile] + \frametitle{Overloading} + +\begin{lstlisting} +point2d operator+(const point2d& p, const dpoint2d& dp) +{ + point2d q(p.row() + dp.row(), p.col() + dp.col()); + return q; +} +point3d operator+(const point3d& p, const dpoint3d& dp) +{ + point3d q; + for (unsigned i = 0; i < 3; ++i) q[i] = p[i] + dp[i]; + return q; +} +\end{lstlisting} + +What do you think of that? + +\end{frame} + + + +%........................................................................ +\begin{frame}[fragile] + \frametitle{A Solution with Genericity} + +\begin{lstlisting} +template <typename P, typename D> +P operator+(const P& p, const D& dp) +{ + P q; + for (unsigned i = 0; i < P::dim; ++i) + q[i] = p[i] + dp[i]; + return q; +} +\end{lstlisting} + +\end{frame} + + +%........................................................................ +\begin{frame}[fragile] + \frametitle{Continuing with Genericity} + +Now the subtraction: + +\begin{lstlisting} +template <typename P> +? operator-(const P& p1, const P& p2) +{ + ? dp; + for (unsigned i = 0; i < P::dim; ++i) + dp[i] = p1[i] - p2[i]; + return dp; +} +\end{lstlisting} + +What shall we write instead of the question mark? + +\end{frame} + + +%........................................................................ +\begin{frame}[fragile] + \frametitle{Solution} + +\begin{lstlisting} +template <typename P> +mln_dpoint(P) operator-(const P& p1, const P& p2) +{ + mln_dpoint(P) dp; + for (unsigned i = 0; i < P::dim; ++i) + dp[i] = p1[i] - p2[i]; + return dp; +} +\end{lstlisting} + +\end{frame} + + +%........................................................................ +\begin{frame}[fragile] + \frametitle{Make Things Better} + +In the addition: + +\begin{lstlisting} +template <typename P, typename D> +P operator+(const P& p, const D& dp) +{ + P q; + // accessing the dimension is really useful: + for (unsigned i = 0; i < P::dim; ++i) + q[i] = p[i] + dp[i]; + return q; +} +\end{lstlisting} + +How can we ensure that the delta-point type \code{D} really correspond +to \code{P}? {\scriptsize (we really do not want \code{P} and + \code{D} resp. being \code{point3d} and \code{dpoint2d}!)} + +\end{frame} + + +%........................................................................ +\begin{frame}[fragile] + \frametitle{Solution} + +\begin{lstlisting} +template <typename P> +P operator+(const P& p, const mln_dpoint(P)& dp) +{ + ... +} +\end{lstlisting} + +\end{frame} + + + +%........................................................................ +\begin{frame}[fragile] + \frametitle{Cohabitation is Hard} + +Consider: + +\begin{lstlisting} +template <typename D> +D operator+(const D& dp1, const D& dp2) { + ... // addition of a couple of delta-points +} + +template <typename I> +I operator+(const I& ima1, const I& ima2) { + ... // addition of a couple of images +} +\end{lstlisting} + +What is the problem? (Hint: read both signatures in natural language) + +\end{frame} + + + +%============================== +\subsection{\mln Programming Paradigm} + + +%........................................................................ +\begin{frame}[fragile] + \frametitle{``Classical'' Object-Orientation} + +In ``classical'' OO programming (OOP), we would write: +\begin{lstlisting} +Dpoint operator+(const Dpoint& dp1, const Dpoint& dp2) { + ... // addition of a couple of delta-points +} + +Image operator+(const Image& ima1, const Image& ima2) { + ... // addition of a couple of images +} +\end{lstlisting} +which is clearly not ambiguous (but slow at run-time...) + +where \code{Dpoint} and \code{Image} are abstract class. + +\end{frame} + + +%........................................................................ +\begin{frame}[fragile] + \frametitle{Between OOP and Genericity} + +Can we try to mix OOP and Generic Programming (GP)? + +\medskip + +That is, getting something between: + +\begin{lstlisting} +Dpoint operator+(const Dpoint& dp1, const Dpoint& dp2) { + ... +} +\end{lstlisting} +and +\begin{lstlisting} +template <typename D> +D operator+(const D& dp1, const D& dp2) { + ... +} +\end{lstlisting} + +\end{frame} + + + +%........................................................................ +\begin{frame}[fragile] + \frametitle{\mln Paradigm} + +Yes: + +\begin{lstlisting} +template <typename D> +D operator+(const Dpoint<D>& dp1, const Dpoint<D>& dp2) { + ... +} +\end{lstlisting} + +\begin{center} + here \code{dp1} is a delta-point (\code{Dpoint}) of type \code{D} +\end{center} + +\medskip + +\begin{itemize} +\item it is not ambiguous at compile-time +\item it is efficient at run-time\\ + \scriptsize{} +\end{itemize} + +\end{frame} + + +%........................................................................ +\begin{frame}[fragile] + \frametitle{Reading a \mln Signature of Routine} + +\begin{lstlisting} +template <typename D> +D operator+(const Dpoint<D>& dp1, const Dpoint<D>& dp2) { + ... +} +\end{lstlisting} + +\medskip + +\begin{center} + The \code{operator+} takes a couple of \code{Dpoint} of type + \code{D} and returns the same type. +\end{center} + +\end{frame} + + + +%============================== +\subsection{How does it Work} + + +%........................................................................ +\begin{frame}[fragile] + \frametitle{Reading Again} + +In \mln: +\begin{center} + when we have something like ``\lstinline@Point<P>& p@'' \\ + it means that \code{p} is actually a point of type \code{P} +\end{center} + +For instance, if the type of \code{p} is \code{point2d}, then +``another'' type for \code{p} is \lstinline@Point<point2d>@. + +\smallskip + +So +\begin{itemize} +\item in ``\lstinline@Point<P>& p@'', \code{P} is the \emph{exact} type of \code{p} +\item a type of point \code{P} derives from the abstraction \lstinline@Point<P>@ +\end{itemize} + +\end{frame} + + +%........................................................................ +\begin{frame}[fragile] + \frametitle{Conclusion} + +More generally: + +\begin{block}{Abstractions and Exact Types} + When a concrete class \code{T} is related to an abstraction named \code{Abstraction}, + then \code{T} derives from \lstinline@Abstraction<T>@. + + \smallskip + + Every abstraction in \mln has exactly one parameter, which + represents its exact type. +\end{block} + +\end{frame} + + + +%........................................................................ +\begin{frame}[fragile] + \frametitle{Examples} + + \begin{center} + \begin{tabular}{lp{5mm}l} + the class && derives from \\ + &&\\ + \lstinline@point2d@ && \lstinline@Point< point2d >@ \\ + \lstinline@point3d@ && \lstinline@Point< point3d >@ \\ + &&\\ + \lstinline@image2d<float>@ && \lstinline@Image< image2d<float> >@ \\ + \lstinline@win::rectangle@ && \lstinline@Window< win::rectangle >@ \\ + &&\\ + \lstinline@box2d@ && \lstinline@Point_Set< box2d >@ \\ + \end{tabular} + \end{center} + +\end{frame} + + + + +%........................................................................ +\begin{frame}[fragile] + \frametitle{Excerpts from \mln} + +\begin{lstlisting} +namespace level +{ + template <typename I, typename J> + void paste(const Image<I>& data, Image<J>& destination); +} +\end{lstlisting} + +\smallskip + +\begin{lstlisting} +namespace morpho +{ + template <typename I, typename W> + mln_concrete(I) erosion(const Image<I>& input, const Window<W>& win); +} +\end{lstlisting} + +\smallskip + +\begin{lstlisting} +namespace convert +{ + template <typename S> + array_p<mln_point(S)> to_array_p(const Point_Set<S>& pset); +} +\end{lstlisting} + +\end{frame} + + + +%============================== +\subsection{From Abstractions to Exact Types} + + +%........................................................................ +\begin{frame}[fragile] + \frametitle{A Hierarchy} + +We have \code{dpoint2d} + +\begin{lstlisting} +template <typename E> +class Dpoint<E> +{}; + +class dpoint2d : public Dpoint< dpoint2d > +{ +public: + int& operator[](unsigned i); + ... +}; +\end{lstlisting} + +\end{frame} + + + +%........................................................................ +\begin{frame}[fragile] + \frametitle{A Troubleshooting} + +This routine is almost (so \emph{not}) correct: +\begin{lstlisting} +template <typename D> +D operator+(const Dpoint<D>& dp1, const Dpoint<D>& dp2) +{ + D dp; + for (unsigned i = 0; i < D::dim; ++i) + dp[i] = dp1[i] + dp2[i]; + // above: \code{dp[i]} is OK + // but \code{dp1[i]} and \code{dp2[i]} do \emph{not} compile! + return dp; +} +\end{lstlisting} + +because the \code{operator[]} +\begin{itemize} +\item is defined in concrete classes like \code{dpoint2d} +\item but \emph{not} in the abstract class + \lstinline@Dpoint<dpoint2d>@ +\end{itemize} + +\end{frame} + + +%........................................................................ +\begin{frame}[fragile] + \frametitle{The \code{exact} Routine} + +This updated routine works fine: + +\begin{lstlisting} +template <typename D> +D operator+(const Dpoint<D>& dp1_, const Dpoint<D>& dp2_) +{ + const D& dp1 = exact(dp1_); // Cast to the exact type. + const D& dp2 = exact(dp2_); + D dp; + for (unsigned i = 0; i < D::dim; ++i) dp[i] = dp1[i] + dp2[i]; + return dp; +} +\end{lstlisting} + +\begin{block}{Exact} + The ``\code{exact}'' routine allows for getting a variable with the exact type of an object. +\end{block} + +\end{frame} + + + +%........................................................................ +\begin{frame}[fragile] + \frametitle{Remember about Genericity} + +When this routine is called with \code{dpoint2d} objects, then +the compiled version is this one: + +\begin{lstlisting} +dpoint2d operator+(const Dpoint<dpoint2d>& dp1_, const Dpoint<dpoint2d>& dp2_) +\end{lstlisting} + +and its definition is finally: +\begin{lstlisting} +{ + dpoint2d dp; + dp[0] = dp1[0] + dp2[0]; + dp[1] = dp1[1] + dp2[1]; + return dp; +} +\end{lstlisting} + +\end{frame} + + + +%........................................................................ +\begin{frame} + \frametitle{Conclusion} + +This routine: + \smallskip + % + +\begin{itemize} +\item is generic\\ + \scriptsize{it works for any delta-point type} + \smallskip + % +\item is fast + \scriptsize{you cannot get more efficient code} + \smallskip + % +\item is user-friendly + \scriptsize{just write ``\code{dp1 + dp2}'' to add a couple of delta-points} +\end{itemize} + +\end{frame} + + + +%........................................................................ +\begin{frame}[fragile] + \frametitle{Exercise 1} + +Explain the code below: + +\begin{lstlisting} +template <typename I> +void set(const Image<I>& ima_, const mln_point(I)& p, const mln_value(I)& v) +{ + const I& ima = exact(ima_); + ima(p) = v; +} +\end{lstlisting} + +\smallskip + +What do have we in image classes? + +\end{frame} + + +%........................................................................ +\begin{frame}[fragile] + \frametitle{Exercise 2} + +Explain the code below: + +\begin{lstlisting} +template <typename I, typename H> +void oper(Image<I>& f_, const Function_v2v<H>& h_) +{ + I& f = exact(f); + const H& h = exact(h_); + mln_piter(I) p(f.domain()); + for_all(p) + f(p) = h(f(p)); +} +\end{lstlisting} + +\smallskip + +What do have we in image classes? \end{frame} @@ -565,4 +2198,5 @@ %%% eval: (ispell-change-dictionary "american") %%% TeX-master: t -% LocalWords: IP interoperability morphers Milena +% LocalWords: IP interoperability morphers Milena dpoint mln const typename dp +% LocalWords: int coord resp OOP GP OO namespace morpho pset Index: mln/trait/ch_value.hh --- mln/trait/ch_value.hh (revision 1434) +++ mln/trait/ch_value.hh (working copy) @@ -62,18 +62,18 @@ template <typename I, typename V> struct ch_value_; // Decl. - template < template <class> class M, typename I, + template < template <class> class M, typename T, typename V > - struct ch_value_< M< tag::image_<I> >, V > + struct ch_value_< M< tag::value_<T> >, V > { - typedef M< mln_ch_value(I, V) > ret; + typedef M< V > ret; }; - template < template <class> class M, typename T, + template < template <class> class M, typename I, typename V > - struct ch_value_< M< tag::value_<T> >, V > + struct ch_value_< M< tag::image_<I> >, V > { - typedef M< V > ret; + typedef M< mln_ch_value(I, V) > ret; }; template < template <class, class> class M, typename T, typename I, Index: mln/border/resize.hh --- mln/border/resize.hh (revision 1434) +++ mln/border/resize.hh (working copy) @@ -34,77 +34,79 @@ * image. */ -# include <cstring> - # include <mln/core/concept/image.hh> # include <mln/core/clone.hh> # include <mln/level/fill.hh> -# include <mln/metal/is_not.hh> +# include <mln/metal/is.hh> # include <mln/border/get.hh> + namespace mln { namespace border { - /*! Resize the virtual (outer) border of image \p ima to at least + /*! Resize the virtual (outer) border of image \p ima to exactly * \p thickness. * * \param[in,out] ima The image whose border is to be resized. - * \param[in] thickness The expected minimum border size. + * \param[in] thickness The expected border thickness. * * \pre \p ima has to be initialized. * - * \warning If the image border already has a size greater than \p + * \warning If the image border already has the expected * thickness, this routine is a no-op. - * - * \todo Implement it. */ template <typename I> void resize(const Image<I>& ima, unsigned thickness); + # ifndef MLN_INCLUDE_ONLY namespace impl { + template <typename I> - void resize_(const I& ima_, trait::image::category::morpher, - unsigned new_border) + void resize_(trait::image::category::morpher, + const I& ima_, unsigned thickness) { - return resize ( *ima_.delegatee_(), new_border); + return resize(*ima_.delegatee_(), thickness); } - template <typename I> - void resize_(const I& ima_, trait::image::category::primary, - unsigned new_border) + void resize_(trait::image::category::primary, + const I& ima_, unsigned thickness) { I& ima = const_cast<I&> (ima_); - I src = clone(ima); - ima.resize_(new_border); - level::fill(ima, src); + mln_concrete(I) memo = clone(ima); + ima.resize_(thickness); + level::fill(ima, memo); } - } // end of namespace mln::border::resize + /// Facade. template <typename I> void resize(const Image<I>& ima_, unsigned thickness) { + trace::entering("border::resize"); mlc_is(mln_trait_image_border(I), trait::image::border::some)::check(); const I& ima = exact(ima_); mln_precondition(ima.has_data()); if (border::get(ima) = thickness) return; // No-op. + // Otherwise: do-it. + impl::resize_(mln_trait_image_category(I)(), + ima, thickness); - impl::resize_(ima, mln_trait_image_category(I)(), thickness); mln_postcondition(border::get(ima) = thickness); + trace::exiting("border::resize"); } # endif // ! MLN_INCLUDE_ONLY Index: mln/border/all.hh --- mln/border/all.hh (revision 1434) +++ mln/border/all.hh (working copy) @@ -51,6 +51,8 @@ # include <mln/border/fill.hh> # include <mln/border/mirror.hh> # include <mln/border/resize.hh> +# include <mln/border/adjust.hh> +# include <mln/border/equalize.hh> # include <mln/border/thickness.hh> Index: mln/border/adjust.hh --- mln/border/adjust.hh (revision 0) +++ mln/border/adjust.hh (revision 0) @@ -0,0 +1,86 @@ +// Copyright (C) 2007 EPITA Research and Development Laboratory +// +// This file is part of the Olena Library. This library is free +// software; you can redistribute it and/or modify it under the terms +// of the GNU General Public License version 2 as published by the +// Free Software Foundation. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this library; see the file COPYING. If not, write to +// the Free Software Foundation, 51 Franklin Street, Fifth Floor, +// Boston, MA 02111-1307, USA. +// +// As a special exception, you may use this file as part of a free +// software library without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to +// produce an executable, this file does not by itself cause the +// resulting executable to be covered by the GNU General Public +// License. This exception does not however invalidate any other +// reasons why the executable file might be covered by the GNU General +// Public License. + +#ifndef MLN_BORDER_ADJUST_HH +# define MLN_BORDER_ADJUST_HH + +/*! \file mln/border/adjust.hh + * + * \brief Define a function that adjusts the thickness of an image + * virtual border. + */ + +# include <mln/border/resize.hh> + + +namespace mln +{ + + namespace border + { + + /*! Adjust the virtual (outer) border of image \p ima so that its + * size is at least \p min_thickness. + * + * \param[in,out] ima The image whose border is to be adjusted. + * \param[in] min_thickness The expected border minimum thickness. + * + * \pre \p ima has to be initialized. + * + * \warning If the image border is already larger than \p + * min_thickness, this routine is a no-op. + */ + template <typename I> + void adjust(const Image<I>& ima, unsigned min_thickness); + + + +# ifndef MLN_INCLUDE_ONLY + + template <typename I> + void adjust(const Image<I>& ima_, unsigned min_thickness) + { + trace::entering("border::adjust"); + mlc_is(mln_trait_image_border(I), trait::image::border::some)::check(); + const I& ima = exact(ima_); + mln_precondition(ima.has_data()); + + if (border::get(ima) < min_thickness) + border::resize(ima, min_thickness); + + mln_postcondition(border::get(ima) >= min_thickness); + trace::exiting("border::adjust"); + } + +# endif // ! MLN_INCLUDE_ONLY + + } // end of namespace mln::border + +} // end of namespace mln + + +#endif // ! MLN_BORDER_ADJUST_HH Index: mln/border/equalize.hh --- mln/border/equalize.hh (revision 0) +++ mln/border/equalize.hh (revision 0) @@ -0,0 +1,117 @@ +// Copyright (C) 2007 EPITA Research and Development Laboratory +// +// This file is part of the Olena Library. This library is free +// software; you can redistribute it and/or modify it under the terms +// of the GNU General Public License version 2 as published by the +// Free Software Foundation. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this library; see the file COPYING. If not, write to +// the Free Software Foundation, 51 Franklin Street, Fifth Floor, +// Boston, MA 02111-1307, USA. +// +// As a special exception, you may use this file as part of a free +// software library without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to +// produce an executable, this file does not by itself cause the +// resulting executable to be covered by the GNU General Public +// License. This exception does not however invalidate any other +// reasons why the executable file might be covered by the GNU General +// Public License. + +#ifndef MLN_BORDER_EQUALIZE_HH +# define MLN_BORDER_EQUALIZE_HH + +/*! \file mln/border/equalize.hh + * + * \brief Define a function that equalizes the thickness of an image + * virtual border. + */ + +# include <mln/border/resize.hh> + + +namespace mln +{ + + namespace border + { + + /*! Equalize the virtual (outer) border of images \p ima1 and \p + * ima2 so that their size is equal and is at least \p min_thickness. + * + * \param[in,out] ima1 The first image whose border is to be equalizeed. + * \param[in,out] ima2 The second image whose border is to be equalizeed. + * \param[in] min_thickness The expected border minimum thickness of both images. + * + * \pre \p ima has to be initialized. + * + * \warning If both image borders already have the same thickness + * and if this thickness is larger than \p min_thickness, this + * routine is a no-op. + */ + template <typename I, typename J> + void equalize(const Image<I>& ima1, const Image<J>& ima2, + unsigned min_thickness); + + + +# ifndef MLN_INCLUDE_ONLY + + template <typename I, typename J> + void equalize(const Image<I>& ima1_, const Image<J>& ima2_, + unsigned min_thickness) + { + trace::entering("border::equalize"); + mlc_is(mln_trait_image_border(I), trait::image::border::some)::check(); + mlc_is(mln_trait_image_border(J), trait::image::border::some)::check(); + const I& ima1 = exact(ima1_); + const J& ima2 = exact(ima2_); + mln_precondition(ima1.has_data() && ima2.has_data()); + + unsigned b1 = border::get(ima1), b2 = border::get(ima2); + if (! (b1 = b2 && b2 >= min_thickness)) + // Something has to be done. + { + if (b1 < min_thickness && b2 < min_thickness) + // Both images have to be border-resized. + { + border::resize(ima1, min_thickness); + border::resize(ima2, min_thickness); + } + else + // A single image has to be border-resized with + // the other image thickness. + if (b1 < min_thickness) + { + mln_assertion(b2 >= min_thickness); + border::resize(ima1, b2); + } + else + { + mln_assertion(b2 < min_thickness); + mln_assertion(b1 >= min_thickness); + border::resize(ima2, b1); + } + } + + mln_postcondition(border::get(ima1) = border::get(ima2) && + border::get(ima1) >= min_thickness && + border::get(ima2) >= min_thickness); + trace::exiting("border::equalize"); + } + +# endif // ! MLN_INCLUDE_ONLY + + } // end of namespace mln::border + +} // end of namespace mln + + +#endif // ! MLN_BORDER_EQUALIZE_HH Index: mln/win/rectangle2d.hh --- mln/win/rectangle2d.hh (revision 1434) +++ mln/win/rectangle2d.hh (working copy) @@ -106,6 +106,10 @@ */ unsigned width() const; + /*! \brief Give the rectangle area. + */ + unsigned area() const; + /*! \brief Give the maximum coordinate gap between the window * center and a window point. */ @@ -166,6 +170,11 @@ return width_; } + unsigned rectangle2d::area() const + { + return width_ * height_; + } + unsigned rectangle2d::delta() const { return width_ > height_ ? width_ / 2 : height_ / 2; Index: mln/win/octagon2d.hh --- mln/win/octagon2d.hh (revision 1434) +++ mln/win/octagon2d.hh (working copy) @@ -114,6 +114,10 @@ */ unsigned delta() const; + /*! \brief Give the area. + */ + unsigned area() const; + /// Apply a central symmetry to the target window. octagon2d& sym(); @@ -188,6 +192,12 @@ return length_ / 2; } + unsigned octagon2d::area() const + { + unsigned l = (length_ - 1) / 6; + return l * (28 * l + 8) + 4; + } + octagon2d& octagon2d::sym() { return *this; Index: mln/morpho/erosion.spe.hh --- mln/morpho/erosion.spe.hh (revision 1434) +++ mln/morpho/erosion.spe.hh (working copy) @@ -28,6 +28,10 @@ #ifndef MLN_MORPHO_EROSION_SPE_HH # define MLN_MORPHO_EROSION_SPE_HH +# include <mln/win/octagon2d.hh> +# include <mln/win/rectangle2d.hh> + + /*! \file mln/morpho/erosion.spe.hh * * \brief Specialization for mln::morpho::erosion. @@ -68,9 +72,11 @@ namespace morpho { - // Fwd decl. - template <typename I, typename W, typename O> - void erosion(const Image<I>& input, const Window<W>& win, Image<O>& output); + // Fwd decl of the facade. + template <typename I, typename W> + mln_concrete(I) + erosion(const Image<I>& input, const Window<W>& win); + namespace impl { @@ -78,44 +84,90 @@ namespace generic { // Fwd decl. - template <typename I, typename W, typename O, typename A> - void erosion_on_function(const I& input, const W& win, O& output, A& min); + template <typename I, typename W> + mln_concrete(I) + erosion_on_function_(const I& input, const W& win); // Fwd decl. - template <typename I, typename W, typename O> - void erosion_on_set(const I& input, const W& win, O& output); + template <typename I, typename W> + mln_concrete(I) + erosion_on_set_(const I& input, const W& win); + } + + + template <typename I, typename W> + mln_concrete(I) + erosion_iterative_(trait::image::kind::any, + trait::image::speed::any, + const I& input, const W& win) + { + return generic::erosion_on_function_(input, win); } - template <typename I, typename W, typename O, typename A> - void erosion_on_function_fast(const I& input, const W& win, O& output, A& min) + template <typename I, typename W> + mln_concrete(I) + erosion_iterative_(trait::image::kind::any, + trait::image::speed::fastest, + const I& input, const W& win) { - trace::entering("morpho::impl::erosion_on_function_fast"); + trace::entering("morpho::impl::erosion_iterative_(kind::any, speed::fastest)"); + + border::adjust(input, win.delta()); + + typedef mln_concrete(I) O; + O output; + initialize(output, input); + mln_assertion(border::get(output) = border::get(input)); + border::fill(input, mln_max(mln_value(I))); mln_pixter(const I) p(input); - mln_pixter(O) p_out(output); + mln_pixter(O) o(output); mln_qixter(const I, W) q(p, win); - for_all_2(p, p_out) + accu::min_<mln_value(I)> min; + for_all_2(p, o) { min.init(); for_all(q) min.take(q.val()); - p_out.val() = min.to_result(); + o.val() = min.to_result(); } - trace::exiting("morpho::impl::erosion_on_function_fast"); + trace::exiting("morpho::impl::erosion_iterative_(kind::any, speed::fastest)"); + return output; } - template <typename I, typename W, typename O> - void erosion_on_set_fast(const I& input, const W& win, O& output) + + template <typename I, typename W> + mln_concrete(I) + erosion_iterative_(trait::image::kind::logic, + trait::image::speed::any, + const I& input, const W& win) { - trace::entering("morpho::impl::erosion_on_set_fast"); - level::fill(output, input); + return generic::erosion_on_set_(input, win); + } + + + template <typename I, typename W> + mln_concrete(I) + erosion_iterative_(trait::image::kind::logic, + trait::image::speed::fastest, + const I& input, const W& win) + { + trace::entering("morpho::impl::erosion_iterative_(kind::logic, speed::fastest)"); + + border::adjust(input, win.delta()); border::fill(input, true); + typedef mln_concrete(I) O; + O output; mln_pixter(const I) p(input); mln_pixter(O) p_out(output); mln_qixter(const I, W) q(p, win); + + if (win.is_centered()) + { + output = clone(input); for_all_2(p, p_out) if (p.val()) for_all(q) @@ -124,165 +176,189 @@ p_out.val() = false; break; } - trace::exiting("morpho::impl::erosion_on_set_fast"); } - - - // Stage 5: dispatch w.r.t. fast property - // | - // V - - template <typename I, typename W, typename O> - void erosion_set_wrt_fast(trait::image::speed::any, const I& input, - const W& win, O& output) + else { - generic::erosion_on_set(input, win, output); - } + initialize(output, input); + level::fill(output, input); - template <typename I, typename W, typename O> - void erosion_set_wrt_fast(trait::image::speed::fastest, const I& input, - const W& win, O& output) - { - impl::erosion_on_set_fast(input, win, output); + for_all_2(p, p_out) + for_all(q) + if (! q.val()) + break; + p_out.val() = ! q.is_valid(); } - template <typename I, typename W, typename O, typename A> - void erosion_fun_wrt_fast(trait::image::speed::any, const I& input, - const W& win, O& output, A& min) - { - generic::erosion_on_function(input, win, output, min); + trace::exiting("morpho::impl::erosion_iterative_(kind::logic, speed::fastest)"); + return output; } - template <typename I, typename W, typename O, typename A> - void erosion_fun_wrt_fast(trait::image::speed::fastest, const I& input, - const W& win, O& output, A& min) + // Facade. + + template <typename I, typename W> + mln_concrete(I) + erosion_iterative_(const I& input, const W& win) { - impl::erosion_on_function_fast(input, win, output, min); + return erosion_iterative_(mln_trait_image_kind(I)(), + mln_trait_image_speed(I)(), + input, win); } - // ^ - // | - // end of stage 5 (dispatch w.r.t. fast property) - // Stage 4: dispatch w.r.t. data quantification - // | - // V - template <typename I, typename W, typename O> - void erosion_wrt_data(trait::image::quant::high, const I& input, - const W& win, O& output) - { - accu::min_<mln_value(I)> min; - impl::erosion_fun_wrt_fast(mln_trait_image_speed(I)(), input, - win, output, min); - } - template <typename I, typename W, typename O> - void erosion_wrt_data(trait::image::quant::low, const I& input, - const W& win, O& output) - { - accu::min_h<mln_vset(I)> min; - impl::erosion_fun_wrt_fast(mln_trait_image_speed(I)(), input, - win, output, min); - } + // // Old code. - // ^ - // | - // end of stage 4 (dispatch w.r.t. the data quantification) - // Stage 3: dispatch w.r.t. the value type - // | - // V - template <typename I, typename W, typename O> - void erosion_wrt_value(const I& input, const W& win, O& output) - { - if (mlc_is(mln_trait_image_kind(I), trait::image::kind::logic)::value) - impl::erosion_set_wrt_fast(mln_trait_image_speed(I)(), input, - win, output); - // | - // `--> call stage 5: dispatch w.r.t. fast property - else - impl::erosion_wrt_data(mln_trait_image_quant(I)(), input, - win, output); - // | - // `--> call stage 4: dispatch w.r.t. the data quantification - } + // // Stage 5: dispatch w.r.t. fast property + // // | + // // V - // ^ - // | - // end of stage 3 (dispatch w.r.t. the value type) + // template <typename I, typename W, typename O> + // void erosion_set_wrt_fast(trait::image::speed::any, const I& input, + // const W& win, O& output) + // { + // generic::erosion_on_set(input, win, output); + // } + // template <typename I, typename W, typename O> + // void erosion_set_wrt_fast(trait::image::speed::fastest, const I& input, + // const W& win, O& output) + // { + // impl::erosion_on_set_fast(input, win, output); + // } + // template <typename I, typename W, typename O, typename A> + // void erosion_fun_wrt_fast(trait::image::speed::any, const I& input, + // const W& win, O& output, A& min) + // { + // generic::erosion_on_function(input, win, output, min); + // } - // Stage 2: dispatch w.r.t. the window morphology - // | - // V + // template <typename I, typename W, typename O, typename A> + // void erosion_fun_wrt_fast(trait::image::speed::fastest, const I& input, + // const W& win, O& output, A& min) + // { + // impl::erosion_on_function_fast(input, win, output, min); + // } - template <typename I, typename W, typename O> - void erosion_wrt_mor(const I& input, const W& win, O& output) - { - // FIXME : Choose the right algorithm between : - impl::erosion_wrt_value(input, win, output); - // and : - // impl::erosion_incr_wrt_value(input, win, output); - } + // // ^ + // // | + // // end of stage 5 (dispatch w.r.t. fast property) - // ^ - // | - // end of stage 2 (dispatch w.r.t. the window morphology) + // // Stage 4: dispatch w.r.t. data quantification + // // | + // // V + // template <typename I, typename W, typename O> + // void erosion_wrt_data(trait::image::quant::high, const I& input, + // const W& win, O& output) + // { + // accu::min_<mln_value(I)> min; + // impl::erosion_fun_wrt_fast(mln_trait_image_speed(I)(), input, + // win, output, min); + // } + // template <typename I, typename W, typename O> + // void erosion_wrt_data(trait::image::quant::low, const I& input, + // const W& win, O& output) + // { + // accu::min_h<mln_vset(I)> min; + // impl::erosion_fun_wrt_fast(mln_trait_image_speed(I)(), input, + // win, output, min); + // } - // Stage 1: dispatch w.r.t. the window type. - // | - // V + // // ^ + // // | + // // end of stage 4 (dispatch w.r.t. the data quantification) - template <typename I, typename W, typename O> - void erosion_wrt_win(const Image<I>& input_, const W& win_, Image<O>& output_) - { - const I& input = exact(input_); - const W& win = exact(win_); - O& output = exact(output_); + // // Stage 3: dispatch w.r.t. the value type + // // | + // // V - impl::erosion_wrt_mor(input, win, output); - // | - // `--> call stage 2: dispatch w.r.t. the data quantification - } + // template <typename I, typename W, typename O> + // void erosion_wrt_value(const I& input, const W& win, O& output) + // { + // if (mlc_is(mln_trait_image_kind(I), trait::image::kind::logic)::value) + // impl::erosion_set_wrt_fast(mln_trait_image_speed(I)(), input, + // win, output); + // // | + // // `--> call stage 5: dispatch w.r.t. fast property + // else + // impl::erosion_wrt_data(mln_trait_image_quant(I)(), input, + // win, output); + // // | + // // `--> call stage 4: dispatch w.r.t. the data quantification + // } -# ifdef MLN_CORE_WIN_RECTANGLE2D_HH + // // ^ + // // | + // // end of stage 3 (dispatch w.r.t. the value type) - template <typename I, typename O> - void erosion_wrt_win(const Image<I>& input, const win::rectangle2d& win, Image<O>& output) + + + // // Stage 2: dispatch w.r.t. the window morphology + // // | + // // V + + // template <typename I, typename W, typename O> + // void erosion_wrt_mor(const I& input, const W& win, O& output) + // { + // // FIXME : Choose the right algorithm between : + // impl::erosion_wrt_value(input, win, output); + // // and : + // // impl::erosion_incr_wrt_value(input, win, output); + // } + + // // ^ + // // | + // // end of stage 2 (dispatch w.r.t. the window morphology) + + + + + + template <typename I, typename W> + mln_concrete(I) + erosion_(const I& input, const W& win) { - O temp(exact(output).domain()); - morpho::erosion(input, win::hline2d(win.width()), temp); - morpho::erosion(temp, win::vline2d(win.height()), output); + // FIXME + return impl::erosion_iterative_(input, win); } -# endif // MLN_CORE_WIN_RECTANGLE2D_HH + template <typename I> + mln_concrete(I) + erosion_(const I& input, const win::rectangle2d& win) + { + trace::entering("morpho::impl::erosion_(win::rectangle2d)"); + + mln_concrete(I) temp, output; + temp = morpho::erosion(input, win::hline2d(win.width())); + output = morpho::erosion(temp, win::vline2d(win.height())); -# ifdef MLN_CORE_WIN_OCTAGON2D_HH + trace::exiting("morpho::impl::erosion_(win::rectangle2d)"); + return output; + } - template <typename I, typename O> - void erosion_wrt_win(const Image<I>& input, const win::octagon2d& win, Image<O>& output) + + template <typename I> + mln_concrete(I) + erosion_(const I& input, const win::octagon2d& win) { + trace::entering("morpho::impl::erosion_(win::octagon2d)"); const unsigned len = win.length() / 3 + 1; - O temp1(exact(output).domain()); - O temp2(exact(output).domain()); - morpho::erosion(input, win::hline2d(len), temp1); - morpho::erosion(temp1, win::vline2d(len), temp2); - morpho::erosion(temp2, win::diag2d(len), temp1); - morpho::erosion(temp1, win::backdiag2d(len), output); - } + mln_concrete(I) temp_1, temp_2, output; + temp_1 = morpho::erosion(input, win::hline2d(len)); + temp_2 = morpho::erosion(temp_1, win::vline2d(len)); + temp_1 = morpho::erosion(temp_2, win::diag2d(len)); + output = morpho::erosion(temp_1, win::backdiag2d(len)); -# endif // MLN_CORE_WIN_OCTAGON2D_HH - - // ^ - // | - // end of stage 1 (dispatch w.r.t. the window type) + trace::exiting("morpho::impl::erosion_(win::octagon2d)"); + return output; + } Index: mln/morpho/includes.hh --- mln/morpho/includes.hh (revision 1434) +++ mln/morpho/includes.hh (working copy) @@ -51,8 +51,7 @@ # include <mln/level/fill.hh> # include <mln/test/positive.hh> -# include <mln/border/resize.hh> -# include <mln/border/fill.hh> +# include <mln/border/all.hh> # include <mln/geom/sym.hh> # include <mln/set/inter.hh> Index: mln/morpho/erosion.hh --- mln/morpho/erosion.hh (revision 1434) +++ mln/morpho/erosion.hh (working copy) @@ -31,7 +31,6 @@ /*! \file mln/morpho/erosion.hh * * \brief Morphological erosion. - * */ # include <mln/morpho/includes.hh> @@ -47,15 +46,7 @@ { /*! Morphological erosion. - * - * \todo Overload erosion_wrt_win for hline and vline and for fast - * images. */ - template <typename I, typename W, typename O> - void erosion(const Image<I>& input, const Window<W>& win, Image<O>& output); - - - // FIXME: Doc! template <typename I, typename W> mln_concrete(I) erosion(const Image<I>& input, const Window<W>& win); @@ -66,15 +57,21 @@ namespace impl { - namespace generic { + // On function. - template <typename I, typename W, typename O, typename A> - void erosion_on_function(const I& input, const W& win, O& output, A& min) + template <typename I, typename W> + mln_concrete(I) + erosion_on_function_(const I& input, const W& win) { - trace::entering("morpho::impl::generic::erosion_on_function"); + trace::entering("morpho::impl::generic::erosion_on_function_"); + + mln_concrete(I) output; + initialize(output, input); + + accu::min_<mln_value(I)> min; mln_piter(I) p(input.domain()); mln_qiter(W) q(win, p); for_all(p) @@ -82,21 +79,28 @@ min.init(); for_all(q) if (input.has(q)) min.take(input(q)); - output(p) = min.to_result(); + output(p) = min; } - trace::exiting("morpho::impl::generic::erosion_on_function"); + + trace::exiting("morpho::impl::generic::erosion_on_function_"); + return output; } // On set. - template <typename I, typename W, typename O> - void erosion_on_set(const I& input, const W& win, O& output) + template <typename I, typename W> + mln_concrete(I) + erosion_on_set_(const I& input, const W& win) { - trace::entering("morpho::impl::generic::erosion_on_set"); - level::fill(output, input); + trace::entering("morpho::impl::generic::erosion_on_set_"); mln_piter(I) p(input.domain()); mln_qiter(W) q(win, p); + mln_concrete(I) output; + + if (win.is_centered()) + { + output = clone(input); for_all(p) if (input(p)) for_all(q) if (input.has(q)) @@ -105,7 +109,23 @@ output(p) = false; break; } - trace::exiting("morpho::impl::generic::erosion_on_set"); + } + else + { + initialize(output, input); + for_all(p) + { + for_all(q) if (input.has(q)) + if (! input(q)) + break; + // If there was no break (so q is not valid) then + // output(p) <- true; otherwise, output(p) <- false. + output(p) = ! q.is_valid(); + } + } + + trace::exiting("morpho::impl::generic::erosion_on_set_"); + return output; } } // end of namespace mln::morpho::impl::generic @@ -116,27 +136,19 @@ // Facades. - template <typename I, typename W, typename O> - void erosion(const Image<I>& input, const Window<W>& win, Image<O>& output) + template <typename I, typename W> + mln_concrete(I) + erosion(const Image<I>& input, const Window<W>& win) { trace::entering("morpho::erosion"); - mln_precondition(exact(output).domain() = exact(input).domain()); + mln_precondition(exact(input).has_data()); mln_precondition(! exact(win).is_empty()); - impl::erosion_wrt_win(input, exact(win), output); + mln_concrete(I) output = impl::erosion_(exact(input), exact(win)); if (exact(win).is_centered()) mln_postcondition(output <= input); trace::exiting("morpho::erosion"); - } - - template <typename I, typename W> - mln_concrete(I) - erosion(const Image<I>& input, const Window<W>& win) - { - mln_concrete(I) output; - initialize(output, input); - erosion(input, win, output); return output; }
participants (1)
-
Thierry Geraud