https://svn.lrde.epita.fr/svn/oln/trunk/milena
Index: ChangeLog
from Thierry Geraud <thierry.geraud(a)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;
}