https://svn.lrde.epita.fr/svn/oln/branches/cleanup-2008/milena
Index: ChangeLog
from Nicolas Ballas <ballas(a)lrde.epita.fr>
Add documentation about the image values.
* doc/tutorial/image_values.txt: New, doc file.
image_values.txt | 234 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 234 insertions(+)
Index: doc/tutorial/image_values.txt
--- doc/tutorial/image_values.txt (revision 0)
+++ doc/tutorial/image_values.txt (revision 0)
@@ -0,0 +1,234 @@
+-*- outline -*-
+
+
+* Image Values
+
+An image is an application:
+ ima: Domain -> Destination
+ p -> ima(p)
+
+Domain is a set of the point, or more generally sites, that compose the
+image. Destination is a set containing the values of the image. Each value
+of the image belongs to the Destination set.
+
+Yet, Destination can have several definitions. In the following, we will
+details these definitions.
+
+
+
+** E: values space
+
+E is a mathematical set. It contains, at least, all the values that the image
+can possibly take. All the image values are in the value spaces E.
+So for all p, ima(p) belongs to E.
+For instance, the value space of an image can be the rgb set, the int_u8 set
+or the gl8 set(gray level coded on 8 bits)...
+
+All the image provide the method .destination() which returns E.
+However, E is not always iterable in Milena. For performance issues, E is
+iterable only if the value are coded on less than 24 bits.
+
+If E is iterable, the following code:
+
+Code A)
+ for all v in ima.destination()
+ print v;
+
+prints all the values contained in the values space.
+
+** V: eligible values set.
+
+Like E, V is a mathematical set. It contains all the values that the image can possibly take. So if v belongs to V, ima(p) <- v is possible without any
+conversions.
+
+For instance, consider the set S composed by the colors RED, BLUE, ORANGE.
+S = (RED, BLUE, ORANGE).
+
+S is a subset of the rgb set. Indeed, the colors RED, BLUE, ORANGE are members
+of the rgb set. So, consider ima, an image defined with S as eligible value
+set. ima admits the rgb set as values space (the rgb set is the superset of S).
+However, ima can take only value from the S set (and not from the rgb set). So,
+ima(p) <- WHITE will not work.
+
+All the image provide the method .values_eligible() which returns S.
+
+Why do we introduce the eligible value set, since its definition is close to
+the value space?
+In the previous example, we can't apply Code A on ima. For performance reasons,
+we don't want to iter on the rgb set. But, it is possible to iterate over the
+ima values; since the ima eligible values set is a restriction of the rgb set.
+
+If we apply the following code on ima,
+
+code B)
+ for all v in ima.values_eligible()
+ print v
+
+the result will be:
+ RED BLUE ORANGE
+
+V can also be the value spaces itself. An image cab have all the rgb colors as
+eligible values. In this case, we can't iterate over the image eligible values.
+
+
+** Vp: values taken set
+
+Vp is a mathematical set that contains the values currently taken by an image.
+So for all p in the image domain, ima(p) belongs to Vp.
+If an image provides the access to its Vp, the image interface has the
+method .values_taken() which returns its Vp.
+
+
+For instance consider the following 2d image:
+
+ -----
+| R | R stands for Red
+| BGB| B stands for Blue
+| OO | G stands for Green
+ ----- O stands for orange.
+
+
+The following code:
+
+code C)
+ for all v in ima.values_taken()
+ print v
+
+prints:
+
+RBGO
+
+If the image admits (RED, BLUE, GREEN, WHITE, ORANGE) as eligible values set,
+the code B results is:
+RBGWO (W stands for white).
+
+
+
+
+** C: value cells
+
+All the milena image types are composed by cell.
+A cell is a location in RAM or in a file that stores an image value.
+
+For instance consider the following 2d images:
+
+ 0 1 2 3 4
+ ----------
+0 | |
+1 | R G R |
+2 | |
+3 | O W|
+4 | |
+ ----------
+
+This image is composed by 5 cells: R, G, R, O, W.
+Each cell correspond to a point 2d (respectively (1, 1), (1, 2), (1, 3),
+(1, 4)).
+
+
+C is the list of cells that is currently composing the image.
+Some image types provide an access to the cells list through the method
+.values_cell() which returns C.
+
+For instance, if we apply the following code the the previous image:
+
+code D)
+ for all v in ima.values_cells()
+ print v
+
+the result will be:
+RGROW, we print the list of cells composing the image.
+
+C is not a mathematical set. Indeed, in cell list a member can be duplicate.
+In the previous example R is present twice in the cells list.
+
+* Example1
+
+Consider the following rle image:
+
+ima = -----
+ | R |
+ | BBB|
+ | OO |
+ | RR|
+ -----
+
+This image encoded by runs (a run is a succession of points).
+Furthermore, only one value is associated to each run.
+
+So, in memory, the image will be encoded this way:
+
+ima = ({p, {R, 1}}, {q, {B, 3}}, {r, {O, 2}}, {s, {R, 2}} )
+ ^^^ ^^^ ^^^
+ run start run value run len
+
+where p, q, r are point at the beginning of a run:
+ -----
+ | p |
+ | q |
+ | r |
+ | s |
+ -----
+
+The run values correspond to the image cells.
+So if we apply the code D to this image, the result will be:
+RBOR
+
+If we apply the code C to this image, the result will be:
+RBO
+
+* Example2
+
+Consider the following sparse image:
+
+ima = -----
+ | R |
+ | BGB|
+ | OG |
+ | RR|
+ -----
+
+This image is also encoded by runs.
+But here, several values can be associated to each run.
+
+So, in memory, the image will be encoded this way:
+
+ima = ({p, (R)}, {q, (B, G, B)}, {r, {O, G}}, {s, {R, R}} )
+ ^^^ ^^^ ^^^
+ run start run values
+
+where p, q, r are point at the beginning of a run.
+
+The different values in each run correspond to the image cells.
+So if we apply the code D to this image, the result will be:
+RBGBOGRR
+
+If we apply the code C to this image, the result will be:
+RGBO
+
+* Example3
+
+Consider the following 2d image:
+
+ima = -----
+ |GROOG|
+ |BRBGB|
+ -----
+
+Every pixel can have a different values, so all the pixels are stored in
+memory.Thus, a cell is associated to each pixel of the image.
+So if we apply the code D to this image, the result will be:
+GROOGBRBGB
+
+If we apply the code C to this image, the result will be:
+RGBO
+
+
+* Order relationship
+
+E <= V <= V = E*
+
+
+* Image properties related to the values
+
+FIXME
https://svn.lrde.epita.fr/svn/oln/branches/cleanup-2008/milena
Index: ChangeLog
from Thierry Geraud <thierry.geraud(a)lrde.epita.fr>
Add tour files from old projects.
* doc/oldies: New.
* doc/oldies/2007__tour.cc: New.
* doc/oldies/2008__tour1.cc: New.
* doc/oldies/2008__tour2.cc: New.
* doc/oldies/2008__tour3.cc: New.
* doc/oldies/2008__tour1_extra.cc: New.
* doc/oldies/2006__tour_1.txt: New.
* doc/oldies/2006__tour_2.txt: New.
2006__tour_1.txt | 671 +++++++++++++++++++++++++++++++++++++++++++++++++++
2006__tour_2.txt | 404 ++++++++++++++++++++++++++++++
2007__tour.cc | 395 ++++++++++++++++++++++++++++++
2008__tour1.cc | 322 ++++++++++++++++++++++++
2008__tour1_extra.cc | 214 ++++++++++++++++
2008__tour2.cc | 393 +++++++++++++++++++++++++++++
2008__tour3.cc | 331 +++++++++++++++++++++++++
7 files changed, 2730 insertions(+)
Index: doc/oldies/2007__tour.cc
--- doc/oldies/2007__tour.cc (revision 0)
+++ doc/oldies/2007__tour.cc (revision 0)
@@ -0,0 +1,395 @@
+/* This is a short tour of the basics of Olena. It isn't in any way
+ meant to cover all the features of Olena. Especially, some
+ important objects, such as the iterators, are NOT presented here.
+ */
+
+// We will run some example with 1D, and 2D, so we include these two
+// files.
+#include <oln/basics1d.hh>
+#include <oln/basics2d.hh>
+//#include <oln/basics3d.hh>
+
+// Let's include all types, for simplicity.
+#include <ntg/all.hh>
+
+// Some algorithms...
+#include <oln/morpho/erosion.hh>
+#include <oln/morpho/dilation.hh>
+#include <oln/morpho/opening.hh>
+#include <oln/morpho/closing.hh>
+#include <oln/morpho/watershed.hh>
+
+#include <oln/utils/stat.hh>
+
+// Basic conversion functions.
+#include <oln/convert/basics.hh>
+
+// Always include system headers after Olena.
+#include <iostream>
+#include <cmath>
+
+
+
+// Namespaces.
+// ===========
+// Olena is organized in a namespace hierarchy. Every thing is
+// declared by Olena under the 'oln::' namespace, and possibly un a
+// sub namespace such as 'oln::arith::' (arithmetic operations on
+// images), 'oln::morpho::' (morphological operations), etc.
+// For the sake of simplicity, we will neglect the 'oln::' prefix
+// in this file.
+using namespace oln;
+
+// Data types are defined in the Int�gre library, so they are
+// in the ntg namespace.
+// In this file, we will neglect the 'ntg::' prefix.
+using namespace ntg;
+
+int
+main (void)
+{
+ // Basic value types.
+ // ==================
+ // Olena ships with a set of basic value types such as
+ // int_u8, int_u16, int_u32, (common unsigned integer types)
+ // int_s8, int_s16, int_s32, (common signed integer types)
+ // float_s, float_d, (common float types)
+ // bin (binary type: false|true)
+ //
+ // These value are defined in the value/ subdirectory. Actually
+ // we defined all of them by including value/all.hh.
+ //
+ // You should use them instead of the standard C/C++ type, because
+ // Olena types are equipped with additional members required to
+ // write generic processings.
+
+ // For instance the max() and min() class methods
+ // will return the maximum value of a type.
+ std::cout << "ntg_max_val(int_u8) = "
+ << ntg_max_val(int_u8) << std::endl;
+
+ // You can combine these values with the standard operators
+ // as expected.
+ int_u8 a = 4;
+ int_u16 b = 1000;
+ std::cout << "a + b = " << a + b << std::endl;
+
+ // Sometime it's hard to figure which type a variable has, because
+ // Olena seems to behave surprisingly at a first glance.
+ // There are two convenient functions that you can use to
+ // inspect a type.
+ // typename_of<T>() returns a std::string describing T
+ // typename_of_var(V) returns a std::string describing the type of V
+ std::cout << typename_of<int_u8>()
+ << " + "
+ << typename_of_var(b)
+ << " = " << typename_of_var(a + b) << std::endl;
+ // The expression above will print
+ // "int_u<8> + int_u<16> = int_u<17>"
+ // This probably seems surprising for two reasons:
+ // 1) int_u8 is printed as int_u<8>
+ // this is because int_u8 is really just a short hand for int_u<8>,
+ // Olena allows you to declare unsigned integer on 13 bits, if
+ // you want (int_u<13>); but int_u<8>, int_u<16>, and int_u<32> are
+ // more common so they have their own typedef.
+ // 2) (a + b) has type int_u<17>, not int_u<16> as one would expect.
+ // The point is that one needs 17 bits to hold the result
+ // of an addition between a 8bit and a 16bit value without
+ // overflowing.
+
+ // Olena will also ensure that you don't such a large value to
+ // a variable with a smaller type:
+ // int_u16 c = a + b;
+ // would fail to compile because (a + b) has type int_u<17> which
+ // cannot fit in int_u<16>.
+ // If you *know* that the result of (a + b) fits in c, you
+ // should cast the value to int_u16 explicitly:
+ int_u16 c = a + b;
+ std::cout << "c = " << c << std::endl;
+ // Of course assigning a+b to a variable of type int_u<17> or
+ // greater is allowed and doesn't require a cast.
+
+
+ // Image types.
+ // ============
+ // There are three kind of images supported for the moment.
+ // image1d, image2d, and image3d: the names are self-explanatory.
+ // All are template, parametrized by the kind of value associated
+ // to each point (we call 'point' a position in the image).
+ //
+ // We will start to use the 1D images, because they are
+ // easier to fill manually (i.e. there are less value
+ // to assign), and easy to display.
+
+ // Here are two most basic way to build an image.
+ image1d<int_u8> img1a; // Build an empty image.
+ image1d<int_u8> img1b(20); // Build an image with 20 points.
+
+ // The empty image hasn't any data. It's really useful
+ // only as a placeholder for the result of some processing,
+ // or another image.
+
+ // Assigning an image to another one is not a costly operation.
+ // In fact, img1a behave like some pointers. After the following
+ // instruction
+ img1a = img1b;
+ // img1a and img1b can be used equivalently to access the
+ // same data (in other words, the point values are shared
+ // by img1a and img1b).
+ img1a(10) = 42; // Assign value 42 to the 11th point of img1a
+ std::cout << "img1b(10) ="
+ << img1b(10) << std::endl; // print 42, although we use img1b
+
+ // We call these assignments 'shallow copies', because they don't copy the
+ // data. If you want to make a deep copy of an image, then use
+ // the clone() method, as in Java.
+ img1a = img1b.clone ();
+ img1a(10) = 13;
+ std::cout << "img1b(10) ="
+ << img1b(10) << std::endl; // still print 42
+
+ // As show above, assignments can be made using the parenthesis
+ // operator, which takes to coordinates of the point you want to
+ // assign a value to in argument. (In 1D there is only one coordinate.)
+ // Let's fill our image with a saw-teeth signal.
+ // (coord is the type used for coordinates)
+ for (coord col = 0; col < img1a.ncols(); ++col)
+ img1a(col) = col % 5;
+
+ std::cout << "img1a:" << std::endl;
+ std::cout << img1a << std::endl;
+ // 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4
+
+ // You can build image2d and image3d objects similarly, except
+ // you have to account for the extra coordinate.
+ image2d<bin> img2a(10, 10);
+ for (coord row = 0; row < img2a.nrows(); ++row)
+ for (coord col = 0; col < img2a.ncols(); ++col)
+ img2a(row, col) = (row >= 3 && col >= 3 && row < 7 && col < 7);
+ std::cout << "img2a:" << std::endl;
+ std::cout << img2a << std::endl;
+ // - - - - - - - - - -
+ // - - - - - - - - - -
+ // - - - - - - - - - -
+ // - - - | | | | - - -
+ // - - - | | | | - - -
+ // - - - | | | | - - -
+ // - - - | | | | - - -
+ // - - - - - - - - - -
+ // - - - - - - - - - -
+ // - - - - - - - - - -
+
+ // Point types
+ // ===========
+ // As said before, a point is a position in an image. Because
+ // Olena supports different dimension, it supports different
+ // types of points: point1d, point2d, point3d.
+
+ // You build a point by passing it as much coordinate as
+ // needed.
+ point1d p1(10);
+ point2d p2(5, 3);
+ // You can address the value associated to a particular point
+ // in a image by using the [] operator:
+ std::cout << "img1b[p1]" << img1b[p1] << std::endl; // print 42
+
+ img2a[p2] = false;
+ std::cout << "img2a:" << std::endl;
+ std::cout << img2a << std::endl;
+ // - - - - - - - - - -
+ // - - - - - - - - - -
+ // - - - - - - - - - -
+ // - - - | | | | - - -
+ // - - - | | | | - - -
+ // - - - - | | | - - -
+ // - - - | | | | - - -
+ // - - - - - - - - - -
+ // - - - - - - - - - -
+ // - - - - - - - - - -
+
+
+ // Delta Point types
+ // =================
+ // You can't add points together, this make no sense. However
+ // you can use a delta-point to record a displacement, and add
+ // this delta-point to a point (yielding a new point).
+ // The types for delta-points are dpoint1d, dpoint2d, and dpoint3d.
+ dpoint1d dp1(2);
+ std::cout << "p1 + dp1 = " << p1 + dp1 << std::endl;
+ dpoint2d dp2(-1, 2);
+ img2a[p2 + dp2] = false;
+ std::cout << "img2a:" << std::endl;
+ std::cout << img2a << std::endl;
+ // - - - - - - - - - -
+ // - - - - - - - - - -
+ // - - - - - - - - - -
+ // - - - | | | | - - -
+ // - - - | | - | - - -
+ // - - - - | | | - - -
+ // - - - | | | | - - -
+ // - - - - - - - - - -
+ // - - - - - - - - - -
+ // - - - - - - - - - -
+
+
+ // Windows
+ // =======
+ // Windows are sets of delta-points.
+ //
+ // There are some predefined windows.
+ // For instance here are two common window2d objects:
+ std::cout << "win_c4p() = " << win_c4p() << std::endl;
+ // [(-1,0)(0,-1)(0,0)(0,1)(1,0)]
+ std::cout << "win_c4_only() = " << win_c4_only() << std::endl;
+ // [(-1,0)(0,-1)(0,1)(1,0)]
+
+ // A window is commonly used to iterate around a fixed point.
+ // For instance
+ window2d w2 = win_c4_only();
+ for (unsigned i = 0; i < w2.card(); ++i)
+ std::cout << "img2a[p2 + w2[" << i << "]] = "
+ << "img2a[" << p2 + w2.dp(i) << "] = "
+ << img2a[p2 + w2.dp(i)] << std::endl;
+ // img2a[p2 + w2[0]] = img2a[(4,3)] = |
+ // img2a[p2 + w2[1]] = img2a[(5,2)] = -
+ // img2a[p2 + w2[2]] = img2a[(5,4)] = |
+ // img2a[p2 + w2[3]] = img2a[(6,3)] = |
+
+ // You can build you own window using by adding delta-points
+ // using the add() method.
+ window1d w1;
+ w1.add(-1).add(0).add(1);
+ std::cout << "w1 = " << w1 << std::endl; // [(-1)(0)(1)]
+
+ // Neighborhoods
+ // =============
+ // These objects are like Windows, except they have
+ // some additional properties (a point is not in its neighborhood,
+ // the neighbor of a point should have the point in its neighborhood).
+ // For this reason, they have types distinct from the windows:
+ // neighborhood1d, neighborhood2d, neighborhood3d.
+ // The interface is just the same as the windows.
+ neighborhood1d n1;
+ n1.add(1);
+ std::cout << "n1 = " << n1 << std::endl; // N[(-1)(1)]
+
+
+ // Processings.
+ // ============
+ // We have seen how to build images and windows, that's
+ // enough to call some morphological operator.
+ // Windows are used as structural elements, so we can
+ // apply some basic morphological operator on img1a
+ // (the saw) using w1 as structural element:
+ std::cout << "erosion" << std::endl;
+ std::cout << morpho::erosion(img1a, w1) << std::endl;
+ // 0 0 1 2 0 0 0 1 2 0 0 0 1 2 0 0 0 1 2 3
+ std::cout << "dilation" << std::endl;
+ std::cout << morpho::dilation(img1a, w1) << std::endl;
+ // 1 2 3 4 4 4 2 3 4 4 4 2 3 4 4 4 2 3 4 4
+ std::cout << "opening" << std::endl;
+ std::cout << morpho::opening(img1a, w1) << std::endl;
+ // 0 1 2 2 2 0 1 2 2 2 0 1 2 2 2 0 1 2 3 3
+ std::cout << "closing" << std::endl;
+ std::cout << morpho::closing(img1a, w1) << std::endl;
+ // 1 1 2 3 4 2 2 2 3 4 2 2 2 3 4 2 2 2 3 4
+
+ // Yet, remember that Olena is a *generic* image
+ // processing library, in which processing are meant
+ // to be written once but yet work on many kind of images.
+
+ // Let's close the small hole we have added to img2d (in the
+ // paragraph about delta points).
+ std::cout << morpho::closing(img2a, win_c4p()) << std::endl;
+ // - - - - - - - - - -
+ // - - - - - - - - - -
+ // - - - - - - - - - -
+ // - - - | | | | - - -
+ // - - - | | | | - - -
+ // - - - - | | | - - -
+ // - - - | | | | - - -
+ // - - - - - - - - - -
+ // - - - - - - - - - -
+ // - - - - - - - - - -
+
+
+ // The watershed algorithm takes a neighborhood (not a window) as
+ // argument, and a type as template parameter.
+
+ // The type parameter specifies the type of the output image value.
+ // Watershed are indicated with the max() of this type, other values
+ // are basin labels.
+ std::cout << "watershed" << std::endl;
+ std::cout << morpho::watershed_seg<int_u8>(img1a, n1) << std::endl;
+ // 4 4 4 4 255 3 3 3 3 255 2 2 2 2 255 1 1 1 1 1
+
+
+ // Reading and writing PNM files.
+ // // You can read image2d from pnm files. The kind
+ // of pnm format supported (1,2,3,4,5,6) is dependent on
+ // the type of the image you load/save. The extension
+ // is also used to guess the format to use.
+ image2d<int_u8> lena = load(IMGDIR "/lena.pgm");
+ if (!lena.has_impl())
+ {
+ std::cerr << "Could not load " << IMGDIR "/lena.pgm" << std::endl;
+ exit(1);
+ }
+ std::cout << "watershedling lena..." << std::endl;
+ save(morpho::watershed_seg<int_u8>(lena, neighb_c4()), "output.pgm");
+
+
+ // High order operators.
+ // // Olena offers a set of high order operators than can simplify
+ // the writing of simple algorithm.
+ // For instance `traverse(f, img)' will apply the function `f'
+ // to each point of `img'. Actually, `f' do not need to be a function,
+ // it just have to _behave_ like a function; it can be a functor, i.e.,
+ // an instance of a class that implements an `operator()' (this allows
+ // `f' to maintain a state without using a global variable).
+
+ // The header `utils/stat.hh' define some functor to compute
+ // statistical data. In the following example we instantiate
+ // an `f_moments' functor, have it traverse the saw-teeth image,
+ // and compute some moments from the data gathered during the traversal.
+ utils::f_moments<int_u8> f;
+ traverse(f, img1a);
+ std::cout << "f.mean() = " << f.mean() << std::endl;
+ std::cout << "f.variance() = " << f.variance() << std::endl;
+
+ // `apply' is an high order operator similar to `traverse', but
+ // it builds an image from the results of the function application.
+ //
+ // o = apply(f, i);
+ //
+ // is a short for
+ //
+ // for all point p in i: o[p] = f(i[p])
+ //
+ // The type of the output image may be different from the type
+ // of the input image, so `apply' need a little more help from
+ // `f' than `traverse' does. Basically, `f' should define
+ // a type member named `result_type' so that `apply' knows which
+ // type of output image it has to create.
+ //
+ // (NOTE: The `result_type' presence is part of the requirement of
+ // the `Adaptable Unary Function' concept in the STL. So if you
+ // have a model of `Adaptable Unary Function', you can safely pass
+ // it to `apply'.)
+ //
+ // Some conversion functions (those for which the output type is
+ // knonw) can be used this way. For instance the
+ // `convert::bound<T>' functor will convert any value to type `T'
+ // and saturate for out-of-bound values. See how the `4' are
+ // converted to `3' when the saw-teeth image is converted to an
+ // image2d<int_u<2> > image.
+ std::cout << apply(convert::bound<int_u<2> >(), img1a) << std::endl;
+ // 0 1 2 3 3 0 1 2 3 3 0 1 2 3 3 0 1 2 3 3
+
+ // Another usefull high order operator is `fold':
+ // - `fold(f, val, img)' computes `f(...f(f(val,i_0),i_1)...,i_n)',
+ // where i_0...i_n are the value associated to each image point.
+ // - `fold(f, img)' computes `f(...f(f(i_0,i_1),i_2)...,i_n)'.
+ // In both cases, `f' must be a model of the
+ // `Adaptable Binary Function' STL concept.
+}
Index: doc/oldies/2008__tour1.cc
--- doc/oldies/2008__tour1.cc (revision 0)
+++ doc/oldies/2008__tour1.cc (revision 0)
@@ -0,0 +1,322 @@
+// Copyright (C) 2001, 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.
+
+// File: tour1.cc.
+
+#include <oln/core/1d/image1d.hh>
+
+#include <oln/arith/plus.hh> // arith
+
+#include <oln/level/fill.hh> // level
+#include <oln/level/paste.hh>
+
+#include <oln/debug/println.hh> // debug
+
+
+int main()
+{
+ // 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 operations), etc. For
+ // the sake of simplicity, we will neglect the 'oln::' prefix in
+ // this file.
+
+ using namespace oln;
+
+ // There are three kinds of image dimensions supported for the
+ // moment: 1D, 2D, and 3D. The respective basic image types are
+ // respectively image1d, image2d, and image3d. All are template'd,
+ // parametrized by the kind of value associated to each point.
+ //
+ // We will start to use the 1D images, because there are less values
+ // to assign (!) and because they are easy to display. Although we
+ // will be in 1D, we will talk about "points" and "pixels", just
+ // like in the classical 2D world.
+
+ // Here are the two most basic ways to build an image:
+
+ image1d<int> img1a; // which builds an empty image;
+ image1d<int> img1b(20); // which builds an image with 20 pixels.
+
+ // The type of values enclosed in those images is 'int' for
+ // integers.
+
+ // The empty image has no data and its definition domain is still
+ // unset. We do not know yet the number of pixels it contains.
+ // However, it is really useful to have such an "empty image"
+ // because it is a placeholder for the result of some processing, or
+ // another image.
+
+ // Trying to access the pixel value from an empty image leads to an
+ // error at run-time.
+
+ // Assigning an image to another one is NOT a costly operation.
+ // Actually img1a behaves like some mathematical variable. Put
+ // differently it is just a name to designate an image. After the
+ // following instruction
+
+ img1a = img1b;
+
+ // Both variables img1a and img1b can be used equivalently to access
+ // the same data. Just like in maths we can state that "img1a IS
+ // img2b" and we only have ONE actual image in memory. The image
+ // definition---its domain and its pixel values--is shared by img1a
+ // AND img1b.
+
+
+ // Since an image is a function that maps values to points, to read
+ // or modify a pixel value, we just the same notation than the one
+ // of functions:
+
+ img1a.at(0) = 7; // Assign value 7 to the 1st pixel of img1a.
+ img1a.at(10) = 51; // Assign value 51 to the 11th pixel of img1a.
+
+ std::cout << "img1b.at(10) = " << img1b.at(10)
+ << std::endl; // Print 51 since img1b is img1a.
+
+ // As you can see, Olena provides a unique easy syntax to access an
+ // image value, whatever we want to read this value or to modify it:
+ // "ima(p)", where p is a variable that represents a point of the 1D
+ // domain. In "val = ima(p)" we read the pixel value, whereas in
+ // "ima(p) = new_val" we write in an image. For 1D images, a 1D
+ // point behaves just like an index so the user can write "ima(i)"
+ // with i being an integer.
+
+
+ // A single image variable can be used to designate one image and
+ // then another one.
+
+ image1d<int> img2a(20); // An image (not empty).
+ image1d<int> img2b(20); // Another one (not empty).
+ image1d<int> img; // A variable.
+
+ img = img2a; // img is img2a
+ img.at(5) = 19; // so img2a at index 5 is set to 19.
+
+ img = img2b; // img is NOW img2b
+ img.at(5) = 69; // so img2b at index 5 is set to 69.
+
+ std::cout << (100 * img2a.at(5) + img2b.at(5)) // Gives 1969.
+ << std::endl;
+
+
+
+ // In the Olena library, all image types behave like image1d:
+ //
+ // +-----------------------------------------------------------+
+ // | |
+ // | - an "empty" image actually is a mathematical variable |
+ // | |
+ // | => just think in a mathemetical way when dealing |
+ // | with images; |
+ // | |
+ // | |
+ // | - no dynamic memory allocation/deallocation is required |
+ // | |
+ // | the user never has to use "new / delete" (the C++ |
+ // | equivalent for the C "malloc / free") so she does |
+ // | not have to manipulate pointers or to directly |
+ // | access memory |
+ // | |
+ // | => Olena prevents the user from making mistakes; |
+ // | |
+ // | |
+ // | - image data/values can be shared between several |
+ // | variables and the memory used for image data is |
+ // | handled by the library |
+ // | |
+ // | => memory management is automatic. |
+ // | |
+ // | |
+ // +-----------------------------------------------------------+
+
+
+
+
+ image1d<char> img3a(0, 19); // These 1D image data go from the
+ // index 0 to the index 19; it thus has
+ // 20 points.
+
+ // Memory has been allocated so data can be stored but pixel values
+ // have not been initialized yet. So we fill img3a, that is, all
+ // pixels of img3a, with the value 'a':
+ level::fill(inplace(img3a), 'a');
+
+ // The "fill" algorithm is located in the sub-namespace "level"
+ // since this algorithm deals with the "level" of pixel 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/point is given by the
+ // corresponding pixel 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".
+
+ // 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 "inplace".
+
+ // The algorithm call shall be "level::fill(inplace(ima), val)".
+ // When forgetting the "inplace(..)" statement it does not compile.
+
+
+ // We then define below a second image to play with. As you can see
+ // this image has data for the indices 5 to 14 (so it has 10
+ // points). The definition domain of a 1D image can start from
+ // any index, even a negative one.
+ image1d<char> img3b(5, 14);
+
+ // We initialize the image values.
+ level::fill(inplace(img3b), 'b');
+
+ // Last we now paste the contents of img3b in img3a...
+ level::paste(img3b, inplace(img3a));
+
+ // ...and print the result.
+ debug::println(img3a);
+
+ // Before pasting, the couple of images looked like:
+ //
+ // index = 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1
+ // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
+ //
+ // img3a = a a a a a a a a a a a a a a a a a a a a
+ // img3b = b b b b b b b b b b
+ //
+ // so after pasting we get:
+ // img3a = a a a a a b b b b b b b b b b a a a a a
+ //
+ // Just remember that a point is an absolute location on the
+ // discrete domain. For the 1D case, an index is thus NOT an
+ // offset. When we write "imgb(5)", we designate the first pixel of
+ // imgb since this image starts at index 5.
+
+
+ // With this simple example we can see that images defined on
+ // different domains (or set of points) can interoperate. The set
+ // of points an image is defined on can be accessed and printed.
+ // The following code:
+
+ std::cout << "img3a.points() = " << img3a.points() << std::endl
+ << "img3b.points() = " << img3b.points() << std::endl;
+
+ // gives:
+ // img3a.points() = { (0) .. (19) }
+ // img3b.points() = { (5) .. (14) }
+
+ // The notion of point sets plays an important role in Olena. Many
+ // tests are performed at run-time to ensure that the program is
+ // correct.
+
+ // For instance, the algorithm level::paste tests that the set of
+ // points of img3b (whose values are to be pasted) is a subset of
+ // the destination image. We can reproduce this same test:
+
+ std::cout << (img3b.points() <= img3a.points() ?
+ "true" :
+ "false") << std::endl; // which gives 'true'.
+
+ // Accessing the value of an image at a given point also performs a
+ // test to make sure that this point belongs to the image domain
+ // (and consequently that data access in memory is valid). For
+ // instance, calling "img3a(9)" actually runs a code equivalent to
+ // this test:
+
+ point1d p(9);
+ std::cout << (img3a.points().has(p) ?
+ "true" :
+ "false") << std::endl; // which gives 'true'.
+
+ // The type of 1D image points is "point1d". The 1D image type
+ // features the method "operator()(point1d p)"; when we write
+ // "img3a(9)" it is just a shortcut for "img3a( point1d(9) )".
+
+ // When having a point we can access its index following:
+ std::cout << p.ind() << std::endl; // which gives 9.
+
+ // To know if a point belongs to an image domain or not, we can run
+ // this shorter test:
+ std::cout << (img3a.has(p) ?
+ "true" :
+ "false") << std::endl; // which gives 'true'.
+
+
+ // Since the notion of point is independent from the image it
+ // applies on, we can form expressions where p is used on several
+ // images:
+
+ img3a(p) = 'M', img3b(p) = 'W'; // At index 9, both values change.
+ debug::println(img3a);
+ debug::println(img3b);
+ // we obtain:
+ // a a a a a b b b b M b b b b b a a a a a
+ // b b b b W b b b b b
+
+
+ // To modify all the values of an image we can iterate over its
+ // domain with an index i:
+
+ for (int i = 5; i <= 14; ++i)
+ img3b.at(i) = 'a' + i - 5;
+ debug::println(img3b);
+ // a b c d e f g h i j
+
+ // There is a safer way to iterate that prevents from providing a
+ // wrong value for the minimum or maximum index value:
+ for (int i = img3b.min_ind(); i <= img3b.max_ind(); ++i)
+ img3b.at(i) = 'b' + i - img3b.min_ind();
+ debug::println(img3b);
+ // b c d e f g h i j k
+
+
+ // The Olena library was built with the following rationale:
+ //
+ // +-----------------------------------------------------------+
+ // | |
+ // | If you do not want to be "generic", if you are used to |
+ // | the classical way of browsing pixel values, you can! |
+ // | |
+ // +-----------------------------------------------------------+
+
+
+ // Indeed, the loops above depict the "classical" way to iterate
+ // over the contents of a 1D image. The next tour file introduces
+ // the solution provided by Olena to write better loops...
+
+
+ // Jump to tour1_extra.cc if you want some more information about
+ // image data management.
+
+ // Jump to tour2.cc to continue the tour.
+}
Index: doc/oldies/2008__tour2.cc
--- doc/oldies/2008__tour2.cc (revision 0)
+++ doc/oldies/2008__tour2.cc (revision 0)
@@ -0,0 +1,393 @@
+// Copyright (C) 2001, 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.
+
+// File: tour2.cc.
+
+#include <oln/core/2d/image2d.hh>
+#include <oln/core/2d/window2d.hh>
+#include <oln/debug/println.hh>
+
+
+
+// Note to the reader: If you do not have read the tour1.cc file, you
+// should have a quick look at it before proceeding with this present
+// file. Some important features and practices are described in the
+// former tour step that are here assumed to be known.
+
+
+
+int main()
+{
+ using namespace oln;
+
+ // As shown before, image data read access and pixel value
+ // assignments can be performed using:
+ // - either the parenthesis operator with takes a point as its
+ // argument,
+ // - or the ".at" method which requires the coordinates of the point
+ // you want to access to.
+
+ // ex: ima(p), with p a 1D point, or ima.at(i), ima being a 1D
+ // image and i an index---single coordinate.
+
+
+ // Objects from image2d and image3d types can be build and access to
+ // in a similar way than image1d, except you have to account for
+ // respectively one and two extra coordinates. Let us take an
+ // example.
+
+ image2d<bool> img(4, 5); // A 4x5 2D binary image.
+
+ for (unsigned row = 0; row < img.nrows(); ++row)
+ for (unsigned col = 0; col < img.ncols(); ++col)
+ img.at(row, col) =
+ (row > 0 and row < 3) and (col > 0 and col < 4);
+
+ debug::println(img); // Gives:
+ // - - - - -
+ // - | | | -
+ // - | | | -
+ // - - - - -
+
+ // When debug::print'ing binary images, the 'true' (object) and
+ // 'false' (background) values are respectively depicted by the '|'
+ // and '-' symbols.
+
+
+
+
+ // As said before, a point is a position in an image. Because
+ // Olena supports different dimensions, it supports different
+ // point types: point1d, point2d, and point3d.
+
+ // We build a point by passing it as much coordinates as
+ // needed:
+ point2d p(2, 0); // a 2D point so a couple of coordinates.
+
+ // Each point coordinate can be accessed separately...
+ std::cout << "row = " << p.row() << std::endl
+ << "col = " << p.col() << std::endl;
+
+ // ...and modified:
+ p.col() = 1;
+ std::cout << "col = " << p.col() << " (new value!)" << std::endl;
+
+ // So we have a way to access image data:
+ img(p) = false;
+ // which is shorter than the equivalent writing:
+ // ima2a.at(2, 1) = false;
+
+ debug::println(img);
+ // Gives (with hand-written coordinates):
+ // col 0 1 2 3 4
+ // row v
+ // 0 - - - - -
+ // 1 - | | | -
+ // 2 > - - | | -
+ // 3 - - - - -
+
+ // Points in Olena are not really like mathematical vectors. The
+ // reason is twofold. Some operations over vectors are meaningless
+ // with points; for instance adding points together makes no sense.
+ // Furthermore we want C++ expressions with points to be more
+ // strongly typed so that errors from the user can be more easily
+ // pointed out.
+
+ // To record a displacement from one point to another one, Olena
+ // introduces the notion of "delta-points". The types for
+ // delta-points are dpoint1d, dpoint2d, and dpoint3d. We have:
+
+ dpoint2d dp(-1, +2); // -1 applies to row, +2 applies to column.
+ img(p + dp) = false;
+ debug::println(img);
+ // Gives:
+ // col 0 1 2 3 4
+ // row . . v
+ // 0 - - - - -
+ // 1 > - | | - -
+ // 2 . - - | | -
+ // 3 - - - - -
+
+ // Let us verify:
+ point2d p2 = p + dp;
+ std::cout << "p2 " << p2
+ << " = p " << p
+ << " + dp " << dp << std::endl;
+ assert(p2 == point2d(1, 3)); // Right: p2 is (1, 3).
+
+ // Taking the difference between a couple of points gives a
+ // delta-point.
+ dpoint2d dp2 = p2 - p; // That should be equal to 'dp'.
+ assert(dp2 == dp); // Indeed.
+
+ // Delta-points (amongst them) feature the classical arithmetical
+ // operators:
+ dpoint2d dp3 = dp + dp2;
+ dp3 -= dp2;
+ assert(dp3 == dp);
+
+
+ // The notion of delta-point is at the base of the definitions of
+ // classical window and neighborhood.
+
+
+ // A window, or "sliding window", is a region defined around a
+ // point. In its most usual forms offered by Olena, for instance
+ // window2d for the 2D case, windows are internally defined by a set
+ // of delta-points.
+
+ window2d win; // Empty window.
+ win
+ .take(dpoint2d(-1, -1)) // Add a delta-point.
+ .take(dpoint2d( 0, 0))
+ .take(dpoint2d( 1, 1))
+ .take(dpoint2d( 1, 2));
+ std::cout << "win = " << win << std::endl;
+ // win = [ (-1, -1), (0, 0), (1, 1), (1, 2) ]
+
+ // A window is commonly used to iterate around a fixed point.
+ std::cout << "around " << p
+ << " window points are ";
+ for (unsigned i = 0; i < win.size(); ++i)
+ std::cout << (p + win[i]) // win[i] gives the ith element of the
+ << ' '; // window, i.e., a delta-point.
+ std::cout << std::endl;
+ // The code above outputs:
+ // around (2, 1) window points are (1, 0) (2, 1) (3, 2) (3, 3)
+
+
+ // If we try to generalize this kind of display to all image points,
+ // one straightforward code is the following:
+
+ {
+ // First version.
+
+ std::cout << std::endl
+ << "First version:" << std::endl
+ << std::endl;
+
+ for (unsigned row = 0; row < img.nrows(); ++row)
+ for (unsigned col = 0; col < img.ncols(); ++col)
+ {
+ point2d p(row, col);
+ std::cout << p << ": ";
+ for (unsigned i = 0; i < win.size(); ++i)
+ {
+ point2d q = p + win[i]; // q is a point around p;
+ // precisely, the ith point of
+ // the window win centered at
+ // point p
+ if (img.has(q)) // we only print q if it actually lies
+ // within the image
+ std::cout << q << ' ';
+ }
+ std::cout << std::endl;
+ }
+
+ } // End of 1st version.
+
+ // We obtain:
+ // (0, 0): (0, 0) (1, 1) (1, 2)
+ // (0, 1): (0, 1) (1, 2) (1, 3)
+ // (0, 2): (0, 2) (1, 3) (1, 4)
+ // (0, 3): (0, 3) (1, 4)
+ // (0, 4): (0, 4)
+ // (1, 0): (1, 0) (2, 1) (2, 2)
+ // (1, 1): (0, 0) (1, 1) (2, 2) (2, 3)
+ // (1, 2): (0, 1) (1, 2) (2, 3) (2, 4)
+ // (1, 3): (0, 2) (1, 3) (2, 4)
+ // (1, 4): (0, 3) (1, 4)
+ // (2, 0): (2, 0) (3, 1) (3, 2)
+ // (2, 1): (1, 0) (2, 1) (3, 2) (3, 3)
+ // (2, 2): (1, 1) (2, 2) (3, 3) (3, 4)
+ // (2, 3): (1, 2) (2, 3) (3, 4)
+ // (2, 4): (1, 3) (2, 4)
+ // (3, 0): (3, 0)
+ // (3, 1): (2, 0) (3, 1)
+ // (3, 2): (2, 1) (3, 2)
+ // (3, 3): (2, 2) (3, 3)
+ // (3, 4): (2, 3) (3, 4)
+
+
+ // An equivalent code, given here just for you to realize that you
+ // may continue to handle images and points with Olena just the way
+ // you are used to it:
+
+ /*
+
+ { // A variation.
+
+ int nrows = img.nrows(), ncols = img.ncols();
+ unsigned n = win.size();
+ for (int row = 0; row < nrows; ++row)
+ for (int col = 0; col < ncols; ++col)
+ {
+ std::cout << "(" << row << ", " << col << "): "; // print p
+ for (unsigned i = 0; i < n; ++i)
+ {
+ int // define q coordinates:
+ r = row + win[i].row(),
+ c = col + win[i].col();
+ if (r >= 0 and r < nrows and c >= 0 and c < ncols) // q is in img
+ std::cout << "(" << r << ", " << c << ") "; // print q
+ }
+ std::cout << std::endl;
+ }
+
+ } // End of a variation.
+
+ */
+
+
+ // Such samples of "classical" image processing code have 3 (three!)
+ // main drawbacks:
+
+ // - it is error-prone; note that there is rather a lot of code for
+ // a so simple algorithm;
+
+ // - the algorithm, that is, the most important part of this code, is
+ // totally drowned in the middle of implementation details;
+
+ // - this kind of writing only applies to a very special type of
+ // images (2D ones, rectangular, and starting at (0,0)) so it is
+ // not reusable.
+
+
+ // If we express the algorithm into natural language, we can say:
+ //
+ // p, a point of img
+ // q, a point of win centered at p
+ //
+ // for all p
+ // print p
+ // for all q
+ // if q is in img
+ // print q
+ // print end of line
+ // end for
+ // end for
+
+
+ // The Olena library has been designed so that you can easily
+ // translate your algorithms into code. With the running example we
+ // can write:
+
+ { // Second version.
+
+ std::cout << std::endl
+ << "Second version (same result):" << std::endl
+ << std::endl;
+
+ box2d::piter p (img.points());
+ window2d::qiter q (win, p);
+
+ for_all(p)
+ {
+ std::cout << p << ": ";
+ for_all(q)
+ if (img.has(q))
+ std::cout << q << ' ';
+ std::cout << std::endl;
+ }
+
+ } // End of 2nd version.
+
+ std::cout << std::endl;
+
+
+ // Above, p and q behave just like points; for instance, the
+ // following expressions are valid:
+
+ // int r = p.row();
+ // to get the current row value,
+
+ // bool b = img(p);
+ // to get the pixel value at the current point,
+
+ // or point2d pp = p + dp;
+ // where dp is a delta-point to get a point nearby p.
+
+ // Yet, p and q are "more than points" since they allow to
+ // browse/iterate over a set of points, respectivelly, the domain of
+ // 'img' and the window centered at p.
+
+
+ // The domain of 'img' is obtained with "img.points()" and is
+ // provided to the 'p' object so that it knows how to iterate.
+
+ // For a "basic" image, its set of points is an n-dimensional box.
+ // In the 2D space, the box type is called 'box2d'. We also have
+ // 'box1d' and 'box3d' for other dimensions.
+
+ box2d pts = img.points();
+ std::cout << "img points are " << pts << std::endl;
+ // Prints:
+ // img points are { (0, 0) .. (3, 4) }
+
+ // The type of iterators over a point set is obtained with the
+ // expression: "name_of_the_point_set_type::piter", where 'piter'
+ // means "point iterator" for short.
+
+ // The same construction is available for iterators on window
+ // points, whose types are obtained in a similar way with
+ // "name_of_the_window_type::qiter". Here the 'q' in 'qiter'
+ // emphases the fact that a window is not really a set of points but
+ // "a set of dpoints and a center point".
+
+
+
+ // The second version of our example contrasts with the more
+ // "classical" ones; it is:
+
+ // - shorter,
+ // so it is less error-prone for the developer;
+
+ // - easy to read,
+ // so the algorithm appears clearly from the code;
+
+ // - (almost) "generic",
+ // for instance, no details within the loops indicate that we are
+ // processing a 2D image, that this image is rectangular, etc.
+
+
+ // +-----------------------------------------------------------+
+ // | |
+ // | A major feature of Olena is to offer to its users a way |
+ // | to write GENERIC algorithms, that is, algorithms that |
+ // | accept different image types as input. |
+ // | |
+ // +-----------------------------------------------------------+
+
+
+ // The next files of the tour give many details about what you can
+ // expect from the notion of "genericity" applied to image
+ // processing.
+
+ // Now you can jump to tour3.cc
+
+
+}
Index: doc/oldies/2008__tour3.cc
--- doc/oldies/2008__tour3.cc (revision 0)
+++ doc/oldies/2008__tour3.cc (revision 0)
@@ -0,0 +1,331 @@
+// Copyright (C) 2001, 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.
+
+// File: tour2.cc.
+
+#include <oln/core/2d/image2d.hh>
+#include <oln/core/2d/neighb2d.hh>
+
+#include <oln/core/gen/such_as.hh>
+#include <oln/core/gen/torus_image.hh>
+#include <oln/core/gen/pw_value.hh>
+#include <oln/core/gen/fun_ops.hh>
+
+#include <oln/level/fill.hh>
+#include <oln/debug/fill.hh>
+#include <oln/debug/println.hh>
+
+
+// Note to the reader: you should have read the files tour1.cc and
+// tour2.cc before starting with this present file.
+
+
+
+// We have encapsulated an algorithm into a procedure which is forward
+// declared below so that it can be used in the section 'main'.
+template <typename I> void algo(const I& img);
+
+
+// Some functions that will be useful in the following:
+bool chessboard(oln::point2d p)
+{
+ return (p.row() + p.col()) % 2;
+}
+
+
+
+int main()
+{
+ using namespace oln;
+
+ // First our domain is 2d box:
+ box2d b(point2d(0, 0), point2d(2, 2));
+ // ^^^^ ^^^^
+ // from to
+
+ // We define a binary image with values on that box.
+ image2d<bool> img(b);
+
+ // With an array of Booleans (1 means true, 0 means false)...
+ bool vals[] = { 1, 0, 0,
+ 0, 1, 0,
+ 0, 1, 1 };
+ // ...the debug::fill routine allows for manually initializing
+ // image data:
+ debug::fill(inplace(img), vals);
+ std::cout << "img = " << std::endl;
+ debug::println(img);
+ // img =
+ // | - -
+ // - | -
+ // - | |
+
+ image2d<int> ima(b); // An image of integers with the same
+ box2d::piter p(ima.points()); // domain as img...
+ int i = 0;
+ for_all(p)
+ ima(p) = i++; // ...and manually filled with values.
+
+ std::cout << "ima = " << std::endl;
+ debug::println(ima);
+ // ima =
+ // 0 1 2
+ // 3 4 5
+ // 6 7 8
+
+
+
+ // The algorithm defined at the end of this file is very close to
+ // the one of the tour former file. The major difference is that it
+ // does not rely on a window but on a neighborhood.
+
+ // In image processing, we usually say that "an image has a given
+ // neighborhood" or that "we associate/embed a neighborhood to/into
+ // an image". In Olena, that is really the case: the image can
+ // "have" a neighborhood, meaning that a neighborhood can be added
+ // to an image in order to obtain an "image with a neighborhood".
+
+ // Joining an image with a neighborhood is performed with the
+ // operator '+':
+ algo(ima + c4); // c4 is the 2D neighborhood corresponding to
+ // 4-connectivity; such as many classical
+ // neighborhoods it is provided by Olena.
+ // The result is given below.
+
+ // ---input:
+ // 0 1 2
+ // 1 2 3
+ // 2 3 4
+ // ---output:
+ // 0: 1 1
+ // 1: 0 2 2
+ // 2: 1 3
+ // 1: 0 2 2
+ // 2: 1 1 3 3
+ // 3: 2 2 4
+ // 2: 1 3
+ // 3: 2 2 4
+ // 4: 3 3
+
+ // That was expectable...
+
+
+ // And now for a little test: what is the result of this code?
+ {
+ image2d<int> test(ima.points());
+ level::fill(inplace(test), ima);
+ (test + c4).at(1, 1) = 9;
+ debug::println(test);
+ }
+ // and can you tell why?
+ // The answers are given in the file tour3-test.txt
+
+
+ // Now let us start experimenting the genericity of Olena!
+
+
+ // First, imagine that you want to restrict the domain of ima to a
+ // subset of points, a region or whatever. For instance, the
+ // chessboard function takes a point as argument and returns a
+ // Boolean so it is like a predicate. We can want to consider only
+ // the points of ima "such as" this predicate is verified. The
+ // "such as" mathematical symbol is '|' so let's rock:
+
+ algo((ima | chessboard) + c8);
+ // gives:
+
+ // ---input:
+ // 1
+ // 3 5
+ // 7
+ // ---output:
+ // 1: 3 5
+ // 3: 1 7
+ // 5: 1 7
+ // 7: 3 5
+
+ // where the blanks in printing the input image denote that the
+ // corresponding points do NOT belong to the image domain.
+
+ // Another similar example is based on the binary image created at
+ // the beginning of this tour:
+ algo((ima | img) + c8);
+ // which gives:
+
+ // ---input:
+ // 0
+ // 4
+ // 7 8
+ // ---output:
+ // 0: 4
+ // 4: 0 7 8
+ // 7: 4 8
+ // 8: 4 7
+
+
+
+ // Second, imagine that you want your initial image to get the
+ // geodesy of a torus, that is, a 2D image wrapped on a torus.
+ // Points located at the image boundary have neighbors; for
+ // instance, the point denoted by the 'x' cross below has for
+ // 4-connectivity neighbors: t, l, r, and b (respectively for top,
+ // left, right, and bottom):
+
+ // b o o o
+ // o o o o
+ // t o o o
+ // x r o l
+
+ // Let us try:
+ algo(torus(ima) + c8);
+ // gives:
+
+ // ---input:
+ // 0 1 2
+ // 3 4 5
+ // 6 7 8
+ // ---output:
+ // 0: 8 6 7 2 1 5 3 4
+ // 1: 6 7 8 0 2 3 4 5
+ // 2: 7 8 6 1 0 4 5 3
+ // 3: 2 0 1 5 4 8 6 7
+ // 4: 0 1 2 3 5 6 7 8
+ // 5: 1 2 0 4 3 7 8 6
+ // 6: 5 3 4 8 7 2 0 1
+ // 7: 3 4 5 6 8 0 1 2
+ // 8: 4 5 3 7 6 1 2 0
+
+
+
+ // We can have both the torus geodesy and a sub-domain:
+
+ algo(torus(ima | chessboard) + c8);
+ algo(torus(ima | img) + c8);
+
+ // which respectively give:
+
+ // ---input:
+ // 1
+ // 3 5
+ // 7
+ // ---output:
+ // 1: 7 3 5
+ // 3: 1 5 7
+ // 5: 1 3 7
+ // 7: 3 5 1
+
+ // and:
+
+ // ---input:
+ // 0
+ // 4
+ // 7 8
+ // ---output:
+ // 0: 8 7 4
+ // 4: 0 7 8
+ // 7: 4 8 0
+ // 8: 4 7 0
+
+
+
+
+ // Last, the way a predicate is defined can also rely on some image
+ // values. For that the user can on the fly provide an expression
+ // built with the "pw_value" facility, where "pw_" means
+ // "point-wise" for short:
+
+ algo((ima | (pw_value(ima) < 4)) + c4);
+
+ // In this example, "pw_value(ima)" is the function that represents
+ // the point-wise value of the 'ima' image, that is, the function
+ // "p -> ima(p)". This naturally leads to:
+
+ // ---input:
+ // 0 1 2
+ // 3
+ //
+ // ---output:
+ // 0: 1 3
+ // 1: 0 2
+ // 2: 1
+ // 3: 0
+
+
+
+ // From those examples, you should realize that:
+
+
+ // +-----------------------------------------------------------+
+ // | |
+ // | The level of "genericity" provided by Olena is rather |
+ // | high; it means: |
+ // | |
+ // | - taking the image dimension you work on; |
+ // | |
+ // | - having the type of pixel values you need; |
+ // | |
+ // | - choosing the neighborhood you want; |
+ // | |
+ // | - changing the geodesy if you need it; |
+ // | |
+ // | - being able to restrict the image domain; |
+ // | |
+ // | - and many other features that are addressed further |
+ // | in the tour... |
+ // | |
+ // +-----------------------------------------------------------+
+
+}
+
+
+
+
+
+// The algorithm 'algo':
+
+template <typename I>
+void algo(const I& img)
+{
+ std::cout << "---input:" << std::endl;
+ oln::debug::print(img);
+ std::cout << "---output:" << std::endl;
+
+ oln_piter(I) p(img.points()); // p iterates on img points
+ oln_niter(I) n(img, p); // n iterates in img on neighbors of p
+
+ for_all(p)
+ {
+ std::cout << oln::debug::format(img(p))
+ << ':';
+ for_all(n)
+ std::cout << ' '
+ << oln::debug::format(img(n));
+ std::cout << std::endl;
+ }
+
+ std::cout << std::endl;
+}
Index: doc/oldies/2008__tour1_extra.cc
--- doc/oldies/2008__tour1_extra.cc (revision 0)
+++ doc/oldies/2008__tour1_extra.cc (revision 0)
@@ -0,0 +1,214 @@
+// 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.
+
+// File: tour1_extra.cc.
+
+#include <oln/core/1d/image1d.hh>
+#include <oln/arith/plus.hh>
+#include <oln/debug/println.hh>
+
+
+
+int main()
+{
+ using namespace oln;
+
+
+ // Let us take a few examples to illustrate how images and data are
+ // managed. In these examples, we will use the notion of "block of
+ // instructions" from the C/C++ languages: "{" ... "}".
+
+
+
+
+ // Example 1:
+
+ { // A new block starts here.
+
+ image1d<float> local_ima(1000);
+ // A non-empty image is created; a memory buffer is automatically
+ // allocated to store image data. Some code using 'local_ima' can
+ // be inserted here...
+
+ } // The block ends and 'local_ima' is not more accessible.
+
+ // At the end of the block, since the user cannot use 'local_ima'
+ // anymore, the memory is automatically deallocated.
+
+
+
+
+ // Example 2:
+
+ image1d<float> ima; // An empty image---a variable.
+
+ { // A new block.
+
+ image1d<float> local_ima(1000); // A non-empty image.
+ // Some work is performed with 'local_ima' here.
+ // ...
+ ima = local_ima; // Last, we state that ima IS local_ima.
+
+ } // End of the block: 'local_ima' is no more accessible.
+
+ assert(not ima.is_empty()); // We test that 'ima' is no more empty.
+
+ // Since we state that "ima IS local_ima" and since 'ima' is still
+ // accessible by the user, the contents of 'local_ima' is preserved.
+
+ // Conversely to the example 1, the memory allocated for 'local_ima'
+ // is thus NOT deallocated: the data of 'local_ima' is "transfered"
+ // to 'ima'. There is NO data "copy" involved during this transfer
+ // so it is fast and it saves memory.
+
+
+
+
+ // Example 3:
+
+ {
+ image1d<int> orig(5); // An original image.
+ for (int i = 0; i < 5; ++i)
+ orig.at(i) = i;
+ debug::println(orig);
+ // 0 1 2 3 4
+
+ image1d<int> ima = orig; // 'ima' is 'orig'.
+ ima = ima + ima; // Point-wise sum of ima and itself.
+ debug::println(ima);
+ // 0 2 4 6 8
+
+ debug::println(orig);
+ // 0 1 2 3 4
+ }
+
+ // To explain this result, let us detail the point-wise sum line.
+ // The assignment "ima = ima + ima" is a two-step process: first
+ // "ima + ima" is computed, then the assignment is performed. This
+ // line can be rewritten as:
+
+ // image1d<int> anon = ima + ima; // line (a)
+ // ima = anon; // line (b)
+
+ // where 'anon' is the "anonymous" result of the sum. We can see
+ // that 'ima' is used in line (a) to compute a new image, namely
+ // 'anon'. At that precise line, 'ima' still designates 'orig'. At
+ // line (b) the definition of 'ima' changes: 'ima' was designating
+ // 'orig', now it designates 'anon', that is, the sum result.
+ // Eventually the data of 'orig' have never changed since it has
+ // been initialized.
+
+ // In this example, two images with effective data have been
+ // created: the sum result, which is accessible through 'ima', and
+ // 'orig'.
+
+ // The same explanation in pictures. When the sum "ima + ima" is
+ // computed, the images and their data look like:
+ //
+ // +-----------+
+ // orig --> | 0 1 2 3 4 |
+ // +-----------+
+ // ^
+ // ima ______|
+ //
+ // +-----------+
+ // anon --> | 0 2 4 6 8 |
+ // +-----------+
+ //
+ // Then the assignment modifies this scheme into:
+ //
+ // +-----------+
+ // orig --> | 0 1 2 3 4 |
+ // +-----------+
+ // ima ______
+ // |
+ // v
+ // +-----------+
+ // anon --> | 0 2 4 6 8 |
+ // +-----------+
+ //
+ // and the temporary 'anon' disappears.
+
+
+
+
+
+ // Example 4:
+
+ {
+ image1d<int> ima(5);
+ for (int i = 0; i < 5; ++i)
+ ima.at(i) = i;
+ debug::println(ima);
+ // 0 1 2 3 4
+
+ ima = ima + ima;
+ debug::println(ima);
+ // 0 2 4 6 8
+ }
+
+ // Let us re-write the assignment line:
+
+ // image1d<int> anon = ima + ima; // line (a)
+ // ima = anon; // line (b)
+
+ // A new image, 'anon', is created to store the sum result; this
+ // image is just like a temporary object since it is anonymous. In
+ // line (a) the definition of 'ima' changes: it was the original
+ // image with its data being "0 1 2 3 4" and it now designates the
+ // sum result. The original data becomes inaccessible by the user
+ // so it is automatically deallocated.
+
+ // The same explanation In pictures. After the sum is computed, we
+ // have:
+ // +-----------+
+ // ima ---> | 0 1 2 3 4 |
+ // +-----------+
+ //
+ // +-----------+
+ // anon --> | 0 2 4 6 8 |
+ // +-----------+
+ //
+ // and the assignment of 'ima' leads to:
+ //
+ // +-----------+
+ // ima | 0 1 2 3 4 |
+ // | +-----------+
+ // |_________
+ // |
+ // v
+ // +-----------+
+ // anon --> | 0 2 4 6 8 |
+ // +-----------+
+ //
+ // so the original data, unreachable, are deallocated and the
+ // temporary 'anon' disappears; we end up with:
+ //
+ // +-----------+
+ // ima ---> | 0 2 4 6 8 |
+ // +-----------+
+}
Index: doc/oldies/2006__tour_1.txt
--- doc/oldies/2006__tour_1.txt (revision 0)
+++ doc/oldies/2006__tour_1.txt (revision 0)
@@ -0,0 +1,671 @@
+ -*- outline -*-
+
+
+* primary image types
+
+
+** image2d<T>
+
+*** definition
+
+rectangular 2D image with a virtual border
+
+*** parameter
+
+T: value type
+
+*** related types
+
+image1d<T> and image3d<T> are similarly constructed
+
+*** sample code
+
+**** step 1
+
+char[] values = { 'a', 'b', 'c',
+ 'd', 'e', 'f' };
+image2d<char> ima(2, 3);
+level::fill(ima, values);
+debug::print(ima.bbox());
+
+// [(0, 0)..(1, 2)]
+
+debug::print(ima);
+
+// 0 1 2
+// - - -
+// 0| a b c
+// 1| d e f
+
+ima.set_name("ima");
+point2d p(0, 1);
+
+std::cout << ima(p) << std::endl;
+// b
+
+debug::print(ima, p);
+// ima.at(0, 1) == b
+
+ima.at(0, 1) = 'B';
+debug::print(ima, p);
+// ima.at(0, 1) == B
+
+
+bbox2d bb = set(from(1,5), to(2,7));
+image2d<char> ima2(bb);
+ima2.set_name("ima2");
+level::fill(ima2, values);
+debug::print(ima2);
+
+// 5 6 7
+// - - -
+// 1| a b c
+// 2| d e f
+
+**** step 2
+
+ima2.set_border_thickness(1);
+border::fill(ima2, '.');
+
+debug::print(ima2.bbox());
+// [(1, 5)..(2, 7)]
+
+debug::print(ima2);
+// 5 6 7
+// - - -
+// 1| a b c
+// 2| d e f
+
+debug::print(ima2.large_bbox());
+// [(0, 4)..(3, 8)]
+
+debug::print_large(ima2);
+// 4 5 6 7 8
+// - - - - -
+// 0| . . . . .
+// 1| . a b c .
+// 2| . d e f .
+// 3| . . . . .
+
+ima2.at( 0, 6) = 'x'; // OK
+ima2.at(-1, 6) = '?'; // error: out of bounds
+
+debug::print_large(ima2);
+// 4 5 6 7 8
+// - - - - -
+// 0| . . x . .
+// 1| . a b c .
+// 2| . d e f .
+// 3| . . . . .
+
+debug::print(ima2);
+// 5 6 7
+// - - -
+// 1| a b c
+// 2| d e f
+
+std::cout << ima2.npoints() << std::endl;
+// 6
+
+std::cout << ima2.bbox().npoints() << std::endl;
+// 6
+
+std::cout << ima2.large_bbox().npoints() << std::endl;
+// 20
+
+std::cout << ima2.n_value_cells() << std::endl;
+// 20
+
+**** step 3
+
+a virtual border (at the outer boundary of the domain) is provided so
+that there is no need for special code to handle pixels at the limit
+of the domain.
+
+int[] values = { 0, 1, 1, 1, 0,
+ 0, 1, 1, 1, 0,
+ 0, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0 };
+image2d<bool> ima(from(1,1), to(4,4));
+level::fill(ima, values);
+debug::print(ima);
+// 1 2 3 4 5
+// - - - - -
+// 1| 0 1 1 1 0
+// 2| 0 1 1 1 0
+// 3| 0 1 1 1 0
+// 4| 0 0 0 0 0
+
+image2d<bool> ima2 = morpho::e_erosion(ima + c4);
+debug::print(ima2);
+// 1 2 3 4 5
+// - - - - -
+// 1| 0 0 1 0 0
+// 2| 0 0 1 0 0
+// 3| 0 0 0 0 0
+// 4| 0 0 0 0 0
+
+actually, after level::fill we have:
+
+// 0 1 2 3 4 5 6
+// - - - - - - -
+// 0| ? ? ? ? ? ? ?
+// 1| ? 0 1 1 1 0 ?
+// 2| ? 0 1 1 1 0 ?
+// 3| ? 0 1 1 1 0 ?
+// 4| ? 0 0 0 0 0 ?
+// 5| ? ? ? ? ? ? ?
+
+in morpho::e_erosion, the border is initialized:
+// 0 1 2 3 4 5 6
+// - - - - - - -
+// 0| 1 1 1 1 1 1 1
+// 1| 1 0 1 1 1 0 1
+// 2| 1 0 1 1 1 0 1
+// 3| 1 0 1 1 1 0 1
+// 4| 1 0 0 0 0 0 1
+// 5| 1 1 1 1 1 1 1
+
+so we get the proper result:
+// 0 1 2 3 4 5 6
+// - - - - - - -
+// 0| 1 1 1 1 1 1 1
+// 1| 1 0 0 1 0 0 1
+// 2| 1 0 0 1 0 0 1
+// 3| 1 0 0 0 0 0 1
+// 4| 1 0 0 0 0 0 1
+// 5| 1 1 1 1 1 1 1
+
+
+
+
+** image_2dhex<T>
+
+*** definition
+
+image defined on a 2D triangular grid (hexagonal pixels)
+it is equipped with a virtual border
+
+*** parameter
+
+T: value type
+
+*** sample code
+
+FIXME
+
+
+
+** igraph<T>
+
+FIXME: ...
+
+
+
+** image2d_without_border<T>
+
+*** definition
+
+same type as image2d<T> but without border
+
+*** parameter
+
+T: value type
+
+*** sample code
+
+**** step 1
+
+image2d<char> ima = set(from(0,0), to(0,0));
+ima.at( 0, 0) = 'a'; // OK
+ima.at(-1, 0) = 'a': // error
+
+std::cout << ima.npoints() << std::endl;
+// 1
+std::cout << ima.n_value_cells() << std::endl;
+// 1
+
+**** step 2
+
+int[] values = { 0, 1, 1, 1, 0,
+ 0, 1, 1, 1, 0,
+ 0, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0 };
+image2d_without_border<bool> ima(from(1,1), to(4,4));
+level::fill(ima, values);
+debug::print(ima);
+// 1 2 3 4 5
+// - - - - -
+// 1| 0 1 1 1 0
+// 2| 0 1 1 1 0
+// 3| 0 1 1 1 0
+// 4| 0 0 0 0 0
+
+image2d<bool> ima2 = morpho::e_erosion(ima + c4);
+debug::print(ima2);
+// 1 2 3 4 5
+// - - - - -
+// 1| 0 0 0 0 0
+// 2| 0 0 1 0 0
+// 3| 0 0 0 0 0
+// 4| 0 0 0 0 0
+
+
+
+** one_value_image<S, T>
+
+*** definition
+
+image defined by a point-set and a (single) value
+this image has the same value for all pixels
+
+*** parameters
+
+S: point set type
+T: value type
+
+*** sample code
+
+bbox2d bb = set(from(1,4), to(2,6));
+one_value_image<bbox2d, char> ima(bb, 'a');
+debug::print(ima);
+
+// 4 5 6
+// - - -
+// 1| a a a
+// 2| a a a
+
+ima.value() = 'b';
+debug::print(ima);
+
+// 4 5 6
+// - - -
+// 1| b b b
+// 2| b b b
+
+std::cout << ima.npoints() << std::endl;
+// 6
+
+std::cout << ima.nvalues() << std::endl;
+// 1
+
+std::cout << ima.n_value_cells() << std::endl;
+// 1
+
+ima.change_value('b', 'c');
+// 4 5 6
+// - - -
+// 1| c c c
+// 2| c c c
+
+std::cout << ima.at(1, 5) << std::endl;
+// c
+
+ima.at(1, 5) = 'd'; // error
+
+ima.change_value('C', ' '); // error at run-time
+ // 'C' is not a value for this image
+
+
+
+** image_p2v<S, F>
+
+*** definition
+
+image defined by a point set and a function "point -> value"
+
+*** parameters
+
+S: point set type
+F: function type
+
+*** sample code
+
+**** step 1
+
+bool chess(point2d p)
+{
+ return (p.row() + p.col()) % 2;
+}
+
+bbox2d bb(from(0,0), to(3,3));
+image2d<bool> ima = image(bb, chess);
+debug::print(ima);
+// 0 1 2 3
+// - - - -
+// 0| 0 1 0 1
+// 1| 1 0 1 0
+// 2| 0 1 0 1
+// 3| 1 0 1 0
+
+or:
+
+image_p2v<bbox2d, bool(*)(point2d)> ima(bb, chess);
+
+std::cout << ima.at(2, 3) << std::endl; // OK: image readable
+// 1
+
+bool val;
+ima.at(2, 3) = val; // error: image not writable
+
+**** step 2
+
+Likewise but with a function-object:
+
+struct chess_t
+{
+ bool operator()(point2d p) const
+ {
+ return (p.row() + p.col()) % 2;
+ }
+};
+
+bbox2d bb(from(0,0), to(3,3));
+image_p2v<bbox2d, chess_t> ima(bb);
+debug::print(ima);
+// 0 1 2 3
+// - - - -
+// 0| 0 1 0 1
+// 1| 1 0 1 0
+// 2| 0 1 0 1
+// 3| 1 0 1 0
+
+**** step 3
+
+struct chess_t : oln::abstract::function_p2v<chess_t>
+{
+ bool value(point2d p) const
+ {
+ return (p.row() + p.col()) % 2;
+ }
+};
+static chess_t chess;
+
+// ...
+
+debug::options opt;
+opt.true_symbol('*').false_symbol(' ');
+debug::print( chess(from(0,0), to(3,3)), opt );
+// 0 1 2 3
+// - - - -
+// 0| * *
+// 1| * *
+// 2| * *
+// 3| * *
+
+
+
+** rle_image<P, T>
+
+*** definition
+
+image with run-length encoding
+
+*** parameters
+
+P: point type
+T: value type
+
+*** sample code
+
+**** step 1
+
+rle_image<point2d, int> ima;
+ima.
+ set_name("ima").
+ insert(from(2,1), len(3), val(6)).
+ insert(from(1,2), len(2), val(8));
+
+debug::print(ima);
+// { ([(1, 2)..(1, 3)], 8), ([(2, 1)..(2, 3)], 6) }
+
+std::cout << ima.n_value_cells() << std::endl;
+// 2
+
+debug::options opt;
+opt.no_symbol('x');
+debug::print( imagine(ima), opt );
+// 1 2 3
+// - - -
+// 1| x 8 8
+// 2| 6 6 6
+
+std::cout << ima.npoints() << std::endl;
+// 5
+
+image2d<int> ima2(from(1,1), to(2,3), val(4));
+debug::print(ima2);
+// 1 2 3
+// - - -
+// 1| 4 4 4
+// 2| 4 4 4
+
+level::assign(ima2, ima);
+debug::print(ima2);
+// 1 2 3
+// - - -
+// 1| 4 8 8
+// 2| 6 6 6
+
+**** step 2
+
+std::cout << ima.nrls() << std::endl;
+// 2
+
+debug::print(ima.rl(0));
+// ([(1, 2)..(1, 3)], 8)
+
+debug::print(ima.rl(1));
+// ([(2, 1)..(2, 3)], 6)
+
+std::cout << ima.rl(1).first_p() << std::endl;
+// (2, 1)
+
+std::cout << ima.rl(1).last_p() << std::endl;
+// (2, 3)
+
+std::cout << ima.rl(1).value() << std::endl;
+// 6
+
+std::cout << ima.rl(1).npoints() << std::endl;
+// 3
+
+FIXME:
+std::cout << ima.rl(1).point(0) << ' '
+ << ima.rl(1).point(1) << ' '
+ << ima.rl_point(1, 2) << std::endl;
+// (2, 1) (2, 2) (2, 3)
+
+**** step 3
+
+// remember that for ima, in the rl #1, the point #1 is (2, 2)
+
+point2d p(2, 2);
+std::cout << ima(p) << std::endl; // KO: does not compile
+
+std::cout << ima.rl_point(1, 1) << std::endl;
+// (2, 2)
+
+rle_psite<point2d> p_(1, 1);
+std::cout << ima(p_) << std::endl; // OK
+// 6
+
+debug::print(ima2);
+// 1 2 3
+// - - -
+// 1| 4 8 8
+// 2| 6 6 6
+rle_image<point2d, int> ima3 = rlencode(ima2);
+debug::print(ima3);
+// { ([(1, 1)..(1, 1)], 4), ([(1, 2)..(1, 3)], 8), ([(2, 1)..(2, 3)], 6) }
+level::in_place::inc(ima3);
+
+
+debug::print(ima3);
+// { ([(1, 1)..(1, 1)], 5), ([(1, 2)..(1, 3)], 9), ([(2, 1)..(2, 3)], 7) }
+
+debug::print( imagine(ima3) );
+// 1 2 3
+// - - -
+// 1| 5 9 9
+// 2| 7 7 7
+
+
+debug::print(ima);
+// { ([(1, 2)..(1, 3)], 8), ([(2, 1)..(2, 3)], 6) }
+
+debug::print( imagine(ima), opt );
+// 1 2 3
+// - - -
+// 1| x 8 8
+// 2| 6 6 6
+
+std::cout << ima.rl_point(1, 1) << std::endl;
+// (2, 2)
+
+
+rl_psite<point2d> p3(ima3, 1, 1); // p3 is not bound to ima3 but to its topology
+
+std::cout << ima3.rl_point(1, 1) << std::endl;
+// (1, 3)
+
+std::cout << ima3(p3) << std::endl; // OK
+// 9
+
+std::cout << ima(p3) << std::endl; // error at run-time
+
+// explanation:
+// 1) p3, when created, clearly designates the 2D point (1, 3) through
+// the couple (rl #1, pt #1)
+// 2) when writing "ima(p3)" we want to access the value of "ima" at point (1, 3)
+// 3) "ima" knows that the couple (rl #1, pt #1) does not designate the point (1, 3)
+// but (2, 2) instead
+// 4) this error is then identified at run-time
+
+
+ima3.remove_rl(0);
+
+debug::print(ima3);
+// { ([(1, 2)..(1, 3)], 9), ([(2, 1)..(2, 3)], 7) }
+
+debug::print( imagine(ima3), opt );
+// 1 2 3
+// - - -
+// 1| x 9 9
+// 2| 7 7 7
+
+rl_psite<point2d> p3_(ima3, 1, 1);
+std::cout << ima3.rl_point(1, 1) << std::endl; // now same as ima.rl_point(1, 1)
+// (2, 2)
+
+std::cout << ima(p3_) << std::endl; // now OK
+// 7
+
+
+
+
+** sparse_image<P, T>
+
+*** definition
+
+FIXME: HERE
+
+
+*** parameter
+
+P: point type
+T: value type
+
+*** main features
+
+not point-wise accessible
+not value-wise accessible
+
+*** data storage
+
+std::vector of couples (p_start, std::vector<T>)
+
+
+** image_vec<P, T>
+
+*** parameters
+
+P: point type
+T: value type
+
+*** main features
+
+not point-wise accessible
+not value-wise accessible
+
+*** data storage
+
+std::vector< std::pair<P, T> >
+
+
+** image_map<P, T>
+
+*** parameters
+
+P: point type
+T: value type
+
+*** main features
+
+not point-wise accessible
+not value-wise accessible
+
+*** data storage
+
+using std::map<P, T>
+
+*** related type
+
+slow::image_map<P, T>
+
+
+** slow::image_bbmap<P, T>
+
+*** parameters
+
+P: point type
+T: value type
+
+*** main features
+
+point-wise accessible and mutable
+not value-wise accessible
+bounding-boxed
+
+*** data storage
+
+some values are set in a std::map<P, T>
+when not set, a default value is provided by an attribute
+
+*** related type
+
+image_map<P, T>
+
+
+
+** Morpher types
+
+** FIXME
+
+do (really!) nothing when writing at p when outside the image domain
+error when reading at p when outside the image domain
+
+** FIXME
+
+add a default value when p is outside the image domain
+
+** sequence<I>
+
+FIXME: ...
+
+
+
+Local Variables:
+mode: outline
+ispell-local-dictionary: "american"
+End:
Index: doc/oldies/2006__tour_2.txt
--- doc/oldies/2006__tour_2.txt (revision 0)
+++ doc/oldies/2006__tour_2.txt (revision 0)
@@ -0,0 +1,404 @@
+ -*- outline -*-
+
+* primary image types
+
+** image2d<T>
+
+*** parameter
+
+T: value type
+
+*** main features
+
+- debase type for a rectangular 2D image
+
+- a virtual border (at the outer boundary of the domain) is provided
+ so that there is no need for special code to handle pixels at the
+ limit of the domain.
+
+*** sample code
+
+int[] values = { 'a', 'b', 'c',
+ 'd', 'e', 'f' };
+image2d<char> ima(2, 3);
+level::fill(ima, values);
+debug::print(ima.bbox());
+
+// [(0, 0)..(1, 2)]
+
+debug::print(ima);
+
+// 0 1 2
+// - - -
+// 0| a b c
+// 1| d e f
+
+ima.set_name("ima");
+point2d p(0, 1);
+
+std::cout << ima(p) << std::endl;
+// b
+
+debug::print(ima, p);
+// ima.at(0, 1) == b
+
+ima.at(0, 1) = 'B';
+debug::print(ima, p);
+// ima.at(0, 1) == B
+
+
+
+bbox2d bb = set(from(1,5), to(2,7));
+image2d<char> ima2(bb);
+ima2.set_name("ima2");
+level::fill(ima2, values);
+debug::print(ima2);
+
+// 5 6 7
+// - - -
+// 1| a b c
+// 2| d e f
+
+
+ima2.border() = 1;
+border::fill(ima2, '.');
+
+debug::print(ima2.bbox());
+// [(1, 5)..(2, 7)]
+
+debug::print(ima2);
+// 5 6 7
+// - - -
+// 1| a b c
+// 2| d e f
+
+debug::print(ima2.large_bbox());
+// [(0, 4)..(3, 8)]
+
+debug::print_large(ima2);
+// 4 5 6 7 8
+// - - - - -
+// 0| . . . . .
+// 1| . a b c .
+// 2| . d e f .
+// 3| . . . . .
+
+ima2.at( 0, 6) = 'x'; // OK
+ima2.at(-1, 6) = '?'; // error: out of bounds
+
+debug::print_large(ima2);
+// 4 5 6 7 8
+// - - - - -
+// 0| . . x . .
+// 1| . a b c .
+// 2| . d e f .
+// 3| . . . . .
+
+debug::print(ima2);
+// 5 6 7
+// - - -
+// 1| a b c
+// 2| d e f
+
+std::cout << ima2.npoints() << std::endl;
+// 6
+
+std::cout << ima2.bbox().npoints() << std::endl;
+// 6
+
+std::cout << ima2.large_bbox().npoints() << std::endl;
+// 20
+
+std::cout << ima2.n_memory_cells() << std::endl;
+// 20
+
+
+FIXME: play with point2d and dpoint2d...
+
+
+*** related types
+
+image1d<T> and image3d<T> are similarly constructed
+
+
+*** level 2
+
+*** main features
+
+has a virtual border (same thickness for every axis)
+point-wise accessible and mutable
+not value-wise accessible
+
+*** data storage
+
+relies on array2d<T>
+
+*** to-do
+
+should rely on array2d< T::storage >
+add unambiguous ctors
+
+*** ideas
+
+point2d p(0, 1);
+point2d p = set(row(0), col(1));
+
+bbox2d bb = set(from(1,5), to(2,7));
+bbox2d bb = set(minrow(1), maxrow(2), mincol(5), maxcol(7));
+bbox2d bb = set(minrow(1), mincol(5), nrows(2), ncols(3));
+bbox2d bb = set(pmin(1,5), nrows(2), ncols(3));
+bbox2d bb = set(pmin(1,5), size(2,3));
+
+
+*** image_2dhex<T>
+
+on a 2D triangular grid (hexagonal pixels)
+FIXME: ...
+
+
+*** igraph<T>
+
+FIXME: ...
+
+
+** image2d_without_border<T>
+
+*** level 1
+
+*** main features
+
+same type as image2d<T> but without border
+
+*** sample code
+
+image2d<char> ima = set(from(0,0), to(0,0));
+ima.at( 0, 0) = 'a'; // OK
+ima.at(-1, 0) = 'a': // error
+
+std::cout << ima.npoints() << std::endl;
+// 1
+std::cout << ima.n_memory_cells() << std::endl;
+// 1
+
+** level 2
+
+*** status
+
+to-do
+
+*** main features
+
+same as image2d<T> but without virtual border
+
+*** data storage
+
+relies on array2d<T>
+
+
+
+** one_value_image<S, T>
+
+*** level 1
+
+*** main features
+
+image defined by a point-set and a (single) value
+this image has the same value for all pixels
+
+*** sample code
+
+bbox2d bb = set(from(1,4), to(2,6));
+one_value_image<bbox2d, char> ima(bb, 'a');
+debug::print(ima);
+
+// 4 5 6
+// - - -
+// 1| a a a
+// 2| a a a
+
+ima.value() = 'b';
+debug::print(ima);
+
+// 4 5 6
+// - - -
+// 1| b b b
+// 2| b b b
+
+std::cout << ima.npoints() << std::endl;
+// 6
+
+std::cout << ima.n_memory_cells() << std::endl;
+// 1
+
+ima.change_value('b', 'c');
+// 4 5 6
+// - - -
+// 1| c c c
+// 2| c c c
+
+std::cout << ima.at(1, 5) << std::endl;
+// c
+
+ima.at(1, 5) = 'd'; // error
+
+
+*** level 2
+
+*** parameters
+
+S: point set type
+T: type of the value
+
+*** main features
+
+point-wise accessible but not mutable
+value-wise accessible and mutable
+
+*** data storage
+
+a single attribute: the unique value
+
+
+** image_p2v<S, F>
+
+*** parameters
+
+S: point set type
+F: function point-site -> value
+
+*** main features
+
+point-wise accessible but not mutable
+not value-wise accessible
+
+*** data storage
+
+combines the point set and the function to produce values
+on the fly
+
+
+** rle_image<P, T>
+
+*** parameter
+
+P: point type
+T: value type
+
+*** main features
+
+not point-wise accessible
+not value-wise accessible
+
+*** data storage
+
+std::vector of triplets (p_start, length, value)
+
+*** related type
+
+sparse_image<T>
+
+
+** sparse_image<P, T>
+
+*** parameter
+
+P: point type
+T: value type
+
+*** main features
+
+not point-wise accessible
+not value-wise accessible
+
+*** data storage
+
+std::vector of couples (p_start, std::vector<T>)
+
+*** related type
+
+rle_image<P, T>
+
+
+** image_vec<P, T>
+
+*** parameters
+
+P: point type
+T: value type
+
+*** main features
+
+not point-wise accessible
+not value-wise accessible
+
+*** data storage
+
+std::vector< std::pair<P, T> >
+
+
+** image_map<P, T>
+
+*** parameters
+
+P: point type
+T: value type
+
+*** main features
+
+not point-wise accessible
+not value-wise accessible
+
+*** data storage
+
+using std::map<P, T>
+
+*** related type
+
+slow::image_map<P, T>
+
+
+** slow::image_bbmap<P, T>
+
+*** parameters
+
+P: point type
+T: value type
+
+*** main features
+
+point-wise accessible and mutable
+not value-wise accessible
+bounding-boxed
+
+*** data storage
+
+some values are set in a std::map<P, T>
+when not set, a default value is provided by an attribute
+
+*** related type
+
+image_map<P, T>
+
+
+
+** Morpher types
+
+** FIXME
+
+do (really!) nothing when writing at p when outside the image domain
+error when reading at p when outside the image domain
+
+** FIXME
+
+add a default value when p is outside the image domain
+
+** sequence<I>
+
+FIXME: ...
+
+
+
+Local Variables:
+mode: outline
+ispell-local-dictionary: "american"
+End:
URL: https://svn.lrde.epita.fr/svn/oln/trunk/milena/sandbox
ChangeLog:
2008-09-02 Matthieu Garrigues <garrigues(a)lrde.epita.fr>
* geraud/fllt/fllt.svg.7.hh: Add comments to the working version of
FLLT.
---
fllt.svg.7.hh | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 85 insertions(+), 11 deletions(-)
Index: trunk/milena/sandbox/geraud/fllt/fllt.svg.7.hh
===================================================================
--- trunk/milena/sandbox/geraud/fllt/fllt.svg.7.hh (revision 2163)
+++ trunk/milena/sandbox/geraud/fllt/fllt.svg.7.hh (revision 2164)
@@ -331,9 +331,6 @@
++label;
- // if (holes.size() == 2)
- // std::cout << holes[0] << holes[1] << std::endl;
- // std::cout << " <<<<<<<exiting blob." << std::endl;
}
template <typename P, typename V>
@@ -393,7 +390,8 @@
}
}
- // LOWER LEVEL SET : region = c4, border = c8
+ // LOWER LEVEL SET information to compute the max tree.
+ // -> region = c4, border = c8
template <typename V>
struct lower
{
@@ -421,7 +419,8 @@
};
- // UPPER LEVEL SET : region = c8, border = c4
+ // UPPER LEVEL SET information to compute the max tree.
+ // -> region = c8, border = c4
template <typename V>
struct upper
{
@@ -445,6 +444,14 @@
static const neighb2d& reg_nbh() { return c8(); }
};
+ /*! Fast computation of a min/max tree.
+ *
+ * \param[in] input_ An input image.
+ * \param[out] smallest_shapes We stock in this image, for each point, a pointer
+ * to the smallest shape containing it.
+ * \return The min/max tree built.
+ *
+ */
template <typename I, typename Set>
fllt_tree(mln_point(I), mln_value(I))&
level_set(const Image<I>& input_,
@@ -560,7 +567,7 @@
deja_vu(x) = in_N;
}
}
- // gN = min u(x) for all x in N
+ // gN <- min u(x) for all x in N
update_gN(N, gN, Set());
// FIXME: update the number of CC of the border of R
@@ -609,7 +616,6 @@
// c)
else
{
- // FIXME: IDEA: this change might be performed while R is constructed(?)
n_step_4c++;
mln_piter(I) r(N_box);
for_all(r)
@@ -627,6 +633,15 @@
return *new tree_type(current_cc);
}
+ /*! Get the hole of a shape which contains a given point.
+ *
+ * \param[in] node a shape.
+ * \param[in] p a point.
+ * \param[in] other_reg The map which associate a point with its smallest shape
+ * of the oposite tree.
+ * \return true if A is included in B.
+ *
+ */
// F is the set in which we get the node.
template <typename P, typename V, typename F>
fllt_node(P, V)*
@@ -636,6 +651,7 @@
{
fllt_node(P, V)* s = other_reg(p);
mln_assertion(s);
+ // Go up the tree.
while (s->parent() && F::compare(s->parent()->elt().value, node.elt().value))
{
mln_assertion(s);
@@ -649,6 +665,14 @@
return s;
}
+ /*! Test the inclusion of two shapes of the same tree
+ *
+ * \param[in] A a shape.
+ * \param[in] B a shape.
+ * \return true if A is included in B.
+ *
+ * \pre The shapes have to come from the same tree.
+ */
template <typename P, typename V>
bool shape_is_included(fllt_node(P, V)* A,
fllt_node(P, V)* B)
@@ -656,6 +680,17 @@
return A->parent() == B || A == B;
}
+ /*! Associated the points of the holes of the min/max tree's shapes.
+ *
+ * \param[in] lower_tree The min tree.
+ * \param[in] upper_tree The max tree.
+ * \param[in] low_reg The map which associate a point with its smallest shape
+ * of the min tree.
+ * \param[in] upp_reg The map which associate a point with its smallest shape
+ * of the max tree.
+ * \return The merged tree.
+ *
+ */
template <typename P, typename V>
void find_all_holes(fllt_tree(P, V)& lower_tree,
fllt_tree(P, V)& upper_tree,
@@ -665,6 +700,7 @@
typedef p_array<P> arr_t;
typedef fllt_node(P, V) node_type;
+ // Get the holes of the min tree
{
fllt_branch_iter_ind(P, V) node_(lower_tree.main_branch());
for_all(node_)
@@ -676,6 +712,7 @@
}
}
+ // Get the holes of the max tree
{
fllt_branch_iter_ind(P, V) node_(upper_tree.main_branch());
for_all(node_)
@@ -688,6 +725,17 @@
}
}
+ /*! Merge the Min and the max tree.
+ *
+ * \param[in] lower_tree The min tree.
+ * \param[in] upper_tree The max tree.
+ * \param[in] low_reg The map which associate a point with its smallest shape
+ * of the min tree.
+ * \param[in] upp_reg The map which associate a point with its smallest shape
+ * of the max tree.
+ * \return The merged tree.
+ *
+ */
template <typename I>
fllt_tree(mln_point(I), mln_value(I))
merge_trees(fllt_tree(mln_point(I), mln_value(I))& lower_tree,
@@ -706,17 +754,24 @@
typedef p_array<P> arr_t;
+ // Here, a hole of a shape of the max or min tree is represented
+ // by a point belonging to this hole. We need to associate each of
+ // these points with its shape in the oposite tree.
find_all_holes(lower_tree, upper_tree, low_reg, upp_reg);
std::vector<node_type*> to_fill;
fllt_branch_iter_ind(P, V) node_(lower_tree.main_branch());
+ // Browse the shapes of the min_tree, in order to put as child of
+ // min tree's shapes the shapes of the max tree corresponding to
+ // their holes.
for_all(node_)
{
node_type& node = *node_;
+ // If the node was not in the min tree at the begining, we ignore it.
if (node.elt().set_id != lower<V>::id)
continue;
- // std::cout << "Fill " << &node << std::endl;
+ // Browse the holes of the shape.
typename std::vector<fllt_node(P, V)*>::iterator hole_;
for (hole_ = node.elt().hole_shapes.begin();
hole_ != node.elt().hole_shapes.end();
@@ -724,6 +779,7 @@
{
fllt_node(P, V)* hole = *hole_;
+ // Check if hole_ is contained by a hole of the children of node.
bool child_has_bigger_hole = false;
typename fllt_node(P, V)::children_t::iterator it;
for (it = node.children().begin(); it != node.children().end() && !child_has_bigger_hole; it++)
@@ -735,8 +791,6 @@
child_hole_++)
{
fllt_node(P, V)* child_hole = *child_hole_;
- // std::cout << "hole : " << hole << " " << hole->elt().points << " " << std::endl;
- // std::cout << "child hole : " << child_hole << " " << child_hole->elt().points << std::endl;
if (shape_is_included(hole, child_hole))
{
child_has_bigger_hole = true;
@@ -744,6 +798,9 @@
}
} // end of browsing child's holes.
} // end of browsing childs.
+
+ // If no, move the shape of the max tree previously associated to this hole.
+ // as child of node.
if (!child_has_bigger_hole)
{
// // std::cout << "move " << hole << " as child of " << &node << std::endl;
@@ -754,6 +811,12 @@
node.elt().holes.clear();
} // end of browsing lower_tree.
+ // At this step, we have filled all the holes of the min
+ // tree. But, by filling these holes, we introduced somes holes of
+ // the max tree in the result tree. We need to fill them.
+
+ // Thus, we browse the shapes of the max tree previously merged in
+ // the min tree, in order to check their holes.
for(typename std::vector<node_type*>::iterator node_ = to_fill.begin();
node_ != to_fill.end();
node_++)
@@ -767,6 +830,7 @@
if (node.elt().set_id != upper<V>::id)
continue;
+ // Check if hole_ is contained by a hole of the children of node.
typename std::vector<fllt_node(P, V)*>::iterator hole_;
for (hole_ = node.elt().hole_shapes.begin();
hole_ != node.elt().hole_shapes.end();
@@ -785,7 +849,6 @@
child_hole_++)
{
fllt_node(P, V)* child_hole = *child_hole_;
- //if (hole->elt().points <= child_hole->elt().points)
if (shape_is_included(hole, child_hole))
{
child_has_bigger_hole = true;
@@ -794,6 +857,8 @@
} // end of browsing child's holes.
} // end of browsing childs.
+ // If no, move the shape of the max tree previously associated to this hole.
+ // as child of node.
if (!child_has_bigger_hole)
node.add_child(hole);
@@ -806,6 +871,12 @@
return lower_tree;
}
+ /*! This function compute the fllt tree of an image.
+ *
+ * \param[in] input_ An input image.
+ * \return The computed tree.
+ *
+ */
template <typename I>
fllt_tree(mln_point(I), mln_value(I))
fllt(const Image<I>& input_)
@@ -820,12 +891,15 @@
image2d<fllt_node(P, V)*> low_reg(input.domain());
image2d<fllt_node(P, V)*> upp_reg(input.domain());
+ // Compute the Min tree.
std::cout << "1/ Compute the lower level set.----------------------------------------" << std::endl;
lower_tree = level_set<I, lower<V> >(input, low_reg);
+ // Compute the Max tree.
std::cout << "2/ Compute the upper level set.----------------------------------------" << std::endl;
upper_tree = level_set<I, upper<V> >(input, upp_reg);
+ // Merge the two trees.
std::cout << "3/ Merge.---------------------------------------------------------------" << std::endl;
fllt_tree(P, V) result_tree = merge_trees(lower_tree, upper_tree, low_reg, upp_reg, input);
https://svn.lrde.epita.fr/svn/oln/branches/cleanup-2008/milena
Index: ChangeLog
from Thierry Geraud <thierry.geraud(a)lrde.epita.fr>
Add image domain extension morphers plus the flat image.
Add image domain extension morphers.
* mln/core/image/extension_ima.hh: New.
* mln/trait/ch_value.hh (ch_value_): New overload to deal with
extension_ima.
* mln/core/image/extension_fun.hh: New.
* mln/core/image/extension_val.hh: New.
* mln/core/routine: New directory.
* mln/core/routine/all.hh: New.
* mln/core/routine/extend.hh: New.
* doc/tutorial/examples/image_if.cc: Augment to test extensions.
Add the flat image type.
* mln/core/image/flat_image.hh: New.
* doc/tutorial/examples/image_flat.cc: New.
* mln/core/image/status.txt: Update.
Enforce consistency for iterator naming.
* mln/core/macros.hh
(mln_iter, mln_fwd_iter, mln_bkd_iter): Rename as...
(mln_eiter, mln_fwd_eiter, mln_bkd_eiter): ...these.
* mln/core/site_set/p_key.hh,
* mln/core/site_set/p_mutable_array_of.hh,
* mln/core/site_set/p_set_of.hh,
* mln/core/p_runs.hh,
* mln/util/set.hh,
* mln/util/array.hh: Update.
Misc.
* mln/core/image/instant.hh (file): Fix.
* sandbox/geraud/p_runs__with_dedicated_piter.hh (todo): Remove;
obsolete.
* mln/core/internal/morpher_lvalue.hh
(mln_morpher_lvalue): New macro.
* mln/core/internal/image_identity.hh: Use the new macro.
* mln/core/safe.hh: Likewise.
doc/tutorial/examples/image_flat.cc | 12 +
doc/tutorial/examples/image_if.cc | 59 ++++-
mln/core/image/extension_fun.hh | 222 ++++++++++++++++++++
mln/core/image/extension_ima.hh | 254 +++++++++++++++++++++++
mln/core/image/extension_val.hh | 240 +++++++++++++++++++++
mln/core/image/flat_image.hh | 273 +++++++++++++++++++++++++
mln/core/image/instant.hh | 2
mln/core/image/status.txt | 4
mln/core/internal/image_identity.hh | 2
mln/core/internal/morpher_lvalue.hh | 4
mln/core/macros.hh | 26 +-
mln/core/p_runs.hh | 4
mln/core/routine/all.hh | 45 ++++
mln/core/routine/extend.hh | 157 ++++++++++++++
mln/core/safe.hh | 4
mln/core/site_set/p_key.hh | 8
mln/core/site_set/p_mutable_array_of.hh | 4
mln/core/site_set/p_set_of.hh | 4
mln/trait/ch_value.hh | 7
mln/util/array.hh | 6
mln/util/set.hh | 6
sandbox/geraud/p_runs__with_dedicated_piter.hh | 4
22 files changed, 1305 insertions(+), 42 deletions(-)
Index: doc/tutorial/examples/image_if.cc
--- doc/tutorial/examples/image_if.cc (revision 2159)
+++ doc/tutorial/examples/image_if.cc (working copy)
@@ -1,10 +1,16 @@
# include <mln/core/image2d.hh>
+# include <mln/core/neighb2d.hh>
# include <mln/core/image_if.hh>
# include <mln/debug/iota.hh>
# include <mln/debug/println.hh>
# include <mln/fun/p2b/chess.hh>
+# include <mln/border/fill.hh>
+# include <mln/core/var.hh>
+# include <mln/core/routine/extend.hh>
+# include <mln/pw/all.hh>
+
template <typename It, typename S>
void ch_target(It it, const S& s)
@@ -13,21 +19,64 @@
}
+template <typename I, typename N>
+void browse(const I& ima, const N& nbh)
+{
+ // Relies on "ima.has(p)".
+ mln_fwd_piter(I) p(ima.domain());
+ mln_fwd_niter(N) n(nbh, p);
+ for_all(p)
+ {
+ std::cout << ima(p) << ": ";
+ for_all(n)
+ if (ima.has(n))
+ std::cout << ima(n) << ' ';
+ std::cout << std::endl;
+ }
+}
+
+template <typename I, typename N>
+void browse_domain(const I& ima, const N& nbh)
+{
+ // Relies on "ima.domain().has(p)".
+ mln_fwd_piter(I) p(ima.domain());
+ mln_fwd_niter(N) n(nbh, p);
+ for_all(p)
+ {
+ std::cout << ima(p) << ": ";
+ for_all(n)
+ if (ima.domain().has(n))
+ std::cout << ima(n) << ' ';
+ std::cout << std::endl;
+ }
+}
+
+
+
+
int main()
{
using namespace mln;
typedef image2d<unsigned> I;
- I ima(3, 5);
+ I ima(3, 3, 1);
+ // FIXME: border::fill(ima, 0);
debug::iota(ima);
+ mln_VAR(ima_, ima | fun::p2b::chess);
+
debug::println(ima);
- debug::println(ima | fun::p2b::chess);
+ debug::println(ima_);
- trait::image::print(ima | fun::p2b::chess);
+ trait::image::print(ima_);
+ std::cout << std::endl;
typedef pset_if<box2d, fun::p2b::chess_t> S;
+ ch_target(mln_fwd_piter_(S)(), ima_.domain());
- ch_target(mln_fwd_piter_(S)(),
- (ima | fun::p2b::chess).domain());
+ // mln_VAR(ima_e, extend(ima_, pw::value(ima)));
+ // mln_VAR(ima_e, extend(ima_, 0));
+ mln_VAR(ima_e, extend(ima_, ima));
+ debug::println(ima_e);
+ browse(ima_e, c4());
}
Index: doc/tutorial/examples/image_flat.cc
--- doc/tutorial/examples/image_flat.cc (revision 0)
+++ doc/tutorial/examples/image_flat.cc (revision 0)
@@ -0,0 +1,12 @@
+# include <mln/core/image2d.hh>
+# include <mln/core/image/flat_image.hh>
+# include <mln/debug/println.hh>
+
+
+int main()
+{
+ using namespace mln;
+
+ flat_image<unsigned, box2d> ima(3, box2d(3,3));
+ debug::println(ima);
+}
Index: mln/trait/ch_value.hh
--- mln/trait/ch_value.hh (revision 2159)
+++ mln/trait/ch_value.hh (working copy)
@@ -98,6 +98,13 @@
typedef M< P, V > ret;
};
+ template < template <class, class> class M, typename I1, typename I2,
+ typename V >
+ struct ch_value_< M< tag::image_<I1>, tag::image_<I2> >, V >
+ {
+ typedef M< mln_ch_value(I1, V), mln_ch_value(I2, V) > ret;
+ };
+
// For mln::value::stack_image<n,I>.
template < template <unsigned, class> class M, unsigned n, typename I,
typename V >
Index: mln/core/macros.hh
--- mln/core/macros.hh (revision 2159)
+++ mln/core/macros.hh (working copy)
@@ -49,10 +49,11 @@
// b
-/// Shortcuts to access the bkd_iter type associated to T.
+/// Shortcuts to access the element-backward-iterator type associated
+/// to T.
/// \{
-# define mln_bkd_iter(T) typename T::bkd_iter
-# define mln_bkd_iter_(T) T::bkd_iter
+# define mln_bkd_eiter(T) typename T::bkd_eiter
+# define mln_bkd_eiter_(T) T::bkd_eiter
/// \}
/// Shortcuts to access the bkd_niter type associated to T.
@@ -118,6 +119,12 @@
// e
+/// Shortcuts to access the element-iterator type associated to T.
+/// \{
+# define mln_eiter(T) typename T::eiter
+# define mln_eiter_(T) T::eiter
+/// \}
+
/// Shortcuts to access the element type associated to T.
/// \{
# define mln_element(T) typename T::element
@@ -139,10 +146,11 @@
// f
-/// Shortcuts to access the fwd_iter type associated to T.
+/// Shortcuts to access the element-forward-iterator type associated
+/// to T.
/// \{
-# define mln_fwd_iter(T) typename T::fwd_iter
-# define mln_fwd_iter_(T) T::fwd_iter
+# define mln_fwd_eiter(T) typename T::fwd_eiter
+# define mln_fwd_eiter_(T) T::fwd_eiter
/// \}
/// Shortcuts to access the fwd_niter type associated to T.
@@ -199,12 +207,6 @@
# define mln_invert_(T) T::invert
/// \}
-/// Shortcuts to access the iterator type associated to T.
-/// \{
-# define mln_iter(T) typename T::iter
-# define mln_iter_(T) T::iter
-/// \}
-
// l
Index: mln/core/internal/morpher_lvalue.hh
--- mln/core/internal/morpher_lvalue.hh (revision 2159)
+++ mln/core/internal/morpher_lvalue.hh (working copy)
@@ -36,6 +36,10 @@
# include <mln/core/macros.hh>
+# define mln_morpher_lvalue(I) typename internal::morpher_lvalue_<I>::ret
+
+
+
namespace mln
{
Index: mln/core/internal/image_identity.hh
--- mln/core/internal/image_identity.hh (revision 2159)
+++ mln/core/internal/image_identity.hh (working copy)
@@ -143,7 +143,7 @@
typedef mln_rvalue(I) rvalue;
/// Return type of read-write access.
- typedef typename internal::morpher_lvalue_<I>::ret lvalue;
+ typedef mln_morpher_lvalue(I) lvalue;
/// Give the set of values.
Index: mln/core/image/extension_ima.hh
--- mln/core/image/extension_ima.hh (revision 0)
+++ mln/core/image/extension_ima.hh (revision 0)
@@ -0,0 +1,254 @@
+// Copyright (C) 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 MLN_CORE_IMAGE_EXTENSION_IMA_HH
+# define MLN_CORE_IMAGE_EXTENSION_IMA_HH
+
+/*!
+ * \file mln/core/image/extension_ima.hh
+ *
+ * \brief Definition of a morpher that extends the domain of an image
+ * with a function.
+ *
+ * \todo Use the 'instant' mechanism.
+ */
+
+# include <mln/core/internal/image_identity.hh>
+# include <mln/metal/converts_to.hh>
+
+
+
+namespace mln
+{
+
+ // Forward declaration.
+ template <typename I, typename J> struct extension_ima;
+
+
+ namespace internal
+ {
+
+ /// \internal Data structure for \c mln::extension_ima<I, J>.
+ template <typename I, typename J>
+ struct data< extension_ima<I, J> >
+ {
+ data(I& ima, J& ext);
+
+ I ima_;
+ J ext_;
+ };
+
+ } // end of namespace mln::internal
+
+
+ namespace trait
+ {
+
+ template <typename I, typename J>
+ struct image_< extension_ima<I, J> > : image_< I > // Same as I except...
+ {
+ // ...these changes.
+ typedef trait::image::category::identity_morpher category;
+ typedef mln_internal_trait_image_speed_from(I) speed; // Un-fastest.
+
+ // extended domain
+ typedef trait::image::ext_domain::extendable ext_domain;
+ typedef trait::image::ext_value::multiple ext_value;
+ typedef mln_trait_image_value_io(J) ext_io;
+ };
+
+ } // end of namespace mln::trait
+
+
+
+ // FIXME: Doc!
+
+ template <typename I, typename J>
+ class extension_ima
+
+ : public internal::image_identity< I, mln_pset(I), extension_ima<I, J> >,
+ private mlc_converts_to(mln_value(J), mln_value(I))::check_t
+ {
+ public:
+
+ /// Skeleton.
+ typedef extension_ima< tag::image_<I>, tag::image_<J> > skeleton;
+ // FIXME: OK when ch_value?
+
+
+ /// Return type of read-only access.
+ typedef mln_value(I) rvalue;
+
+
+ /// Constructor without argument.
+ extension_ima();
+
+ /// Constructor from an image \p ima and a function \p ext.
+ extension_ima(I& ima, J& ext);
+
+ /// Deferred initialization from an image \p ima and a function \p
+ /// ext.
+ void init(I& ima, J& ext);
+
+
+ /// Test if \p p is valid.
+ // Tech note: the 'template' allows for multiple input.
+ template <typename P>
+ bool has(const P& p) const;
+
+
+ /// Read-only access to the image value located at site \p p;
+ mln_value(I) operator()(const mln_psite(I)& p) const;
+
+ /// Read-write access to the image value located at site \p p.
+ mln_morpher_lvalue(I) operator()(const mln_psite(I)& p);
+
+
+ /// Read-only access to the extension domain (image).
+ mlc_const(J)& extension() const;
+
+ /// Mutable access to the extension domain (image). This domain
+ /// can be modified if J a read-write image type.
+ J& extension();
+ };
+
+
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+ // internal::data< extension_ima<I,S> >
+
+ namespace internal
+ {
+
+ template <typename I, typename J>
+ inline
+ data< extension_ima<I, J> >::data(I& ima, J& ext)
+ : ima_(ima),
+ ext_(ext)
+ {
+ }
+
+ } // end of namespace mln::internal
+
+ // extension_ima<I, J>
+
+ template <typename I, typename J>
+ inline
+ extension_ima<I, J>::extension_ima()
+ {
+ }
+
+ template <typename I, typename J>
+ inline
+ extension_ima<I, J>::extension_ima(I& ima, J& ext)
+ {
+ init(ima, ext);
+ }
+
+ template <typename I, typename J>
+ inline
+ void
+ extension_ima<I, J>::init(I& ima, J& ext)
+ {
+ this->data_ = new internal::data< extension_ima<I, J> >(ima, ext);
+ }
+
+ template <typename I, typename J>
+ template <typename P>
+ inline
+ bool
+ extension_ima<I, J>::has(const P& p) const
+ {
+ mln_precondition(this->has_data());
+ mln_precondition(this->data_->ext_.has_data());
+ return
+ this->data_->ima_.domain().has(p)
+ || this->data_->ext_.has(p);
+ }
+
+ template <typename I, typename J>
+ inline
+ mln_value(I)
+ extension_ima<I, J>::operator()(const mln_psite(I)& p) const
+ {
+ mln_precondition(this->has_data());
+ mln_precondition(has(p));
+ // if-else is preferred to the ternary op to allow for the
+ // function result to convert towards the expected return type.
+ if (this->data_->ima_.domain().has(p))
+ return this->data_->ima_(p);
+ else
+ return this->data_->ext_(p);
+ }
+
+ template <typename I, typename J>
+ inline
+ mln_morpher_lvalue(I)
+ extension_ima<I, J>::operator()(const mln_psite(I)& p)
+ {
+ static mln_value(I) cpy;
+ mln_precondition(this->has_data());
+ mln_precondition(has(p));
+ // See the above comment about if-else v. ternary.
+ if (this->data_->ima_.domain().has(p))
+ return this->data_->ima_(p);
+ else
+ {
+ // This hack makes this signature valid both in the image
+ // domain and in its extension. It works even if
+ // mln_morpher_lvalue(I) is a mutable reference.
+ cpy = this->data_->ext_(p);
+ return cpy;
+ }
+ }
+
+ template <typename I, typename J>
+ inline
+ mlc_const(J)&
+ extension_ima<I, J>::extension() const
+ {
+ mln_precondition(this->has_data());
+ return this->data_->ext_;
+ }
+
+ template <typename I, typename J>
+ inline
+ J&
+ extension_ima<I, J>::extension()
+ {
+ mln_precondition(this->has_data());
+ return this->data_->ext_;
+ }
+
+# endif // ! MLN_INCLUDE_ONLY
+
+} // end of namespace mln
+
+
+#endif // ! MLN_CORE_IMAGE_EXTENSION_IMA_HH
Index: mln/core/image/status.txt
--- mln/core/image/status.txt (revision 2159)
+++ mln/core/image/status.txt (working copy)
@@ -57,6 +57,10 @@
** identity morpher
new instant
+new extension_ima
+new extension_fun
+new extension_val
+
ok plain
ok safe
Index: mln/core/image/extension_fun.hh
--- mln/core/image/extension_fun.hh (revision 0)
+++ mln/core/image/extension_fun.hh (revision 0)
@@ -0,0 +1,222 @@
+// Copyright (C) 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 MLN_CORE_IMAGE_EXTENSION_FUN_HH
+# define MLN_CORE_IMAGE_EXTENSION_FUN_HH
+
+/*!
+ * \file mln/core/image/extension_fun.hh
+ *
+ * \brief Definition of a morpher that extends the domain of an image
+ * with a function.
+ *
+ * \todo Deal with two-ways functions...
+ */
+
+# include <mln/core/internal/image_identity.hh>
+# include <mln/metal/converts_to.hh>
+
+
+
+namespace mln
+{
+
+ // Forward declaration.
+ template <typename I, typename F> struct extension_fun;
+
+
+ namespace internal
+ {
+
+ /// \internal Data structure for \c mln::extension_fun<I, F>.
+ template <typename I, typename F>
+ struct data< extension_fun<I, F> >
+ {
+ data(I& ima, const F& fun);
+
+ I ima_;
+ const F fun_;
+ };
+
+ } // end of namespace mln::internal
+
+
+ namespace trait
+ {
+
+ template <typename I, typename F>
+ struct image_< extension_fun<I, F> > : image_< I > // Same as I except...
+ {
+ // ...these changes.
+ typedef trait::image::category::identity_morpher category;
+ typedef mln_internal_trait_image_speed_from(I) speed; // Un-fastest.
+
+ // extended domain
+ typedef trait::image::ext_domain::infinite ext_domain;
+ typedef trait::image::ext_value::multiple ext_value;
+ typedef trait::image::ext_io::read_only ext_io;
+ };
+
+ } // end of namespace mln::trait
+
+
+
+ // FIXME: Doc!
+
+ template <typename I, typename F>
+ class extension_fun
+
+ : public internal::image_identity< I, mln_pset(I), extension_fun<I, F> >,
+ private mlc_converts_to(mln_result(F), mln_value(I))::check_t
+ {
+ public:
+
+ /// Skeleton.
+ typedef extension_fun< tag::image_<I>, tag::function_<F> > skeleton;
+ // FIXME: OK when ch_value?
+
+
+ /// Return type of read-only access.
+ typedef mln_value(I) rvalue;
+
+
+ /// Constructor without argument.
+ extension_fun();
+
+ /// Constructor from an image \p ima and a function \p fun.
+ extension_fun(I& ima, const F& fun);
+
+ /// Deferred initialization from an image \p ima and a function \p
+ /// fun.
+ void init(I& ima, const F& fun);
+
+
+ /// Test if \p p is valid. It returns always true.
+ // Tech note: the 'template' allows for multiple input.
+ template <typename P>
+ bool has(const P& p) const;
+
+
+ /// Read-only access to the image value located at site \p p;
+ mln_value(I) operator()(const mln_psite(I)& p) const;
+
+ /// Read-write access to the image value located at site \p p.
+ mln_morpher_lvalue(I) operator()(const mln_psite(I)& p);
+ };
+
+
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+ // internal::data< extension_fun<I,S> >
+
+ namespace internal
+ {
+
+ template <typename I, typename F>
+ inline
+ data< extension_fun<I, F> >::data(I& ima, const F& fun)
+ : ima_(ima),
+ fun_(fun)
+ {
+ }
+
+ } // end of namespace mln::internal
+
+ // extension_fun<I, F>
+
+ template <typename I, typename F>
+ inline
+ extension_fun<I, F>::extension_fun()
+ {
+ }
+
+ template <typename I, typename F>
+ inline
+ extension_fun<I, F>::extension_fun(I& ima, const F& fun)
+ {
+ init(ima, fun);
+ }
+
+ template <typename I, typename F>
+ inline
+ void
+ extension_fun<I, F>::init(I& ima, const F& fun)
+ {
+ this->data_ = new internal::data< extension_fun<I, F> >(ima, fun);
+ }
+
+ template <typename I, typename F>
+ template <typename P>
+ inline
+ bool
+ extension_fun<I, F>::has(const P&) const
+ {
+ return true;
+ }
+
+ template <typename I, typename F>
+ inline
+ mln_value(I)
+ extension_fun<I, F>::operator()(const mln_psite(I)& p) const
+ {
+ mln_precondition(this->has_data());
+ // if-else is preferred to the ternary op to allow for the
+ // function result to convert towards the expected return type.
+ if (this->data_->ima_.domain().has(p))
+ return this->data_->ima_(p);
+ else
+ return this->data_->fun_(p);
+ }
+
+ template <typename I, typename F>
+ inline
+ mln_morpher_lvalue(I)
+ extension_fun<I, F>::operator()(const mln_psite(I)& p)
+ {
+ static mln_value(I) cpy;
+ mln_precondition(this->has_data());
+ // See the above comment about if-else v. ternary.
+ if (this->data_->ima_.domain().has(p))
+ return this->data_->ima_(p);
+ else
+ {
+ // This hack makes this signature valid both in the image
+ // domain and in its extension. It works even if
+ // mln_morpher_lvalue(I) is a mutable reference.
+ cpy = this->data_->fun_(p);
+ return cpy;
+ }
+ }
+
+# endif // ! MLN_INCLUDE_ONLY
+
+} // end of namespace mln
+
+
+#endif // ! MLN_CORE_IMAGE_EXTENSION_FUN_HH
Index: mln/core/image/flat_image.hh
--- mln/core/image/flat_image.hh (revision 0)
+++ mln/core/image/flat_image.hh (revision 0)
@@ -0,0 +1,273 @@
+// Copyright (C) 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 MLN_CORE_FLAT_IMAGE_HH
+# define MLN_CORE_FLAT_IMAGE_HH
+
+/*!
+ * \file mln/core/flat_image.hh
+ *
+ * \brief Definition of a image with a signle value.
+ *
+ * \todo Zed: Address the values v. destination issue.
+ */
+
+# include <mln/core/internal/image_primary.hh>
+
+
+namespace mln
+{
+
+
+ // Forward declaration.
+ template <typename T, typename S> class flat_image;
+
+
+ namespace internal
+ {
+
+ /// \internal Data structure for \c mln::flat_image<T,S>.
+ template <typename T, typename S>
+ struct data< flat_image<T,S> >
+ {
+ data(const T& val, const S& pset);
+
+ T val_;
+ S pset_;
+ };
+
+ } // end of namespace mln::internal
+
+
+
+ namespace trait
+ {
+
+ template <typename T, typename S>
+ struct image_< flat_image<T,S> > : default_image_< T, flat_image<T,S> >
+ {
+ // misc
+ typedef trait::image::category::primary category;
+ typedef trait::image::speed::fast speed;
+ typedef trait::image::size::regular size;
+
+ // value
+ typedef trait::image::value_access::direct value_access;
+ typedef trait::image::value_storage::one_block value_storage;
+ typedef trait::image::value_browsing::site_wise_only value_browsing;
+ typedef trait::image::value_io::read_only value_io;
+
+ // site / domain
+ typedef trait::image::localization::basic_grid localization; // FIXME
+ typedef trait::image::dimension::two_d dimension; // FIXME
+
+ // extended domain
+ typedef trait::image::ext_domain::infinite ext_domain;
+ typedef trait::image::ext_value::single ext_value;
+ typedef trait::image::ext_io::read_only ext_io;
+ };
+
+ } // end of namespace mln::trait
+
+
+
+ // FIXME: Doc!
+
+ template <typename T, typename S>
+ struct flat_image : public internal::image_primary< S, flat_image<T,S> >
+ {
+ /// Skeleton.
+ typedef flat_image< tag::value_<T>, tag::pset_<S> > skeleton;
+
+
+ /// Value associated type.
+ typedef T value;
+
+ /// Return type of read-only access.
+ typedef const T& rvalue;
+
+ /// Return type of read-write access.
+ typedef const T& lvalue;
+
+
+ /// Constructor without argument.
+ flat_image();
+
+ /// Constructor.
+ flat_image(const T& val, const S& pset);
+
+ /// Initialization.
+ void init_(const T& val, const S& pset);
+
+ /// Give the definition domain.
+ const S& domain() const;
+
+ /// Test if \p p is valid: always return true.
+ bool has(const mln_psite(S)& p) const;
+
+
+ /// Read-only access to the image value located at point \p p.
+ const T& operator()(const mln_psite(S)& p) const;
+
+ /// Read-write access to the image value located at point \p p.
+ const T& operator()(const mln_psite(S)& p);
+
+
+ // FIXME: Weird...
+
+ /// Value_Set associated type.
+ typedef mln::value::set<T> vset;
+
+ /// Give the set of values of the image.
+ const mln::value::set<T>& values() const;
+
+ // end of FIXME
+
+
+ /// Change the image value.
+ void change_value(const T& val);
+ };
+
+
+
+ template <typename T, typename S, typename J>
+ void init_(tag::image_t, flat_image<T,S>& target, const J& model);
+
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+ // init_
+
+ template <typename T, typename S, typename J>
+ inline
+ void init_(tag::image_t, flat_image<T,S>& target, const J& model)
+ {
+ S pset;
+ init_(tag::domain, pset, model);
+ T dummy;
+ target.init_(dummy, pset);
+ }
+
+
+ // internal::data< flat_image<T,S> >
+
+ namespace internal
+ {
+
+ template <typename T, typename S>
+ inline
+ data< flat_image<T,S> >::data(const T& val, const S& pset)
+ : val_(val),
+ pset_(pset)
+ {
+ }
+
+ } // end of namespace mln::internal
+
+
+ // flat_image<T,S>
+
+ template <typename T, typename S>
+ inline
+ flat_image<T,S>::flat_image()
+ {
+ }
+
+ template <typename T, typename S>
+ inline
+ flat_image<T,S>::flat_image(const T& val, const S& pset)
+ {
+ init_(val, pset);
+ }
+
+ template <typename T, typename S>
+ inline
+ void
+ flat_image<T,S>::init_(const T& val, const S& pset)
+ {
+ mln_precondition(! this->has_data());
+ this->data_ = new internal::data< flat_image<T,S> >(val, pset);
+ }
+
+ template <typename T, typename S>
+ inline
+ const S&
+ flat_image<T,S>::domain() const
+ {
+ return this->data_->pset_;
+ }
+
+ template <typename T, typename S>
+ inline
+ bool
+ flat_image<T,S>::has(const mln_psite(S)&) const
+ {
+ return true;
+ }
+
+ template <typename T, typename S>
+ inline
+ const T&
+ flat_image<T,S>::operator()(const mln_psite(S)& p) const
+ {
+ mln_precondition(this->has_data());
+ return this->data_->val_;
+ }
+
+ template <typename T, typename S>
+ inline
+ const T&
+ flat_image<T,S>::operator()(const mln_psite(S)& p)
+ {
+ mln_precondition(this->has_data());
+ return this->data_->val_;
+ }
+
+ template <typename T, typename S>
+ inline
+ const mln::value::set<T>&
+ flat_image<T,S>::values() const
+ {
+ return vset::the();
+ }
+
+ template <typename T, typename S>
+ inline
+ void
+ flat_image<T,S>::change_value(const T& val)
+ {
+ mln_precondition(this->has_data());
+ this->data_->val_ = val;
+ }
+
+# endif // ! MLN_INCLUDE_ONLY
+
+} // end of namespace mln
+
+
+#endif // ! MLN_CORE_FLAT_IMAGE_HH
Index: mln/core/image/extension_val.hh
--- mln/core/image/extension_val.hh (revision 0)
+++ mln/core/image/extension_val.hh (revision 0)
@@ -0,0 +1,240 @@
+// Copyright (C) 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 MLN_CORE_IMAGE_EXTENSION_VAL_HH
+# define MLN_CORE_IMAGE_EXTENSION_VAL_HH
+
+/*!
+ * \file mln/core/image/extension_val.hh
+ *
+ * \brief Definition of a morpher that extends the domain of an image.
+ *
+ * \todo Use the 'instant' mechanism.
+ */
+
+# include <mln/core/internal/image_identity.hh>
+# include <mln/metal/converts_to.hh>
+
+
+
+namespace mln
+{
+
+ // Forward declaration.
+ template <typename I> struct extension_val;
+
+
+ namespace internal
+ {
+
+ /// \internal Data structure for \c mln::extension_val<I>.
+ template <typename I>
+ struct data< extension_val<I> >
+ {
+ data(I& ima, const mln_value(I)& val_);
+
+ I ima_;
+ mln_value(I) val_;
+ };
+
+ } // end of namespace mln::internal
+
+
+ namespace trait
+ {
+
+ template <typename I>
+ struct image_< extension_val<I> > : image_< I > // Same as I except...
+ {
+ // ...these changes.
+ typedef trait::image::category::identity_morpher category;
+ typedef mln_internal_trait_image_speed_from(I) speed; // Un-fastest.
+
+ // extended domain
+ typedef trait::image::ext_domain::infinite ext_domain;
+ typedef trait::image::ext_value::single ext_value;
+ typedef trait::image::ext_io::read_write ext_io;
+ };
+
+ } // end of namespace mln::trait
+
+
+
+ // FIXME: Doc!
+
+ template <typename I>
+ class extension_val : public internal::image_identity< I, mln_pset(I), extension_val<I> >
+ {
+ public:
+
+ /// Skeleton.
+ typedef extension_val< tag::image_<I> > skeleton;
+ // FIXME: OK when ch_value?
+
+
+ /// Return type of read-only access.
+ typedef mln_value(I) rvalue;
+
+
+ /// Constructor without argument.
+ extension_val();
+
+ /// Constructor from an image \p ima and a value \p val.
+ extension_val(I& ima, const mln_value(I)& val);
+
+ /// Deferred initialization from an image \p ima and a value \p
+ /// val.
+ void init(I& ima, const mln_value(I)& val);
+
+
+ /// Test if \p p is valid. It returns always true.
+ // Tech note: the 'template' allows for multiple input.
+ template <typename P>
+ bool has(const P& p) const;
+
+
+ /// Read-only access to the image value located at site \p p;
+ mln_value(I) operator()(const mln_psite(I)& p) const;
+
+ /// Read-write access to the image value located at site \p p.
+ mln_morpher_lvalue(I) operator()(const mln_psite(I)& p);
+
+
+ /// Read-only access to the value of the extension domain.
+ const mln_value(I)& extension_value() const;
+
+ /// Change the value of the extension domain.
+ void change_extension_value(const mln_value(I)& val);
+ };
+
+
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+ // internal::data< extension_val<I,S> >
+
+ namespace internal
+ {
+
+ template <typename I>
+ inline
+ data< extension_val<I> >::data(I& ima, const mln_value(I)& val)
+ : ima_(ima),
+ val_(val)
+ {
+ }
+
+ } // end of namespace mln::internal
+
+ // extension_val<I>
+
+ template <typename I>
+ inline
+ extension_val<I>::extension_val()
+ {
+ }
+
+ template <typename I>
+ inline
+ extension_val<I>::extension_val(I& ima, const mln_value(I)& val)
+ {
+ init(ima, val);
+ }
+
+ template <typename I>
+ inline
+ void
+ extension_val<I>::init(I& ima, const mln_value(I)& val)
+ {
+ this->data_ = new internal::data< extension_val<I> >(ima, val);
+ }
+
+ template <typename I>
+ template <typename P>
+ inline
+ bool
+ extension_val<I>::has(const P&) const
+ {
+ return true;
+ }
+
+ template <typename I>
+ inline
+ mln_value(I)
+ extension_val<I>::operator()(const mln_psite(I)& p) const
+ {
+ mln_precondition(this->has_data());
+ // if-else is preferred to the ternary op to allow conversions.
+ if (this->data_->ima_.domain().has(p))
+ return this->data_->ima_(p);
+ else
+ return this->data_->val_;
+ }
+
+ template <typename I>
+ inline
+ mln_morpher_lvalue(I)
+ extension_val<I>::operator()(const mln_psite(I)& p)
+ {
+ static mln_value(I) cpy;
+ mln_precondition(this->has_data());
+ // See the above comment about if-else v. ternary.
+ if (this->data_->ima_.domain().has(p))
+ return this->data_->ima_(p);
+ else
+ {
+ // This hack makes the extension value non-modifiable.
+ cpy = this->data_->val_;
+ return cpy;
+ }
+ }
+
+ template <typename I>
+ inline
+ const mln_value(I)&
+ extension_val<I>::extension_value() const
+ {
+ mln_precondition(this->has_data());
+ return this->data_->val_;
+ }
+
+ template <typename I>
+ inline
+ void
+ extension_val<I>::change_extension_value(const mln_value(I)& val)
+ {
+ mln_precondition(this->has_data());
+ this->data_->val_ = val;
+ }
+
+# endif // ! MLN_INCLUDE_ONLY
+
+} // end of namespace mln
+
+
+#endif // ! MLN_CORE_IMAGE_EXTENSION_VAL_HH
Index: mln/core/image/instant.hh
--- mln/core/image/instant.hh (revision 2159)
+++ mln/core/image/instant.hh (working copy)
@@ -28,7 +28,7 @@
#ifndef MLN_CORE_IMAGE_INSTANT_HH
# define MLN_CORE_IMAGE_INSTANT_HH
-/*! \file mln/core/instant.hh
+/*! \file mln/core/image/instant.hh
*
* \brief Definition of a morpher that prevent an image from sharing
* his data.
Index: mln/core/site_set/p_key.hh
--- mln/core/site_set/p_key.hh (revision 2159)
+++ mln/core/site_set/p_key.hh (working copy)
@@ -88,12 +88,12 @@
/// Forward Site_Iterator associated type.
typedef p_double_piter<self_,
- mln_fwd_iter(util::set<K>),
+ mln_fwd_eiter(util::set<K>),
mln_fwd_piter(p_set<P>)> fwd_piter;
/// Backward Site_Iterator associated type.
typedef p_double_piter<self_,
- mln_bkd_iter(util::set<K>),
+ mln_bkd_eiter(util::set<K>),
mln_bkd_piter(p_set<P>)> bkd_piter;
/// Site_Iterator associated type.
@@ -439,7 +439,7 @@
// Update b_.
{
util::set<K> new_b;
- mln_iter(util::set<K>) k(b_);
+ mln_eiter(util::set<K>) k(b_);
for_all(k)
new_b.insert(lut[k] = f(k));
b_ = new_b;
@@ -570,7 +570,7 @@
}
unsigned n = 0;
- mln_iter(util::set<K>) key(b_);
+ mln_eiter(util::set<K>) key(b_);
for_all(key)
{
typename s_t::const_iterator k_s = s_.find(key);
Index: mln/core/site_set/p_mutable_array_of.hh
--- mln/core/site_set/p_mutable_array_of.hh (revision 2159)
+++ mln/core/site_set/p_mutable_array_of.hh (working copy)
@@ -91,12 +91,12 @@
/// Forward Site_Iterator associated type.
typedef p_double_piter<self_,
- mln_fwd_iter(array_),
+ mln_fwd_eiter(array_),
mln_fwd_piter(S)> fwd_piter;
/// Backward Site_Iterator associated type.
typedef p_double_piter<self_,
- mln_bkd_iter(array_),
+ mln_bkd_eiter(array_),
mln_bkd_piter(S)> bkd_piter;
/// Site_Iterator associated type.
Index: mln/core/site_set/p_set_of.hh
--- mln/core/site_set/p_set_of.hh (revision 2159)
+++ mln/core/site_set/p_set_of.hh (working copy)
@@ -88,12 +88,12 @@
/// Forward Site_Iterator associated type.
typedef p_double_piter<self_,
- mln_fwd_iter(set_),
+ mln_fwd_eiter(set_),
mln_fwd_piter(S)> fwd_piter;
/// Backward Site_Iterator associated type.
typedef p_double_piter<self_,
- mln_bkd_iter(set_),
+ mln_bkd_eiter(set_),
mln_bkd_piter(S)> bkd_piter;
/// Site_Iterator associated type.
Index: mln/core/safe.hh
--- mln/core/safe.hh (revision 2159)
+++ mln/core/safe.hh (working copy)
@@ -84,7 +84,6 @@
template <typename I>
class safe_image : public internal::image_identity< I, mln_pset(I), safe_image<I> >
{
- typedef internal::image_identity< I, mln_pset(I), safe_image<I> > super_;
public:
/// Skeleton.
@@ -96,8 +95,7 @@
mln_rvalue(I) operator()(const mln_psite(I)& p) const;
- typedef typename super_::lvalue lvalue;
- lvalue operator()(const mln_psite(I)& p);
+ mln_morpher_lvalue(I) operator()(const mln_psite(I)& p);
/// Const promotion via conversion.
operator safe_image<const I>() const;
Index: mln/core/routine/extend.hh
--- mln/core/routine/extend.hh (revision 0)
+++ mln/core/routine/extend.hh (revision 0)
@@ -0,0 +1,157 @@
+// Copyright (C) 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 MLN_CORE_ROUTINE_EXTEND_HH
+# define MLN_CORE_ROUTINE_EXTEND_HH
+
+/*!
+ * \file mln/core/routine/extend.hh
+ *
+ * \brief Definition of a morpher that extends the domain of an image.
+ *
+ * \todo Use the 'instant' mechanism.
+ * \todo Deal with ambiguities.
+ */
+
+# include <mln/core/image/extension_ima.hh>
+# include <mln/core/image/extension_fun.hh>
+# include <mln/core/image/extension_val.hh>
+
+
+
+namespace mln
+{
+
+
+ /// Routines for domain extension with a function.
+
+ template <typename I, typename F>
+ extension_fun<const I, F>
+ extend(const Image<I>& ima, const Function_v2v<F>& fun);
+
+ template <typename I, typename F>
+ extension_fun<I, F>
+ extend(Image<I>& ima, const Function_v2v<F>& fun);
+
+
+ /// Routines for domain extension with an image.
+
+ template <typename I, typename J>
+ extension_ima<const I, const J>
+ extend(const Image<I>& ima, const Image<J>& ext);
+
+ template <typename I, typename J>
+ extension_ima<I, J>
+ extend(Image<I>& ima, Image<J>& ext);
+
+
+ /// Routines for domain extension with a value.
+
+ template <typename I>
+ extension_val<const I>
+ extend(const Image<I>& ima, const mln_value(I)& val);
+
+ template <typename I>
+ extension_val<I>
+ extend(Image<I>& ima, const mln_value(I)& val);
+
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+
+ // With a function.
+
+ template <typename I, typename F>
+ inline
+ extension_fun<const I, F>
+ extend(const Image<I>& ima, const Function_v2v<F>& fun)
+ {
+ mlc_converts_to(mln_result(F), mln_value(I))::check();
+ extension_fun<const I, F> tmp(exact(ima), exact(fun));
+ return tmp;
+ }
+
+ template <typename I, typename F>
+ inline
+ extension_fun<I, F>
+ extend(Image<I>& ima, const Function_v2v<F>& fun)
+ {
+ mlc_converts_to(mln_result(F), mln_value(I))::check();
+ extension_fun<I, F> tmp(exact(ima), exact(fun));
+ return tmp;
+ }
+
+
+ // With an image.
+
+ template <typename I, typename J>
+ extension_ima<const I, const J>
+ extend(const Image<I>& ima, const Image<J>& ext)
+ {
+ mlc_converts_to(mln_value(J), mln_value(I))::check();
+ extension_ima<const I, const J> tmp(exact(ima), exact(ext));
+ return tmp;
+ }
+
+ template <typename I, typename J>
+ extension_ima<I, J>
+ extend(Image<I>& ima, Image<J>& ext)
+ {
+ mlc_converts_to(mln_value(J), mln_value(I))::check();
+ extension_ima<I, J> tmp(exact(ima), exact(ext));
+ return tmp;
+ }
+
+
+ // With a value.
+
+ template <typename I>
+ inline
+ extension_val<const I>
+ extend(const Image<I>& ima, const mln_value(I)& val)
+ {
+ extension_val<const I> tmp(exact(ima), val);
+ return tmp;
+ }
+
+ template <typename I>
+ inline
+ extension_val<I>
+ extend(Image<I>& ima, const mln_value(I)& val)
+ {
+ extension_val<I> tmp(exact(ima), val);
+ return tmp;
+ }
+
+
+# endif // ! MLN_INCLUDE_ONLY
+
+} // end of namespace mln
+
+
+#endif // ! MLN_CORE_ROUTINE_EXTEND_HH
Index: mln/core/routine/all.hh
--- mln/core/routine/all.hh (revision 0)
+++ mln/core/routine/all.hh (revision 0)
@@ -0,0 +1,45 @@
+// Copyright (C) 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 MLN_CORE_ROUTINE_ALL_HH
+# define MLN_CORE_ROUTINE_ALL_HH
+
+/*! \file mln/core/routine/all.hh
+ *
+ * \brief File that includes all core routines.
+ *
+ * \todo Move files, update, and activate.
+ */
+
+
+// # include <mln/core/routine/clone.hh>
+// # include <mln/core/routine/exact.hh>
+# include <mln/core/routine/extend.hh>
+// # include <mln/core/routine/initialize.hh>
+
+
+#endif // ! MLN_CORE_ROUTINE_ALL_HH
Index: mln/core/p_runs.hh
--- mln/core/p_runs.hh (revision 2159)
+++ mln/core/p_runs.hh (working copy)
@@ -99,12 +99,12 @@
/// Forward Site_Iterator associated type.
typedef p_double_piter<self_,
- mln_fwd_iter(set_),
+ mln_fwd_eiter(set_),
mln_fwd_piter(p_run<P>)> fwd_piter;
/// Backward Site_Iterator associated type.
typedef p_double_piter<self_,
- mln_bkd_iter(set_),
+ mln_bkd_eiter(set_),
mln_bkd_piter(p_run<P>)> bkd_piter;
/// Site_Iterator associated type.
Index: mln/util/set.hh
--- mln/util/set.hh (revision 2159)
+++ mln/util/set.hh (working copy)
@@ -89,13 +89,13 @@
/// Forward iterator associated type.
- typedef set_fwd_iter<T> fwd_iter;
+ typedef set_fwd_iter<T> fwd_eiter;
/// Backward iterator associated type.
- typedef set_bkd_iter<T> bkd_iter;
+ typedef set_bkd_iter<T> bkd_eiter;
/// Iterator associated type.
- typedef fwd_iter iter;
+ typedef fwd_eiter eiter;
/*! \brief Insert an element \p elt into the set.
Index: mln/util/array.hh
--- mln/util/array.hh (revision 2159)
+++ mln/util/array.hh (working copy)
@@ -74,13 +74,13 @@
/// Forward iterator associated type.
- typedef array_fwd_iter<T> fwd_iter;
+ typedef array_fwd_iter<T> fwd_eiter;
/// Backward iterator associated type.
- typedef array_bkd_iter<T> bkd_iter;
+ typedef array_bkd_iter<T> bkd_eiter;
/// Iterator associated type.
- typedef fwd_iter iter;
+ typedef fwd_eiter eiter;
/// Constructor without arguments.
Index: sandbox/geraud/p_runs__with_dedicated_piter.hh
--- sandbox/geraud/p_runs__with_dedicated_piter.hh (revision 2159)
+++ sandbox/geraud/p_runs__with_dedicated_piter.hh (working copy)
@@ -31,10 +31,6 @@
/*! \file mln/core/p_runs.hh
*
* \brief Definition of a set of point runs.
- *
- * \todo Zed: Use p_double* stuff.
- *
- * \todo Zed: Test for unicity (see FIXMEs).
*/
# include <mln/accu/bbox.hh>