00001 // Copyright (C) 2001, 2007, 2008 EPITA Research and Development 00002 // Laboratory 00003 // 00004 // This file is part of the Milena Library. This library is free 00005 // software; you can redistribute it and/or modify it under the terms 00006 // of the GNU General Public License version 2 as published by the 00007 // Free Software Foundation. 00008 // 00009 // This library is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 // General Public License for more details. 00013 // 00014 // You should have received a copy of the GNU General Public License 00015 // along with this library; see the file COPYING. If not, write to 00016 // the Free Software Foundation, 51 Franklin Street, Fifth Floor, 00017 // Boston, MA 02111-1307, USA. 00018 // 00019 // As a special exception, you may use this file as part of a free 00020 // software library without restriction. Specifically, if other files 00021 // instantiate templates or use macros or inline functions from this 00022 // file, or you compile this file and link it with other files to 00023 // produce an executable, this file does not by itself cause the 00024 // resulting executable to be covered by the GNU General Public 00025 // License. This exception does not however invalidate any other 00026 // reasons why the executable file might be covered by the GNU General 00027 // Public License. 00028 00029 // File: tour2.cc. 00030 00031 #include <oln/core/2d/image2d.hh> 00032 #include <oln/core/2d/neighb2d.hh> 00033 00034 #include <oln/core/gen/such_as.hh> 00035 #include <oln/core/gen/torus_image.hh> 00036 #include <oln/core/gen/pw_value.hh> 00037 #include <oln/core/gen/fun_ops.hh> 00038 00039 #include <oln/data/fill.hh> 00040 #include <oln/debug/fill.hh> 00041 #include <oln/debug/println.hh> 00042 00043 00044 // Note to the reader: you should have read the files tour1.cc and 00045 // tour2.cc before starting with this present file. 00046 00047 00048 00049 // We have encapsulated an algorithm into a procedure which is forward 00050 // declared below so that it can be used in the section 'main'. 00051 template <typename I> void algo(const I& img); 00052 00053 00054 // Some functions that will be useful in the following: 00055 bool chessboard(oln::point2d p) 00056 { 00057 return (p.row() + p.col()) % 2; 00058 } 00059 00060 00061 00062 int main() 00063 { 00064 using namespace oln; 00065 00066 // First our domain is 2d box: 00067 box2d b(point2d(0, 0), point2d(2, 2)); 00068 // ^^^^ ^^^^ 00069 // from to 00070 00071 // We define a binary image with values on that box. 00072 image2d<bool> img(b); 00073 00074 // With an array of Booleans (1 means true, 0 means false)... 00075 bool vals[] = { 1, 0, 0, 00076 0, 1, 0, 00077 0, 1, 1 }; 00078 // ...the debug::fill routine allows for manually initializing 00079 // image data: 00080 debug::fill(img, vals); 00081 std::cout << "img = " << std::endl; 00082 debug::println(img); 00083 // img = 00084 // | - - 00085 // - | - 00086 // - | | 00087 00088 image2d<int> ima(b); // An image of integers with the same 00089 box2d::piter p(ima.points()); // domain as img... 00090 int i = 0; 00091 for_all(p) 00092 ima(p) = i++; // ...and manually filled with values. 00093 00094 std::cout << "ima = " << std::endl; 00095 debug::println(ima); 00096 // ima = 00097 // 0 1 2 00098 // 3 4 5 00099 // 6 7 8 00100 00101 00102 00103 // The algorithm defined at the end of this file is very close to 00104 // the one of the tour former file. The major difference is that it 00105 // does not rely on a window but on a neighborhood. 00106 00107 // In image processing, we usually say that "an image has a given 00108 // neighborhood" or that "we associate/embed a neighborhood to/into 00109 // an image". In Olena, that is really the case: the image can 00110 // "have" a neighborhood, meaning that a neighborhood can be added 00111 // to an image in order to obtain an "image with a neighborhood". 00112 00113 // Joining an image with a neighborhood is performed with the 00114 // operator '+': 00115 algo(ima + c4); // c4 is the 2D neighborhood corresponding to 00116 // 4-connectivity; such as many classical 00117 // neighborhoods it is provided by Olena. 00118 // The result is given below. 00119 00120 // ---input: 00121 // 0 1 2 00122 // 1 2 3 00123 // 2 3 4 00124 // ---output: 00125 // 0: 1 1 00126 // 1: 0 2 2 00127 // 2: 1 3 00128 // 1: 0 2 2 00129 // 2: 1 1 3 3 00130 // 3: 2 2 4 00131 // 2: 1 3 00132 // 3: 2 2 4 00133 // 4: 3 3 00134 00135 // That was expectable... 00136 00137 00138 // And now for a little test: what is the result of this code? 00139 { 00140 image2d<int> test(ima.points()); 00141 data::fill(test, ima); 00142 (test + c4).at(1, 1) = 9; 00143 debug::println(test); 00144 } 00145 // and can you tell why? 00146 // The answers are given in the file tour3-test.txt 00147 00148 00149 // Now let us start experimenting the genericity of Olena! 00150 00151 00152 // First, imagine that you want to restrict the domain of ima to a 00153 // subset of points, a region or whatever. For instance, the 00154 // chessboard function takes a point as argument and returns a 00155 // Boolean so it is like a predicate. We can want to consider only 00156 // the points of ima "such as" this predicate is verified. The 00157 // "such as" mathematical symbol is '|' so let's rock: 00158 00159 algo((ima | chessboard) + c8); 00160 // gives: 00161 00162 // ---input: 00163 // 1 00164 // 3 5 00165 // 7 00166 // ---output: 00167 // 1: 3 5 00168 // 3: 1 7 00169 // 5: 1 7 00170 // 7: 3 5 00171 00172 // where the blanks in printing the input image denote that the 00173 // corresponding points do NOT belong to the image domain. 00174 00175 // Another similar example is based on the binary image created at 00176 // the beginning of this tour: 00177 algo((ima | img) + c8); 00178 // which gives: 00179 00180 // ---input: 00181 // 0 00182 // 4 00183 // 7 8 00184 // ---output: 00185 // 0: 4 00186 // 4: 0 7 8 00187 // 7: 4 8 00188 // 8: 4 7 00189 00190 00191 00192 // Second, imagine that you want your initial image to get the 00193 // geodesy of a torus, that is, a 2D image wrapped on a torus. 00194 // Points located at the image boundary have neighbors; for 00195 // instance, the point denoted by the 'x' cross below has for 00196 // 4-connectivity neighbors: t, l, r, and b (respectively for top, 00197 // left, right, and bottom): 00198 00199 // b o o o 00200 // o o o o 00201 // t o o o 00202 // x r o l 00203 00204 // Let us try: 00205 algo(torus(ima) + c8); 00206 // gives: 00207 00208 // ---input: 00209 // 0 1 2 00210 // 3 4 5 00211 // 6 7 8 00212 // ---output: 00213 // 0: 8 6 7 2 1 5 3 4 00214 // 1: 6 7 8 0 2 3 4 5 00215 // 2: 7 8 6 1 0 4 5 3 00216 // 3: 2 0 1 5 4 8 6 7 00217 // 4: 0 1 2 3 5 6 7 8 00218 // 5: 1 2 0 4 3 7 8 6 00219 // 6: 5 3 4 8 7 2 0 1 00220 // 7: 3 4 5 6 8 0 1 2 00221 // 8: 4 5 3 7 6 1 2 0 00222 00223 00224 00225 // We can have both the torus geodesy and a sub-domain: 00226 00227 algo(torus(ima | chessboard) + c8); 00228 algo(torus(ima | img) + c8); 00229 00230 // which respectively give: 00231 00232 // ---input: 00233 // 1 00234 // 3 5 00235 // 7 00236 // ---output: 00237 // 1: 7 3 5 00238 // 3: 1 5 7 00239 // 5: 1 3 7 00240 // 7: 3 5 1 00241 00242 // and: 00243 00244 // ---input: 00245 // 0 00246 // 4 00247 // 7 8 00248 // ---output: 00249 // 0: 8 7 4 00250 // 4: 0 7 8 00251 // 7: 4 8 0 00252 // 8: 4 7 0 00253 00254 00255 00256 00257 // Last, the way a predicate is defined can also rely on some image 00258 // values. For that the user can on the fly provide an expression 00259 // built with the "pw_value" facility, where "pw_" means 00260 // "point-wise" for short: 00261 00262 algo((ima | (pw_value(ima) < 4)) + c4); 00263 00264 // In this example, "pw_value(ima)" is the function that represents 00265 // the point-wise value of the 'ima' image, that is, the function 00266 // "p -> ima(p)". This naturally leads to: 00267 00268 // ---input: 00269 // 0 1 2 00270 // 3 00271 // 00272 // ---output: 00273 // 0: 1 3 00274 // 1: 0 2 00275 // 2: 1 00276 // 3: 0 00277 00278 00279 00280 // From those examples, you should realize that: 00281 00282 00283 // +-----------------------------------------------------------+ 00284 // | | 00285 // | The level of "genericity" provided by Olena is rather | 00286 // | high; it means: | 00287 // | | 00288 // | - taking the image dimension you work on; | 00289 // | | 00290 // | - having the type of pixel values you need; | 00291 // | | 00292 // | - choosing the neighborhood you want; | 00293 // | | 00294 // | - changing the geodesy if you need it; | 00295 // | | 00296 // | - being able to restrict the image domain; | 00297 // | | 00298 // | - and many other features that are addressed further | 00299 // | in the tour... | 00300 // | | 00301 // +-----------------------------------------------------------+ 00302 00303 } 00304 00305 00306 00307 00308 00309 // The algorithm 'algo': 00310 00311 template <typename I> 00312 void algo(const I& img) 00313 { 00314 std::cout << "---input:" << std::endl; 00315 oln::debug::print(img); 00316 std::cout << "---output:" << std::endl; 00317 00318 oln_piter(I) p(img.points()); // p iterates on img points 00319 oln_niter(I) n(img, p); // n iterates in img on neighbors of p 00320 00321 for_all(p) 00322 { 00323 std::cout << oln::debug::format(img(p)) 00324 << ':'; 00325 for_all(n) 00326 std::cout << ' ' 00327 << oln::debug::format(img(n)); 00328 std::cout << std::endl; 00329 } 00330 00331 std::cout << std::endl; 00332 }