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: