Olena-patches
Threads by month
- ----- 2025 -----
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- 9625 discussions
* doc/tutorial/samples/borderthickness-output.tex,
* doc/tutorial/samples/borderthickness.tex,
* doc/tutorial/samples/ima2d-4.tex,
* doc/tutorial/samples/point-1-output.tex,
* doc/tutorial/samples/point-1.tex: Fix mistakes in code sample.
* doc/tutorial/samples/ima2d-6-clone.tex: clone() is not a
method. Use a routine instead.
* doc/tutorial/samples/logical-not-output.tex,
* doc/tutorial/samples/logical-not.tex: new sample code.
* doc/tutorial/tutorial.tex: Update tutorial.
- Add a section about useful macros.
- Emphazise keywords such as variable names, method names, type
names,...
- Add a section about logical::not() routine.
---
milena/ChangeLog | 22 +
.../tutorial/samples/borderthickness-output.tex | 24 +-
milena/doc/tutorial/samples/borderthickness.tex | 23 +-
milena/doc/tutorial/samples/ima2d-4.tex | 9 +-
milena/doc/tutorial/samples/ima2d-6-clone.tex | 2 +-
milena/doc/tutorial/samples/logical-not-output.tex | 17 +
milena/doc/tutorial/samples/logical-not.tex | 31 ++
milena/doc/tutorial/samples/point-1-output.tex | 4 +-
milena/doc/tutorial/samples/point-1.tex | 17 +-
milena/doc/tutorial/tutorial.tex | 522 +++++++++++++-------
10 files changed, 470 insertions(+), 201 deletions(-)
create mode 100644 milena/doc/tutorial/samples/logical-not-output.tex
create mode 100644 milena/doc/tutorial/samples/logical-not.tex
diff --git a/milena/ChangeLog b/milena/ChangeLog
index aaab1dd..c8d3e1d 100644
--- a/milena/ChangeLog
+++ b/milena/ChangeLog
@@ -1,3 +1,25 @@
+2008-10-24 Guillaume Lazzara <z(a)lrde.epita.fr>
+
+ Update tutorial.
+
+ * doc/tutorial/samples/borderthickness-output.tex,
+ * doc/tutorial/samples/borderthickness.tex,
+ * doc/tutorial/samples/ima2d-4.tex,
+ * doc/tutorial/samples/point-1-output.tex,
+ * doc/tutorial/samples/point-1.tex: Fix mistakes in code sample.
+
+ * doc/tutorial/samples/ima2d-6-clone.tex: clone() is not a
+ method. Use a routine instead.
+
+ * doc/tutorial/samples/logical-not-output.tex,
+ * doc/tutorial/samples/logical-not.tex: new sample code.
+
+ * doc/tutorial/tutorial.tex: Update tutorial.
+ - Add a section about useful macros.
+ - Emphazise keywords such as variable names, method names, type
+ names,...
+ - Add a section about logical::not() routine.
+
2008-10-24 Thierry Geraud <thierry.geraud(a)lrde.epita.fr>
De-activate not compiling tests in level transform.
diff --git a/milena/doc/tutorial/samples/borderthickness-output.tex b/milena/doc/tutorial/samples/borderthickness-output.tex
index e1db166..201aedb 100644
--- a/milena/doc/tutorial/samples/borderthickness-output.tex
+++ b/milena/doc/tutorial/samples/borderthickness-output.tex
@@ -1,13 +1,13 @@
-ima_def - border = 3
-- - - - - - - -
-- - - - - - - -
-- - - - - - - -
-- - - - | - - -
-- - - | - - - -
-- - - - - - - -
-- - - - - - - -
-- - - - - - - -
+- - - - - - - -
+- - - - - - - -
+- - - - - - - -
+- - - - | - - -
+- - - | - - - -
+- - - - - - - -
+- - - - - - - -
+- - - - - - - -
-ima_bt0 - border = 0
-- |
-| -
+===========
+
+- |
+| -
diff --git a/milena/doc/tutorial/samples/borderthickness.tex b/milena/doc/tutorial/samples/borderthickness.tex
index d491f16..a059ba3 100644
--- a/milena/doc/tutorial/samples/borderthickness.tex
+++ b/milena/doc/tutorial/samples/borderthickness.tex
@@ -1,8 +1,17 @@
-bool vals[2][2] = { {0, 1},
- {1, 0} };
-image2d<bool> ima_def = make::image2d(vals);
-display::format(ima_def);
+#include <mln/core/image/image2d.hh>
+#include <mln/debug/println_with_border.hh>
+int main()
+{
+ using namespace mln;
-border::thickness = 0;
-image2d<bool> ima_bt0 = make::image2d(vals);
-display::format(ima_bt0);
+ bool vals[2][2] = { {0, 1},
+ {1, 0} };
+ image2d<bool> ima_def = make::image2d(vals);
+ debug::println_with_border(ima_def);
+
+ std::cout << "===========" << std::endl << std::endl;
+
+ border::thickness = 0;
+ image2d<bool> ima_bt0 = make::image2d(vals);
+ debug::println_with_border(ima_bt0);
+}
diff --git a/milena/doc/tutorial/samples/ima2d-4.tex b/milena/doc/tutorial/samples/ima2d-4.tex
index 2add937..b5417fc 100644
--- a/milena/doc/tutorial/samples/ima2d-4.tex
+++ b/milena/doc/tutorial/samples/ima2d-4.tex
@@ -1,5 +1,6 @@
-// At index (9, 9), both values change.
-imga(p) = 'M', imgb(p) = 'W';
+point2d p(9,9);
+
+// At (9, 9), both values change.
+imga(p) = 'M';
+imgb(p) = 'W';
-debug::println(imga);
-debug::println(imgb);
diff --git a/milena/doc/tutorial/samples/ima2d-6-clone.tex b/milena/doc/tutorial/samples/ima2d-6-clone.tex
index 396306a..872b93d 100644
--- a/milena/doc/tutorial/samples/ima2d-6-clone.tex
+++ b/milena/doc/tutorial/samples/ima2d-6-clone.tex
@@ -1,4 +1,4 @@
-image2d<int> ima3 = ima1.clone(); // Makes a deep copy.
+image2d<int> ima3 = clone(ima1); // Makes a deep copy.
ima3(p) = 3;
diff --git a/milena/doc/tutorial/samples/logical-not-output.tex b/milena/doc/tutorial/samples/logical-not-output.tex
new file mode 100644
index 0000000..27c6ceb
--- /dev/null
+++ b/milena/doc/tutorial/samples/logical-not-output.tex
@@ -0,0 +1,17 @@
+ima:
+| -
+- |
+
+----
+ima_neg:
+- |
+| -
+
+ima:
+| -
+- |
+
+----
+not_inplace(ima)
+- |
+| -
diff --git a/milena/doc/tutorial/samples/logical-not.tex b/milena/doc/tutorial/samples/logical-not.tex
new file mode 100644
index 0000000..ecb7748
--- /dev/null
+++ b/milena/doc/tutorial/samples/logical-not.tex
@@ -0,0 +1,31 @@
+#include <mln/core/image/image2d.hh>
+#include <mln/logical/not.hh>
+#include <mln/debug/println.hh>
+int main()
+{
+ using namespace mln;
+
+ bool vals[2][2] = {
+ {1, 0},
+ {0, 1}
+ };
+ image2d<bool> ima = make::image2d(vals);
+ std::cout << "ima:" << std::endl;
+ debug::println(ima);
+
+ std::cout << "----" << std::endl;
+
+ image2d<bool> ima_neg = logical::not_(ima);
+
+ std::cout << "ima_neg:" << std::endl;
+ debug::println(ima_neg);
+ std::cout << "ima:" << std::endl;
+ debug::println(ima);
+
+ std::cout << "----" << std::endl;
+
+ logical::not_inplace(ima);
+
+ std::cout << "not_inplace(ima)" << std::endl;
+ debug::println(ima);
+}
diff --git a/milena/doc/tutorial/samples/point-1-output.tex b/milena/doc/tutorial/samples/point-1-output.tex
index d5a3da6..39f77d0 100644
--- a/milena/doc/tutorial/samples/point-1-output.tex
+++ b/milena/doc/tutorial/samples/point-1-output.tex
@@ -1,2 +1,2 @@
-has(p1)? true
-has(p2)? false
+has(p1)? false
+has(p2)? true
diff --git a/milena/doc/tutorial/samples/point-1.tex b/milena/doc/tutorial/samples/point-1.tex
index 01163df..9efb7ec 100644
--- a/milena/doc/tutorial/samples/point-1.tex
+++ b/milena/doc/tutorial/samples/point-1.tex
@@ -1,18 +1,21 @@
-#include <core/image/image2d.hh>
-#include <core/alias/box2d.hh>
+#include <mln/core/image/image2d.hh>
+#include <mln/core/alias/box2d.hh>
int main()
{
using namespace mln;
- image2d<bool> ima(box2d(0,0, 10,10));
- mln_site(image2d<bool>) p1(9, 9);
- mln_site(image2d<bool>) p2(10, 10);
+ // Create an image on a 2D box
+ // with 10 columns and 10 rows.
+ image2d<bool> ima(make::box2d(10, 10));
+
+ mln_site_(image2d<bool>) p1(20, 20);
+ mln_site_(image2d<bool>) p2(3, 3);
std::cout << "has(p1)? "
- << (img.has(p1) ? "true" : "false")
+ << (ima.has(p1) ? "true" : "false")
<< std::endl;
std::cout << "has(p2)? "
- << (img.has(p2) ? "true" : "false")
+ << (ima.has(p2) ? "true" : "false")
<< std::endl;
}
diff --git a/milena/doc/tutorial/tutorial.tex b/milena/doc/tutorial/tutorial.tex
index d6a9226..25e9862 100644
--- a/milena/doc/tutorial/tutorial.tex
+++ b/milena/doc/tutorial/tutorial.tex
@@ -99,6 +99,25 @@ $$
%\end{latexonly}
+\newcommand{\code}[1]{%
+\textit{#1}%
+}
+\newcommand{\var}[1]{%
+\textit{$#1$}%
+}
+\newcommand{\type}[1]{%
+\textit{#1}%
+}
+\newcommand{\namespace}[1]{%
+\textit{#1}%
+}
+\newcommand{\header}[1]{%
+\textit{#1}%
+}
+\newcommand{\hpath}[1]{%
+\textit{#1}%
+}
+
\usetikzlibrary{er}
\newcommand{\neighcfour}{%
@@ -244,9 +263,9 @@ Here is also a list of common variable name conventions:
Olena is organized in a namespace hierarchy. Everything is declared by Olena
within the 'oln::' namespace, and possibly a sub-namespace such as
-'oln::arith::' (arithmetic operations on images), 'oln::morpho::' (morphological
+'\namespace{oln::arith::}' (arithmetic operations on images), '\namespace{oln::morpho::}' (morphological
operations), etc. Usually, the namespace hierarchy is mapped to the mln
-directory tree. For the sake of simplicity, we will neglect the 'oln::'
+directory tree. For the sake of simplicity, we will neglect the '\namespace{oln::}'
prefix in all the code examples.
Methods provided by objects in the library are in constant time. If you need
@@ -296,7 +315,7 @@ This concept allows us to divide a pixel into two information:
\item The value.
\end{itemize}
-Let's say we have 2D grid like this:
+Let's say we have a 2D grid like this:
//FIXME
[dessin de grille 2d, colonnes/lignes numerotees + repere x/y]
@@ -334,11 +353,11 @@ Sites may have a different types, depending on the image type:
\begin{tabular}{l|l}
Name & Description \\
\hline
-point2d & 2D point on a regular grid \\
-point & Generic point ($n-D$) on a regular grid \\
-util::vec & Algebraic vector \\
-util::vertex & Graph vertex \\
-util::edge & Graph edge \\
+\type{point2d} & 2D point on a regular grid \\
+\type{point} & Generic point ($n-D$) on a regular grid \\
+\type{util::vec} & Algebraic vector \\
+\type{util::vertex} & Graph vertex \\
+\type{util::edge} & Graph edge \\
\end{tabular}
[Illustration : grille + intersection + pmin() + pmax() + distance entre 2
@@ -424,12 +443,12 @@ is it's own bounding box.
\doxycode{box2d-1}
-A p\_array does not have this
-method since sites do not have to be adjacent. Maintaining such information, in
+A \type{p\_array} does not have the bbox
+method since its sites do not have to be adjacent. Maintaining such information, in
order to keep getting the bbox in constant time, would be time and memory
-consuming. Instead of providing a method directly in p\_array, an algorithm is
+consuming. Instead of providing a method directly in \type{p\_array}, an algorithm is
available if this information is needed.
-p\_array and box both have a nsites method since the internal structure allows a
+\type{p\_array} and \type{box} both have a nsites method since the internal structure allows a
constant time retrieval.
\doxycode{box2d-2}
@@ -468,11 +487,11 @@ Olena: \\
\begin{tabular}{l|l}
Name & Description \\
\hline
-image1d & 1D image \\
-image2d & 2D image \\
-image3d & 3D image \\
-flat\_image & Constant value image \\
-image\_if & Image defined by a function \\
+\type{image1d} & 1D image \\
+\type{image2d} & 2D image \\
+\type{image3d} & 3D image \\
+\type{flat\_image} & Constant value image \\
+\type{image\_if} & Image defined by a function \\
FIXME & FIXME \\
\end{tabular}
@@ -482,14 +501,14 @@ FIXME & FIXME \\
Every image type must take its type of value as parameter.
The value type can be one of the builtins one:
\begin{itemize}
- \item bool
- \item char
- \item unsigned
- \item int
- \item short
- \item long
- \item float
- \item double
+ \item \type{bool}
+ \item \type{char}
+ \item \type{unsigned}
+ \item \type{int}
+ \item \type{short}
+ \item \type{long}
+ \item \type{float}
+ \item \type{double}
\end{itemize}
Other data types are also available:
@@ -497,73 +516,78 @@ Other data types are also available:
\begin{tabular}{l|l}
Value type & underlying data type \\
\hline
-float01\_8 & unsigned long \\
-float01\_16 & unsigned long \\
-float01\_f & float \\
-gl8 & unsigned char \\
-gl16 & unsigned short \\
-glf & float \\
-hsi\_d & double \\
-hsi\_f & float \\
-int\_s8 & char \\
-int\_s16 & short \\
-int\_s32 & int \\
-int\_u8 & unsigned char \\
-int\_u16 & unsigned short \\
-int\_u32 & unsigned int \\
-rgb16 & mln::util::vec$<$unsigned short$>$ \\
-rgb8 & mln::util::vec$<$unsigned char$>$ \\
+\type{float01\_8} & \type{unsigned long} \\
+\type{float01\_16} & \type{unsigned long} \\
+\type{float01\_f} & \type{float} \\
+\type{gl8} & \type{unsigned char} \\
+\type{gl16} & \type{unsigned short} \\
+\type{glf} & \type{float} \\
+\type{hsi\_d} & \type{double} \\
+\type{hsi\_f} & \type{float} \\
+\type{int\_s8} & \type{char} \\
+\type{int\_s16} & \type{short} \\
+\type{int\_s32} & \type{int} \\
+\type{int\_u8} & \type{unsigned char} \\
+\type{int\_u16} & \type{unsigned short} \\
+\type{int\_u32} & \type{unsigned int} \\
+\type{rgb16} & \type{mln::util::vec$<$unsigned short$>$} \\
+\type{rgb8} & \type{mln::util::vec$<$unsigned char$>$} \\
\end{tabular} \\
-All these types are available in mln/value and accessible in the mln::value namespace.
+All these types are available in mln/value and accessible in the
+\namespace{mln::value} namespace.
Most of the time, the name of the header which must be included to use one of these data
-types is actually ``type\_name.hh". For instance, for rgb8 the header will be
-rgb8.hh.
+types is actually ``type\_name.hh". For instance, for \type{rgb8} the header will be
+\header{rgb8.hh}.
%----------------
\doxysubsection{imavalues}{About value, rvalue and lvalue}
+//FIXME: to be rewritten or removed.
+
Since the values are of a specific type, it exists a set of all the possible
site values. This set is called "destination" set. It may be iterable and
printable if it is finite and not too huge.
-Image types provide a method to access values, namely "operator() const".
-Yet, its signature is NOT "value operator()(const site\& p) const"
-but "rvalue operator()(const psite\& p) const"
+Image types provide a method to access values, namely "\code{operator() const}".
+Yet, its signature is NOT "\code{value operator()(const site\& p) const}"
+but "\code{rvalue operator()(const psite\& p) const}".
-For instance, with I being image2d$<$int\_u8$>$, we have :
+For instance, with \type{I} being \type{image2d$<$int\_u8$>$}, we have :
\begin{center}
- I::value == int\_u8 but I::rvalue == const int\_u8\&
+ \type{I::value} == i\type{nt\_u8} but \type{I::rvalue} ==\type{const
+ int\_u8\&}
\end{center}
-so copying the value when the call "f(p)" returns is avoided.
+So copying the value when the call "\code{f(p)}" returns is avoided.
In that case, it is a low-level implementation issue that makes rvalue
be different from value. In some other cases, the difference can be
more fundamental. For instance, a proxy is returned so that some extra
code is performed if this value is eventually read.
-Likewise, lvalue is also used as return type for methods such as "operator()".
+Likewise, lvalue is also used as return type for methods such as
+"\code{operator()}".
The difference is that lvalue allows the data to be modified.
-With I being image2d$<$int\_u8$>$, we have :
+With \type{I} being \type{image2d$<$int\_u8$>$}, we have :
\begin{center}
- I::value == int\_u8 but I::lvalue == int\_u8\&
+ \type{I::value} == \type{int\_u8} but \type{I::lvalue} == \type{int\_u8\&}
\end{center}
%**************************
\doxysection{imadomain}{Domain}
The site set contains the sites which compose the image. Sites are based on a
grid so the image depends on that grid as well.
-It means that an image 2D can only be defined by sites based on a 2D grid.
-Likewise, an image2d will always have its bouding box defined by a box2d.
+It means that a 2D images can only be defined by sites based on a 2D grid.
+Likewise, an \type{image2d} will always have its bouding box defined by a \type{box2d}.
Being defined on a grid means that the image can be defined anywhere.
-For instance, defining a 2D image with a box2d starting from point (-20, -20)
+For instance, defining a 2D image with a \type{box2d} starting from point (-20, -20)
to (-3, 5) is completely valid.
The following example shows that the definition domain and the site set are
@@ -574,7 +598,7 @@ Output:
\doxycode{ima2d-1-output}
-To know if a site belongs to an image domain or not, a method ``has()'' is
+To know if a site belongs to an image domain or not, a method ``\code{has()}'' is
available.
\doxycode{point-1}
Output:
@@ -593,9 +617,9 @@ These concepts are useful in many algorithms and can avoid costly tests while
working with sites located on image edges.
A border is a finite extension provided to a basic image type, such as
-image2d. By default, every image is created with a border. The default width is
-defined through the global variable border::thickness defined in
-mln/border/thickness.hh. Since this is a variable, it can be changed
+\type{image2d}. By default, every image is created with a border. The default width is
+defined through the global variable \var{border::thickness} defined in
+\header{mln/border/thickness.hh}. Since this is a variable, it can be changed
as shown in the following example.
\doxycode{borderthickness}
@@ -605,12 +629,14 @@ Output:
\doxycode{borderthickness-output}
It is important to note that to display the border in the ouput, we use a
-special debug function, debug::print\_with\_border. Indeed, the border and the
+special debug function, \code{debug::println\_with\_border}. Indeed, the border and the
extension are considered as part of an image only in the algorithms. They are
ignored while saving or printing an image.
Some operations can be performed on the border. The functions are located in
-mln/border.\\
+\hpath{mln/border}.\\
+
+FIXME: More details about border manipulation! border:get(), \ldots
%
\bigskip
@@ -634,7 +660,7 @@ On morphed images, decribed in section \ref{imamorphed}, the border concept
does not exist and is generalized to the extension concept.
A simple example of a morphed image is a sub-image. A sub image does not have
border nor extension by default.
-Thanks to mln/core/routine/extend.hh, an extension can be defined through a
+Thanks to \header{mln/core/routine/extend.hh}, an extension can be defined through a
function. This means that the extension can be infinite.
Another point is that an image can be used as extension. For instance, in the
case of a sub-image, you may be interested in extending the sub-image with the
@@ -643,7 +669,7 @@ image itself.
[FIXME: schema - voir cahier]
The extension supports the following operations. These functions are located in
-mln/extension.\\
+\hpath{mln/extension}.\\
%
\bigskip
@@ -657,12 +683,16 @@ fill & Fill the extension with a given value.\\
%----------------
\subsection*{IMPORTANT NOTE}
Many times, you may want to check if a site is part of the image before applying
-a treatment. All images provide a method ``has(Site)'' which can return this
+a treatment. All images provide a method ``\code{has(Site)}'' which can return this
information.
-Be careful though, calling has() on the image returns true if the given site is
-part of the domain \textbf{OR} the the extension/border. All algorithms in Olena
-call that method which means that all the algorithms take in consideration the
-extension/border if it exists.
+\textbf{Be careful though, calling \code{has()} on the image returns ``true'' if
+ the given site is part of the domain OR the the extension/border}. All
+ algorithms in Olena call that method which means that all the algorithms take
+ in consideration the extension/border if it exists. The default border
+ thickness is set to 3 as shown by the following example.
+
+[FIXME: Add example has(p) when p is in the border and border::thickness
+modified.]
Most of the time, this is the good behavior. For instance, if a rotation of 20
degrees is applied to an image, sites which were not previously in the domain
@@ -675,15 +705,16 @@ Sometimes taking the domain in consideration may not be the expected behavior.
If you do not want to use the extension/border for a specific routine, simply
restrict the image to its domain.
+
\doxycode{extension-ignore}
Note that:
\begin{center}
-ima.domain().has() $\equiv$ (ima | ima.domain()).has()
+\code{ima.domain().has()} $\equiv$ \code{(ima | ima.domain()).has()}
and
-border::get(ima.domain()) == border::get(ima | ima.domain()) == 0
+\code{border::get(ima.domain())} == \code{border::get(ima | ima.domain())} == 0
\end{center}
So it is also valid to write:
@@ -735,14 +766,15 @@ Currently, Olena supports the following input image formats:
\item PPM
\end{itemize}
-This support is provided through two headers for each type, save.hh and load.hh.
-They are located in mln/io/$<$image-format$>$/.
+This support is provided through two headers for each type, \header{save.hh} and
+\header{load.hh}.
+They are located in \hpath{mln/io/$<$image-format$>$/}.
Once the right header is included, the image can be loaded:
\doxycode{ima-load}
-Note that for the PBM format, you \textbf{MUST} use ``bool'' as value type.
+Note that for the PBM format, you \textbf{MUST} use ``\type{bool}'' as value type.
No special value type is required for other formats though.
\doxycode{ima-save}
@@ -768,10 +800,10 @@ Img1b is defined on a domain but does not have data yet.\\
%================================================
\doxysection{imaaccessmodval}{Access and modify values}
-There are several ways to access/modify an image ``ima'':
+There are several ways to access/modify an image ``\var{ima}'':
\begin{itemize}
-\item ima.at(x, y, \dots)
-\item ima(Site)
+\item \code{ima.at(x, y, \dots)}
+\item \code{ima(Site)}
\end{itemize}
Most of the time, images can be modified and these two methods can be used both
@@ -780,13 +812,13 @@ to read a value and modify it. Both methods are equivalent.
Output:
\doxycode{ima2d-3-output}
-Usually, you will want to use the functional way, ``ima(Site)'', more
+Usually, you will want to use the functional way, ``\code{ima(Site)}'', more
particularly while iterating over all the sites through an iterator. This use
case will be detailed further in section \ref{iterators}.
-s%================================================
+%================================================
\doxysection{imasize}{Image size}
Most typical image types owns special methods to retrieve the image size.
@@ -799,11 +831,11 @@ image3d & ncols(), nrows(), nslis() \\
\end{tabular}
If you need a more generic way to get the size, you can use the routines
-provided in mln/geom in the following files:
+provided in \hpath{mln/geom} in the following files:
\begin{itemize}
- \item ncols.hh
- \item nrows.hh
- \item nslis.hh
+ \item \header{ncols.hh}
+ \item \header{nrows.hh}
+ \item \header{nslis.hh}
\end{itemize}
\doxycode{ima-size}
@@ -811,10 +843,20 @@ Output:
\doxycode{ima-size-output}
+%================================================
+\doxysection{imaconvvals}{Conversion of image values}
+
+parler de level::compute/level::apply.
+parler de i2v et v2v.
+Voir les vset => attendre que ca soit ameliore?
%====================================
\clearpage
\newpage
+%Ugly workaround to avoid missing chapter references in doxygen.
+\begin{htmlonly}
+\doxychapter{1}{}
+\end{htmlonly}
\doxychapter{winneigh}{Structural elements: Window and neighborhood}
In Olena, there are both the window and neighborhood concept. A window can be
@@ -824,7 +866,7 @@ Therefore these two concepts are really similar and are detailed together in
this section.
By default, structural elements are centered. The central site is located at the
-origin of the grid: ``literal::origin''. With image2d, the central site is
+origin of the grid: ``\var{literal::origin}''. With image2d, the central site is
(0,0).
@@ -882,7 +924,7 @@ cuboid3d & Cuboid & - \\
\end{tabular}
These predefined windows can be passed directly to a function. The headers are
-located in mln/core/alias/window*.hh.
+located in \header{mln/core/alias/window*.hh}.
@@ -898,7 +940,7 @@ c8 & 8-connectivity & \neighceight \\
\end{tabular}
These predefined neighborhood can be passed directly to a function. The headers are
-located in mln/core/alias/neigh*.hh.
+located in \header{mln/core/alias/neigh*.hh}.
Use case example:
\doxycode{ima2d-decl-2-blobs}
@@ -918,7 +960,8 @@ which the window is computed:
Another way to define the same window is to provide a bool array:
\doxycode{win-create-2}
-Note that ``win'' == ``win2''.
+\textbf{Note that despite the different ways of defining these windows,
+ ``'var{win}'' == ``\var{win2}''}.
The boolean array must always have an odd size.
While creating a windows thanks to a bool array/matrix, the window's center is the
central site of the array/matrix.
@@ -934,7 +977,7 @@ central site of the array/matrix.
Windows are not convertible to a Neighborhood.
Neighborhood are convertible to a window though.
-A neighborhood has a method ``win()'' which returns the definition window.
+A neighborhood has a method ``\code{win()}'' which returns the definition window.
Be ware that this window is not centered, thus does not include the central
point.
@@ -954,19 +997,19 @@ data and a site set which defines the domain of the image on that grid.
Usually, we need to access a value by its coordinates. With default images it
can be done easily, at no cost.
-Example with an image2d:
+Example with an \type{image2d}:
\doxycode{ima2d-display-1}
-The site x is the point (0, 1). The image values are stored in a
+The site \var{x} is the point (0, 1). The image values are stored in a
multi-dimensional array. The point coordinates can be used directly. The site
(0, 1) \textbf{is} the point (0, 1) and the data is stored at row 0 and column
1.
Here we have:
- I::site == I::psite == point2d
+ \type{I::site} == \type{I::psite} == \type{point2d}
-where, roughly, point2d = \{ row, column \}.
+where, roughly, \type{point2d} = \{ row, column \}.
%**************************
\doxysection{sitespsite}{Need for psite}
@@ -982,31 +1025,34 @@ point:
So, for each point having (0, x) as coordinate, this function will return 8,
otherwise it will be 9.
-Then, define a p\_array with few point2d:
+Then, define a \type{p\_array} with few \type{point2d}:
\doxycode{parray-append}
-Now, create a point-wise image from this function and this p\_array:
+Now, create a point-wise image from this function and this \type{p\_array}:
\doxycode{mln_var-1}
Ima is actually that image:
\doxycode{ima2d-display-2}
-However, in memory, since it is based on a p\_array, sites are stored in a
+However, in memory, since it is based on a \type{p\_array}, sites are stored in a
vector.
-The site x is the point (3, 7) which corresponds to the cell 1 in the p\_array.
+The site x is the point (3, 7) which corresponds to the cell 1 in the
+\type{p\_array}.
\doxycode{parray-display-1}
-Obviously, we cannot check in constant time whether the site x, point2d here,
+Obviously, we cannot check in constant time whether the site \var{x},
+ \type{point2d} here,
is part of that image or not: knowing the point coordinates is not enough.
That's why we need a different mechanism in order to access this information:
the psites.
Here we have:
- I::site $==$ point2d but I::psite $==$ pseudo\_site$<$point2d$>$
+ \type{I::site} $==$ \type{point2d} but \type{I::psite} $==$
+ \type{pseudo\_site$<$point2d$>$}
-where, roughly, pseudo\_site$<$point2d$>$ $=$ \{ i\_in\_p\_array, p\_array\_ptr
+where, roughly, \type{pseudo\_site$<$point2d$>$} $=$ \{ i\_in\_p\_array, p\_array\_ptr
\}.
Psites contains all the needed information to access the values in
@@ -1015,25 +1061,27 @@ constant-time.
%**************************
\doxysection{sitespsitensite}{From psite to site}
-In the last example there was an image of type I such as I::site != I::psite.
-In that case, an object of type I::psite is actually convertible towards an
-object of type I::site. Furthermore, a psite shall behave as if it was a
-site.
+In the last example there was an image of type \type{I} such as \type{I::site}
+!= \type{I::psite}.
+In that case, an object of type \type{I::psite} is actually convertible towards an
+object of type \type{I::site}. Furthermore, a \type{psite} shall behave as if it was a
+\type{site}.
Design note: it seems impossible to offer through the interface of
-some psite what is expected from its corresponding site. For instance, when a
-site has a given feature, say a method "m", then this
-method has to appear in the psite interface. However, thanks to
+some \type{psite} what is expected from its corresponding \type{site}. For instance, when a
+site has a given feature, say a method "\code{m}", then this
+method has to appear in the \type{psite} interface. However, thanks to
inheritance, we fetch an interface and an implementation that delegates
to the site.
-For instance, in the last example, I::psite has a method ::row() because
-I::site, point2d, provides such a method.
+For instance, in the last example, \type{I::psite} has a method \code{row(}) because
+\type{I::site}, \type{point2d}, provides such a method.
-How it works: a psite inherits from internal::site\_impl$<$site$>$ which is
-specialized for every site type; for instance, internal::site\_impl$<$point2d$>$
-owns the method "coord row() const" which is defined as
-"return exact(this)-$>$to\_site().row()"
+How it works: a \type{psite} inherits from \type{internal::site\_impl$<$site$>$} which is
+specialized for every site type; for instance,
+ \type{internal::site\_impl$<$point2d$>$}
+owns the method ``\code{coord row() const}'' which is defined as
+``\code{return exact(this)-$>$to\_site().row()}''.
%**************************
\doxysection{sitesdpoint}{Dpoint}
@@ -1050,10 +1098,6 @@ Output:
%====================================
\clearpage
\newpage
-%Ugly workaround to avoid missing chapter references in doxygen.
-\begin{htmlonly}
-\doxychapter{1}{}
-\end{htmlonly}
\doxychapter{iterators}{Iterators}
Each container object in Olena like site sets or images have iterators.
@@ -1079,11 +1123,12 @@ The iterator type name depends on the data pointed by it: \\
Data type & Iterator Names \\ \hline
Site & fwd\_piter, bkd\_piter, piter \\ \hline
Value & fwd\_viter, bkd\_viter, viter \\ \hline
+Neighboors & fwd\_niter, bkd\_niter, niter \\ \hline
\end{tabular} \\
-As you may have noticed, according to the data type, the word "iter" is prefixed
+As you may have noticed, according to the data type, the word ``iter'' is prefixed
by the usual name variable used for that data type. Sites variables are usually
-called 'p' so the proper iterator is "piter". (See the foreword)\\
+called ``p'' so the proper iterator is ``type{piter}''. (See the foreword)\\
An iterator has the following interface: \\
@@ -1105,22 +1150,29 @@ Example of different forward iterations:
\item p\_array$<$point2d$>$: from left to right.
\end{itemize}
-A for\_all() macro is available to iterate over all the sites: \\
+A \code{for\_all()} macro is available to iterate over all the sites: \\
\doxycode{forall-piter-1}
-Note that when you declare an iterator, prefer using the "mln\_*iter" macros.
+Note that when you declare an iterator, prefer using the ``\code{mln\_*iter}'' macros.
They resolve the iterator type automatically from the given container type
passed as parameter. These macros can be used with any container like images or
site sets.
-Here follow an example with the implemantions of the most basic routines which use the for\_all
-loop: fill and paste.
+Here follow an example with the implemantions of the most basic routines which
+use the \code{for\_all} loop: \code{level::fill()} and \code{level::paste()}.
\doxycode{fill}
\doxycode{paste}
+Important note: macros for iterators exist in two versions:
+``\code{mln\_*iter}'' and ``\code{mln\_*iter\_}''. The difference is that the
+first version must be used in templated function whereas the second one must be
+used in non templated functions.
+
+If you want a list of all the macros available in Olena, please refert to
+section \ref{macros}.
%================================================
@@ -1158,7 +1210,7 @@ variable behaves like some mathematical variable. Put differently it is just a
name to designate an image:
\doxycode{ima2d-5}
-If a deep copy of the image is needed, a method clone() is available:
+If a deep copy of the image is needed, a clone() routine is available:
\doxycode{ima2d-6-clone}
@@ -1166,11 +1218,9 @@ If a deep copy of the image is needed, a method clone() is available:
%====================================
\clearpage
\newpage
-\doxychapter{basicops}{Basic operations}
+\doxychapter{basicops}{Basic routines}
//FIXME : illustrer
-%**************************
-\doxysection{basicroutines}{Basic routines}
\begin{tabular}{l|p{8cm}}
\hline
Routine name & Description \\ \hline
@@ -1183,6 +1233,9 @@ level::paste() & paste object data to another object. \\
labeling::blobs() & find and label the different components of an image. \\
+logical::not\_()
+logical::not\_inplace() & Point-wise "logical not" \\
+
*::compute() & compute an accumulator on specific elements. \\
\hline
\end{tabular} \\
@@ -1193,21 +1246,21 @@ First, create an image:
\doxycode{ima2d-decl-1}
Memory has been allocated so data can be stored but site values
-have not been initialized yet. So we fill imga with the value 'a':
+have not been initialized yet. So we fill \var{imga} with the value 'a':
\doxycode{fill-call-1}
-The "fill" algorithm is located in the sub-namespace "level" since this
-algorithm deals with the "level" of site values.
+The ``\code{fill}'' algorithm is located in the sub-namespace "\namespace{mln::level}" since this
+algorithm deals with the ``level'' of site values.
Note that the term "level" refers to the fact that an image can be considered as
a landscape where the elevation at a particular location/site is given by
the corresponding site value.
-The full name of this routine is "oln::level::fill". To access to a particular
-algorithm, the proper file shall be included. The file names of algorithms
-strictly map their C++ name; so oln::level::fill is defined in the file
-"oln/level/fill.hh".
+The full name of this routine is ``\namespace{mln::level::fill}''.
+To access to a particular algorithm, the proper file shall be included.
+The file names of algorithms strictly map their C++ name; so
+\namespace{mln::level::fill} is defined in the file \header{mln/level/fill.hh}.
%----------------
\subsection*{Note}
@@ -1215,8 +1268,8 @@ Most algorithms in Olena are constructed following the classical scheme: "output
algo(input)", where the input image is only read. However some few algorithms
take an input image in order to modify it. To enforce this particular feature,
the user shall explicitly state that the image is provided so that its data is
-modified "read/write". The algorithm call shall be "level::fill(ima.rw(),
-val)". When forgetting the "rw()" call it does not compile.
+modified "read/write". The algorithm call shall be ``\code{level::fill(ima.rw(),
+val)}''. When forgetting the ``\code{rw()}'' call it does not compile.
%**************************
@@ -1258,14 +1311,14 @@ For instance, the algorithm level::paste tests that the set of sites of imgb
%====================================
\doxysection{blobs}{Blobs}
-Labeling::blobs() is used to label an image. It returns a new image with the
+\code{Labeling::blobs()} is used to label an image. It returns a new image with the
component id as value for each site. The background has 0 as id therefore the
component ids start from 1.
Consider the following image:
\doxycode{ima2d-decl-2}
-Then label this image thanks to labeling::blobs:
+Then label this image thanks to \code{labeling::blobs()}:
\doxycode{ima2d-decl-2-blobs}
Output:
\doxycode{ima2d-decl-2-blobs-output}
@@ -1275,6 +1328,32 @@ This parameter \textbf{must} be of the same type as the returned image value.
%**************************
+\doxysection{logicalnot}{Logical not}
+\begin{center}
+ \begin{tabular}{|l|l|}
+ \hline
+ \textbf{Header} & mln/logical/not.hh \\
+
+ \textbf{Full namespace} & mln::logical \\
+
+ \textbf{Routine(s)} & not\_(),
+ not\_inplace() \\
+ \hline
+ \end{tabular}
+\end{center}
+
+\bigskip
+
+This small routine only works on binary images. It performs a point-wise
+"logical not" and therefore "negates" the image. There are two versions of that
+algorithm a version which returns a new image and another which works in place.
+
+Sample code:
+\doxycode{logical-not}
+Output:
+\doxycode{logical-not-output}
+
+%**************************
\doxysection{compute}{Compute}
There are several flavour of the compute routine, depending on what the kind of
@@ -1334,21 +1413,20 @@ pair & Pair of accumulators\\
tuple & $n$-uplets of accumulators\\
\end{tabular}
-Each accumulator can be used in *::compute().
+Each accumulator can be used in \code{*::compute()}.
It exists two versions of each accumulator.
\begin{itemize}
- \item mln::accu::*, this version require the site or value type as parameter.
+ \item \namespace{mln::accu::*}, this version require the site or value type as parameter.
For instance, for the bbox accumulator, the type would be
- accu::bbox<mln\_psite(I)>, where I is the type of the image on which it will be
+ \type{accu::bbox<mln\_psite(I)>}, where \type{I} is the type of the image on which it will be
computed.
- \item mln::accu::meta::*, this is usually the easiest version to use. The type
+ \item \namespace{mln::accu::meta::*}, this is usually the easiest version to use. The type
of site or value do not need to be specified and will be deduced at compile
time. For the bbox accumulator, the accumulator type would be
- accu::meta::bbox.
+ \type{accu::meta::bbox}.
\end{itemize}
-Note that when an accumulator is passed to *::compute, it must be instanciated.
-You cannot write:
+Note that when an accumulator is passed to \code{*::compute()}, it must be instanciated.You cannot write:
\doxycode{accu-wrong-instanciation}
Instead, you must write:
\doxycode{accu-right-instanciation}
@@ -1361,19 +1439,19 @@ image.
Consider the following image:
\doxycode{ima2d-decl-2}
-Then label this image thanks to labeling::blobs:
+Then label this image thanks to \code{labeling::blobs()}:
\doxycode{ima2d-decl-2-blobs}
Output:
\doxycode{ima2d-decl-2-blobs-output}
-Then, use labeling::compute() with the bbox accumulator:
+Then, use \code{labeling::compute()} with the bbox accumulator:
\doxycode{labeling-compute-call}
-Labeling::compute() hold an accumulator for each component, which means it
+\code{Labeling::compute()} hold an accumulator for each component, which means it
returns an array of accumulator results.
-In this case, it returns an array of box2d.
+In this case, it returns an array of \type{box2d}.
-\textbf{Important note:} since labeling::blobs() labels the component from 1 and
+\textbf{Important note:} since \code{labeling::blobs()} labels the component from 1 and
set the background to 0, we will want to iterate from 1 to nlabels included.
\doxycode{labeling-compute-result}
Output:
@@ -1395,8 +1473,8 @@ min\_max & Return the min and max values of the values of an image.\\
sum & Return the sum of the values of an image.
\end{tabular}
-These routines can be found in mln/estim.
-For example, with estim::nsites() simply write:
+These routines can be found in \hpath{mln/estim}.
+For example, with \code{estim::nsites()} simply write:
\doxycode{estim-sites}
%====================================
@@ -1421,25 +1499,25 @@ Function\_p2v $|$ Sub Domain & Do not create a new image but create a morpher.\\
A Sub Domain can be a site set, an image or any value returned by this
operator.
-For a given site, Function\_p2v returns a Value and Function\_p2b returns a
+For a given site, \type{Function\_p2v} returns a value and \type{Function\_p2b} returns a
boolean. These functions. are actually a sort of predicate. A common
-function\_p2v is pw::value(Image). It returns the
+\type{Function\_p2v} is \code{pw::value(Image)}. It returns the
point to value function used in the given image. C functions can also be used as
predicate by passing the function pointer.
-You can easily get a function\_p2b by comparing the value returned
-by a function\_p2v to another Value.
+You can easily get a \type{Function\_p2b} by comparing the value returned
+by a \type{Function\_p2v} to another Value.
The following sample codes illustrate this feature.
In order to use C functions as predicate, they must have one of the following
prototype if you work on 2D images:
\doxycode{predicate-1}
Of course, you just need to change the point type if you use another image
-type. For instance, you would use point3d with 3D images.
-The returned value type V for function\_p2v depends on the image value type.
-With image2d$<$int$>$, V would be int.
+type. For instance, you would use \type{point3d} with 3D images.
+The returned value type \type{V} for \type{Function\_p2v} depends on the image value type.
+With \type{image2d$<$int$>$}, \type{V} would be \type{int}.
-In this section, all along the examples, the image "ima" will refer to the
+In this section, all along the examples, the image "\var{ima}" will refer to the
following declaration:
\doxycode{ima2d-decl-2}
@@ -1468,14 +1546,14 @@ When writing:
\doxycode{ima2d-restricted-1}
-sub\_D must be included in ima.domain().
+\var{sub\_D} must be included in \code{ima.domain()}.
-Let's have an image, \textit{imab}, like this:
+Let's have an image, \var{imab}, like this:
\doxycode{ima2d-display-output-1}
-Extract a sub image from \textit{imab} with sites having their value set to 1.
+Extract a sub image from \var{imab} with sites having their value set to 1.
\doxycode{mln_var-2}
-Then, \textit{imab1} looks like:
+Then, \var{imab1} looks like:
\doxycode{ima2d-display-output-2}
Now, if we want to extract a sub image it may fail, depending on the site set
@@ -1498,7 +1576,9 @@ site set.
\newpage
\clearpage
%Ugly workaround to avoid missing chapter references in doxygen.
+\begin{htmlonly}
\doxychapter{2}{}
+\end{htmlonly}
\doxychapter{graphandima}{Graphes and images}
FIXME: REWRITE
@@ -1539,7 +1619,8 @@ g.add_edge(4, 2); // Associated to edge 4.
Now there is a graph topology and we want to associate elements of this graph
to a site in the image.
-The idea is to use specific site sets such as p\_vertices and p\_edges.
+The idea is to use specific site sets such as \type{p\_vertices} and
+\type{p\_edges}.
Let's associate the vertices with sites. To do so we need to create a functor
which for a given vertex returns a site.
@@ -1557,15 +1638,16 @@ struct assoc_fun : public Function_v2v< assoc_fun >
};
\end{lstlisting}
-Then declare a p\_vertices:
+Then declare a \type{p\_vertices}:
\begin{lstlisting}[frame=single]
p_vertices<util::graph, assoc_fun> pv(g, assoc_fun());
\end{lstlisting}
-Thanks to the p\_vertices there is now a mapping between vertices and sites.
+Thanks to the \type{p\_vertices} there is now a mapping between vertices and sites.
We may like to map data to it. The idea is to provide a function which returns the associated data
according to the site given as parameter. Combining this function and the
-p\_vertices, we get an image. Since this is an image, you can use it with algorithms and for\_all loops.
+\type{p\_vertices}, we get an image. Since this is an image, you can use it with
+algorithms and \code{for\_all} loops.
\begin{lstlisting}[frame=single]
@@ -1593,7 +1675,7 @@ Note that like any image in Olena, graph images share their data. Therefore,
while constructing a graph image from a graph and a function, the graph is not
copied and this is NOT a costly operation.
-Like other images, graph images also have an overloaded operator() to access the
+Like other images, graph images also have an overloaded \code{operator()} to access the
data associated to a vertex or an edge.
\begin{lstlisting}
//Prints each edge's associated value.
@@ -1696,4 +1778,108 @@ border::thickness & Set the default border thickness of images & $[0-UINT_MAX]$\
trace::quiet & Enable trace printing & true/false \\
\end{tabular}
+%====================================
+\newpage
+\clearpage
+\doxychapter{macros}{Useful Macros}
+
+\doxysection{macrositerators}{Iterator type macros}
+
+\doxysubsection{macrosdefit}{Default iterator types}
+\renewcommand{\arraystretch}{2}
+\begin{tabular}{l|p{4cm}|p{6cm}}
+Name & Arguments & Description \\
+\hline
+mln\_eiter(T) & T : iterable container type & Type of the element
+ iterator of T \\
+
+mln\_niter(T) & T : iterable container/Image type & Type of the neighborhood
+ iterator of T \\
+
+mln\_piter(T) & T : iterable container/image type & Type of the site
+ iterator \\
+
+mln\_qiter(T) & T : iterable container/image type & Type of the window
+ neighbors iterator of T \\
+
+mln\_viter(T) & T : iterable value container type & Type of the value
+ iterator of T \\
+
+mln\_pixter(I) & I : image & Type of the pixel
+ iterator of I \\
+
+mln\_qixter(I, W) & I : image type, & \\
+ & W : window Type & Type of the pixel iterator of a
+ window on an image of type I. \\
+
+mln\_nixter(I, N) & I : image type, & \\
+ & N : neighborhood type & Type of the pixel iterator of a
+ neighborhood on an image of type I. \\
+\end{tabular}
+
+
+
+\doxysubsection{macrosfwdit}{Forward iterator types}
+\begin{tabular}{l|p{4cm}|p{6cm}}
+Name & Arguments & Description \\
+\hline
+mln\_fwd\_eiter(T) & T : iterable container type & Type of the
+ element forward iterator of T \\
+
+mln\_fwd\_niter(T) & T : iterable container/Image type & Type of the
+ neighborhood forward iterator of T \\
+
+mln\_fwd\_piter(T) & T : iterable container/image type & Type of the site
+ forward iterator \\
+
+mln\_fwd\_qiter(T) & T : iterable container/image type & Type of the window
+ neighbors forward iterator of T \\
+
+mln\_fwd\_viter(T) & T : iterable value container type & Type of the value
+ forward iterator of T \\
+
+mln\_fwd\_pixter(I) & I : image & Type of the pixel
+ forward iterator of I \\
+
+mln\_fwd\_qixter(I, W) & I : image type, & \\
+ & W : window Type & Type of the pixel
+ forward iterator of a window on an image of type I. \\
+
+mln\_fwd\_nixter(I, N) & I : image type, & \\
+ & N : neighborhood type & Type of the pixel
+ forward iterator of a neighborhood on an image of type I. \\
+\end{tabular}
+
+
+\doxysubsection{macrosbkdit}{Backward iterators}
+\begin{tabular}{l|p{4cm}|p{6cm}}
+Name & Arguments & Description \\
+\hline
+mln\_bkd\_eiter(T) & T : iterable container type & Type of the
+ element backward iterator of T \\
+
+mln\_bkd\_niter(T) & T : iterable container/Image type & Type of the
+ neighborhood backward iterator of T \\
+
+mln\_bkd\_piter(T) & T : iterable container/image type & Type of the site
+ backward iterator \\
+
+mln\_bkd\_qiter(T) & T : iterable container/image type & Type of the window
+ neighbors backward iterator of T \\
+
+mln\_bkd\_viter(T) & T : iterable value container type & Type of the value
+ backward iterator of T \\
+
+mln\_bkd\_pixter(I) & I : image & Type of the pixel
+ backward iterator of I \\
+
+mln\_bkd\_qixter(I, W) & I : image type, & \\
+ & W : window Type & Type of the pixel
+ backward iterator of a window on an image of type I. \\
+
+mln\_bkd\_nixter(I, N) & I : image type, & \\
+ & N : neighborhood type & Type of the pixel
+ backward iterator of a neighborhood on an image of type I. \\
+\end{tabular}
+
\end{document}
--
1.5.6.5
1
0
https://svn.lrde.epita.fr/svn/oln/branches/cleanup-2008/milena/sandbox
Index: ChangeLog
from Thierry Geraud <thierry.geraud(a)lrde.epita.fr>
Add demo code for Laurent N.
* geraud/toto: Remove.
* geraud/laurent: New.
* geraud/laurent/wst2d.cc: New.
* geraud/laurent/wst3d.cc: New.
* geraud/laurent/classif.cc: New.
* geraud/laurent/segmentation.hh: New.
classif.cc | 115 +++++++++++++++++++++++++++++++++++++++++
segmentation.hh | 14 +++++
wst2d.cc | 154 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
wst3d.cc | 79 ++++++++++++++++++++++++++++
4 files changed, 362 insertions(+)
Index: geraud/laurent/wst2d.cc
--- geraud/laurent/wst2d.cc (revision 0)
+++ geraud/laurent/wst2d.cc (revision 0)
@@ -0,0 +1,154 @@
+# include <cstdlib>
+
+# include <mln/value/int_u8.hh>
+# include <mln/value/rgb8.hh>
+
+# include <mln/io/pgm/load.hh>
+# include <mln/io/ppm/save.hh>
+
+# include <mln/core/var.hh>
+# include <mln/core/image/image2d.hh>
+# include <mln/core/alias/neighb2d.hh>
+# include <mln/make/double_neighb2d.hh>
+
+# include <mln/level/transform.hh>
+# include <mln/literal/black.hh>
+# include <mln/debug/println.hh>
+
+# include <mln/morpho/closing_area.hh>
+# include <mln/morpho/gradient.hh>
+# include <mln/accu/min_max.hh>
+# include <mln/morpho/meyer_wst.hh>
+
+
+using namespace mln;
+using value::int_u8;
+
+
+template <typename I, typename N>
+mln_concrete(I)
+morpho_gradient(const Image<I>& input_, const Neighborhood<N>& nbh_)
+{
+ const I& input = exact(input_);
+ const N& nbh = exact(nbh_);
+
+ mln_concrete(I) output;
+ initialize(output, input);
+ accu::min_max<mln_value(I)> mm;
+
+ mln_piter(I) p(input.domain());
+ mln_niter(N) n(nbh, p);
+
+ for_all(p)
+ {
+ mm.take_as_init(input(p));
+ for_all(n)
+ mm.take(input(n));
+ output(p) = mm.second() - mm.first();
+ }
+
+ return output;
+}
+
+struct colorize : Function_v2v< colorize >
+{
+ typedef value::rgb8 result;
+ colorize(unsigned max)
+ : lut(max + 1)
+ {
+ lut[0] = literal::black;
+ for (unsigned i = 1; i <= max; ++i)
+ lut[i] = result(100 + std::rand() % 150,
+ 100 + std::rand() % 150,
+ 100 + std::rand() % 150);
+ }
+ result operator()(unsigned i) const
+ {
+ return lut[i];
+ }
+ std::vector<result> lut;
+};
+
+
+bool is_chess(const point2d& p)
+{
+ return p.col() % 2 == p.row() % 2;
+}
+
+
+void usage(char* argv[])
+{
+ std::cerr << "usage: " << argv[0] << " input.pgm nbh lambda output.ppm" << std::endl;
+ std::cerr << " nbh in {4, 6, 8}; lambda >= 0" << std::endl;
+ abort();
+}
+
+
+template <typename I, typename N>
+void do_it(const I& ima,
+ const N& nbh,
+ int lambda,
+ const std::string& filename)
+{
+ I grad = morpho_gradient(ima, nbh);
+
+ I clo;
+ if (lambda > 1)
+ clo = morpho::closing_area(grad, nbh, lambda);
+ else
+ clo = grad;
+
+ unsigned l;
+ mln_ch_value(I, unsigned) wst = morpho::meyer_wst(clo, nbh, l);
+
+ std::cout << "nbasins = " << l << std::endl;
+// debug::println(labeling::regional_minima(clo, nbh, l));
+// debug::println(wst);
+
+ io::ppm::save(level::transform(wst, colorize(l)), filename);
+}
+
+
+int main(int argc, char* argv[])
+{
+ if (argc != 5)
+ usage(argv);
+
+ image2d<int_u8> ima;
+
+ io::pgm::load(ima, argv[1]);
+
+ int nbh_ = atoi(argv[2]);
+ if (! (nbh_ == 4 || nbh_ == 6 || nbh_ == 8))
+ usage(argv);
+
+ int lambda = atoi(argv[3]);
+ if (lambda < 0)
+ usage(argv);
+
+ std::string filename(argv[4]);
+
+ if (nbh_ == 4)
+ {
+ mln_VAR(nbh, c4());
+ do_it(ima, nbh, lambda, filename);
+ }
+ else if (nbh_ == 8)
+ {
+ mln_VAR(nbh, c8());
+ do_it(ima, nbh, lambda, filename);
+ }
+ else if (nbh_ == 6)
+ {
+ bool vert[] = { 1, 1, 0,
+ 1, 0, 1,
+ 0, 1, 1 };
+
+ bool hori[] = { 0, 1, 1,
+ 1, 0, 1,
+ 1, 1, 0 };
+
+ mln_VAR(nbh, make::double_neighb2d(is_chess, vert, hori));
+ do_it(ima, nbh, lambda, filename);
+ }
+}
Index: geraud/laurent/wst3d.cc
--- geraud/laurent/wst3d.cc (revision 0)
+++ geraud/laurent/wst3d.cc (revision 0)
@@ -0,0 +1,79 @@
+# include <cstdlib>
+# include <cstdio>
+
+# include <mln/value/int_u16.hh>
+# include <mln/value/int_u8.hh>
+# include <mln/level/stretch.hh>
+
+# include <mln/io/pgm/load.hh>
+# include <mln/io/ppm/save.hh>
+
+# include <mln/core/var.hh>
+# include <mln/core/image/image3d.hh>
+# include <mln/core/alias/neighb3d.hh>
+
+# include <mln/morpho/meyer_wst.hh>
+# include <mln/morpho/closing_area.hh>
+# include <mln/morpho/closing_volume.hh>
+
+
+
+using namespace mln;
+using value::int_u8;
+
+
+void usage(char* argv[])
+{
+ std::cerr << "usage: " << argv[0] << " input.raw lambda output.ppm" << std::endl;
+ std::cerr << " lambda >= 0" << std::endl;
+ abort();
+}
+
+
+
+int main(int argc, char* argv[])
+{
+ using namespace mln;
+ using value::int_u8;
+ using value::int_u16;
+
+ if (argc != 3)
+ usage(argv);
+
+ trace::quiet = false;
+
+ image3d<int_u16> ima16(256, 256, 256, 0);
+ int size = 256 * 256 * 256 * 2;
+
+ std::FILE* file = std::fopen(argv[1], "r");
+ std::fread(ima16.buffer(), size, 1, file);
+
+// typedef image3d<int_u16> I;
+// mln_piter_(I) p(ima16.domain());
+// for_all(p)
+// if (ima16(p) != 0)
+// std::cout << ima16(p) << std::endl;
+
+// abort();
+
+ int_u16 min_, max_;
+ estim::min_max(ima16, min_, max_);
+ std::cout << min_ << ' ' << max_ << std::endl;
+
+ abort();
+
+ image3d<int_u8> ima(ima16.domain());
+ level::stretch(ima16, ima);
+ ima16.destroy();
+
+ int lambda = atoi(argv[2]);
+ if (lambda < 0)
+ usage(argv);
+
+ image3d<int_u8> clo(ima.domain());
+ morpho::closing_volume(ima, c6(), lambda, clo);
+
+ unsigned nbasins;
+ image3d<unsigned> wst = morpho::meyer_wst(clo, c6(), nbasins);
+ std::cout << "nbasins = " << nbasins << std::endl;
+}
Index: geraud/laurent/classif.cc
--- geraud/laurent/classif.cc (revision 0)
+++ geraud/laurent/classif.cc (revision 0)
@@ -0,0 +1,115 @@
+#include <vector>
+#include <mln/core/image/image2d.hh>
+#include <mln/core/routine/clone.hh>
+#include <mln/core/alias/neighb2d.hh>
+#include <mln/core/site_set/p_queue_fast.hh>
+#include <mln/labeling/blobs.hh>
+#include <mln/io/pbm/load.hh>
+#include <mln/debug/println.hh>
+
+
+namespace mln
+{
+
+ template <typename I, typename N>
+ mln_concrete(I)
+ influence_zones(const I& input, const N& nbh)
+ {
+ mln_concrete(I) output = clone(input);
+
+ p_queue_fast<mln_site(I)> q;
+
+ // Init.
+ {
+ mln_piter(I) p(input.domain());
+ mln_niter(N) n(nbh, p);
+ for_all(p)
+ if (input(p) != 0)
+ for_all(n) if (input.has(n))
+ if (input(n) == 0)
+ {
+ q.push(p);
+ break;
+ }
+ }
+
+ // Body.
+ {
+ mln_site(I) p;
+ mln_niter(N) n(nbh, p);
+ while (! q.is_empty())
+ {
+ p = q.pop_front();
+ mln_invariant(output(p) != 0);
+ for_all(n) if (input.has(n))
+ if (output(n) == 0)
+ {
+ output(n) = output(p);
+ q.push(n);
+ }
+ }
+ }
+
+ return output;
+
+ } // IZ
+
+
+ template <typename I>
+ void
+ mk_graph(const I& iz, unsigned nlabels)
+ {
+ std::vector< std::vector<bool> > adj(nlabels + 1);
+ for (unsigned l = 1; l <= nlabels; ++l)
+ adj[l].resize(l, false);
+
+ mln_piter(I) p(iz.domain());
+ for_all(p)
+ {
+ mln_site(I) r = p + right, b = p + down;
+ if (iz.has(r) && iz(p) != iz(r))
+ {
+ if (iz(p) < iz(r))
+ adj[iz(p)][iz(r)] = true;
+ else
+ adj[iz(r)][iz(p)] = true;
+ }
+ if (iz.has(b) && iz(p) != iz(b))
+ {
+ if (iz(p) < iz(b))
+ adj[iz(p)][iz(b)] = true;
+ else
+ adj[iz(b)][iz(p)] = true;
+ }
+ }
+
+ for (unsigned l1 = 1; l1 <= nlabels; ++l1)
+ for (unsigned l2 = 1; l2 <= nlabels; ++l2)
+ if (adj[l1][l2])
+ std::cout << l1 << ' ' << l2 << std::endl;
+ }
+
+}
+
+
+
+int main()
+{
+ using namespace mln;
+
+ border::thickness = 0;
+
+ image2d<bool> seeds;
+ io::pbm::load(seeds, "+seeds.pbm");
+
+ debug::println(seeds);
+
+ unsigned n;
+ image2d<unsigned> label = labeling::blobs(seeds, c4(), n);
+ debug::println(label);
+
+ image2d<unsigned> iz = influence_zones(label, c4());
+ debug::println(iz);
+
+ mk_graph(iz, n);
+}
Index: geraud/laurent/segmentation.hh
--- geraud/laurent/segmentation.hh (revision 0)
+++ geraud/laurent/segmentation.hh (revision 0)
@@ -0,0 +1,14 @@
+
+
+template <typename I, typename N>
+mln_ch_value(I, rgb8) segmentation(const I& ima,
+ const N& nbh,
+ unsigned area)
+{
+ mln_concrete(I) filtered = morpho::closing_area(ima, nbh, area);
+
+ unsigned nbasins;
+ mln_ch_value(I, unsigned) wst = morpho::wst_meyer(filtered, nbh, nbasins);
+
+ return level::transform(wst, colorize(nbasins));
+}
1
0
From: Maxime van Noppen <yabo(a)lrde.epita.fr>
To: olena-patches(a)lrde.epita.fr
Subject: r2674: Enhance the build-system
URL: https://svn.lrde.epita.fr/svn/oln/branches/cleanup-2008/milena/sandbox
ChangeLog:
2008-10-24 Maxime van Noppen <yabo(a)lrde.epita.fr>
Enhance the build-system.
* Makefile: Make a nice and usefull Makefile.
---
Makefile | 48 +++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 43 insertions(+), 5 deletions(-)
Index: branches/cleanup-2008/milena/sandbox/classif/Makefile
===================================================================
--- branches/cleanup-2008/milena/sandbox/classif/Makefile (revision 2673)
+++ branches/cleanup-2008/milena/sandbox/classif/Makefile (revision 2674)
@@ -1,7 +1,45 @@
-CCFLAGS=-I../.. -O1 -DNDEBUG
+INCLUDES=-I../..
-all:
- g++ iccvg04.cc $(CCFLAGS)
+SRC=iccvg04.cc
+TARGET=iccvg
-debug:
- g++ iccvg04.cc -I../../ -O0 -g3 -ggdb3
+TARGET_DBG=iccvg_dbg
+
+IMG?=../../img/lena.ppm
+DIV?=8
+LAMBDA?=10
+
+LOG=> stdout.log 2> stderr.log
+
+all: $(TARGET)
+
+$(TARGET): $(SRC)
+ g++ $(INCLUDES) -O1 -DNDEBUG $(SRC) -o $(TARGET)
+
+debug: $(TARGET_DBG)
+
+iccvg_dbg: $(SRC)
+ g++ $(INCLUDES) -O0 -g3 -ggdb3 $(SRC) -o $(TARGET_DBG)
+
+.PHONY:clean check check-debug valgrind
+
+clean:
+ rm -f $(TARGET)
+ rm -f $(TARGET_DBG)
+
+check-debug: $(TARGET_DBG)
+ ./iccvg_dbg $(IMG) $(DIV) $(LAMBDA) $(LOG)
+ cat stdout.log
+ display out.ppm &
+
+check: $(TARGET)
+ ./iccvg $(IMG) $(DIV) $(LAMBDA) $(LOG)
+ cat stdout.log
+ display out.ppm &
+
+valgrind:
+ valgrind --log-file=valgrind.log ./iccvg_dbg ../../img/lena.ppm $(DIV) $(LAMBDA) $(LOG)
+
+gdb: $(TARGET_DBG)
+ echo "run ../../img/lena.ppm $(DIV) $(LAMBDA)" > gdb.cmd
+ gdb $(TARGET_DBG) -x gdb.cmd
1
0
cleanup-2008 2673: Add bijective functors, 2-way functors and meta-fun.
by Alexandre Abraham 24 Oct '08
by Alexandre Abraham 24 Oct '08
24 Oct '08
https://svn.lrde.epita.fr/svn/oln/branches/cleanup-2008/milena/sandbox
Index: ChangeLog
from Alexandre Abraham <abraham(a)lrde.epita.fr>
Add bijective functors, 2-way functors and meta-fun.
* abraham/tests/morpho/test_component_tree.cc: Remove
This test was outdated.
* abraham/tests/morpho/test_watershed.cc:
Clean.
* abraham/tests/morpho/test_watershed_topo.cc:
Clean.
* abraham/tests/fun/meta: New.
* abraham/tests/fun/meta/red.cc: New
(mln::meta::red) : meta function to access red in rgb.
* abraham/tests/core/image/thru_norm.cc: New
test for norm functor.
* abraham/tests/core/image/thru_v2v.cc: New
test for abs functor.
* abraham/tests/core/image/thru.cc: Remove.
* abraham/tests/core/image/thru_const.cc: New
test of writing in a const image.
* abraham/tests/core/image/thru_v2w2v.cc: New
test for cosinus functor.
* abraham/tests/core/concept: New.
* abraham/tests/core/concept/test.cc: New.
* abraham/mln/morpho/najman_wst.hh: New
M-W watershed.
* abraham/mln/morpho/basic_najman.hh:
Obsolete, will eventually be removed.
* abraham/mln/morpho/topo_wst.hh: New
1 pass topological watershed.
* abraham/mln/core/image/thru.hh:
(mln::thru): see an image throught a function.
* abraham/mln/core/image/shell.hh: New
(mln::shell): value shell.
* abraham/mln/core/concept/function.hh:
Add bijective and 2-way function.
* abraham/mln/core/concept/meta_fun.hh: New
Add concept for meta function.
* abraham/mln/fun/meta: New.
* abraham/mln/fun/meta/red.hh: New
red fun object.
* abraham/mln/fun/v2w_w2v/norm.hh:
2-way functor.
* vigouroux/tests.cc: Rename image_if_value > image_if.
* vigouroux/color/rgb_to_cmy.hh: Rename image_if_value > image_if.
* vigouroux/color/rgb_to_xyz.hh: Rename image_if_value > image_if.
* vigouroux/color/rgb_to_hsi.hh: Rename image_if_value > image_if.
* vigouroux/color/rgb_to_yuv.hh: Rename image_if_value > image_if.
abraham/mln/core/concept/function.hh | 2
abraham/mln/core/concept/meta_fun.hh | 83 ++
abraham/mln/core/image/shell.hh | 118 ++++
abraham/mln/core/image/thru.hh | 40 -
abraham/mln/fun/meta/red.hh | 45 +
abraham/mln/fun/v2w_w2v/norm.hh | 4
abraham/mln/morpho/basic_najman.hh | 196 +++---
abraham/mln/morpho/najman_wst.hh | 791 ++++++++++++++++++++++++++++
abraham/mln/morpho/topo_wst.hh | 744 ++++++++++++++++++++++++++
abraham/tests/core/concept/test.cc | 75 ++
abraham/tests/core/image/thru.cc | 56 -
abraham/tests/core/image/thru_const.cc | 64 ++
abraham/tests/core/image/thru_norm.cc | 58 ++
abraham/tests/core/image/thru_v2v.cc | 56 +
abraham/tests/core/image/thru_v2w2v.cc | 64 ++
abraham/tests/fun/meta/red.cc | 60 ++
abraham/tests/morpho/test_component_tree.cc | 230 --------
abraham/tests/morpho/test_watershed.cc | 60 --
abraham/tests/morpho/test_watershed_topo.cc | 8
vigouroux/color/rgb_to_cmy.hh | 8
vigouroux/color/rgb_to_hsi.hh | 2
vigouroux/color/rgb_to_xyz.hh | 14
vigouroux/color/rgb_to_yuv.hh | 8
vigouroux/tests.cc | 6
24 files changed, 2311 insertions(+), 481 deletions(-)
Index: abraham/tests/morpho/test_watershed.cc
--- abraham/tests/morpho/test_watershed.cc (revision 2672)
+++ abraham/tests/morpho/test_watershed.cc (working copy)
@@ -7,7 +7,7 @@
#include <mln/io/pgm/load.hh>
#include <mln/io/pgm/save.hh>
-#include <mln/morpho/basic_najman.hh>
+#include <mln/morpho/najman_wst.hh>
#include <string>
#include <iostream>
@@ -22,15 +22,15 @@
// #define TEST
- io::pgm::load(input, "./images/test_watershed.pgm");
+ // io::pgm::load(input, "./images/test_watershed.pgm");
// io::pgm::load(input, "./images/little_test.pgm");
- // io::pgm::load(input, "./images/test_2.pgm");
+ io::pgm::load(input, "./images/test.pgm");
// io::pgm::load(input, "./images/lena_light.pgm");
// io::pgm::load(mverif, "./images/result_m_watershed.pgm");
// io::pgm::load(wverif, "./images/result_topo_watershed.pgm");
- morpho::basic_najman< image2d<int_u8>, neighb2d> n(input, c4());
+ morpho::najman_wst< image2d<int_u8>, neighb2d> n(input, c4());
/*
image2dint::fwd_piter it(input.domain());
@@ -43,60 +43,8 @@
// io::tikz::save(input, "start.tex");
- std::cout << "Building Component tree..." << std::endl;
-
n.go();
- std::cout << "M-Watershed" << std::endl;
-
- n.m_watershed();
-
- io::pgm::save(n.pima, "int.pgm");
-
- // io::tikz::save(n.pima, "step.tex");
-
-#ifdef TEST
-
- bool equal = true;
-
- equal = n.pima == mverif;
-
- if (!equal)
- {
- std::cout << "M-Watershed broken" << std::endl;
- return 1;
- }
- else
- std::cout << "M-Watershed good as chocolate ice cream" << std::endl;
-
-#endif
-
- std::cout << "W-watershed" << std::endl;
-
- n.w_watershed();
- // io::pgm::save(n.pima, "int.pgm");
- // std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl;
- // n.w_watershed();
-
- // for_all(it)
- // n.pima(it) = n.pima(it) * 17;
-
-#ifdef TEST
- equal = n.pima == wverif;
-
- if (!equal)
- {
- std::cout << "W-Watershed broken" << std::endl;
- return 1;
- }
- else
- std::cout << "W-Watershed good as chocolate ice cream" << std::endl;
-#endif
-
- // io::tikz::save(n.pima, "end.tex");
-
- // n.image_output(n.pima);
-
io::pgm::save(n.pima, "out.pgm");
return 0;
Index: abraham/tests/morpho/test_watershed_topo.cc
--- abraham/tests/morpho/test_watershed_topo.cc (revision 2672)
+++ abraham/tests/morpho/test_watershed_topo.cc (working copy)
@@ -9,7 +9,7 @@
#include <mln/io/pgm/load.hh>
#include <mln/io/pgm/save.hh>
-#include <mln/morpho/basic_najman.hh>
+#include <mln/morpho/topo_wst.hh>
#include <string>
#include <iostream>
@@ -32,7 +32,7 @@
// io::pgm::load(input, "./images/test_watershed.pgm");
// io::pgm::load(input, "./images/little_test.pgm");
- io::pgm::load(input, "./images/test_4.pgm");
+ io::pgm::load(input, "./images/test.pgm");
// io::pgm::load(input, "../../img/dots.pgm");
//io::pgm::load(input, "./images/+irm6.pgm");
@@ -40,7 +40,7 @@
// io::pgm::load(mverif, "./images/result_m_watershed.pgm");
// io::pgm::load(wverif, "./images/result_topo_watershed.pgm");
- morpho::basic_najman< image2d<int_u8>, neighb2d> n(input, c4());
+ morpho::topo_wst< image2d<int_u8>, neighb2d> n(input, c4());
/*
image2dint::fwd_piter it(input.domain());
@@ -53,7 +53,7 @@
// io::tikz::save(input, "start.tex");
- n.gotopo();
+ n.go();
io::pgm::save(n.pima, "out.pgm");
Index: abraham/tests/fun/meta/red.cc
--- abraham/tests/fun/meta/red.cc (revision 0)
+++ abraham/tests/fun/meta/red.cc (revision 0)
@@ -0,0 +1,60 @@
+#include <mln/fun/meta/red.hh>
+#include <mln/core/image/image2d.hh>
+#include <mln/core/image/thru.hh>
+
+namespace mln
+{
+
+ template <class T>
+ struct rgb
+ {
+ T red() const { return r; }
+ T& red() { return r; }
+ T r;
+ };
+
+ template <class T>
+ struct function< meta::red, rgb<T> > : public Function_v2w_w2v<function< meta::red, rgb<T> > >
+ {
+ typedef T result;
+ T read(const rgb<T>& c)
+ {
+ std::cout << "read red rgb<T>" << std::endl;
+ return c.red();
+ }
+
+ typedef T& lresult;
+ T& write(rgb<T>& c)
+ {
+ std::cout << "write red rgb<T>" << std::endl;
+ return c.red();
+ }
+ };
+}
+
+int main ()
+{
+ typedef mln::rgb<int> C;
+ mln::image2d<C> i(3, 2, 0);
+ C c;
+ c.r = 51;
+ i(mln::point2d(0,0)) = c;
+ c.r = 23;
+ i(mln::point2d(0,1)) = c;
+ c.r = 43;
+ i(mln::point2d(1,0)) = c;
+ c.r = 0;
+ i(mln::point2d(1,1)) = c;
+ c.r = 65;
+ i(mln::point2d(2,0)) = c;
+ c.r = 1;
+ i(mln::point2d(2,1)) = c;
+
+ mln::thru<mln::meta::red, mln::image2d<C> > out(i);
+
+ for_all (p)
+ std::cout << out(p) << std::endl;
+
+
+}
+
Index: abraham/tests/core/image/thru_norm.cc
--- abraham/tests/core/image/thru_norm.cc (revision 0)
+++ abraham/tests/core/image/thru_norm.cc (revision 0)
@@ -0,0 +1,58 @@
+// Copyright (C) 2007, 2008 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.
+
+# include <mln/core/image/image2d.hh>
+# include <mln/core/image/thru.hh>
+# include <mln/fun/v2w_w2v/norm.hh>
+# include <mln/algebra/vec.hh>
+# include <mln/level/fill.hh>
+# include <mln/core/image/violent_cast_image.hh>
+
+
+int main ()
+{
+
+ using namespace mln;
+ typedef image2d<algebra::vec<2, double> > I;
+
+ I ima(3, 2, 0);
+
+ ima(point2d(0,0)).set (1, 1);
+ ima(point2d(0,1)).set (1, 3);
+ ima(point2d(1,0)).set (4, 4);
+ ima(point2d(1,1)).set (-1, 3);
+ ima(point2d(2,0)).set (23, 23);
+ ima(point2d(2,1)).set (3, 1);
+
+ thru<mln::fun::v2w_w2v::l1_norm<algebra::vec<2, double>, double>, I > out(ima);
+ level::fill(out, 1);
+
+ box_fwd_piter_<point2d> p(ima.domain());
+
+ for_all (p)
+ std::cout << ima(p) << std::endl;
+}
Index: abraham/tests/core/image/thru_v2v.cc
--- abraham/tests/core/image/thru_v2v.cc (revision 0)
+++ abraham/tests/core/image/thru_v2v.cc (revision 0)
@@ -0,0 +1,56 @@
+// Copyright (C) 2007, 2008 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.
+
+# include <mln/core/image/image2d.hh>
+# include <mln/core/image/thru.hh>
+# include <mln/fun/v2v/abs.hh>
+
+int main ()
+{
+
+ using namespace mln;
+
+ typedef image2d<int> I;
+
+ int vs[6][5] = {
+
+ { -3, -3, -4, -4, -4 },
+ { -2, -1, -1, -1, -1 },
+ { -1, -4, -4, -4, -1 },
+ { -1, -4, -3, -4, -1 },
+ { -1, -4, -5, -3, -1 },
+ { -1, -1, -1, -1, -1 }
+
+ };
+
+ image2d<int> ima(make::image2d(vs));
+ thru<mln::fun::v2v::abs<int>, image2d<int> > out(ima);
+
+ box_fwd_piter_<point2d> p(ima.domain());
+ for_all (p)
+ mln_assertion (out(p) >= 0);
+}
Index: abraham/tests/core/image/thru_const.cc
--- abraham/tests/core/image/thru_const.cc (revision 0)
+++ abraham/tests/core/image/thru_const.cc (revision 0)
@@ -0,0 +1,64 @@
+// Copyright (C) 2007, 2008 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.
+
+# include <mln/core/image/image2d.hh>
+# include <mln/core/image/thru.hh>
+# include <mln/fun/v2w2v/cos.hh>
+
+int main ()
+{
+
+ using namespace mln;
+
+ typedef const image2d<double> I;
+
+ double vs[6][5] = {
+
+ { 12, -3, 8, -4, 6 },
+ { -2, 22, -1, 45, -1 },
+ { -1, -4, -4, -4, -1 },
+ { -1, -4, -3, -4, -1 },
+ { -1, -4, -5, -3, -1 },
+ { -1, -1, -1, -1, -1 }
+
+ };
+
+ I ima(make::image2d(vs));
+ thru<mln::fun::v2w2v::cos<double>, I > out(ima);
+
+ double i = 0;
+
+ box_fwd_piter_<point2d> p(ima.domain());
+ for_all (p)
+ {
+ out(p) = i;
+ i += 1./40.;
+ }
+
+ for_all (p)
+ std::cout << out(p) << std::endl;
+}
Index: abraham/tests/core/image/thru_v2w2v.cc
--- abraham/tests/core/image/thru_v2w2v.cc (revision 0)
+++ abraham/tests/core/image/thru_v2w2v.cc (revision 0)
@@ -0,0 +1,64 @@
+// Copyright (C) 2007, 2008 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.
+
+# include <mln/core/image/image2d.hh>
+# include <mln/core/image/thru.hh>
+# include <mln/fun/v2w2v/cos.hh>
+
+int main ()
+{
+
+ using namespace mln;
+
+ typedef image2d<double> I;
+
+ double vs[6][5] = {
+
+ { 12, -3, 8, -4, 6 },
+ { -2, 22, -1, 45, -1 },
+ { -1, -4, -4, -4, -1 },
+ { -1, -4, -3, -4, -1 },
+ { -1, -4, -5, -3, -1 },
+ { -1, -1, -1, -1, -1 }
+
+ };
+
+ image2d<double> ima(make::image2d(vs));
+ thru<mln::fun::v2w2v::cos<double>, image2d<double> > out(ima);
+
+ double i = 0;
+
+ box_fwd_piter_<point2d> p(ima.domain());
+ for_all (p)
+ {
+ out(p) = i;
+ i += 1./40.;
+ }
+
+ for_all (p)
+ std::cout << out(p) << std::endl;
+}
Index: abraham/tests/core/concept/test.cc
--- abraham/tests/core/concept/test.cc (revision 0)
+++ abraham/tests/core/concept/test.cc (revision 0)
@@ -0,0 +1,75 @@
+#include <iostream>
+#include <mln/core/concept/meta_fun.hh>
+
+using namespace mln;
+
+meta::red red; // fun-obj
+
+
+
+template <class T>
+struct rgb
+{
+ T red() const { return r; }
+ T& red() { return r; }
+ T r;
+};
+
+
+
+template <class T>
+struct fun< meta::red, rgb<T> > : Function_v2v< fun< meta::red, rgb<T> > >
+{
+ typedef T result;
+ T read(const rgb<T>& c)
+ {
+ std::cout << "read red rgb<T>" << std::endl;
+ return c.red();
+ }
+
+ typedef T& lresult;
+ T& write(rgb<T>& c)
+ {
+ std::cout << "write red rgb<T>" << std::endl;
+ return c.red();
+ }
+};
+
+
+/*
+
+ morpher apply(M m, I ima)
+ {
+ M et value(I) -> F -> nature
+ }
+
+ */
+
+
+
+int main()
+{
+ typedef rgb<int> C;
+ C c;
+ c.r = 51;
+
+ int r = red(c);
+ std::cout << r << std::endl;
+
+
+ // norm(v) = 1;
+
+
+ // norm( ima(p) ) = n;
+
+ // norm( v& ) = n;
+ // v = n * v / norm(v);
+
+ // norm( v& ) = 1;
+
+
+
+ // ima' = apply(norm, ima)
+ // ima'(p) = 1;
+
+}
Index: abraham/mln/morpho/najman_wst.hh
--- abraham/mln/morpho/najman_wst.hh (revision 0)
+++ abraham/mln/morpho/najman_wst.hh (revision 0)
@@ -0,0 +1,791 @@
+// Copyright (C) 2008 EPITA Research and Development Laboratory (LRDE)
+//
+// 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_MORPHO_NAJMAN_WST_HH
+# define MLN_MORPHO_NAJMAN_WST_HH
+
+
+
+#include <mln/level/sort_psites.hh>
+#include <mln/level/fill.hh>
+#include <mln/core/image/image2d.hh>
+#include <mln/core/site_set/p_set.hh>
+#include <mln/estim/min_max.hh>
+#include <mln/math/sqr.hh>
+#include <mln/util/greater_psite.hh>
+#include <mln/util/ord.hh>
+
+#include <mln/core/site_set/p_priority.hh>
+#include <mln/core/site_set/p_queue_fast.hh>
+
+#include <queue>
+#include <vector>
+#include <map>
+
+namespace mln
+{
+ namespace morpho
+ {
+
+ template <class I, class N>
+ struct najman_wst
+ {
+
+ // Typedefs
+ // --------
+ typedef mln_site(I) site;
+
+ // Component tree management
+ // -------------------------
+ private:
+ struct node {
+ mln_value(I) level;
+ int area;
+ int highest;
+ typedef mln_site(I) site;
+ // Can't modify the sites in a p_array
+ // p_array<mln_site(I)> children;
+ std::vector<site> children;
+
+ void addChildren(const node& n)
+ {
+ // typename p_array<mln_site(I)>::fwd_piter it(n.children);
+ // for (it.start();
+ // it.is_valid();
+ // it.next())
+ // children.append(it.to_site());
+ for (unsigned i=0; i < n.children.size(); ++i)
+ children.push_back(n.children[i]);
+ }
+
+ void addChild(const site p)
+ {
+ // children.append(n);
+ children.push_back(p);
+ }
+ }; // struct node
+
+ const mln_exact(N)& nbh;
+ mln_ch_value(I, site) Par_node;
+ mln_ch_value(I, site) Par_tree;
+
+ mln_ch_value(I, int) Rnk_tree;
+ mln_ch_value(I, int) Rnk_node;
+ mln_ch_value(I, site) subtreeRoot;
+ mln_ch_value(I, node) nodes;
+ site Root;
+
+ void MakeSet_tree(site x);
+ void MakeSet_node(site x);
+ site Find_tree(site x);
+ void swap(site& x, site& y);
+ site Find_node(site x);
+ void BuildComponentTree();
+ site MergeNode(site& node1, site& node2);
+ site Link_tree(site x, site y);
+ site Link_node(site x, site y);
+ node MakeNode(int level);
+
+
+ // Watershed algorithm
+ // -------------------
+
+ private:
+ mln_ch_value(I, bool) isproc;
+
+ // Ctor
+ public:
+ najman_wst(const Image<I>& i,
+ const Neighborhood<N>& n);
+
+
+ // Result
+ public:
+ mln_exact(I) pima;
+
+ public:
+ void go();
+
+ private:
+ site min (p_set<site>& components);
+ site max (p_set<site>& components);
+ bool highest_fork (p_set<site>& components);
+ bool highest_fork (p_set<site>& components, site &r);
+ bool m_destructible(site p);
+ bool w_destructible(site p);
+ bool m_destructible(site p, site &r);
+ bool w_destructible(site p, site &r);
+ void m_watershed ();
+ void w_watershed ();
+
+ // Optimized LCA Algorithm
+ private:
+ int *euler;
+ int *depth;
+ int ctree_size;
+ std::map<site, int, mln::util::ord<site> > pos;
+ site *repr;
+
+ int *minim;
+ int **Minim;
+
+ void compute_ctree_size (site p);
+ void build_euler_tour_rec(site p, int &position, int d);
+ void build_euler_tour();
+ void build_minim ();
+ site lca (site a, site b);
+ void removeOneSonNodes(site *p, mln_ch_value(I, site) &newPar_node);
+ void compressTree();
+ }; // struct najman_wst
+
+# ifndef MLN_INCLUDE_ONLY
+
+ // Ctor
+ template <class I, class N>
+ najman_wst<I, N>::najman_wst(const Image<I>& i,
+ const Neighborhood<N>& n)
+ : pima(exact(i)),
+ nbh(exact(n)),
+ Par_node(exact(i).domain(), exact(i).border()),
+ Par_tree(exact(i).domain(), exact(i).border()),
+ Rnk_tree(exact(i).domain(), exact(i).border()),
+ Rnk_node(exact(i).domain(), exact(i).border()),
+ subtreeRoot(exact(i).domain(), exact(i).border()),
+ nodes(exact(i).domain(), exact(i).border()),
+ isproc(exact(i).domain(), exact(i).border())
+ {
+ }
+
+ template <class I, class N>
+ void najman_wst<I, N>::MakeSet_tree(site x)
+ {
+ Par_tree(x) = x;
+ Rnk_tree(x) = 0;
+ }
+
+ template <class I, class N>
+ void najman_wst<I, N>::MakeSet_node(site x)
+ {
+ Par_node(x) = x;
+ Rnk_node(x) = 0;
+ }
+
+ template <class I, class N>
+ typename najman_wst<I, N>::site najman_wst<I, N>::Find_tree(site x)
+ {
+ if (Par_tree(x) != x)
+ Par_tree(x) = Find_tree(Par_tree(x));
+ return Par_tree(x);
+ }
+
+ template <class I, class N>
+ void najman_wst<I, N>::swap(site& x, site& y)
+ {
+ site memo = x;
+ x = y;
+ y = memo;
+ }
+
+ template <class I, class N>
+ typename najman_wst<I, N>::site najman_wst<I, N>::Find_node(site x)
+ {
+ if (Par_node(x) != x)
+ Par_node(x) = Find_node(Par_node(x));
+ return Par_node(x);
+ }
+
+ template <class I, class N>
+ void najman_wst<I, N>::go()
+ {
+ BuildComponentTree();
+ compressTree();
+ build_euler_tour();
+ build_minim();
+ m_watershed();
+ w_watershed();
+ }
+
+ template <class I, class N>
+ void najman_wst<I, N>::BuildComponentTree()
+ {
+ // Init:
+
+ // Sort the sites in increasing order
+ p_array<mln_site(I)> S;
+ S = level::sort_psites_increasing(pima);
+
+ // Clear the marker map
+ level::fill(isproc, false);
+ for (int ip = 0; ip < int(S.nsites()); ++ip)
+ {
+ site p = S[ip];
+ MakeSet_node(p);
+ MakeSet_tree(p);
+ // if (subtreeRoot.hold(p))
+ subtreeRoot(p) = p;
+ // if (nodes.hold(p))
+ nodes(p) = MakeNode(pima(p));
+ }
+
+
+
+ typename p_array<mln_site(I)>::fwd_piter ip(S);
+ for_all(ip)
+ {
+ site p = ip.to_site();
+
+ site curCanonicalElt = Find_tree(p);
+ site curNode = Find_node(subtreeRoot(curCanonicalElt));
+
+ mln_niter(N) q(nbh, ip);
+ for_all(q)
+ if (pima.has(q) and isproc(q) and pima(q) <= pima(p))
+ {
+ site adjCanonicalElt = Find_tree(q);
+ site adjNode = Find_node(subtreeRoot(adjCanonicalElt));
+ if (curNode != adjNode)
+ {
+ if (nodes(curNode).level == nodes(adjNode).level)
+ curNode = MergeNode(adjNode, curNode);
+ else
+ {
+ nodes(curNode).addChild(adjNode);
+ nodes(curNode).area += nodes(adjNode).area;
+ nodes(curNode).highest += nodes(adjNode).highest;
+ }
+ }
+
+ curCanonicalElt = Link_tree(adjCanonicalElt, curCanonicalElt);
+ subtreeRoot(curCanonicalElt) = curNode;
+ }
+ isproc(p) = true;
+ }
+ // Pour garder une map de correspondance site <-> local_root
+ // for (int ip = 0; ip < int(S.size()); ++ip)
+ // {
+ // site p = S[ip];
+ // M(p) = Find_node(p);
+ // }
+
+ mln_piter(I) r(Par_node.domain());
+ for_all(r)
+ Par_node(r) = Find_node(r);
+
+ Root = subtreeRoot(Find_tree(Find_node(site(0, 0))));
+ }
+
+
+ template <class I, class N>
+ typename najman_wst<I, N>::site najman_wst<I, N>::MergeNode(site& node1, site& node2)
+ {
+ site tmpNode = Link_node(node1, node2);
+ site tmpNode2;
+ if (tmpNode == node2)
+ {
+ nodes(node2).addChildren(nodes(node1));
+ tmpNode2 = node1;
+ }
+ else
+ {
+ nodes(node1).addChildren(nodes(node2));
+ tmpNode2 = node2;
+ }
+ nodes(tmpNode).area += nodes(tmpNode2).area;
+ nodes(tmpNode).highest += nodes(tmpNode2).highest;
+ return tmpNode;
+ }
+
+ template <class I, class N>
+ typename najman_wst<I, N>::site najman_wst<I, N>::Link_tree(site x, site y)
+ {
+ if (Rnk_tree(x) > Rnk_tree(y))
+ swap(x, y);
+ else
+ if (Rnk_tree(x) == Rnk_tree(y))
+ Rnk_tree(y) += 1;
+ Par_tree(x) = y;
+ return y;
+ }
+
+ template <class I, class N>
+ typename najman_wst<I, N>::site najman_wst<I, N>::Link_node(site x, site y)
+ {
+ if (Rnk_node(x) > Rnk_node(y))
+ swap(x, y);
+ else
+ if (Rnk_node(x) == Rnk_node(y))
+ Rnk_node(y) += 1;
+ Par_node(x) = y;
+ return y;
+ }
+
+ template <class I, class N>
+ typename najman_wst<I, N>::node najman_wst<I, N>::MakeNode(int level)
+ {
+ node n;
+ n.level = level;
+ n.area = 1;
+ n.highest = level;
+ return n;
+ }
+
+ template <class I, class N>
+ typename najman_wst<I, N>::site najman_wst<I, N>::min (p_set<site>& components)
+ {
+ if (components.nsites() == 0)
+ return site(-1, -1);
+
+ typename p_set<site>::fwd_piter it(components);
+ site min = components[0];
+
+ for_all(it)
+ if (pima(it.to_site()) < pima(min))
+ min = it.to_site();
+
+ return min;
+ }
+
+ template <class I, class N>
+ typename najman_wst<I, N>::site najman_wst<I, N>::max (p_set<site>& components)
+ {
+ if (components.nsites() == 0)
+ return site(-1, -1);
+
+ typename p_set<site>::fwd_piter it(components);
+ site max = components[0];
+
+ for_all(it)
+ if (pima(it.to_site()) > pima(max))
+ max = it.to_site();
+
+ return max;
+ }
+
+
+ template <class I, class N>
+ bool najman_wst<I, N>::highest_fork (p_set<site>& components, site &r)
+ {
+ if (components.nsites() == 0)
+ {
+ std::cerr << "highest fork : empty set" << std::endl;
+ return false;
+ }
+
+ site
+ m = min(components),
+ hfork = m;
+
+ typename p_set<site>::fwd_piter it(components);
+ for_all(it)
+ {
+ // Can't remove the site from the set
+ if (it.to_site() == m)
+ continue;
+
+ site c = lca(hfork, it.to_site());
+ if (c != it.to_site())
+ hfork = c;
+ }
+
+ if (nodes(m).level == nodes(hfork).level)
+ return false;
+
+ r = hfork;
+ return true;
+ }
+
+ template <class I, class N>
+ bool najman_wst<I, N>::w_destructible(site p, site &r)
+ {
+ mln_niter(N) q(nbh, p);
+ p_set<site> v;
+
+ for_all(q)
+ if (pima.has(q) && pima(q) < pima(p))
+ v.insert(Par_node(q));
+
+ if (v.nsites() == 0)
+ return false;
+
+ site hf;
+ bool is_hf = highest_fork(v, hf);
+
+ if (!is_hf) {
+ r = min(v);
+ return true;
+ }
+
+ if (nodes(hf).level <= pima(p)) {
+ r = hf;
+ return true;
+ }
+ return false;
+ }
+
+ template <class I, class N>
+ bool najman_wst<I, N>::highest_fork (p_set<site>& components) {
+ site i;
+ return highest_fork(components, i);
+ }
+
+ template <class I, class N>
+ bool najman_wst<I, N>::m_destructible(site p) {
+ site i;
+ return m_destructible(p, i);
+ }
+
+ template <class I, class N>
+ bool najman_wst<I, N>::w_destructible(site p) {
+ site i;
+ return w_destructible(p, i);
+ }
+
+ template <class I, class N>
+ bool najman_wst<I, N>::m_destructible(site p, site &r)
+ {
+ mln_niter(N) q(nbh, p);
+ p_set<site> v = p_set<site>();
+
+ for_all(q)
+ if (pima.has(q) && pima(q) < pima(p))
+ v.insert(Par_node(q));
+
+ if (v.nsites() == 0)
+ return false;
+
+ // if (nodes(min(v)).children.nsites() != 0)
+ if (nodes(min(v)).children.size() != 0)
+ return false;
+
+ bool is_hf = highest_fork(v);
+
+ if (!is_hf) {
+ r = min(v);
+ return true;
+ }
+
+ return false;
+ }
+
+
+ template <class I, class N>
+ void najman_wst<I, N>::m_watershed ()
+ {
+ typedef
+ // p_priority_queue<site, mln_value(I) >
+ std::priority_queue<site, std::vector<site>, util::greater_psite<I> >
+ ordered_queue_type;
+
+
+ ordered_queue_type l(util::make_greater_psite(pima));
+
+ // Clear the marker map
+ level::fill(isproc, false);
+ mln_piter(I) it(pima.domain());
+
+ for_all(it)
+ if (m_destructible(it.to_site()))
+ {
+ l.push(it.to_site());
+ isproc(it.to_site()) = true;
+ }
+
+ site p, i;
+ while (!l.empty())
+ {
+ // Extract priority queue
+ p = l.top();
+ l.pop();
+
+ // unmark p
+ isproc(p) = false;
+
+ bool is_m = m_destructible(p, i);
+
+ if (is_m)
+ {
+ pima(p) = nodes(i).level;
+ Par_node(p) = i;
+
+ mln_niter(N) q(nbh, p);
+ for_all(q)
+ if (pima.has(q) && !isproc(q))
+ if (m_destructible(q))
+ {
+ // Add priority queue
+ l.push(q);
+
+ // mark q
+ isproc(q) = true;
+ }
+ }
+ }
+ }
+
+
+ template <class I, class N>
+ void najman_wst<I, N>::w_watershed ()
+ {
+ mln::p_priority< mln_value(I), p_queue_fast<site> > L;
+
+ mln_value(I) max = level::compute(accu::meta::max(), pima);
+
+ // I K(pima.domain(), pima.border());
+ mln_ch_value(I, unsigned) K(pima.domain(), pima.border());
+ mln_ch_value(I, site) H(pima.domain(), pima.border());
+
+ // For All p of E do
+ mln_piter(I) it(pima.domain());
+ for_all(it)
+ {
+ site p = it.to_site();
+ site i;
+
+ // i <- W-Destructible(p)
+ bool is_w = w_destructible(p, i);
+
+ // If i != infinity then
+ if (is_w)
+ {
+ L.push(max - nodes(i).level, p);
+ K(p) = nodes(i).level;
+ H(p) = i;
+ }
+ }
+
+ while (!L.is_empty())
+ {
+ mln_value(I) k = max - L.highest_priority();
+
+ site p = L.front();
+ L.pop();
+
+ if (K(p) == k)
+ {
+ pima(p) = k;
+ Par_node(p) = H(p);
+
+ mln_niter(N) q(nbh, p);
+ for_all(q)
+ if (pima.has(q) && k < pima(q))
+ {
+ site i;
+ bool is_w = w_destructible(q, i);
+ if (!is_w)
+ K(q) = 10000; // FIXME : supposed to be infinity...
+ else
+ if (K(q) != nodes(i).level)
+ {
+ L.push(max - nodes(i).level, q);
+ K(q) = nodes(i).level;
+ H(q) = i;
+ }
+ }
+ }
+ }
+ }
+
+
+ template <class I, class N>
+ void najman_wst<I, N>::compute_ctree_size (site p)
+ {
+ ctree_size += 1;
+ node& n = nodes(p);
+
+ // typename p_array<mln_site(I)>::fwd_piter it(n.children);
+ // for_all(it)
+ // compute_ctree_size(it.to_site());
+
+ for (unsigned i=0; i < n.children.size(); ++i)
+ compute_ctree_size(n.children[i]);
+ }
+
+
+ template <class I, class N>
+ void najman_wst<I, N>::build_euler_tour_rec(site p, int &position, int d)
+ {
+ if (pos.find(p) == pos.end())
+ pos[p] = position;
+
+ repr[position] = p;
+ depth[position] = d;
+ euler[position] = pos[p];
+ ++position;
+ node& n = nodes(p);
+
+ // typename p_array<mln_site(I)>::fwd_piter it(n.children);
+ // for_all(it)
+ // {
+ // build_euler_tour_rec(it.to_site(), position, d+1);
+ // depth[position] = d; // Not optimized
+ // euler[position] = pos[p];
+ // repr[position] = p; // Pas necessaire?
+ // ++position;
+ // }
+
+ for(unsigned i=0; i < n.children.size(); ++i)
+ {
+ build_euler_tour_rec(n.children[i], position, d+1);
+ depth[position] = d; // Not optimized
+ euler[position] = pos[p];
+ repr[position] = p; // Pas necessaire?
+ ++position;
+ }
+ }
+
+
+ template <class I, class N>
+ void najman_wst<I, N>::build_euler_tour ()
+ {
+ ctree_size = 0;
+ compute_ctree_size(Root);
+
+ int size = 2 * ctree_size - 1;
+
+ // FIXME : free this
+ euler = new int[size];
+ depth = new int[size];
+ repr = new site[size];
+
+ int position = 0;
+ build_euler_tour_rec(Root, position, 0);
+ }
+
+
+ template <class I, class N>
+ void najman_wst<I, N>::build_minim ()
+ {
+ // compute_tree_size(); // Already done in build_euler_tour
+ int size = 2 * ctree_size - 1;
+ int logn = (int)(ceil(log((double)(size))/log(2.0)));
+ // minim.reserve(size);
+ minim = new int [logn * size]; // FIXME : Think about freeing this
+ Minim = new int* [logn];
+
+ Minim[0] = minim;
+
+ // Init
+ for (int i = 0; i < size - 1; ++i)
+ if (depth[euler[i]] < depth[euler[i+1]]) {
+ Minim[0][i] = i;
+ } else {
+ Minim[0][i] = i+1;
+ }
+
+ // Minim[0][size - 1] = size - 1;
+
+ int k;
+ for (int j = 1; j < logn; j++) {
+ k = 1 << (j - 1);
+ Minim[j] = &minim[j * size];
+ for (int i = 0; i < size; i++) {
+ if ((i + (k << 1)) >= size) {
+ //Minim[j][i] = size - 1;
+ }
+ else {
+ if (depth[euler[Minim[j - 1][i]]] <= depth[euler[Minim[j - 1][i + k]]])
+ Minim[j][i] = Minim[j - 1][i];
+ else
+ Minim[j][i] = Minim[j - 1][i + k];
+ }
+ }
+ }
+
+ } // void build_minim ()
+
+
+ template <class I, class N>
+ typename najman_wst<I, N>::site najman_wst<I, N>::lca (site a, site b)
+ {
+ int
+ m = pos[a],
+ n = pos[b],
+ k;
+
+ if (m == n)
+ return repr[m];
+
+ if (m > n)
+ {
+ k = n;
+ n = m;
+ m = k;
+ }
+
+ k = (int)(log((double)(n - m))/log(2.));
+
+ if (depth[euler[Minim[k][m]]] < depth[euler[Minim[k][n - (1 << k)]]]) {
+ return repr[euler[Minim[k][m]]];
+ } else {
+ return repr[euler[Minim[k][n - (1 << k)]]];
+ }
+ }
+
+
+ template <class I, class N>
+ void najman_wst<I, N>::removeOneSonNodes(site *p, mln_ch_value(I, site) &newPar_node)
+ {
+ node &n = nodes(*p);
+
+ if (n.children.size() == 1) // this node has 1 son, delete it
+ {
+ n.area = -1;
+ newPar_node(*p) = n.children[0];
+ *p = n.children[0];
+ removeOneSonNodes(p, newPar_node);
+ }
+ else // there is more than one son, recursive call
+ {
+ for (unsigned i = 0; i < n.children.size(); ++i)
+ removeOneSonNodes(&(n.children[i]), newPar_node);
+ }
+ }
+
+
+ template <class I, class N>
+ void najman_wst<I, N>::compressTree()
+ {
+ mln_ch_value(I, site) newPar_node(Par_node.domain(), Par_node.border());
+
+ // Remove the nodes with one son
+ removeOneSonNodes(&Root, newPar_node);
+
+ // Update the references on deleted nodes
+ mln_piter(I) p(Par_node.domain());
+ for_all(p)
+ while (nodes(Par_node(p)).area == -1)
+ Par_node(p) = newPar_node(Par_node(p));
+ }
+
+# endif // MLN_INCLUDE_ONLY
+
+
+ }; // namespace morpho
+
+}; // namespace mln
+
+#endif // MLN_MORPHO_NAJMAN_WST_HH
Index: abraham/mln/morpho/basic_najman.hh
--- abraham/mln/morpho/basic_najman.hh (revision 2672)
+++ abraham/mln/morpho/basic_najman.hh (working copy)
@@ -33,8 +33,10 @@
#include <mln/estim/min_max.hh>
#include <mln/math/sqr.hh>
#include <mln/util/greater_psite.hh>
+#include <mln/util/ord.hh>
-#include <mln/core/site_set/p_priority_queue.hh>
+#include <mln/core/site_set/p_priority.hh>
+#include <mln/core/site_set/p_queue_fast.hh>
#include <queue>
#include <vector>
@@ -78,8 +80,8 @@
}
}; // struct node
- I pima;
- const Neighborhood<N>& nbh;
+ mln_exact(I) pima;
+ const mln_exact(N)& nbh;
mln_ch_value(I, site) Par_node;
mln_ch_value(I, site) Par_tree;
@@ -148,6 +150,8 @@
compressTree();
build_euler_tour();
build_minim();
+ m_watershed();
+ w_watershed();
}
@@ -269,22 +273,6 @@
return n;
}
- template <typename C>
- void image_output(image2d<C>& img)
- {
- for(unsigned int i = 0; i < img.domain().len(0); ++i)
- {
- for(unsigned int j = 0; j < img.domain().len(1); ++j)
- {
- C l = (img(site(i, j)));//.row() * img.domain().len(1) + (img(site(i, j))).col();
- std::cout << " " << l << " ";
- }
- std::cout << std::endl;
- }
- }
-
-
-
void print_tree(site p)
{
node& n = nodes(p);
@@ -335,12 +323,12 @@
}
- site highest_fork (p_set<site>& components)
+ bool highest_fork (p_set<site>& components, site &r)
{
if (components.nsites() == 0)
{
std::cerr << "highest fork : empty set" << std::endl;
- return site(-1, -1);
+ return false;
}
site
@@ -360,12 +348,13 @@
}
if (nodes(m).level == nodes(hfork).level)
- return site(-1, -1);
+ return false;
- return hfork;
+ r = hfork;
+ return true;
}
- site w_destructible(site p)
+ bool w_destructible(site p, site &r)
{
mln_niter(N) q(nbh, p);
p_set<site> v;
@@ -375,20 +364,45 @@
v.insert(Par_node(q));
if (v.nsites() == 0)
- return site(-1, -1);
+ return false;
- site hf = highest_fork(v);
+ site hf;
+ bool is_hf = highest_fork(v, hf);
- if (hf == site(-1, -1))
- return min(v);
+ if (!is_hf) {
+ r = min(v);
+ return true;
+ }
- if (nodes(hf).level <= pima(p))
- return hf;
+ if (nodes(hf).level <= pima(p)) {
+ r = hf;
+ return true;
+ }
+ return false;
+ }
- return site(-1, -1);
+ bool highest_fork (p_set<site>& components) {
+ site i;
+ return highest_fork(components, i);
}
- site m_destructible(site p)
+ bool m_destructible(site p) {
+ site i;
+ return m_destructible(p, i);
+ }
+
+ bool w_destructible(site p) {
+ site i;
+ return w_destructible(p, i);
+ }
+
+ bool w_constructible(site p) {
+ site i;
+ return w_constructible(p, i);
+ }
+
+
+ bool m_destructible(site p, site &r)
{
mln_niter(N) q(nbh, p);
p_set<site> v = p_set<site>();
@@ -398,21 +412,23 @@
v.insert(Par_node(q));
if (v.nsites() == 0)
- return site(-1, -1);
+ return false;
// if (nodes(min(v)).children.nsites() != 0)
if (nodes(min(v)).children.size() != 0)
- return (site(-1, -1));
+ return false;
- site hf = highest_fork(v);
+ bool is_hf = highest_fork(v);
- if (hf == site(-1, -1))
- return min(v);
+ if (!is_hf) {
+ r = min(v);
+ return true;
+ }
- return site(-1, -1);
+ return false;
}
- site w_constructible(site p)
+ bool w_constructible(site p, site &r)
{
mln_niter(N) q(nbh, p);
p_set<site> v;
@@ -422,10 +438,12 @@
v.insert(Par_node(q));
if (v.nsites() == 0)
- return site(-1, -1);
+ return false;
- if (v.nsites() == 1)
- return v[0];
+ if (v.nsites() == 1) {
+ r = v[0];
+ return true;
+ }
site
c = max(v),
@@ -445,9 +463,10 @@
}
if (nodes(c).level <= pima(p))
- return site(-1, -1);
+ return false;
- return c;
+ r = c;
+ return true;
}
void m_watershed ()
@@ -465,7 +484,7 @@
mln_piter(I) it(pima.domain());
for_all(it)
- if (m_destructible(it.to_site()) != site(-1, -1))
+ if (m_destructible(it.to_site()))
{
l.push(it.to_site());
isproc(it.to_site()) = true;
@@ -481,9 +500,9 @@
// unmark p
isproc(p) = false;
- i = m_destructible(p);
+ bool is_m = m_destructible(p, i);
- if (i != site(-1, -1))
+ if (is_m)
{
pima(p) = nodes(i).level;
Par_node(p) = i;
@@ -491,7 +510,7 @@
mln_niter(N) q(nbh, p);
for_all(q)
if (pima.has(q) && !isproc(q))
- if (m_destructible(q) != site(-1, -1))
+ if (m_destructible(q))
{
// Add priority queue
l.push(q);
@@ -505,15 +524,9 @@
void w_watershed()
{
- std::map< mln_value(I), std::set<site> > L;
+ mln::p_priority< mln_value(I), p_queue_fast<site> > L;
- // Setting the min and the max of the image
- mln_value(I) k, kmin, kmax;
- mln::estim::min_max(pima, kmin, kmax);
-
- // For k From kmin to kmax - 1 Do Lk <- <empty set>
- for (k = kmin; k < kmax; k++)
- L[k] = std::set<site>();
+ mln_value(I) max = level::compute(accu::meta::max(), pima);
// I K(pima.domain(), pima.border());
mln_ch_value(I, unsigned) K(pima.domain(), pima.border());
@@ -524,27 +537,26 @@
for_all(it)
{
site p = it.to_site();
+ site i;
// i <- W-Destructible(p)
- site i = w_destructible(p);
+ bool is_w = w_destructible(p, i);
// If i != infinity then
- if (i != site(-1, -1))
+ if (is_w)
{
- L[nodes(i).level].insert(p);
+ L.push(max - nodes(i).level, p);
K(p) = nodes(i).level;
H(p) = i;
}
}
- for (k = kmin; k < kmax; k++)
+ while (!L.is_empty())
{
- std::set<site>& Lk = L[k];
+ mln_value(I) k = max - L.highest_priority();
- while (!Lk.empty())
- {
- site p = *(Lk.begin());
- Lk.erase(p);
+ site p = L.front();
+ L.pop();
if (K(p) == k)
{
@@ -555,13 +567,14 @@
for_all(q)
if (pima.has(q) && k < pima(q))
{
- site i = w_destructible(q);
- if (i == site(-1, -1))
+ site i;
+ bool is_w = w_destructible(q, i);
+ if (!is_w)
K(q) = 10000; // FIXME : supposed to be infinity...
else
if (K(q) != nodes(i).level)
{
- L[nodes(i).level].insert(q);
+ L.push(max - nodes(i).level, q);
K(q) = nodes(i).level;
H(q) = i;
}
@@ -569,8 +582,6 @@
}
}
}
- }
-
void revert_tree (site p)
{
@@ -628,7 +639,7 @@
// Mark enqueued sites
mln_ch_value(I, bool) enqueued(pima.domain(), pima.border());
- p_priority_queue < site, mln_value(I) > l;
+ p_priority< mln_value(I), p_queue_fast<site> > l;
// p_queue < site > m;
std::queue<site> m;
mln_value(I) max = mln_max(mln_value(I));
@@ -655,7 +666,7 @@
if (cmax.has(q) && !cmax(q) && !enqueued(q))
{
enqueued(q) = true;
- l.push(q, pima(q));
+ l.push(pima(q), q);
}
m.pop();
}
@@ -670,9 +681,10 @@
l.pop();
enqueued(x) = false;
- site c = w_constructible(x);
+ site c;
+ bool is_w = w_constructible(x, c);
- if (c != site(-1, -1))
+ if (is_w)
{
pima(x) = nodes(c).level;
Par_node(x) = c;
@@ -692,7 +704,7 @@
{
enqueued(q) = true;
- l.push(q, pima(q));
+ l.push(pima(q), q);
}
} // if (c != site(-1, -1))
} // while(!l.empty())
@@ -707,7 +719,7 @@
int *euler;
int *depth;
int ctree_size;
- std::map<site, int> pos;
+ std::map<site, int, mln::util::ord<site> > pos;
site *repr;
int *minim;
Index: abraham/mln/morpho/topo_wst.hh
--- abraham/mln/morpho/topo_wst.hh (revision 0)
+++ abraham/mln/morpho/topo_wst.hh (revision 0)
@@ -0,0 +1,744 @@
+// Copyright (C) 2008 EPITA Research and Development Laboratory (LRDE)
+//
+// 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_MORPHO_TOPO_WST_HH
+# define MLN_MORPHO_TOPO_WST_HH
+
+
+
+#include <mln/level/sort_psites.hh>
+#include <mln/level/fill.hh>
+#include <mln/core/image/image2d.hh>
+#include <mln/core/site_set/p_set.hh>
+#include <mln/estim/min_max.hh>
+#include <mln/math/sqr.hh>
+#include <mln/util/greater_psite.hh>
+#include <mln/util/ord.hh>
+#include <mln/arith/revert.hh>
+
+#include <mln/core/site_set/p_priority.hh>
+#include <mln/core/site_set/p_queue_fast.hh>
+
+#include <queue>
+#include <vector>
+#include <map>
+
+namespace mln
+{
+ namespace morpho
+ {
+
+ template <class I, class N>
+ struct topo_wst
+ {
+
+ // Typedefs
+ // --------
+ typedef mln_site(I) site;
+
+ // Component tree management
+ // -------------------------
+ private:
+ struct node {
+ mln_value(I) level;
+ int area;
+ int highest;
+ typedef mln_site(I) site;
+ // Can't modify the sites in a p_array
+ // p_array<mln_site(I)> children;
+ std::vector<site> children;
+
+ void addChildren(const node& n)
+ {
+ // typename p_array<mln_site(I)>::fwd_piter it(n.children);
+ // for (it.start();
+ // it.is_valid();
+ // it.next())
+ // children.append(it.to_site());
+ for (unsigned i=0; i < n.children.size(); ++i)
+ children.push_back(n.children[i]);
+ }
+
+ void addChild(const site p)
+ {
+ // children.append(n);
+ children.push_back(p);
+ }
+
+ mln_value(I) min() { return mln_min(mln_value(I)); }
+ mln_value(I) max() { return mln_max(mln_value(I)); }
+
+ }; // struct node
+
+ const mln_exact(N)& nbh;
+ mln_ch_value(I, site) Par_node;
+ mln_ch_value(I, site) Par_tree;
+
+ mln_ch_value(I, int) Rnk_tree;
+ mln_ch_value(I, int) Rnk_node;
+ mln_ch_value(I, site) subtreeRoot;
+ mln_ch_value(I, node) nodes;
+ site Root;
+
+ void MakeSet_tree(site x);
+ void MakeSet_node(site x);
+ site Find_tree(site x);
+ void swap(site& x, site& y);
+ site Find_node(site x);
+ void BuildComponentTree();
+ site MergeNode(site& node1, site& node2);
+ site Link_tree(site x, site y);
+ site Link_node(site x, site y);
+ node MakeNode(int level);
+
+
+ // Watershed algorithm
+ // -------------------
+
+ private:
+ mln_ch_value(I, bool) isproc;
+
+ // Ctor
+ public:
+ topo_wst(const Image<I>& i,
+ const Neighborhood<N>& n);
+
+
+ // Result
+ public:
+ mln_exact(I) pima;
+
+ public:
+ void go();
+
+ private:
+ site min (p_set<site>& components);
+ site max (p_set<site>& components);
+ bool highest_fork (p_set<site>& components);
+ bool highest_fork (p_set<site>& components, site &r);
+ bool w_constructible(site p, site &r);
+ bool w_constructible(site p);
+ void topo_watershed();
+
+
+ // Optimized LCA Algorithm
+ private:
+ int *euler;
+ int *depth;
+ int ctree_size;
+ std::map<site, int, mln::util::ord<site> > pos;
+ site *repr;
+
+ int *minim;
+ int **Minim;
+
+ void compute_ctree_size (site p);
+ void build_euler_tour_rec(site p, int &position, int d);
+ void build_euler_tour();
+ void build_minim ();
+ site lca (site a, site b);
+ void removeOneSonNodes(site *p, mln_ch_value(I, site) &newPar_node);
+ void compressTree();
+ }; // struct topo_wst
+
+# ifndef MLN_INCLUDE_ONLY
+
+ // Ctor
+ template <class I, class N>
+ topo_wst<I, N>::topo_wst(const Image<I>& i,
+ const Neighborhood<N>& n)
+ : pima(exact(i)),
+ nbh(exact(n)),
+ Par_node(exact(i).domain(), exact(i).border()),
+ Par_tree(exact(i).domain(), exact(i).border()),
+ Rnk_tree(exact(i).domain(), exact(i).border()),
+ Rnk_node(exact(i).domain(), exact(i).border()),
+ subtreeRoot(exact(i).domain(), exact(i).border()),
+ nodes(exact(i).domain(), exact(i).border()),
+ isproc(exact(i).domain(), exact(i).border())
+ {
+ }
+
+ template <class I, class N>
+ void topo_wst<I, N>::MakeSet_tree(site x)
+ {
+ Par_tree(x) = x;
+ Rnk_tree(x) = 0;
+ }
+
+ template <class I, class N>
+ void topo_wst<I, N>::MakeSet_node(site x)
+ {
+ Par_node(x) = x;
+ Rnk_node(x) = 0;
+ }
+
+ template <class I, class N>
+ typename topo_wst<I, N>::site topo_wst<I, N>::Find_tree(site x)
+ {
+ if (Par_tree(x) != x)
+ Par_tree(x) = Find_tree(Par_tree(x));
+ return Par_tree(x);
+ }
+
+ template <class I, class N>
+ void topo_wst<I, N>::swap(site& x, site& y)
+ {
+ site memo = x;
+ x = y;
+ y = memo;
+ }
+
+ template <class I, class N>
+ typename topo_wst<I, N>::site topo_wst<I, N>::Find_node(site x)
+ {
+ if (Par_node(x) != x)
+ Par_node(x) = Find_node(Par_node(x));
+ return Par_node(x);
+ }
+
+ template <class I, class N>
+ void topo_wst<I, N>::go()
+ {
+ BuildComponentTree();
+ compressTree();
+ arith::revert_inplace(pima);
+ arith::revert_inplace(nodes);
+ build_euler_tour();
+ build_minim();
+ topo_watershed();
+ arith::revert_inplace(pima);
+ }
+
+ template <class I, class N>
+ void topo_wst<I, N>::BuildComponentTree()
+ {
+ // Init:
+
+ // Sort the sites in increasing order
+ p_array<mln_site(I)> S;
+ S = level::sort_psites_increasing(pima);
+
+ // Clear the marker map
+ level::fill(isproc, false);
+ for (int ip = 0; ip < int(S.nsites()); ++ip)
+ {
+ site p = S[ip];
+ MakeSet_node(p);
+ MakeSet_tree(p);
+ // if (subtreeRoot.hold(p))
+ subtreeRoot(p) = p;
+ // if (nodes.hold(p))
+ nodes(p) = MakeNode(pima(p));
+ }
+
+
+
+ typename p_array<mln_site(I)>::fwd_piter ip(S);
+ for_all(ip)
+ {
+ site p = ip.to_site();
+
+ site curCanonicalElt = Find_tree(p);
+ site curNode = Find_node(subtreeRoot(curCanonicalElt));
+
+ mln_niter(N) q(nbh, ip);
+ for_all(q)
+ if (pima.has(q) and isproc(q) and pima(q) <= pima(p))
+ {
+ site adjCanonicalElt = Find_tree(q);
+ site adjNode = Find_node(subtreeRoot(adjCanonicalElt));
+ if (curNode != adjNode)
+ {
+ if (nodes(curNode).level == nodes(adjNode).level)
+ curNode = MergeNode(adjNode, curNode);
+ else
+ {
+ nodes(curNode).addChild(adjNode);
+ nodes(curNode).area += nodes(adjNode).area;
+ nodes(curNode).highest += nodes(adjNode).highest;
+ }
+ }
+
+ curCanonicalElt = Link_tree(adjCanonicalElt, curCanonicalElt);
+ subtreeRoot(curCanonicalElt) = curNode;
+ }
+ isproc(p) = true;
+ }
+ // Pour garder une map de correspondance site <-> local_root
+ // for (int ip = 0; ip < int(S.size()); ++ip)
+ // {
+ // site p = S[ip];
+ // M(p) = Find_node(p);
+ // }
+
+ mln_piter(I) r(Par_node.domain());
+ for_all(r)
+ Par_node(r) = Find_node(r);
+
+ Root = subtreeRoot(Find_tree(Find_node(site(0, 0))));
+ }
+
+
+ template <class I, class N>
+ typename topo_wst<I, N>::site topo_wst<I, N>::MergeNode(site& node1, site& node2)
+ {
+ site tmpNode = Link_node(node1, node2);
+ site tmpNode2;
+ if (tmpNode == node2)
+ {
+ nodes(node2).addChildren(nodes(node1));
+ tmpNode2 = node1;
+ }
+ else
+ {
+ nodes(node1).addChildren(nodes(node2));
+ tmpNode2 = node2;
+ }
+ nodes(tmpNode).area += nodes(tmpNode2).area;
+ nodes(tmpNode).highest += nodes(tmpNode2).highest;
+ return tmpNode;
+ }
+
+ template <class I, class N>
+ typename topo_wst<I, N>::site topo_wst<I, N>::Link_tree(site x, site y)
+ {
+ if (Rnk_tree(x) > Rnk_tree(y))
+ swap(x, y);
+ else
+ if (Rnk_tree(x) == Rnk_tree(y))
+ Rnk_tree(y) += 1;
+ Par_tree(x) = y;
+ return y;
+ }
+
+ template <class I, class N>
+ typename topo_wst<I, N>::site topo_wst<I, N>::Link_node(site x, site y)
+ {
+ if (Rnk_node(x) > Rnk_node(y))
+ swap(x, y);
+ else
+ if (Rnk_node(x) == Rnk_node(y))
+ Rnk_node(y) += 1;
+ Par_node(x) = y;
+ return y;
+ }
+
+ template <class I, class N>
+ typename topo_wst<I, N>::node topo_wst<I, N>::MakeNode(int level)
+ {
+ node n;
+ n.level = level;
+ n.area = 1;
+ n.highest = level;
+ return n;
+ }
+
+ template <class I, class N>
+ typename topo_wst<I, N>::site topo_wst<I, N>::min (p_set<site>& components)
+ {
+ if (components.nsites() == 0)
+ return site(-1, -1);
+
+ typename p_set<site>::fwd_piter it(components);
+ site min = components[0];
+
+ for_all(it)
+ if (pima(it.to_site()) < pima(min))
+ min = it.to_site();
+
+ return min;
+ }
+
+ template <class I, class N>
+ typename topo_wst<I, N>::site topo_wst<I, N>::max (p_set<site>& components)
+ {
+ if (components.nsites() == 0)
+ return site(-1, -1);
+
+ typename p_set<site>::fwd_piter it(components);
+ site max = components[0];
+
+ for_all(it)
+ if (pima(it.to_site()) > pima(max))
+ max = it.to_site();
+
+ return max;
+ }
+
+
+ template <class I, class N>
+ bool topo_wst<I, N>::highest_fork (p_set<site>& components, site &r)
+ {
+ if (components.nsites() == 0)
+ {
+ std::cerr << "highest fork : empty set" << std::endl;
+ return false;
+ }
+
+ site
+ m = min(components),
+ hfork = m;
+
+ typename p_set<site>::fwd_piter it(components);
+ for_all(it)
+ {
+ // Can't remove the site from the set
+ if (it.to_site() == m)
+ continue;
+
+ site c = lca(hfork, it.to_site());
+ if (c != it.to_site())
+ hfork = c;
+ }
+
+ if (nodes(m).level == nodes(hfork).level)
+ return false;
+
+ r = hfork;
+ return true;
+ }
+
+ template <class I, class N>
+ bool topo_wst<I, N>::highest_fork (p_set<site>& components) {
+ site i;
+ return highest_fork(components, i);
+ }
+
+ template <class I, class N>
+ bool topo_wst<I, N>::w_constructible(site p) {
+ site i;
+ return w_constructible(p, i);
+ }
+
+ template <class I, class N>
+ bool topo_wst<I, N>::w_constructible(site p, site &r)
+ {
+ mln_niter(N) q(nbh, p);
+ p_set<site> v;
+
+ for_all(q)
+ if (pima.has(q) && pima(q) > pima(p))
+ v.insert(Par_node(q));
+
+ if (v.nsites() == 0)
+ return false;
+
+ if (v.nsites() == 1) {
+ r = v[0];
+ return true;
+ }
+
+ site
+ c = max(v),
+ cmax = c;
+
+ typename p_set<site>::fwd_piter it(v);
+ for_all(it)
+ {
+ // Can't remove the site from the set
+ if (it.to_site() == cmax)
+ continue;
+
+ site c1 = lca(c, it.to_site());
+
+ if (c1 != it.to_site())
+ c = c1;
+ }
+
+ if (nodes(c).level <= pima(p))
+ return false;
+
+ r = c;
+ return true;
+ }
+
+
+ template <class I, class N>
+ void topo_wst<I, N>::topo_watershed()
+ {
+ // Maxima components
+ mln_ch_value(I, bool) cmax(pima.domain(), pima.border());
+
+ // Mark enqueued sites
+ mln_ch_value(I, bool) enqueued(pima.domain(), pima.border());
+
+ p_priority< mln_value(I), p_queue_fast<site> > l;
+ // p_queue < site > m;
+ std::queue<site> m;
+ mln_value(I) max = mln_max(mln_value(I));
+
+ std::cout << "Init" << std::endl;
+
+ // Flag C-maxima
+ level::fill(cmax, false);
+ level::fill(enqueued, false);
+
+ mln_piter(I) it(Par_node.domain());
+ for_all(it)
+ // if (nodes(Par_node(it.to_site())).children.nsites() == 0)
+ if (nodes(Par_node(it.to_site())).children.size() == 0)
+ {
+ cmax(it.to_site()) = true;
+ m.push(it.to_site());
+ }
+
+ while (!m.empty())
+ {
+ mln_niter(N) q(nbh, m.front());
+ for_all(q)
+ if (cmax.has(q) && !cmax(q) && !enqueued(q))
+ {
+ enqueued(q) = true;
+ l.push(pima(q), q);
+ }
+ m.pop();
+ }
+
+
+ std::cout << "end" << std::endl;
+
+ // Main loop
+ while(!l.is_empty())
+ {
+ site x = l.front();
+ l.pop();
+ enqueued(x) = false;
+
+ site c;
+ bool is_w = w_constructible(x, c);
+
+ if (is_w)
+ {
+ pima(x) = nodes(c).level;
+ Par_node(x) = c;
+
+ // if (nodes(c).children.nsites() == 0)
+ if (nodes(c).children.size() == 0)
+ cmax(x) = true;
+ else
+ // if (nodes(c).children.nsites() > 1)
+ if (nodes(c).children.size() == 1)
+ std::cerr << "ERREUR COMPOSANTE BRANCHE " << nodes(c).children.size() << std::endl;
+
+
+ mln_niter(N) q(nbh, x);
+ for_all(q)
+ if (pima.has(q) && !cmax(q) && !enqueued(q))
+ {
+ enqueued(q) = true;
+
+ l.push(pima(q), q);
+ }
+ } // if (c != site(-1, -1))
+ } // while(!l.empty())
+
+ for_all(it)
+ pima(it.to_site()) = nodes(Par_node(it.to_site())).level;
+ }
+
+
+
+ template <class I, class N>
+ void topo_wst<I, N>::compute_ctree_size (site p)
+ {
+ ctree_size += 1;
+ node& n = nodes(p);
+
+ // typename p_array<mln_site(I)>::fwd_piter it(n.children);
+ // for_all(it)
+ // compute_ctree_size(it.to_site());
+
+ for (unsigned i=0; i < n.children.size(); ++i)
+ compute_ctree_size(n.children[i]);
+ }
+
+
+ template <class I, class N>
+ void topo_wst<I, N>::build_euler_tour_rec(site p, int &position, int d)
+ {
+ if (pos.find(p) == pos.end())
+ pos[p] = position;
+
+ repr[position] = p;
+ depth[position] = d;
+ euler[position] = pos[p];
+ ++position;
+ node& n = nodes(p);
+
+ // typename p_array<mln_site(I)>::fwd_piter it(n.children);
+ // for_all(it)
+ // {
+ // build_euler_tour_rec(it.to_site(), position, d+1);
+ // depth[position] = d; // Not optimized
+ // euler[position] = pos[p];
+ // repr[position] = p; // Pas necessaire?
+ // ++position;
+ // }
+
+ for(unsigned i=0; i < n.children.size(); ++i)
+ {
+ build_euler_tour_rec(n.children[i], position, d+1);
+ depth[position] = d; // Not optimized
+ euler[position] = pos[p];
+ repr[position] = p; // Pas necessaire?
+ ++position;
+ }
+ }
+
+
+ template <class I, class N>
+ void topo_wst<I, N>::build_euler_tour ()
+ {
+ ctree_size = 0;
+ compute_ctree_size(Root);
+
+ int size = 2 * ctree_size - 1;
+
+ // FIXME : free this
+ euler = new int[size];
+ depth = new int[size];
+ repr = new site[size];
+
+ int position = 0;
+ build_euler_tour_rec(Root, position, 0);
+ }
+
+
+ template <class I, class N>
+ void topo_wst<I, N>::build_minim ()
+ {
+ // compute_tree_size(); // Already done in build_euler_tour
+ int size = 2 * ctree_size - 1;
+ int logn = (int)(ceil(log((double)(size))/log(2.0)));
+ // minim.reserve(size);
+ minim = new int [logn * size]; // FIXME : Think about freeing this
+ Minim = new int* [logn];
+
+ Minim[0] = minim;
+
+ // Init
+ for (int i = 0; i < size - 1; ++i)
+ if (depth[euler[i]] < depth[euler[i+1]]) {
+ Minim[0][i] = i;
+ } else {
+ Minim[0][i] = i+1;
+ }
+
+ // Minim[0][size - 1] = size - 1;
+
+ int k;
+ for (int j = 1; j < logn; j++) {
+ k = 1 << (j - 1);
+ Minim[j] = &minim[j * size];
+ for (int i = 0; i < size; i++) {
+ if ((i + (k << 1)) >= size) {
+ //Minim[j][i] = size - 1;
+ }
+ else {
+ if (depth[euler[Minim[j - 1][i]]] <= depth[euler[Minim[j - 1][i + k]]])
+ Minim[j][i] = Minim[j - 1][i];
+ else
+ Minim[j][i] = Minim[j - 1][i + k];
+ }
+ }
+ }
+
+ } // void build_minim ()
+
+
+ template <class I, class N>
+ typename topo_wst<I, N>::site topo_wst<I, N>::lca (site a, site b)
+ {
+ int
+ m = pos[a],
+ n = pos[b],
+ k;
+
+ if (m == n)
+ return repr[m];
+
+ if (m > n)
+ {
+ k = n;
+ n = m;
+ m = k;
+ }
+
+ k = (int)(log((double)(n - m))/log(2.));
+
+ if (depth[euler[Minim[k][m]]] < depth[euler[Minim[k][n - (1 << k)]]]) {
+ return repr[euler[Minim[k][m]]];
+ } else {
+ return repr[euler[Minim[k][n - (1 << k)]]];
+ }
+ }
+
+
+ template <class I, class N>
+ void topo_wst<I, N>::removeOneSonNodes(site *p, mln_ch_value(I, site) &newPar_node)
+ {
+ node &n = nodes(*p);
+
+ if (n.children.size() == 1) // this node has 1 son, delete it
+ {
+ n.area = -1;
+ newPar_node(*p) = n.children[0];
+ *p = n.children[0];
+ removeOneSonNodes(p, newPar_node);
+ }
+ else // there is more than one son, recursive call
+ {
+ for (unsigned i = 0; i < n.children.size(); ++i)
+ removeOneSonNodes(&(n.children[i]), newPar_node);
+ }
+ }
+
+
+ template <class I, class N>
+ void topo_wst<I, N>::compressTree()
+ {
+ mln_ch_value(I, site) newPar_node(Par_node.domain(), Par_node.border());
+
+ // Remove the nodes with one son
+ removeOneSonNodes(&Root, newPar_node);
+
+ // Update the references on deleted nodes
+ mln_piter(I) p(Par_node.domain());
+ for_all(p)
+ while (nodes(Par_node(p)).area == -1)
+ Par_node(p) = newPar_node(Par_node(p));
+ }
+
+# endif // MLN_INCLUDE_ONLY
+
+
+ }; // namespace morpho
+
+}; // namespace mln
+
+#endif // MLN_MORPHO_TOPO_WST_HH
Index: abraham/mln/core/image/thru.hh
--- abraham/mln/core/image/thru.hh (revision 2672)
+++ abraham/mln/core/image/thru.hh (working copy)
@@ -36,7 +36,9 @@
*/
# include <mln/core/internal/image_value_morpher.hh>
+# include <mln/trait/images.hh>
# include <mln/value/set.hh>
+# include <mln/core/image/shell.hh>
namespace mln
{
@@ -50,8 +52,8 @@
template <typename F, typename I>
struct data< thru<F,I> >
{
- data(const I& ima);
- const I& ima_;
+ data( I& ima);
+ I& ima_;
};
} // end of namespace mln::internal
@@ -64,7 +66,9 @@
template <typename F, typename I>
struct image_< thru<F,I> > : default_image_morpher< I, mln_result(F), thru<F,I> >
{
- typedef trait::image::value_io::read_only value_io;
+ typedef trait::image::value_io::read_write value_io;
+ typedef trait::image::value_access::computed value_access;
+ typedef trait::image::value_storage::disrupted value_storage;
};
} // end of namespace mln::trait
@@ -85,28 +89,22 @@
typedef mln_result(F) rvalue;
/// Return type of read-write access.
- typedef mln_result(F) lvalue;
+ typedef shell<F,I> lvalue;
/// Skeleton.
typedef thru< tag::value_<mln_result(F)>, tag::image_<I> > skeleton;
/// Constructor.
- thru(const Image<I>& ima);
+ thru(Image<I>& ima);
/// Initialize an empty image.
- void init_(const Image<I>& ima);
+ void init_(Image<I>& ima);
/// Read-only access of pixel value at point site \p p.
mln_result(F) operator()(const mln_psite(I)& p) const;
- /// Mutable access is only OK for reading (not writing).
- // T operator()(const mln_psite(I)& p);
- };
-
- template <typename F, typename I>
- struct thru <F, const I>
- {
- mln_result(F) operator()(const mln_psite(I)& p);
+ /// Mutable access is for reading and writing.
+ lvalue operator()(const mln_psite(I)& p);
};
# ifndef MLN_INCLUDE_ONLY
@@ -119,7 +117,7 @@
template <typename F, typename I>
inline
- data< thru<F,I> >::data(const I& ima)
+ data< thru<F,I> >::data(I& ima)
: ima_(ima)
{
}
@@ -130,22 +128,22 @@
template <typename F, typename I>
inline
- thru<F,I>::thru(const Image<I>& ima)
+ thru<F,I>::thru(Image<I>& ima)
{
mln_precondition(exact(ima).has_data());
this->data_ = new internal::data< thru<F,I> >(exact(ima));
}
- /*
+
template <typename F, typename I>
inline
void
- thru<F,I>::init_(const Image<I>& ima)
+ thru<F,I>::init_(Image<I>& ima)
{
mln_precondition(exact(ima).has_data());
this->data_ = new internal::data<thru<F,I> >(exact(ima));
}
- */
+
template <typename F, typename I>
inline
@@ -158,10 +156,10 @@
template <typename F, typename I>
inline
- mln_result(F)
+ shell<F, I>
thru<F,I>::operator()(const mln_psite(I)& p)
{
- return *(F*)(void*)&( this->data_->ima_(p) );
+ return shell<F, I>( this->data_->ima_, p );
}
# endif // ! MLN_INCLUDE_ONLY
Index: abraham/mln/core/image/shell.hh
--- abraham/mln/core/image/shell.hh (revision 0)
+++ abraham/mln/core/image/shell.hh (revision 0)
@@ -0,0 +1,118 @@
+// 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_CORE_VALUE_SHELL_HH
+# define MLN_CORE_VALUE_SHELL_HH
+
+# include <mln/core/concept/image.hh>
+
+namespace mln
+{
+
+ // FIXME : traits
+
+ template <typename F, typename I, class C>
+ struct shell_write;
+
+ template <typename F, typename I>
+ struct shell_write<F, I, Function_v2w2v<void> >
+ {
+ mln_value(I) set_ (I &ima, const mln_site(I) &s, const typename F::result &v);
+ };
+
+ template <typename F, typename I>
+ struct shell_write<F, I, Function_v2w_w2v<void> >
+ {
+ mln_value(I) set_ (I &ima, const mln_site(I) &s, const typename F::result &v);
+ };
+
+
+ template <typename F, typename I>
+ struct shell;
+
+ template <typename F, typename I>
+ struct shell : shell_write<F, I, typename F::category> // FIXME : inherit of value_base or sth?
+ {
+ typedef mln_value(I) value;
+
+ // Ctor
+ shell(Image<I> &ima, const mln_site(I) &s);
+
+ // Read
+ operator value ();
+
+ // Write
+ mln_value(I) operator= (typename F::result);
+
+ protected :
+ I &ima;
+ mln_site(I) s;
+ };
+
+# ifndef MLN_INCLUDE_ONLY
+
+ // Ctor
+
+ template <typename F, typename I>
+ shell<F, I>::shell(Image<I> &ima, const mln_site(I) &s)
+ : ima(exact(ima)), s(s)
+ { }
+
+
+ // Read for everyone
+ template <typename F, typename I>
+ shell<F, I>::operator value ()
+ {
+ return F()(ima(s));
+ }
+
+ // Write for everyone
+ template <typename F, typename I>
+ mln_value(I) shell<F, I>::operator= (typename F::result v)
+ {
+ set_(ima, s, v);
+ }
+
+ template <typename F, typename I>
+ mln_value(I) shell_write<F, I, Function_v2w2v<void> >::set_ (I &ima, const mln_site(I) &s, const typename F::result &v)
+ {
+ ima(s) = F().f_1(v);
+ return ima(s);
+ }
+
+ template <typename F, typename I>
+ mln_value(I) shell_write<F, I, Function_v2w_w2v<void> >::set_ (I &ima, const mln_site(I) &s, const typename F::result &v)
+ {
+ ima(s) = F().f_1(ima(s), v);
+ return ima(s);
+ }
+
+# endif // MLN_INCLUDE_ONLY
+
+}; // end of namespace mln
+
+#endif // MLN_CORE_VALUE_SHELL_HH
Index: abraham/mln/core/concept/function.hh
--- abraham/mln/core/concept/function.hh (revision 2672)
+++ abraham/mln/core/concept/function.hh (working copy)
@@ -160,7 +160,7 @@
template <typename E>
struct Function_v2w_w2v : public Function<E>
{
- typedef Function_v2w2v<void> category;
+ typedef Function_v2w_w2v<void> category;
/*
result operator() (value);
Index: abraham/mln/core/concept/meta_fun.hh
--- abraham/mln/core/concept/meta_fun.hh (revision 0)
+++ abraham/mln/core/concept/meta_fun.hh (revision 0)
@@ -0,0 +1,83 @@
+// 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_CORE_CONCEPT_META_FUN_HH
+# define MLN_CORE_CONCEPT_META_FUN_HH
+
+/*! \file mln/core/concept/meta_fun.hh
+ *
+ * \brief Definition of concept of meta function.
+ */
+
+# include <mln/core/concept/object.hh>
+# include <mln/core/concept/function.hh>
+
+namespace mln
+{
+
+ template <class M, class T>
+ struct function;
+
+ namespace meta
+ {
+
+ template <class M>
+ struct impl
+ {
+
+ template <class T>
+ struct info
+ {
+ typedef function<M, T> F;
+ typedef typename F::result result;
+ typedef typename F::lresult lresult;
+ };
+
+ template <class T>
+ typename info<T>::result
+ operator()(const T& t) const
+ {
+ function<M,T> f;
+ return f.read(t);
+ }
+
+ template <class T>
+ T&
+ f_1(typename info<T>::result v, T& t)
+ {
+ function<M,T> f;
+ f.write(t) = v;
+ return t;
+ }
+
+ };
+
+ } // end of namespace meta
+
+} // end of namespace mln
+
+#endif // MLN_CORE_CONCEPT_META_FUN_HH
Index: abraham/mln/fun/meta/red.hh
--- abraham/mln/fun/meta/red.hh (revision 0)
+++ abraham/mln/fun/meta/red.hh (revision 0)
@@ -0,0 +1,45 @@
+// 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_FUN_META_RED_HH
+# define MLN_FUN_META_RED_HH
+
+# include <mln/core/concept/meta_fun.hh>
+
+namespace mln {
+
+ namespace meta {
+
+ struct red : impl<red> { };
+
+ };
+
+ meta::red red; // fun obj
+
+};
+
+#endif // MLN_FUN_META_RED_HH
Index: abraham/mln/fun/v2w_w2v/norm.hh
--- abraham/mln/fun/v2w_w2v/norm.hh (revision 2672)
+++ abraham/mln/fun/v2w_w2v/norm.hh (working copy)
@@ -71,7 +71,7 @@
* \see mln::norm::l2.
*/
template <typename V, typename R>
- struct l2_norm : public Function_v2v< l2_norm<V, R> >
+ struct l2_norm : public Function_v2w_w2v< l2_norm<V, R> >
{
typedef R result;
R operator()(const V& v) const;
@@ -85,7 +85,7 @@
* \see mln::norm::linfty.
*/
template <typename V, typename R>
- struct linfty_norm : public Function_v2v< linfty_norm<V, R> >
+ struct linfty_norm : public Function_v2w_w2v< linfty_norm<V, R> >
{
typedef R result;
R operator()(const V& v) const;
Index: vigouroux/tests.cc
--- vigouroux/tests.cc (revision 2672)
+++ vigouroux/tests.cc (working copy)
@@ -1,4 +1,4 @@
-#include <mln/core/image_if_value.hh>
+#include <mln/core/image/image_if.hh>
#include <mln/core/alias/w_window2d_int.hh>
#include <mln/display/show.hh>
Index: vigouroux/color/rgb_to_cmy.hh
--- vigouroux/color/rgb_to_cmy.hh (revision 2672)
+++ vigouroux/color/rgb_to_cmy.hh (working copy)
@@ -1,4 +1,4 @@
-#include <mln/core/image_if_value.hh>
+#include <mln/core/image/image_if.hh>
#include <mln/core/alias/w_window2d_int.hh>
#include <mln/display/show.hh>
Index: vigouroux/color/rgb_to_xyz.hh
--- vigouroux/color/rgb_to_xyz.hh (revision 2672)
+++ vigouroux/color/rgb_to_xyz.hh (working copy)
@@ -1,7 +1,7 @@
#ifndef OLENA_CONVERT_RGBXYZ_HH
# define OLENA_CONVERT_RGBXYZ_HH
-# include <mln/core/image_if_value.hh>
+# include <mln/core/image/image_if.hh>
# include <mln/core/alias/w_window2d_int.hh>
# include <mln/display/show.hh>
Index: vigouroux/color/rgb_to_hsi.hh
--- vigouroux/color/rgb_to_hsi.hh (revision 2672)
+++ vigouroux/color/rgb_to_hsi.hh (working copy)
@@ -1,7 +1,7 @@
#include <cmath>
-#include <mln/core/image_if_value.hh>
+#include <mln/core/image/image_if.hh>
#include <mln/core/alias/w_window2d_int.hh>
#include <mln/display/show.hh>
Index: vigouroux/color/rgb_to_yuv.hh
--- vigouroux/color/rgb_to_yuv.hh (revision 2672)
+++ vigouroux/color/rgb_to_yuv.hh (working copy)
@@ -1,4 +1,4 @@
-#include <mln/core/image_if_value.hh>
+#include <mln/core/image/image_if.hh>
#include <mln/core/alias/w_window2d_int.hh>
#include <mln/display/show.hh>
1
0
24 Oct '08
https://svn.lrde.epita.fr/svn/oln/branches/cleanup-2008/milena
Index: ChangeLog
from Thierry Geraud <thierry.geraud(a)lrde.epita.fr>
De-activate not compiling tests in level transform.
* doc/examples/tuto_bis.cc: Layout.
(label): Set no border.
(lab): Change extension from pw fun to image.
That fixes some weird behavior.
* mln/level/transform.hh (todo): New.
De-activate tests since Nicolas has not fixed it yet.
* mln/level/stretch.hh (FIXME): Fix.
Avoid escaping allows for properly tracing.
* mln/estim/nsites.hh: Rename as...
* mln/geom/nsites.hh: ...this.
Update.
* mln/level/sort_psites.hh: Use geom::nsites.
Remember that only some images have the nsites method.
* mln/trace/exiting.hh: Print the scope when exiting.
It eases debugging (reading traces).
* mln/morpho/closing_volume.hh,.
* mln/morpho/meyer_wst.hh: Add trace equipment
doc/examples/tuto_bis.cc | 11 +++++++----
mln/geom/nsites.hh | 34 +++++++++++++++++-----------------
mln/level/sort_psites.hh | 8 +++++---
mln/level/stretch.hh | 6 +++---
mln/level/transform.hh | 18 +++++++++++-------
mln/morpho/closing_volume.hh | 2 ++
mln/morpho/meyer_wst.hh | 2 ++
mln/trace/exiting.hh | 6 +++---
8 files changed, 50 insertions(+), 37 deletions(-)
Index: doc/examples/tuto_bis.cc
--- doc/examples/tuto_bis.cc (revision 2671)
+++ doc/examples/tuto_bis.cc (working copy)
@@ -20,6 +20,7 @@
# include <mln/level/paste.hh>
# include <mln/level/fill.hh>
# include <mln/level/transform.hh>
+# include <mln/extension/fill.hh>
# include <mln/morpho/meyer_wst.hh>
@@ -113,7 +114,7 @@
dilation(const I& input, const N& nbh)
{
typedef mln_value(I) V;
- // extension::fill(input, mln_min(V));
+ // FIXME: extension::fill(input, mln_min(V));
mln_concrete(I) output;
initialize(output, input);
@@ -133,10 +134,12 @@
} // mln::morpho
+
} // mln
+
// Functions
inline
@@ -239,8 +242,7 @@
// 1 1
- image2d<unsigned> label(ima.bbox(), 1);
- border::fill(label, 0);
+ image2d<unsigned> label(ima.bbox(), 0);
level::fill(label, 9);
debug::println(label);
// 9 9 9 9 9
@@ -309,7 +311,8 @@
//
// 9 9 9
- level::paste(morpho::dilation(extend(lab, pw::value(label)),
+
+ level::paste(morpho::dilation(extend(lab, label),
c4()),
label);
Index: mln/level/transform.hh
--- mln/level/transform.hh (revision 2671)
+++ mln/level/transform.hh (working copy)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007 EPITA Research and Development Laboratory
+// Copyright (C) 2007, 2008 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
@@ -33,6 +33,8 @@
* \brief Transform the contents of an image into another one.
*
* \todo Clean this file + overload with pixel iterators.
+ *
+ * \todo Re-activate tests and make them static.
*/
# include <mln/core/concept/image.hh>
@@ -91,10 +93,11 @@
(void) output;
// Properties check
- mln_precondition((mlc_is(mln_trait_image_pw_io(O),
- trait::image::pw_io::read_write)::value ||
- mlc_is(mln_trait_image_vw_io(O),
- trait::image::vw_io::read_write)::value));
+ // FIXME: Re-activate!
+// mln_precondition((mlc_is(mln_trait_image_pw_io(O),
+// trait::image::pw_io::read_write)::value ||
+// mlc_is(mln_trait_image_vw_io(O),
+// trait::image::vw_io::read_write)::value));
// FIXME Convert test
mlc_converts_to(mln_result(F), mln_value(O))::check();
@@ -129,8 +132,9 @@
level::internal::transform_tests(input, f, output);
- mlc_is(mln_trait_image_pw_io(O),
- trait::image::pw_io::read_write)::check();
+ // FIXME: Re-activate!
+// mlc_is(mln_trait_image_pw_io(O),
+// trait::image::pw_io::read_write)::check();
mln_piter(I) p(input.domain());
for_all(p)
Index: mln/level/stretch.hh
--- mln/level/stretch.hh (revision 2671)
+++ mln/level/stretch.hh (working copy)
@@ -72,8 +72,8 @@
mln_value(I) min_, max_;
estim::min_max(input, min_, max_);
- if (max_ == min_)
- return; // FIXME
+ if (max_ != min_)
+ {
float min = float(min_), max = float(max_);
const float epsilon = mln_epsilon(float);
float m = 0.0f - 0.5f + epsilon;
@@ -82,7 +82,7 @@
float b = (m * max - M * min) / (max - min);
fun::v2v::linear<float, float, int> f(a, b);
level::transform(input, f, output);
-
+ }
trace::exiting("level::impl::stretch");
}
Index: mln/level/sort_psites.hh
--- mln/level/sort_psites.hh (revision 2671)
+++ mln/level/sort_psites.hh (working copy)
@@ -1,4 +1,5 @@
-// Copyright (C) 2007, 2008 EPITA Research and Development Laboratory (LRDE)
+// Copyright (C) 2007, 2008 EPITA Research and Development Laboratory
+// (LRDE)
//
// This file is part of the Olena Library. This library is free
// software; you can redistribute it and/or modify it under the terms
@@ -39,6 +40,7 @@
# include <mln/convert/to_p_array.hh>
# include <mln/histo/compute.hh>
# include <mln/util/ord.hh>
+# include <mln/geom/nsites.hh>
namespace mln
@@ -154,7 +156,7 @@
loc[i] = loc[i-1] + h[i-1];
// computing output data
- std::vector<mln_psite(I)> vec(input.nsites());
+ std::vector<mln_psite(I)> vec(geom::nsites(input));
mln_fwd_piter(I) p(input.domain());
for_all(p)
vec[loc[vset.index_of(input(p))]++] = p;
@@ -198,7 +200,7 @@
loc[i] = loc[i+1] + h[i+1];
// computing output data
- std::vector<mln_psite(I)> vec(input.nsites());
+ std::vector<mln_psite(I)> vec(geom::nsites(input));
mln_fwd_piter(I) p(input.domain());
for_all(p)
vec[loc[vset.index_of(input(p))]++] = p;
Index: mln/geom/nsites.hh
--- mln/geom/nsites.hh (revision 2670)
+++ mln/geom/nsites.hh (working copy)
@@ -25,10 +25,10 @@
// reasons why the executable file might be covered by the GNU General
// Public License.
-#ifndef MLN_ESTIM_NSITES_HH
-# define MLN_ESTIM_NSITES_HH
+#ifndef MLN_GEOM_NSITES_HH
+# define MLN_GEOM_NSITES_HH
-/*! \file mln/estim/nsites.hh
+/*! \file mln/geom/nsites.hh
*
* \brief Compute the number of sites of an image or a site set.
*/
@@ -40,7 +40,7 @@
namespace mln
{
- namespace estim
+ namespace geom
{
/// Compute the number of sites of the site set \p input.
@@ -69,7 +69,7 @@
template <typename S>
unsigned nsites(const Site_Set<S>& s_)
{
- trace::entering("estim::impl::generic::nsites");
+ trace::entering("geom::impl::generic::nsites");
const S& s = exact(s_);
mln_precondition(s.is_valid());
@@ -78,11 +78,11 @@
for_all(p)
++n;
- trace::exiting("estim::impl::generic::nsites");
+ trace::exiting("geom::impl::generic::nsites");
return n;
}
- } // end of namespace mln::estim::impl::generic
+ } // end of namespace mln::geom::impl::generic
// A single specialization.
@@ -91,13 +91,13 @@
inline
unsigned nsites_method(const Site_Set<S>& s)
{
- trace::entering("estim::impl::nsites_method");
+ trace::entering("geom::impl::nsites_method");
unsigned n = exact(s).nsites();
- trace::exiting("estim::impl::nsites_method");
+ trace::exiting("geom::impl::nsites_method");
return n;
}
- } // end of namespace mln::estim::impl
+ } // end of namespace mln::geom::impl
@@ -132,7 +132,7 @@
s);
}
- } // end of namespace mln::estim::internal
+ } // end of namespace mln::geom::internal
@@ -142,12 +142,12 @@
inline
unsigned nsites(const Site_Set<S>& s)
{
- trace::entering("estim::nsites");
+ trace::entering("geom::nsites");
mln_precondition(exact(s).is_valid());
unsigned n = internal::nsites_dispatch(s);
- trace::exiting("estim::nsites");
+ trace::exiting("geom::nsites");
return n;
}
@@ -155,7 +155,7 @@
inline
unsigned nsites(const Image<I>& input_)
{
- trace::entering("estim::nsites");
+ trace::entering("geom::nsites");
const I& input = exact(input_);
mln_precondition(input.has_data());
@@ -164,15 +164,15 @@
// Relies on the nsites routines on a site set.
unsigned n = internal::nsites_dispatch(input.domain());
- trace::exiting("estim::nsites");
+ trace::exiting("geom::nsites");
return n;
}
# endif // ! MLN_INCLUDE_ONLY
- } // end of namespace mln::estim
+ } // end of namespace mln::geom
} // end of namespace mln
-#endif // ! MLN_ESTIM_NSITES_HH
+#endif // ! MLN_GEOM_NSITES_HH
Index: mln/trace/exiting.hh
--- mln/trace/exiting.hh (revision 2671)
+++ mln/trace/exiting.hh (working copy)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007 EPITA Research and Development Laboratory
+// Copyright (C) 2007, 2008 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
@@ -50,14 +50,14 @@
# ifndef MLN_INCLUDE_ONLY
inline
- void exiting(const std::string&)
+ void exiting(const std::string& str)
{
if (quiet)
return;
--tab;
for (unsigned i = 0; i < tab; ++i)
std::cout << " ";
- std::cout << "}" << std::endl;
+ std::cout << "} " << str << std::endl;
}
# endif // ! MLN_INCLUDE_ONLY
Index: mln/morpho/closing_volume.hh
--- mln/morpho/closing_volume.hh (revision 2671)
+++ mln/morpho/closing_volume.hh (working copy)
@@ -54,9 +54,11 @@
void closing_volume(const Image<I>& input, const Neighborhood<N>& nbh,
std::size_t lambda, Image<O>& output)
{
+ trace::entering("morpho::closing_volume");
mln_precondition(exact(output).domain() == exact(input).domain());
// FIXME: Change sig of closing_attribute!
closing_attribute< accu::volume<I> >(input, nbh, lambda, output);
+ trace::exiting("morpho::closing_volume");
}
# endif // ! MLN_INCLUDE_ONLY
Index: mln/morpho/meyer_wst.hh
--- mln/morpho/meyer_wst.hh (revision 2671)
+++ mln/morpho/meyer_wst.hh (working copy)
@@ -108,6 +108,7 @@
meyer_wst(const Image<I>& input_, const Neighborhood<N>& nbh_,
L& nbasins)
{
+ trace::entering("morpho::meyer_wst");
/* FIXME: Ensure the input image has scalar values. */
const I input = exact(input_);
@@ -192,6 +193,7 @@
}
}
}
+ trace::exiting("morpho::meyer_wst");
return output;
}
1
0
24 Oct '08
https://svn.lrde.epita.fr/svn/oln/branches/cleanup-2008/milena/sandbox
Index: ChangeLog
from Thierry Geraud <thierry.geraud(a)lrde.epita.fr>
Add a processing chain about segmentation on edges.
* geraud/wst_edge.cc: New.
wst_edge.cc | 406 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 406 insertions(+)
Index: geraud/wst_edge.cc
--- geraud/wst_edge.cc (revision 0)
+++ geraud/wst_edge.cc (revision 0)
@@ -0,0 +1,406 @@
+# include <mln/core/var.hh>
+
+# include <mln/core/image/image2d.hh>
+# include <mln/core/image/image_if.hh>
+# include <mln/core/image/extended.hh>
+# include <mln/core/routine/extend.hh>
+
+# include <mln/core/alias/window2d.hh>
+# include <mln/core/alias/neighb2d.hh>
+# include <mln/make/double_neighb2d.hh>
+# include <mln/core/site_set/p_centered.hh>
+
+# include <mln/literal/origin.hh>
+# include <mln/literal/black.hh>
+# include <mln/literal/white.hh>
+
+# include <mln/value/int_u8.hh>
+# include <mln/io/pgm/load.hh>
+# include <mln/io/pgm/save.hh>
+
+# include <mln/value/rgb8.hh>
+# include <mln/io/ppm/save.hh>
+
+# include <mln/accu/min_max.hh>
+# include <mln/accu/mean.hh>
+
+# include <mln/fun/i2v/array.hh>
+# include <mln/fun/p2v/iota.hh>
+
+# include <mln/level/paste.hh>
+# include <mln/level/fill.hh>
+# include <mln/level/transform.hh>
+# include <mln/extension/fill.hh>
+
+# include <mln/morpho/meyer_wst.hh>
+# include <mln/morpho/closing_area.hh>
+
+# include <mln/debug/println.hh>
+
+
+
+// Functions
+
+inline
+bool is_row_odd(const mln::point2d& p)
+{
+ return p.row() % 2;
+}
+
+inline
+bool is_cell(const mln::point2d& p)
+{
+ return p.row() % 2 == 0 && p.col() % 2 == 0;
+}
+
+inline
+bool is_edge(const mln::point2d& p)
+{
+ return p.row() % 2 + p.col() % 2 == 1;
+}
+
+inline
+bool is_point(const mln::point2d& p)
+{
+ return p.row() % 2 && p.col() % 2;
+}
+
+
+inline
+bool is_not_edge(const mln::point2d& p)
+{
+ return ! is_edge(p);
+}
+
+
+
+namespace mln
+{
+
+ namespace border
+ {
+
+ template <typename I>
+ void
+ fill(I& ima, const mln_value(I)& v)
+ {
+ const int nrows = ima.nrows();
+ const int ncols = ima.ncols();
+ for (int r = -1; r <= nrows; ++r)
+ {
+ ima.at(r, -1) = v;
+ ima.at(r, ncols) = v;
+ }
+ for (int c = -1; c <= ncols; ++c)
+ {
+ ima.at(-1, c) = v;
+ ima.at(nrows, c) = v;
+ }
+ }
+
+ } // mln::border
+
+ namespace accu
+ {
+
+ template <typename I, typename L, typename A, typename V>
+ inline
+ void
+ compute(const Image<I>& input_,
+ const Image<L>& label_,
+ const Accumulator<A>&,
+ V& v)
+ {
+ trace::entering("accu::compute");
+
+ const I& input = exact(input_);
+ const L& label = exact(label_);
+
+ const unsigned n = v.size();
+ std::vector<A> a(n);
+
+ mln_piter(I) p(input.domain());
+ for_all(p)
+ a[label(p)].take(input(p));
+
+ for (unsigned l = 1; l < n; ++l)
+ v(l) = a[l].to_result();
+
+ trace::exiting("accu::compute");
+ }
+
+ } // mln::accu
+
+ namespace morpho
+ {
+
+ template <typename I, typename N>
+ mln_concrete(I)
+ gradient(const I& input, const N& nbh)
+ {
+ mln_concrete(I) output;
+ initialize(output, input);
+ accu::min_max<mln_value(I)> mm;
+
+ mln_piter(I) p(input.domain());
+ mln_niter(N) n(nbh, p);
+ for_all(p)
+ {
+ mm.init();
+ for_all(n) if (input.has(n))
+ mm.take(input(n));
+ output(p) = mm.second() - mm.first();
+ }
+ return output;
+ }
+
+ template <typename I, typename N>
+ mln_concrete(I)
+ dilation(const I& input, const N& nbh)
+ {
+ typedef mln_value(I) V;
+ // FIXME: extension::fill(input, mln_min(V));
+
+ mln_concrete(I) output;
+ initialize(output, input);
+ accu::max<V> m;
+
+ mln_piter(I) p(input.domain());
+ mln_niter(N) n(nbh, p);
+ for_all(p)
+ {
+ m.init();
+ for_all(n) if (input.has(n))
+ m.take(input(n));
+ output(p) = m;
+ }
+ return output;
+ }
+
+ } // mln::morpho
+
+
+ struct colorize : Function_v2v< colorize >
+ {
+ typedef value::rgb8 result;
+ colorize(unsigned max)
+ : lut(max + 1)
+ {
+ lut[0] = literal::black;
+ for (unsigned i = 1; i <= max; ++i)
+ lut[i] = result(100 + std::rand() % 150,
+ 100 + std::rand() % 150,
+ 100 + std::rand() % 150);
+ }
+ result operator()(unsigned i) const
+ {
+ return lut[i];
+ }
+ std::vector<result> lut;
+ };
+
+
+ template <typename I>
+ I display_edge(const I& ima, mln_value(I) bg, unsigned zoom)
+ {
+ unsigned nrows = ima.nrows() / 2 + 1;
+ unsigned ncols = ima.ncols() / 2 + 1;
+ I output(nrows * (zoom + 1) - 1,
+ ncols * (zoom + 1) - 1);
+ level::fill(output, bg);
+ mln_VAR( edge, ima | is_edge );
+ mln_piter(edge_t) p(edge.domain());
+ for_all(p)
+ if (p.row() % 2) // horizontal edge
+ {
+ unsigned row = (p.row() / 2 + 1) * (zoom + 1) - 1;
+ unsigned col = (p.col() / 2) * (zoom + 1);
+ for (unsigned i = 0; i < zoom; ++i)
+ output.at(row, col + i) = ima(p);
+ }
+ else // vertical edge
+ {
+ unsigned row = (p.row() / 2) * (zoom + 1);
+ unsigned col = (p.col() / 2 + 1) * (zoom + 1) - 1;
+ for (unsigned i = 0; i < zoom; ++i)
+ output.at(row + i, col) = ima(p);
+ }
+ return output;
+ }
+
+} // mln
+
+
+
+template <typename T>
+mln::image2d<T>
+image2cells(const mln::image2d<T>& input)
+{
+ mln::image2d<T> output(2 * input.nrows() - 1,
+ 2 * input.ncols() - 1);
+ for (int row = 0; row < input.nrows(); ++row)
+ for (int col = 0; col < input.ncols(); ++col)
+ output.at(2 * row, 2 * col) = input.at(row, col);
+ return output;
+}
+
+
+template <typename T>
+mln::image2d<T>
+cells2image(const mln::image2d<T>& input)
+{
+ mln::image2d<T> output((input.nrows() + 1) / 2,
+ (input.ncols() + 1) / 2);
+ for (int row = 0; row < input.nrows(); row += 2)
+ for (int col = 0; col < input.ncols(); col += 2)
+ output.at(row / 2, col / 2) = input.at(row, col);
+ return output;
+}
+
+
+
+
+template <typename I>
+void
+do_it(I& ima, int lambda, const std::string& filename, unsigned& nbasins)
+{
+ using namespace mln;
+
+ // e2c
+
+ bool e2c_h[] = { 0, 1, 0,
+ 0, 0, 0,
+ 0, 1, 0 };
+
+ bool e2c_v[] = { 0, 0, 0,
+ 1, 0, 1,
+ 0, 0, 0 };
+
+ mln_VAR( e2c, make::double_neighb2d(is_row_odd, e2c_h, e2c_v) );
+
+ bool e2e_h[] = { 0, 0, 1, 0, 0,
+ 0, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 0, 1, 0,
+ 0, 0, 1, 0, 0 };
+
+ bool e2e_v[] = { 0, 0, 0, 0, 0,
+ 0, 1, 0, 1, 0,
+ 1, 0, 0, 0, 1,
+ 0, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0 };
+
+ mln_VAR( e2e, make::double_neighb2d(is_row_odd, e2e_h, e2e_v) );
+
+ // cell
+ mln_VAR(cell, ima | is_cell);
+
+ // edge
+ mln_VAR(edge, extend((ima | is_edge).rw(),
+ pw::value(ima)));
+
+ level::paste(morpho::gradient(edge, e2c), edge);
+ // ^^^
+ // edge -> neighboring cells
+
+ // 'edge' looks like:
+ //
+ // 1 1
+ // 3 3 3
+ // 1 1
+
+ {
+ io::pgm::save(display_edge(ima, 0, 3),
+ "temp_edge.pgm");
+ }
+
+
+ level::paste( morpho::closing_area(edge, e2e, lambda), edge );
+
+
+ image2d<unsigned> label(ima.bbox(), 0);
+ // mln_ch_value(I, unsigned) label;
+ // initialize(label, ima);
+
+
+ mln_VAR(wst, label | is_edge);
+
+ level::fill(wst, morpho::meyer_wst(edge, e2e, nbasins));
+ // ^^^
+ // edge -> neighboring edges
+
+ // 'wst' looks like:
+ //
+ // 2 2
+ // 0 0 0
+ // 1 1
+
+ colorize colors(nbasins);
+
+ {
+ image2d<value::rgb8> temp(label.domain());
+ level::fill(temp, literal::white);
+
+ level::paste( level::transform(label | is_edge,
+ colors),
+ temp );
+
+ io::ppm::save(display_edge(temp, literal::white, 3),
+ "temp_label.ppm");
+ }
+
+ // YET THOSE VALUES ARE ON EDGES, NOT ON CELLS...
+
+
+ mln_VAR(lab, label | is_cell);
+
+ level::paste(morpho::dilation(extend(lab, label),
+ c4()),
+ label);
+
+ // 'lab' looks like:
+ //
+ // 2 2 2
+ //
+ // 1 1 1
+
+ io::ppm::save(level::transform(cells2image(label),
+ colors),
+ filename);
+}
+
+
+
+void usage(char* argv[])
+{
+ std::cerr << "usage: " << argv[0] << " input.pgm lambda output.ppm" << std::endl;
+ std::cerr << " lambda >= 0" << std::endl;
+ abort();
+}
+
+
+
+int main(int argc, char* argv[])
+{
+ using namespace mln;
+ using value::int_u8;
+
+ if (argc != 4)
+ usage(argv);
+
+ image2d<int_u8> temp;
+ io::pgm::load(temp, argv[1]);
+
+ image2d<int_u8> ima = image2cells(temp);
+
+
+ int lambda = atoi(argv[2]);
+ if (lambda < 0)
+ usage(argv);
+
+ std::string filename(argv[3]);
+
+ unsigned nbasins;
+ do_it(ima, lambda, filename, nbasins);
+ std::cout << "nbasins = " << nbasins << std::endl;
+}
1
0
URL: https://svn.lrde.epita.fr/svn/oln/branches/cleanup-2008/milena/sandbox
ChangeLog:
2008-10-24 Jimmy Ma <jimmy.ma(a)lrde.epita.fr>
Fix the skeleton algorithm introduced by aroumougame.
* garrigues/ocr/skeleton.cc,
garrigues/ocr/skeleton.hh: New.
The code has been updated to work with the current version of
milena. However, the code itself has to be cleaned and improved.
---
skeleton.cc | 30 ++
skeleton.hh | 611 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 641 insertions(+)
Index: branches/cleanup-2008/milena/sandbox/garrigues/ocr/skeleton.hh
===================================================================
--- branches/cleanup-2008/milena/sandbox/garrigues/ocr/skeleton.hh (revision 0)
+++ branches/cleanup-2008/milena/sandbox/garrigues/ocr/skeleton.hh (revision 2670)
@@ -0,0 +1,611 @@
+// Copyright (C) 2007, 2008 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 SKELETON_HH
+# define SKELETON_HH
+
+#include <mln/core/image/image2d.hh>
+#include <mln/core/alias/neighb2d.hh>
+#include <sandbox/aroumougame/skeleton/sedt.hh>
+
+#include <mln/core/site_set/p_set.hh>
+#include <mln/math/sqrt.hh>
+
+namespace mln
+{
+
+
+template <typename P>
+ std::vector< std::pair< double, P > > remove(std::vector< std::pair< double, P > > Q, P p)
+{
+ typename std::vector<std::pair< double, P > >::iterator it;
+
+ for(it = Q.begin(); it!=Q.end(); it++)
+ {
+ if((*it).second==p)
+ {
+ it = Q.erase(it);
+ break;
+ }
+ }
+ return Q;
+}
+template <typename N>
+ double distance(N a, N b, N c, N d)
+{
+ double dist = sqrt((a-c)*(a-c)+(b-d)*(b-d));
+ return dist;
+}
+template <typename P>
+ std::vector< std::pair< double, P > > insertDicho(std::vector< std::pair< double, P > > Q, std::pair< double, P> p)
+{
+ int indMin, indMax, indMid;
+
+ indMin = 0;
+ indMax = Q.size();
+
+ if(indMax==0 || Q[indMax-1].first <= p.first)
+ Q.push_back(p);
+ else
+ {
+ while(indMax > indMin)
+ {
+ indMid = int(indMin + (indMax-indMin)/2);
+ if(Q[indMid].first < p.first)
+ {
+ indMin = indMid+1;
+ if(Q[indMin].first > p.first)
+ {
+ indMax = indMid;
+ }
+ }
+ else
+ {
+ indMax = indMid-1;
+ if(Q[indMax].first < p.first)
+ {
+ indMin = indMid;
+ }
+ }
+ }
+
+ typename std::vector< std::pair< double, P > >::iterator it=Q.begin();
+ it = Q.insert ( it+indMin, p);
+ }
+
+ return Q;
+}
+
+
+const neighb2d& complement_neighborhood(const Neighborhood<neighb2d>& nbh)
+{
+ if(&nbh == &c4())
+ return c8();
+ return c4();
+}
+
+template <typename N>
+ int nb_composant_connexe(p_set< mln_psite(N) > X_full,const Neighborhood<N>& nbh_,const mln_psite(N)& p_ref, bool local)
+{
+ N nbh = exact(nbh_);
+ p_set< mln_psite(N) > X;
+ if(local)
+ {
+ mln_niter(N) n(max_neighborhood(nbh), p_ref);
+
+ for_all(n)
+ {
+ if (X_full.has(n))
+ X.insert(n);
+ }
+ }
+ else
+ {
+ X = X_full;
+ }
+
+ int T;
+ p_set< mln_psite(N) > done;
+ p_set< mln_psite(N) > neighbors;
+ p_set< mln_psite(N) > composant;
+
+ done.insert(p_ref);
+ mln_niter(N) q(nbh, p_ref);
+ for_all(q)
+ {
+ if (X.has(q)&&!done.has(q))
+ {
+ neighbors.insert(q);
+ }
+ }
+// std::cout << "nb_composant_connexe: neighbors " << neighbors.nsites() <<std::endl;
+ if(neighbors.nsites()<=1)
+ {
+ return neighbors.nsites();
+ }
+ else
+ T=0;
+
+ while(neighbors.nsites()!=0)
+ {
+ T++;
+ done.insert(neighbors[0]);
+ mln_niter(N) t(nbh, neighbors[0]);
+ neighbors.remove(neighbors[0]);
+ for_all(t)
+ {
+ if (X.has(t)&&!done.has(t))
+ {
+ composant.insert(t);
+ }
+ }
+
+ while(composant.nsites()!=0)
+ {
+ done.insert(composant[0]);
+ if(neighbors.has(composant[0]))
+ {
+ neighbors.remove(composant[0]);
+ if(neighbors.nsites()==0)
+ return T;
+ }
+
+ mln_niter(N) r(nbh, composant[0]);
+ composant.remove(composant[0]);
+ for_all(r)
+ {
+ if (X.has(r) && !done.has(r))
+ {
+ composant.insert(r);
+ }
+ }
+ }
+ }
+ return T;
+}
+
+template <typename N>
+ bool simple_point(p_set< mln_psite(N) > X,const Neighborhood<N>& nbh, p_set< mln_psite(N) > X_complement, const mln_psite(N)& p_ref, bool local)
+{
+ int nX = nb_composant_connexe(X,exact(nbh),p_ref,local);
+ int nX_complement = nb_composant_connexe(X_complement,complement_neighborhood(exact(nbh)),p_ref,local);
+
+ if((nX_complement == 1)&&(nX == 1))
+ return true;
+ return false;
+}
+
+
+ template <typename N>
+ p_set<mln_psite(N)> euclideanSkeleton(p_set<mln_psite(N)> X, p_set<mln_psite(N)> X_complement, image2d<value::int_u8> dt, p_set<mln_psite(N)>& Y, const Neighborhood<N>& nbh_, bool local)
+ {
+ std::vector< std::pair< double, mln::point2d> > Q;
+ std::vector< std::pair< double, mln::point2d> > R;
+ N nbh = exact(nbh_);
+
+ // fill Q
+ for (uint i = 0; i < X.nsites(); i++)
+ {
+ if (!Y.has(X[i]))
+ {
+ std::pair<double, mln_psite(N)> p(math::sqrt(double(dt(X[i]))),X[i]);
+ Q = insertDicho(Q,p);
+ }
+ }
+
+ // fill R
+ for (uint i = 0; i < X.nsites(); i++)
+ {
+ if (!Y.has(X[i]))
+ {
+ double min = 1023.99;
+ mln_niter(N) r(nbh, X[i]);
+ for_all(r)
+ {
+ if (Y.has(r))
+ {
+ double tmp = distance(r[0], r[1], X[i][0], X[i][1]);
+ double d = math::sqrt(double(dt(r)))+(math::sqrt(double(dt(X[i])))-math::sqrt(double(dt(r))))/tmp;
+ min = math::min(min,d);
+ }
+ }
+ if (min!=1023.99)
+ {
+ std::pair<double, mln_psite(N)> p(min,X[i]);
+ R = insertDicho(R, p);
+ }
+ }
+ }
+
+ while (!Q.empty() || !R.empty())
+ {
+ mln_psite(N) tmp;
+ if (Q[0].first < R[0].first)
+ {
+ tmp = Q[0].second;
+ }
+ else
+ {
+ tmp = R[0].second;
+ }
+
+ Q = remove(Q, tmp);
+ R = remove(R, tmp);
+
+ if (!Y.has(tmp) && X.has(tmp))
+ {
+ if (simple_point(X, nbh, X_complement, tmp, local))
+ {
+ X.remove(tmp);
+ X_complement.insert(tmp);
+ }
+ else
+ {
+ Y.insert(tmp);
+ mln_niter(N) r(nbh, tmp);
+ for_all(r)
+ {
+ if (!Y.has(r) && X.has(r))
+ {
+ double dist = distance(r[0], r[1], tmp[0], tmp[1]);
+ double d = math::sqrt(double(dt(tmp)))+(math::sqrt(double(dt(r)))-math::sqrt(double(dt(tmp))))/dist;
+ std::pair<double, mln_psite(N)> p(d,r);
+ R = insertDicho(R, p);
+ }
+ }
+
+ }
+ }
+
+ }
+ return X;
+ }
+
+
+ p_set<point2d> EP(image2d<value::int_u8> dt, point2d x, std::vector< std::vector<std::pair< int, int> > > lut, const neighb2d& nbh)
+ {
+ p_set<point2d> EP;
+ p_set<point2d> tmp;
+ int w = geom::ncols(dt);
+ int h = geom::nrows(dt);
+
+
+ mln_niter_(neighb2d) r(nbh, x);
+ for_all(r)
+ {
+ if (dt(r) <= dt(x))
+ {
+ for (uint i=0; i<lut[dt(r)].size(); i++)
+ {
+ if ((r[0]+lut[dt(r)][i].first < h) && (r[1]+lut[dt(r)][i].second < w))
+ {
+ if (!dt(r+dpoint2d(lut[dt(r)][i].first, lut[dt(r)][i].second)))
+ EP.insert(r+dpoint2d(lut[dt(r)][i].first, lut[dt(r)][i].second));
+ }
+ if ((r[0]-lut[dt(r)][i].first >= 0) && (r[1]-lut[dt(r)][i].second >= 0))
+ {
+ if (!dt(r+dpoint2d(-lut[dt(r)][i].first, -lut[dt(r)][i].second)))
+ EP.insert(r+dpoint2d(-lut[dt(r)][i].first, -lut[dt(r)][i].second));
+ }
+ if ((r[0]+lut[dt(r)][i].first < h) && (r[1]-lut[dt(r)][i].second >= 0))
+ {
+ if (!dt(r+dpoint2d(lut[dt(r)][i].first, -lut[dt(r)][i].second)))
+ EP.insert(r+dpoint2d(lut[dt(r)][i].first, -lut[dt(r)][i].second));
+ }
+ if ((r[0]-lut[dt(r)][i].first >= 0) && (r[1]+lut[dt(r)][i].second < w))
+ {
+ if (!dt(r+dpoint2d(-lut[dt(r)][i].first, lut[dt(r)][i].second)))
+ EP.insert(r+dpoint2d(-lut[dt(r)][i].first, lut[dt(r)][i].second));
+ }
+ if ((r[0]+lut[dt(r)][i].second < h) && (r[1]+lut[dt(r)][i].first < w))
+ {
+ if (!dt(r+dpoint2d(lut[dt(r)][i].second, lut[dt(r)][i].first)))
+ EP.insert(r+dpoint2d(lut[dt(r)][i].second, lut[dt(r)][i].first));
+ }
+ if ((r[0]-lut[dt(r)][i].second >= 0) && (r[1]-lut[dt(r)][i].first >= 0))
+ {
+ if (!dt(r+dpoint2d(-lut[dt(r)][i].second, -lut[dt(r)][i].first)))
+ EP.insert(r+dpoint2d(-lut[dt(r)][i].second, -lut[dt(r)][i].first));
+ }
+ if ((r[0]+lut[dt(r)][i].second < h) && (r[1]-lut[dt(r)][i].first >= 0))
+ {
+ if (!dt(r+dpoint2d(lut[dt(r)][i].second, -lut[dt(r)][i].first)))
+ EP.insert(r+dpoint2d(lut[dt(r)][i].second, -lut[dt(r)][i].first));
+ }
+ if ((r[0]-lut[dt(r)][i].second >= 0) && (r[1]+lut[dt(r)][i].first < w))
+ {
+ if (!dt(r+dpoint2d(-lut[dt(r)][i].second, lut[dt(r)][i].first)))
+ EP.insert(r+dpoint2d(-lut[dt(r)][i].second, lut[dt(r)][i].first));
+ }
+ }
+ }
+ }
+
+ return EP;
+ }
+
+ std::vector< std::vector<std::pair< int, int> > > Lut2d(int N)
+ {
+ int n = int(sqrt(N))+1;
+ int i=0;
+ std::vector< std::vector<std::pair< int, int> > > lut;
+
+ for(i = 0; i <= N; i++)
+ {
+ std::vector<std::pair< int, int> > vect;
+ lut.push_back(vect);
+ }
+
+ for(int x = 0; x <= n; x++)
+ {
+ for(int y = 0; y <= x; y++)
+ {
+ i=x*x+y*y;
+ if(i<=N)
+ {
+ std::pair<int,int> p(x,y);
+ lut[i].push_back(p);
+ }
+ }
+ }
+
+ return lut;
+}
+
+ image2d<value::int_u8> DiscreteBisector(image2d<value::int_u8> dt, p_set<point2d> Y, const neighb2d& nbh, int N)
+ {
+ int w = geom::ncols(dt);
+ int h = geom::nrows(dt);
+
+ int ux,uy,vx,vy, produit, angle, max;
+ double cos, normu, normv;
+
+ std::vector< std::vector<std::pair< int, int> > > lut;
+ lut = Lut2d(N);
+
+ p_set<point2d> proj;
+
+ image2d<value::int_u8> bisector(h, w);
+ level::fill(bisector, 0);
+
+ for (uint i=0; i<Y.nsites(); i++)
+ {
+ proj = EP(dt, Y[i], lut, nbh);
+
+ int n=proj.nsites();
+
+ if (n>1)
+ {
+ max = 0;
+ for (int y=0; y<n; y++)
+ {
+ for (int z=0; z<y; z++)
+ {
+ ux = proj[y][0]-Y[i][0];
+ uy = proj[y][1]-Y[i][1];
+ vx = proj[z][0]-Y[i][0];
+ vy = proj[z][1]-Y[i][1];
+
+ produit = ux * vx + uy * vy;
+
+ normu = sqrt(ux*ux + uy*uy);
+ normv = sqrt(vx*vx + vy*vy);
+
+ cos = produit/(normu*normv);
+ angle = int(acos(cos)*180.0/3.1415);
+
+ max = math::max(max, angle);
+ }
+ }
+ bisector(Y[i]) = max;
+ }
+
+ }
+
+ return bisector;
+
+ }
+
+
+
+const neighb2d& max_neighborhood(const Neighborhood<neighb2d>& nbh)
+{
+ return c8();
+}
+template <typename N>
+ p_set<mln_psite(N)> ultimateSkeleton(p_set<mln_psite(N)> X, p_set<mln_psite(N)> X_complement, image2d<value::int_u8> dt, p_set<mln_psite(N)> Y, const Neighborhood<N>& nbh_, bool local)
+{
+ std::vector< std::pair< double, mln::point2d> > Q;
+
+ N nbh = exact(nbh_);
+ // fill Q
+ for(uint i = 0; i < X.nsites(); i++)
+ {
+ if (!Y.has(X[i]))
+ {
+ std::pair<double, mln_psite(N)> p(dt(X[i]),X[i]);
+ Q = insertDicho(Q,p);
+ }
+ }
+
+
+ while(!Q.empty())
+ {
+ mln_psite(N) tmp = Q[0].second;
+
+ Q = remove(Q, tmp);
+
+ if(simple_point(X, nbh, X_complement, tmp, local))
+ {
+ X.remove(tmp);
+ X_complement.insert(tmp);
+ mln_niter(N) r(nbh, tmp);
+ for_all(r)
+ {
+ if(!Y.has(r) && X.has(r))
+ {
+ std::pair<double, mln_psite(N)> p(dt(r),r);
+ Q = insertDicho(Q, p);
+ }
+ }
+ }
+
+ }
+ return X;
+}
+
+ image2d<value::int_u8> intImage(image2d<bool> pic)
+{
+ int w = geom::ncols(pic);
+ int h = geom::nrows(pic);
+
+ image2d<value::int_u8> out(h,w);
+ for(int i=0; i<w; i++)
+ for(int j=0; j<h; j++)
+ {
+ if(pic.at(j,i))
+ out.at(j,i) = 1;
+ else
+ out.at(j,i) = 0;
+ }
+ return out;
+}
+ image2d<bool> filteredSkeleton(image2d<bool> pic, const neighb2d& nbh, uint r, uint alpha, bool local)
+ {
+ using value::int_u8;
+
+ typedef image2d<bool> I;
+ typedef p_set<point2d> S;
+
+ image2d<value::int_u8> pic1 = intImage(pic);
+ image2d<value::int_u8> dt = sedt(pic1);
+
+ mln::io::pgm::save(dt, "dt.pgm");
+
+ int w = geom::ncols(pic);
+ int h = geom::nrows(pic);
+ int l= math::min(w, h);
+ uint rmax = getRMax(dt);
+ uint rknown = 0;
+ p_set<point2d> X,Y,Z;
+ p_set<point2d> X_complement, Z_complement;
+
+ image2d<value::int_u8> DTg(l,l,0);
+ std::vector< std::vector<int> > Mgl;
+ std::vector< std::vector<int> > Lut;
+
+ Mgl = CompLutMask (DTg,Mgl,Lut,l,0,rmax);
+
+ rknown =rmax;
+
+ mln_fwd_piter_(image2d<bool>) p(pic.domain());
+
+ for_all(p)
+ {
+ if (pic(p)==1)
+ {
+ X.insert(p);
+ }
+ else
+ {
+ X_complement.insert(p);
+ }
+ }
+ std::cout << " medial axis " << std::endl;
+ pic = MA(pic, Mgl, dt, Lut);
+
+ mln::io::pbm::save(pic, "ma.pbm");
+
+ for_all(p)
+ {
+ if (pic(p)==1)
+ {
+ Y.insert(p);
+ }
+ }
+
+ std::cout << " euclidean skeleton " << std::endl;
+ Z = euclideanSkeleton(X, X_complement, dt, Y, nbh, local);
+
+ sub_image<I, S> es = pic | Z;
+ I es1(pic.domain());
+ level::fill(es1, false);
+
+ level::paste(es, es1);
+
+ mln::io::pbm::save(es1, "euclidean.pbm");
+
+ for_all(p)
+ {
+ if (!Z.has(p))
+ {
+ Z_complement.insert(p);
+ }
+ }
+ std::cout << " discrete bisector " << std::endl;
+ pic1 = DiscreteBisector(dt, Y, nbh, rmax);
+
+
+ mln::io::pgm::save(pic1, "bisector.pgm");
+
+ uint cpt=0;
+ while (cpt!=Y.nsites())
+ {
+ if (dt(Y[cpt])>=r && pic1(Y[cpt])>=alpha)
+ {
+ cpt++;
+ }
+ else
+ {
+ Y.remove(Y[cpt]);
+ }
+ }
+
+
+ sub_image<I, S> skel = pic | Y;
+ I test(pic.domain());
+ level::fill(test, false);
+
+ level::paste(skel, test);
+
+ mln::io::pbm::save(test, "Y.pbm");
+
+ std::cout << " ultimate skeleton " << std::endl;
+ Z = ultimateSkeleton(Z, Z_complement, dt, Y, nbh, local);
+
+
+
+ sub_image<I, S> skeleton = pic | Z;
+ I output(pic.domain());
+ level::fill(output, false);
+
+ level::paste(skeleton, output);
+
+ return output;
+ }
+
+} // End of namespace mln
+#endif // ! SKELETON_HH
Index: branches/cleanup-2008/milena/sandbox/garrigues/ocr/skeleton.cc
===================================================================
--- branches/cleanup-2008/milena/sandbox/garrigues/ocr/skeleton.cc (revision 0)
+++ branches/cleanup-2008/milena/sandbox/garrigues/ocr/skeleton.cc (revision 2670)
@@ -0,0 +1,30 @@
+
+#include <mln/core/alias/point2d.hh>
+#include "skeleton.hh"
+#include <mln/level/paste.hh>
+#include <mln/level/fill.hh>
+#include <mln/core/image/sub_image.hh>
+#include <mln/io/pgm/save.hh>
+#include <mln/io/pbm/save.hh>
+#include <mln/io/pbm/load.hh>
+
+
+int main(int argc, char* argv[])
+{
+ if(argc!=5)
+ {
+ std::cout << "arguments: filename voisinage R alpha" << std::endl;
+ exit(1);
+ }
+ image2d<bool> output;
+ std::string filename = argv[1];
+ int r = atoi(argv[3]);
+ int alpha = atoi(argv[4]);
+
+ image2d<bool> pic = io::pbm::load(filename);
+ if(atoi(argv[2])==4)
+ output = filteredSkeleton( pic, c4(), r, alpha, true);
+ else
+ output = filteredSkeleton( pic, c8(), r, alpha, true);
+ mln::io::pbm::save(output, "FS-"+std::string(argv[2])+"_"+std::string(argv[3])+"_"+std::string(argv[4])+"_"+filename);
+}
1
0
URL: https://svn.lrde.epita.fr/svn/oln/branches/cleanup-2008/milena/sandbox
ChangeLog:
2008-10-24 Jimmy Ma <jimmy.ma(a)lrde.epita.fr>
Update OCR using tesseract.
* garrigues/ocr/enlarge.hh: New.
New enlargement algorithm better than the naive resize.
* garrigues/ocr/ocr.cc: Provide sample code to link milena against
tesseract.
---
enlarge.hh | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ocr.cc | 91 ++++++++++++++++++++++++++++++++++++++-------
2 files changed, 198 insertions(+), 14 deletions(-)
Index: branches/cleanup-2008/milena/sandbox/garrigues/ocr/ocr.cc
===================================================================
--- branches/cleanup-2008/milena/sandbox/garrigues/ocr/ocr.cc (revision 2668)
+++ branches/cleanup-2008/milena/sandbox/garrigues/ocr/ocr.cc (revision 2669)
@@ -36,40 +36,103 @@
#include <mln/value/int_u8.hh>
#include "resize.hh"
-#include <mln/linear/convolve.hh>
+#include "enlarge.hh"
+//#include "skeleton.hh"
#include <mln/linear/gaussian.hh>
#include <mln/trace/all.hh>
-#include <mln/io/pbm/load.hh>
+#include <mln/io/pgm/load.hh>
#include <mln/io/pgm/save.hh>
+#include <mln/io/pbm/load.hh>
+#include <mln/io/pbm/save.hh>
#include <mln/core/alias/w_window2d_float.hh>
+#include <mln/debug/println.hh>
+#include <mln/geom/chamfer.hh>
+#include <mln/make/win_chamfer.hh>
+#include <mln/labeling/regional_maxima.hh>
+#include <mln/morpho/dilation.hh>
+
+#include <tesseract/baseapi.h>
+
+// _COMPILATION_
+// g++ -DNDEBUG -O3 -I../../.. ocr.cc -L/usr/lib -ltesseract_full -lpthread
+
+
+// Call tesseract
+// lang: expected language
+template <typename T>
+char* tesseract(const char* lang, const mln::image2d<T>& input)
+{
+ TessBaseAPI::InitWithLanguage(NULL, NULL, lang, NULL, false, 0, NULL);
+ char* s = TessBaseAPI::TesseractRect(
+ (unsigned char*) input.buffer(),
+ sizeof (T),
+ input.ncols() * sizeof (T),
+ 0, 0,
+ input.ncols(),
+ input.nrows());
+ return s;
+}
int main(int argc, char** argv)
{
- mln::trace::quiet = false;
-
using namespace mln;
using value::int_u8;
image2d<bool> input;
- image2d<int_u8> output;
- image2d<int_u8> output2;
- if (argc != 3)
+ if (argc < 2)
return 1;
-
+ mln::border::thickness = 0;
io::pbm::load(input, argv[1]);
+ std::cout << "> without any preprocessing." << std::endl;
+ char* s = tesseract("fra", input);
+ std::cout << s;
+ free(s);
+
+ //
+ // PREPROCESS !!
+ //
+ // Resize
+// output2 = geom::resize(cast_image<int_u8>(input), 3);
+ image2d<int_u8> output = enlarge(input, 1);
+
+ // TODO CLEANUP
+#if 0
+ // Blur.
+ image2d<int_u8> output;
+ initialize(output, output2);
+ linear::gaussian(output2, 1, output);
+#endif
+
+#if 0
+ // Threshold
+ mln_piter_(image2d<unsigned>) p(output.domain());
+ for_all(p)
+ {
+ output(p) = output(p) > 127 ? 1 : 0;
+ }
+#endif
- // Step 1: Enlarge input.
- output = geom::resize(cast_image<int_u8>(input), 4);
+#if 0
+ // Compute chamfer distance map.
+ const w_window2d_int& w_win = make::mk_chamfer_3x3_int<8, 0> ();
+ image2d<unsigned> out = geom::chamfer(output, w_win, 255);
+
+ for_all(p)
+ {
+ out(p) = out(p) > 10 ? 255 : 0;
+ }
+#endif
- // Step 2: Blur.
- initialize(output2, output);
- linear::gaussian(output, 15, output2);
+ io::pgm::save(cast_image<int_u8>(output), argv[2]);
- io::pgm::save(output2, argv[2]);
+ std::cout << "> with preprocessing." << std::endl;
+ s = tesseract("fra", output);
+ std::cout << s;
+ free(s);
}
Index: branches/cleanup-2008/milena/sandbox/garrigues/ocr/enlarge.hh
===================================================================
--- branches/cleanup-2008/milena/sandbox/garrigues/ocr/enlarge.hh (revision 0)
+++ branches/cleanup-2008/milena/sandbox/garrigues/ocr/enlarge.hh (revision 2669)
@@ -0,0 +1,121 @@
+#ifndef ENLARGE_HH
+# define ENLARGE_HH
+
+# include <iostream>
+
+# include <mln/core/image/image2d.hh>
+# include <mln/value/int_u8.hh>
+
+
+float val(bool b) { return b ? 1 : 0; }
+
+int do_threshold(float value)
+{
+ return 255.f * value;
+}
+
+
+mln::image2d<mln::value::int_u8>
+enlargex2(mln::image2d<bool> input)
+{
+ using namespace mln;
+ using value::int_u8;
+
+ unsigned nrows, ncols;
+
+ nrows = input.nrows();
+ ncols = input.ncols();
+
+ image2d<int_u8> output(2 * nrows, 2 * ncols);
+ float value;
+
+ // row 0
+
+ output.at(0, 0) = do_threshold(input.at(0, 0));
+
+ for (int col = 2; col < output.ncols(); col += 2)
+ {
+ value = val(input.at(0, col / 2));
+ value += val(input.at(0, col / 2 - 1));
+ output.at(0, col) = do_threshold(value / 2);
+ }
+
+ for (int col = 1; col < output.ncols(); col += 2)
+ output.at(0, col) = do_threshold(input.at(0, col / 2));
+
+ // col 0
+
+ for (int row = 2; row < output.nrows(); row += 2)
+ {
+ value = val(input.at(row / 2, 0));
+ value += val(input.at(row / 2 - 1, 0));
+ output.at(row, 0) = do_threshold(value / 2);
+ }
+
+ for (int row = 1; row < output.nrows(); row += 2)
+ output.at(row, 0) = do_threshold(input.at(row / 2, 0));
+
+ // others
+
+ for (int row = 2; row < output.nrows(); row += 2)
+ {
+ for (int col = 2; col < output.ncols(); col += 2)
+ {
+ value = val(input.at(row / 2, col / 2));
+ value += val(input.at(row / 2 - 1, col / 2));
+ value += val(input.at(row / 2, col / 2 - 1));
+ value += val(input.at(row / 2 - 1, col / 2 - 1));
+ output.at(row, col) = do_threshold(value / 4);
+ }
+ for (int col = 1; col < output.ncols(); col += 2)
+ {
+ value = val(input.at(row / 2, col / 2));
+ value += val(input.at(row / 2 - 1, col / 2));
+ output.at(row, col) = do_threshold(value / 2);
+ }
+ }
+
+ for (int row = 1; row < output.nrows(); row += 2)
+ {
+ for (int col = 2; col < output.ncols(); col += 2)
+ {
+ value = val(input.at(row / 2, col / 2));
+ value += val(input.at(row / 2, col / 2 - 1));
+ output.at(row, col) = do_threshold(value / 2);
+ }
+ for (int col = 1; col < output.ncols(); col += 2)
+ output.at(row, col) = do_threshold(input.at(row / 2, col / 2));
+ }
+
+ return output;
+}
+
+
+// enlarge 2^n times
+mln::image2d<mln::value::int_u8>
+enlarge(mln::image2d<bool> input, unsigned int n)
+{
+ using namespace mln;
+ using value::int_u8;
+
+ image2d<int_u8> output;
+
+ do
+ {
+ output = enlargex2(input);
+
+ if (--n > 0)
+ {
+ initialize(input, output);
+ mln_piter_(image2d<bool>) p(input.domain());
+ for_all(p)
+ input(p) = output(p) > 0;
+ }
+ else
+ break;
+ }
+ while (1);
+ return output;
+}
+
+#endif // ! ENLARGE_HH
1
0
cleanup-2008 2668: Update directional erosion so that it can now be used on sets.
by Thierry Geraud 23 Oct '08
by Thierry Geraud 23 Oct '08
23 Oct '08
https://svn.lrde.epita.fr/svn/oln/branches/cleanup-2008/milena
Index: ChangeLog
from Thierry Geraud <thierry.geraud(a)lrde.epita.fr>
Update directional erosion so that it can now be used on sets.
* mln/accu/rank.hh (todo): New.
* mln/accu/rank_bool.hh (todo): New.
Fix doc.
(rank): Fix ctor.
(take_as_init): Fix.
* mln/accu/land.hh: New.
* mln/morpho/erosion.spe.hh
(erosion_directional_nd_functor),
(erosion_directional_nd_fastest_functor): Add accumulator type
as parameter and rename min as accu.
(erosion_directional_nd),
(erosion_directional_nd_fastest): Update; compute A.
(erosion_dispatch_wrt_win): Update overload for hline2d and
vline2d.
* mln/morpho/includes.hh: Update.
accu/land.hh | 81 ++++++++++++++++++++++++--------------------------
accu/rank.hh | 3 +
accu/rank_bool.hh | 18 +++++------
morpho/erosion.spe.hh | 58 ++++++++++++++++++-----------------
morpho/includes.hh | 2 +
5 files changed, 83 insertions(+), 79 deletions(-)
Index: mln/accu/rank.hh
--- mln/accu/rank.hh (revision 2667)
+++ mln/accu/rank.hh (working copy)
@@ -31,6 +31,9 @@
/*! \file mln/accu/rank.hh
*
* \brief Define an rank accumulator.
+ *
+ * \todo It should be renamed as rank_h since it relies on histogram
+ * (thus low quantization).
*/
# include <vector>
Index: mln/accu/rank_bool.hh
--- mln/accu/rank_bool.hh (revision 2667)
+++ mln/accu/rank_bool.hh (working copy)
@@ -28,16 +28,17 @@
#ifndef MLN_ACCU_RANK_BOOL_HH
# define MLN_ACCU_RANK_BOOL_HH
-/*! \file mln/accu/rankbool.hh
+/*! \file mln/accu/rank_bool.hh
*
* \brief Define an rank accumulator.
+ *
+ * \todo There is no-arg-ctor so this accumulator does not support
+ * deferred initialization!
+ *
+ * \todo Add untake routines...
*/
-# include <vector>
# include <mln/accu/internal/base.hh>
-# include <mln/core/concept/meta_accumulator.hh>
-# include <mln/trait/value_.hh>
-# include <mln/util/pix.hh>
namespace mln
@@ -49,7 +50,7 @@
// Fwd declaration.
template <typename T> struct rank;
- /*! \brief rank accumulator class for boolean.
+ /*! \brief rank accumulator class for Boolean.
*
*/
template <>
@@ -85,8 +86,7 @@
inline
rank<bool>::rank(unsigned k, unsigned n)
- : nfalse_(0),
- k_(k),
+ : k_(k),
n_(n)
{
mln_assertion(k_ < n_);
@@ -105,7 +105,7 @@
inline
void rank<bool>::take_as_init(const argument& t)
{
- nfalse_ += !t;
+ nfalse_ = t ? 0 : 1;
}
Index: mln/accu/land.hh
--- mln/accu/land.hh (revision 2667)
+++ mln/accu/land.hh (working copy)
@@ -25,19 +25,15 @@
// reasons why the executable file might be covered by the GNU General
// Public License.
-#ifndef MLN_ACCU_RANK_BOOL_HH
-# define MLN_ACCU_RANK_BOOL_HH
+#ifndef MLN_ACCU_LAND_HH
+# define MLN_ACCU_LAND_HH
-/*! \file mln/accu/rankbool.hh
+/*! \file mln/accu/land.hh
*
- * \brief Define an rank accumulator.
+ * \brief Define a 'logical-and' accumulator.
*/
-# include <vector>
# include <mln/accu/internal/base.hh>
-# include <mln/core/concept/meta_accumulator.hh>
-# include <mln/trait/value_.hh>
-# include <mln/util/pix.hh>
namespace mln
@@ -46,25 +42,23 @@
namespace accu
{
- // Fwd declaration.
- template <typename T> struct rank;
-
- /*! \brief rank accumulator class for boolean.
- *
- */
- template <>
- struct rank<bool> : public mln::accu::internal::base< bool, rank<bool> >
+ /// "Logical-and" accumulator class.
+ struct land : public mln::accu::internal::base< bool, land >
{
typedef bool argument;
- rank(unsigned k, unsigned n);
+ land();
/// Manipulators.
/// \{
void init();
void take_as_init(const argument& t);
+
void take(const argument& t);
- void take(const rank<bool>& other);
+ void take(const land& other);
+
+ void untake(const argument& t);
+ void untake(const land& other);
/// \}
/// Get the value of the accumulator.
@@ -76,67 +70,71 @@
protected:
unsigned nfalse_;
- unsigned k_; // 0 <= k_ < n
- unsigned n_;
};
# ifndef MLN_INCLUDE_ONLY
inline
- rank<bool>::rank(unsigned k, unsigned n)
- : nfalse_(0),
- k_(k),
- n_(n)
+ land::land()
{
- mln_assertion(k_ < n_);
init();
}
-
inline
void
- rank<bool>::init()
+ land::init()
{
nfalse_ = 0;
}
-
inline
- void rank<bool>::take_as_init(const argument& t)
+ void land::take_as_init(const argument& t)
{
- nfalse_ += !t;
+ nfalse_ = t ? 0 : 1;
}
-
inline
- void rank<bool>::take(const argument& t)
+ void land::take(const argument& t)
{
- nfalse_ += !t;
+ if (t == false)
+ ++nfalse_;
}
-
inline
void
- rank<bool>::take(const rank<bool>& other)
+ land::take(const land& other)
{
nfalse_ += other.nfalse_;
}
+ inline
+ void land::untake(const argument& t)
+ {
+ if (t == false)
+ --nfalse_;
+ }
+
+ inline
+ void
+ land::untake(const land& other)
+ {
+ mln_precondition(other.nfalse_ <= nfalse_);
+ nfalse_ -= other.nfalse_;
+ }
inline
bool
- rank<bool>::to_result() const
+ land::to_result() const
{
- mln_assertion(nfalse_ <= n_);
- return k_ >= nfalse_;
+ return nfalse_ == 0;
}
inline
bool
- rank<bool>::is_valid() const
+ land::is_valid() const
{
- return nfalse_ <= n_;
+ return true;
}
# endif // ! MLN_INCLUDE_ONLY
@@ -145,5 +143,4 @@
} // end of namespace mln
-
-#endif // ! MLN_ACCU_RANK_BOOL_HH
+#endif // ! MLN_ACCU_AND_HH
Index: mln/morpho/erosion.spe.hh
--- mln/morpho/erosion.spe.hh (revision 2667)
+++ mln/morpho/erosion.spe.hh (working copy)
@@ -636,7 +636,7 @@
return dp;
}
- template <typename I_, typename W>
+ template <typename I_, typename W, typename A>
struct erosion_directional_nd_functor
{
typedef I_ I;
@@ -645,7 +645,7 @@
const I& input;
const W& win;
mln_concrete(I) output;
- accu::min_h<mln_value(I)> min;
+ A accu;
enum { dim = I::site::dim };
mln_psite(I) p;
@@ -662,7 +662,7 @@
erosion_directional_nd_functor(const I& input, const W& win, int dir)
: input(input),
win(win),
- min(),
+ accu(),
dir(dir),
win_left(win::shift(win, -dp_directional<dpsite>(dir)) - win),
win_right(win - win::shift(win, -dp_directional<dpsite>(dir))),
@@ -675,27 +675,27 @@
void init()
{
// FIXME: border::adjust(input, win.delta());
- extension::fill(input, mln_max(mln_value(I)));
+ extension::fill(input, accu);
initialize(output, input);
}
void init_run()
{
- min.init();
+ accu.init();
p[dir]--;
mln_qiter(W) q(win, p);
for_all(q) if (input.has(q))
- min.take(input(q));
+ accu.take(input(q));
p[dir]++;
}
void next()
{
for_all(q_l) if (input.has(q_l))
- min.untake(input(q_l));
+ accu.untake(input(q_l));
for_all(q_r) if (input.has(q_r))
- min.take(input(q_r));
- output(p) = min;
+ accu.take(input(q_r));
+ output(p) = accu;
}
void final()
@@ -711,7 +711,11 @@
{
trace::entering("morpho::impl:erosion_directional_nd");
- typedef erosion_directional_nd_functor<I, W> F;
+ typedef mlc_is(mln_trait_image_kind(I),
+ trait::image::kind::binary) is_binary;
+ typedef mlc_if(is_binary, accu::land, accu::min_h<mln_value(I)>) A;
+
+ typedef erosion_directional_nd_functor<I, W, A> F;
F f(exact(input), exact(win), dir);
canvas::browsing::directional(f);
@@ -721,7 +725,7 @@
}
- template <typename I_, typename W>
+ template <typename I_, typename W, typename A>
struct erosion_directional_nd_fastest_functor
{
typedef I_ I;
@@ -730,7 +734,7 @@
const I& input;
const W& win;
mln_concrete(I) output;
- accu::min_h<mln_value(I)> min;
+ A accu;
mln_psite(I) p;
enum { dim = I::site::dim };
@@ -743,7 +747,7 @@
erosion_directional_nd_fastest_functor(const I& input, const W& win, unsigned dir)
: input(input),
win(win),
- min(),
+ accu(),
dir(dir),
win_left(win::shift(win, -dp_directional<dpsite>(dir)) - win),
win_right(win - win::shift(win, -dp_directional<dpsite>(dir))),
@@ -755,27 +759,27 @@
void init()
{
// FIXME: border::adjust(input, win.delta());
- extension::fill(input, mln_max(mln_value(I)));
+ extension::fill(input, accu);
initialize(output, input);
}
void next()
{
for_all(q_l)
- min.untake(q_l.val());
+ accu.untake(q_l.val());
for_all(q_r)
- min.take(q_r.val());
- output(p) = min;
+ accu.take(q_r.val());
+ output(p) = accu;
}
void init_run()
{
- min.init();
+ accu.init();
p[dir]--;
mln_qixter(const I, W) q(input, win, p);
for_all(q)
- min.take(q.val());
+ accu.take(q.val());
p[dir]++;
}
@@ -793,7 +797,11 @@
{
trace::entering("morpho::impl:erosion_directional_nd_fastest");
- typedef erosion_directional_nd_fastest_functor<I, W> F;
+ typedef mlc_is(mln_trait_image_kind(I),
+ trait::image::kind::binary) is_binary;
+ typedef mlc_if(is_binary, accu::land, accu::min_h<mln_value(I)>) A;
+
+ typedef erosion_directional_nd_fastest_functor<I, W, A> F;
F f(exact(input), exact(win), dir);
canvas::browsing::directional(f);
@@ -1400,13 +1408,10 @@
return erosion_dispatch_for_generic(input, win);
else
{
- typedef mlc_is_not(mln_trait_image_kind(I),
- mln::trait::image::kind::logic) test_not_logic;
typedef mlc_is_a(mln_pset(I), Box) test_box;
typedef mlc_equal(mln_trait_image_quant(I),
mln::trait::image::quant::low) test_lowq;
- typedef mlc_and(test_not_logic, test_box) temp;
- typedef mlc_and(temp, test_lowq) tests;
+ typedef mlc_and(test_box, test_lowq) tests;
return erosion_dispatch_wrt_win(typename tests::eval (),
input, win);
}
@@ -1445,13 +1450,10 @@
return erosion_dispatch_for_generic(input, win);
else
{
- typedef mlc_is_not(mln_trait_image_kind(I),
- mln::trait::image::kind::logic) test_not_logic;
typedef mlc_is_a(mln_pset(I), Box) test_box;
typedef mlc_equal(mln_trait_image_quant(I),
mln::trait::image::quant::low) test_lowq;
- typedef mlc_and(test_not_logic, test_box) temp;
- typedef mlc_and(temp, test_lowq) tests;
+ typedef mlc_and(test_box, test_lowq) tests;
return erosion_dispatch_wrt_win(typename tests::eval (),
input, win);
}
Index: mln/morpho/includes.hh
--- mln/morpho/includes.hh (revision 2667)
+++ mln/morpho/includes.hh (working copy)
@@ -44,6 +44,8 @@
# include <mln/value/ops.hh>
+# include <mln/accu/land.hh>
+// # include <mln/accu/lor.hh>
# include <mln/accu/min.hh>
# include <mln/accu/max.hh>
# include <mln/accu/min_h.hh>
1
0
* scribo/demat.hh: Fix a endless loop.
---
milena/sandbox/ChangeLog | 6 +++
milena/sandbox/scribo/demat.hh | 95 +++++++++++++++++++++++++++++++++++-----
2 files changed, 90 insertions(+), 11 deletions(-)
diff --git a/milena/sandbox/ChangeLog b/milena/sandbox/ChangeLog
index 512eac2..9faa0a9 100644
--- a/milena/sandbox/ChangeLog
+++ b/milena/sandbox/ChangeLog
@@ -1,3 +1,9 @@
+2008-10-23 Guillaume Lazzara <z(a)lrde.epita.fr>
+
+ Fix an endless loop.
+
+ * scribo/demat.hh: Fix a endless loop.
+
2008-10-22 Maxime van Noppen <yabo(a)lrde.epita.fr>
Work on ICCVG04 for INIM.
diff --git a/milena/sandbox/scribo/demat.hh b/milena/sandbox/scribo/demat.hh
index a6985d5..5f01993 100644
--- a/milena/sandbox/scribo/demat.hh
+++ b/milena/sandbox/scribo/demat.hh
@@ -100,6 +100,13 @@ namespace scribo
using value::rgb8;
+ void draw_component_boxes(image2d<rgb8>& output, const util::array<box2d>& boxes)
+ {
+ for (unsigned i = 1; i < boxes.nelements(); ++i)
+ if (boxes[i].is_valid())
+ draw::box(output, boxes[i], literal::red);
+ }
+
template <typename V>
void save_lbl_image(const image2d<V>& lbl, unsigned nlabels,
const char *filename)
@@ -126,6 +133,14 @@ namespace scribo
return level::transform(input, fconvert);
}
+ void negate(image2d<bool>& in)
+ {
+ fun::i2v::array<unsigned> negate(2);
+ negate(0) = 1;
+ negate(1) = 0;
+ level::apply(in, negate);
+ }
+
/// Functions related to the table removal
/// \{
@@ -207,8 +222,8 @@ namespace scribo
#ifndef NOUT
image2d<rgb8> tmp = clone(output);
- erase_table_boxes(tmp, vboxes, n);
- erase_table_boxes(tmp, hboxes, n);
+ draw_component_boxes(tmp, vboxes);
+ draw_component_boxes(tmp, hboxes);
io::ppm::save(tmp, "./table-filtered.ppm");
#endif
@@ -222,6 +237,7 @@ namespace scribo
/// Function related to text extraction
/// \{
+ inline
int_u16
most_left(const fun::i2v::array<int_u16>& left_link, unsigned i)
{
@@ -230,6 +246,15 @@ namespace scribo
return i;
}
+ inline
+ int_u16
+ uncurri_left_link(const fun::i2v::array<int_u16>& left_link, unsigned i)
+ {
+ if (left_link(i) != i)
+ left_link(i) = most_left(left_link, left_link(i));
+ return left_link(i);
+ }
+
template <typename V>
void
remove_small_comps_i2v(image2d<V>& lbl,
@@ -276,12 +301,14 @@ namespace scribo
tboxes.resize(ncomp + 1);
for (unsigned i = 1; i <= ncomp; ++i)
{
- if (left_link(i) != i)
- left_link(i) = most_left(left_link, left_link(i));
- tboxes[left_link(i)].take(cboxes[i]);
+ //if (left_link(i) != i)
+ // left_link(i) = most_left(left_link, left_link(i));
+ tboxes[most_left(left_link, i)].take(cboxes[i]);
}
//Update labels
+ for (unsigned i = 1; i <= ncomp; ++i)
+ uncurri_left_link(left_link, i);
level::apply(lbl, left_link);
#ifndef NOUT
@@ -290,7 +317,8 @@ namespace scribo
util::array<box2d> result;
for (unsigned i = 1; i <= ncomp; ++i)
- result.append(tboxes[i].to_result());
+ if (tboxes[i].is_valid())
+ result.append(tboxes[i].to_result());
return result;
}
@@ -305,7 +333,7 @@ namespace scribo
if (lbl.domain().has(p) && lbl(p) != 0 && lbl(p) != i
&& (p.col() - c.col()) < dmax)
{
- if (left_link(lbl(p)) == lbl(p))
+ if (left_link(lbl(p)) == lbl(p) && most_left(left_link, i) != lbl(p))
left_link(lbl(p)) = i;
// else
// left_link(lbl(p)) = 0;//FIXME: should be uncommented?
@@ -350,7 +378,39 @@ namespace scribo
return left_link;
}
+/*
+ void merge_bboxes(util::array<box2d>& cboxes,
+ image2d<int_u16>& lbl, unsigned &nlabels)
+ {
+ fun::i2v::array<int_u16> merge;
+ unsigned current = 1;
+ for (unsigned i = 1; i <= nlabels;)
+ {
+ unsigned midcol = (cboxes[i].pmax().col() - cboxes[i].pmin().col()) / 2;
+ /// FIXME: Box center => Routine?
+ point2d c (cboxes[i].pmin().row()
+ + ((cboxes[i].pmax().row() - cboxes[i].pmin().row()) / 2),
+ cboxes[i].pmin().col() + midcol);
+ /// First site on the right of the center site
+ point2d p(c.row(), c.col() + 1);
+
+ // FIXME: Lemmings with a condition on the distance => write a special version?
+ while (lbl.domain().has(p) && (lbl(p) == 0 || lbl(p) == i)
+ && (p.col() - c.col()) <= midcol)
+ ++p.col();
+
+ if (lbl.domain().has(p) && lbl(p) != 0 && lbl(p) != i
+ && (p.col() - c.col()) <= midcol)
+ {
+
+ }
+ }
+
+ level::apply(lbl, merge);
+ cboxes.resize(nlabels);
+ }
+*/
util::array<box2d>
extract_text(image2d<bool>& in,
@@ -373,6 +433,14 @@ namespace scribo
boxes_t cboxes = labeling::compute(accu::meta::bbox(), lbl, nlabels);
+#ifndef NOUT
+ image2d<rgb8> tmp = clone(output);
+ draw_component_boxes(tmp, cboxes);
+ io::ppm::save(tmp, "character-bboxes.ppm");
+#endif
+
+ //merge_bboxes(cboxes, lbl, nlabels);
+
//Link character bboxes to their left neighboor if possible.
fun::i2v::array<int_u16> left =
link_character_bboxes(lbl, cboxes, nlabels, bbox_distance);
@@ -407,6 +475,12 @@ namespace scribo
//Load image
image2d<bool> in;
io::pbm::load(in, argv[1]);
+ internal::negate(in);
+
+#ifndef NOUT
+ io::pbm::save(in, "in-neg.pbm");
+#endif
+
image2d<rgb8> output = internal::to_color(in);
internal::extract_tables(in, output, l, bbox_larger);
@@ -414,13 +488,12 @@ namespace scribo
util::array<box2d> tboxes =
internal::extract_text(in, output, bbox_distance, min_comp_size);
- for (unsigned i = 1; i < tboxes.nelements(); ++i)
- if (tboxes[i].is_valid())
- draw::box(output, tboxes[i], literal::red);
+ internal::draw_component_boxes(output, tboxes);
io::ppm::save(output, argv[2]);
/// Use txt bboxes here with Tesseract
- /// => in | tboxes[i]
+ /// for (i = 1; i < tboxes.nelements(); ++i)
+ /// tesseract(in | tboxes[i])
}
} // end of namespace scribo
--
1.5.6.5
1
0