[ VIGRA Homepage | Class Index | Function Index | File Index | Main Page ]

details vigra/inspectimage.hxx VIGRA

00001 /************************************************************************/
00002 /*                                                                      */
00003 /*               Copyright 1998-2002 by Ullrich Koethe                  */
00004 /*       Cognitive Systems Group, University of Hamburg, Germany        */
00005 /*                                                                      */
00006 /*    This file is part of the VIGRA computer vision library.           */
00007 /*    ( Version 1.3.2, Jan 27 2005 )                                    */
00008 /*    You may use, modify, and distribute this software according       */
00009 /*    to the terms stated in the LICENSE file included in               */
00010 /*    the VIGRA distribution.                                           */
00011 /*                                                                      */
00012 /*    The VIGRA Website is                                              */
00013 /*        http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/      */
00014 /*    Please direct questions, bug reports, and contributions to        */
00015 /*        koethe@informatik.uni-hamburg.de                              */
00016 /*                                                                      */
00017 /*  THIS SOFTWARE IS PROVIDED AS IS AND WITHOUT ANY EXPRESS OR          */
00018 /*  IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED      */
00019 /*  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */
00020 /*                                                                      */
00021 /************************************************************************/
00022 
00023 
00024 #ifndef VIGRA_INSPECTIMAGE_HXX
00025 #define VIGRA_INSPECTIMAGE_HXX
00026 
00027 #include <vector>
00028 #include <algorithm>
00029 #include "vigra/utilities.hxx"
00030 #include "vigra/numerictraits.hxx"
00031 #include "vigra/iteratortraits.hxx"
00032 #include "vigra/functortraits.hxx"
00033 #include "vigra/rgbvalue.hxx"
00034 
00035 namespace vigra {
00036 
00037 /** \addtogroup InspectAlgo Algorithms to Inspect Images
00038 
00039     Apply read-only functor to every pixel
00040 */
00041 //@{
00042 
00043 /********************************************************/
00044 /*                                                      */
00045 /*                      inspectLine                     */
00046 /*                                                      */
00047 /********************************************************/
00048 
00049 template <class SrcIterator, class SrcAccessor, class Functor>
00050 void
00051 inspectLine(SrcIterator s,
00052             SrcIterator send, SrcAccessor src,
00053             Functor & f)
00054 {
00055     for(; s != send; ++s)
00056         f(src(s));
00057 }
00058 
00059 template <class SrcIterator, class SrcAccessor,
00060           class MaskIterator, class MaskAccessor,
00061           class Functor>
00062 void
00063 inspectLineIf(SrcIterator s,
00064               SrcIterator send, SrcAccessor src,
00065               MaskIterator m, MaskAccessor mask,
00066               Functor & f)
00067 {
00068     for(; s != send; ++s, ++m)
00069         if(mask(m))
00070             f(src(s));
00071 }
00072 
00073 template <class SrcIterator1, class SrcAccessor1,
00074           class SrcIterator2, class SrcAccessor2,
00075           class Functor>
00076 void
00077 inspectTwoLines(SrcIterator1 s1,
00078                 SrcIterator1 s1end, SrcAccessor1 src1,
00079                 SrcIterator2 s2, SrcAccessor2 src2,
00080                 Functor & f)
00081 {
00082     for(; s1 != s1end; ++s1, ++s2)
00083         f(src1(s1), src2(s2));
00084 }
00085 
00086 template <class SrcIterator1, class SrcAccessor1,
00087           class SrcIterator2, class SrcAccessor2,
00088           class MaskIterator, class MaskAccessor,
00089           class Functor>
00090 void
00091 inspectTwoLinesIf(SrcIterator1 s1,
00092                   SrcIterator1 s1end, SrcAccessor1 src1,
00093                   SrcIterator2 s2, SrcAccessor2 src2,
00094                   MaskIterator m, MaskAccessor mask,
00095                   Functor & f)
00096 {
00097     for(; s1 != s1end; ++s1, ++s2, ++m)
00098         if(mask(m))
00099             f(src1(s1), src2(s2));
00100 }
00101 
00102 /********************************************************/
00103 /*                                                      */
00104 /*                        inspectImage                  */
00105 /*                                                      */
00106 /********************************************************/
00107 
00108 /** \brief Apply read-only functor to every pixel in the image.
00109 
00110     This function can be used to collect statistics of the image etc.
00111     The results must be stored in the functor, which serves as a return
00112     value.
00113     The function uses an accessor to access the pixel data.
00114 
00115     <b> Declarations:</b>
00116 
00117     pass arguments explicitly:
00118     \code
00119     namespace vigra {
00120         template <class ImageIterator, class Accessor, class Functor>
00121         void
00122         inspectImage(ImageIterator upperleft, ImageIterator lowerright,
00123                      Accessor a, Functor & f)
00124     }
00125     \endcode
00126 
00127     use argument objects in conjunction with \ref ArgumentObjectFactories:
00128     \code
00129     namespace vigra {
00130         template <class ImageIterator, class Accessor, class Functor>
00131         void
00132         inspectImage(triple<ImageIterator, ImageIterator, Accessor> img,
00133              Functor & f)
00134     }
00135     \endcode
00136 
00137     <b> Usage:</b>
00138 
00139         <b>\#include</b> "<a href="inspectimage_8hxx-source.html">vigra/inspectimage.hxx</a>"<br>
00140         Namespace: vigra
00141 
00142     \code
00143     // init functor
00144     vigra::BImage img;
00145 
00146     vigra::FindMinMax<vigra::BImage::PixelType> minmax;
00147 
00148     vigra::inspectImage(srcImageRange(img), minmax);
00149 
00150     cout << "Min: " << minmax.min << " Max: " << minmax.max;
00151 
00152     \endcode
00153 
00154     <b> Required Interface:</b>
00155 
00156     \code
00157     ConstImageIterator upperleft, lowerright;
00158     ConstImageIterator::row_iterator ix = upperleft.rowIterator();
00159 
00160     Accessor accessor;
00161     Functor functor;
00162 
00163     functor(accessor(ix));         // return not used
00164     \endcode
00165 
00166 */
00167 template <class ImageIterator, class Accessor, class Functor>
00168 void
00169 inspectImage(ImageIterator upperleft, ImageIterator lowerright,
00170          Accessor a, Functor & f)
00171 {
00172     int w = lowerright.x - upperleft.x;
00173 
00174     for(; upperleft.y<lowerright.y; ++upperleft.y)
00175     {
00176         inspectLine(upperleft.rowIterator(),
00177                     upperleft.rowIterator() + w, a, f);
00178     }
00179 }
00180 
00181 template <class ImageIterator, class Accessor, class Functor>
00182 inline
00183 void
00184 inspectImage(triple<ImageIterator, ImageIterator, Accessor> img,
00185          Functor & f)
00186 {
00187     inspectImage(img.first, img.second, img.third, f);
00188 }
00189 
00190 namespace functor
00191 {
00192     template <class T> class UnaryAnalyser;
00193 }
00194 
00195 template <class ImageIterator, class Accessor, class Functor>
00196 inline
00197 void
00198 inspectImage(ImageIterator upperleft, ImageIterator lowerright,
00199          Accessor a, functor::UnaryAnalyser<Functor> const & f)
00200 {
00201     inspectImage(upperleft, lowerright, a,
00202                  const_cast<functor::UnaryAnalyser<Functor> &>(f));
00203 }
00204 
00205 template <class ImageIterator, class Accessor, class Functor>
00206 inline
00207 void
00208 inspectImage(triple<ImageIterator, ImageIterator, Accessor> img,
00209          functor::UnaryAnalyser<Functor> const & f)
00210 {
00211     inspectImage(img.first, img.second, img.third,
00212                  const_cast<functor::UnaryAnalyser<Functor> &>(f));
00213 }
00214 
00215 /********************************************************/
00216 /*                                                      */
00217 /*                      inspectImageIf                  */
00218 /*                                                      */
00219 /********************************************************/
00220 
00221 /** \brief Apply read-only functor to every pixel in the ROI.
00222 
00223     This function can be used to collect statistics of the roi etc.
00224     The functor is called whenever the return value of the mask's
00225     accessor is not zero.
00226     The results must be stored in the functor, which serves as a return
00227     value.
00228     Accessors are used to access the pixel and mask data.
00229 
00230     <b> Declarations:</b>
00231 
00232     pass arguments explicitly:
00233     \code
00234     namespace vigra {
00235         template <class ImageIterator, class Accessor,
00236                   class MaskImageIterator, class MaskAccessor, class Functor>
00237         void
00238         inspectImageIf(ImageIterator upperleft, ImageIterator lowerright,
00239                MaskImageIterator mask_upperleft, MaskAccessor ma,
00240                Functor & f)
00241     }
00242     \endcode
00243 
00244 
00245     use argument objects in conjunction with \ref ArgumentObjectFactories:
00246     \code
00247     namespace vigra {
00248         template <class ImageIterator, class Accessor,
00249               class MaskImageIterator, class MaskAccessor, class Functor>
00250         void
00251         inspectImageIf(triple<ImageIterator, ImageIterator, Accessor> img,
00252                pair<MaskImageIterator, MaskAccessor> mask,
00253                Functor & f)
00254     }
00255     \endcode
00256 
00257     <b> Usage:</b>
00258 
00259         <b>\#include</b> "<a href="inspectimage_8hxx-source.html">vigra/inspectimage.hxx</a>"<br>
00260         Namespace: vigra
00261 
00262     \code
00263     vigra::BImage img(100, 100);
00264     vigra::BImage mask(100, 100);
00265 
00266     // init functor
00267     vigra::FindMinMax<vigra::BImage::PixelType> minmax();
00268 
00269     vigra::inspectImageIf(srcImageRange(img),
00270                           maskImage(mask), minmax);
00271 
00272     cout << "Min: " << minmax.min << " Max: " << minmax.max;
00273 
00274     \endcode
00275 
00276     <b> Required Interface:</b>
00277 
00278     \code
00279     ConstImageIterator upperleft, lowerright;
00280     MaskImageIterator mask_upperleft;
00281     ConstImageIterator::row_iterator ix = upperleft.rowIterator();
00282     MaskImageIterator::row_iterator mx = mask_upperleft.rowIterator();
00283 
00284     Accessor accessor;
00285     MaskAccessor mask_accessor;
00286 
00287     Functor functor;
00288 
00289     if(mask_accessor(mx)) functor(accessor(ix));
00290     \endcode
00291 
00292 */
00293 template <class ImageIterator, class Accessor,
00294       class MaskImageIterator, class MaskAccessor, class Functor>
00295 void
00296 inspectImageIf(ImageIterator upperleft,
00297                ImageIterator lowerright, Accessor a,
00298            MaskImageIterator mask_upperleft, MaskAccessor ma,
00299            Functor & f)
00300 {
00301     int w = lowerright.x - upperleft.x;
00302 
00303     for(; upperleft.y<lowerright.y; ++upperleft.y, ++mask_upperleft.y)
00304     {
00305         inspectLineIf(upperleft.rowIterator(),
00306                       upperleft.rowIterator() + w, a,
00307                       mask_upperleft.rowIterator(), ma, f);
00308     }
00309 }
00310 
00311 template <class ImageIterator, class Accessor,
00312       class MaskImageIterator, class MaskAccessor, class Functor>
00313 inline
00314 void
00315 inspectImageIf(triple<ImageIterator, ImageIterator, Accessor> img,
00316                pair<MaskImageIterator, MaskAccessor> mask,
00317                Functor & f)
00318 {
00319     inspectImageIf(img.first, img.second, img.third,
00320                    mask.first, mask.second, f);
00321 }
00322 
00323 /********************************************************/
00324 /*                                                      */
00325 /*                  inspectTwoImages                    */
00326 /*                                                      */
00327 /********************************************************/
00328 
00329 /** \brief Apply read-only functor to every pixel of both images.
00330 
00331     This function can be used to collect statistics for each region of a
00332     labeled image, especially in conjunction with
00333     the \ref ArrayOfRegionStatistics functor. The results must be
00334     stored in the functor which serves as a return value.
00335     Accessors are used to access the pixel data.
00336 
00337     <b> Declarations:</b>
00338 
00339     pass arguments explicitly:
00340     \code
00341     namespace vigra {
00342         template <class ImageIterator1, class Accessor1,
00343               class ImageIterator2, class Accessor2,
00344               class Functor>
00345         void
00346         inspectTwoImages(ImageIterator1 upperleft1, ImageIterator1 lowerright1, Accessor1 a1,
00347                  ImageIterator2 upperleft2, Accessor2 a2,
00348                  Functor & f)
00349     }
00350     \endcode
00351 
00352 
00353     use argument objects in conjunction with \ref ArgumentObjectFactories:
00354     \code
00355     namespace vigra {
00356         template <class ImageIterator1, class Accessor1,
00357               class ImageIterator2, class Accessor2,
00358               class Functor>
00359         void
00360         inspectTwoImages(triple<ImageIterator1, ImageIterator1, Accessor1> img1,
00361                          pair<ImageIterator2, Accessor2> img2,
00362                  Functor & f)
00363     }
00364     \endcode
00365 
00366     <b> Usage:</b>
00367 
00368         <b>\#include</b> "<a href="inspectimage_8hxx-source.html">vigra/inspectimage.hxx</a>"<br>
00369         Namespace: vigra
00370 
00371     \code
00372     vigra::BImage image1;
00373     vigra::BImage image2;
00374 
00375     SomeStatisticsFunctor stats(...);     // init functor
00376 
00377     vigra::inspectTwoImages(srcImageRange(image1), srcImage(image2),
00378                             stats);
00379 
00380 
00381     \endcode
00382 
00383     <b> Required Interface:</b>
00384 
00385     \code
00386     ImageIterator1 upperleft1, lowerright1;
00387     ImageIterator2 upperleft2;
00388     ImageIterator1::row_iterator ix1 = upperleft1.rowIterator();
00389     ImageIterator2::row_iterator ix2 = upperleft2.rowIterator();
00390 
00391     Accessor1 accessor1;
00392     Accessor2 accessor2;
00393 
00394     Functor functor;
00395     functor(accessor1(ix1), accessor2(ix2));  // return not used
00396     \endcode
00397 
00398 */
00399 template <class ImageIterator1, class Accessor1,
00400           class ImageIterator2, class Accessor2,
00401       class Functor>
00402 void
00403 inspectTwoImages(ImageIterator1 upperleft1, ImageIterator1 lowerright1, Accessor1 a1,
00404                  ImageIterator2 upperleft2, Accessor2 a2,
00405          Functor & f)
00406 {
00407     int w = lowerright1.x - upperleft1.x;
00408 
00409     for(; upperleft1.y<lowerright1.y; ++upperleft1.y, ++upperleft2.y)
00410     {
00411         inspectTwoLines(upperleft1.rowIterator(),
00412                         upperleft1.rowIterator() + w, a1,
00413                         upperleft2.rowIterator(), a2, f);
00414     }
00415 }
00416 
00417 template <class ImageIterator1, class Accessor1,
00418       class ImageIterator2, class Accessor2,
00419       class Functor>
00420 inline
00421 void
00422 inspectTwoImages(triple<ImageIterator1, ImageIterator1, Accessor1> img1,
00423          pair<ImageIterator2, Accessor2> img2,
00424          Functor & f)
00425 {
00426     inspectTwoImages(img1.first, img1.second, img1.third,
00427                      img2.first, img2.second, f);
00428 }
00429 
00430 /********************************************************/
00431 /*                                                      */
00432 /*                inspectTwoImagesIf                    */
00433 /*                                                      */
00434 /********************************************************/
00435 
00436 /** \brief Apply read-only functor to those pixels of both images where
00437     the mask image is non-zero.
00438 
00439     This function can be used to collect statistics for selected regions of a
00440     labeled image, especially in conjunction with
00441     the \ref ArrayOfRegionStatistics functor. The results must be
00442     stored in the functor which serves as a return value.
00443     Accessors are used to access the pixel data.
00444 
00445     <b> Declarations:</b>
00446 
00447     pass arguments explicitly:
00448     \code
00449     namespace vigra {
00450         template <class ImageIterator1, class Accessor1,
00451                   class ImageIterator2, class Accessor2,
00452                   class MaskImageIterator, class MaskAccessor,
00453                   class Functor>
00454         void
00455         inspectTwoImagesIf(ImageIterator1 upperleft1, ImageIterator1 lowerright1, Accessor1 a1,
00456                          ImageIterator2 upperleft2, Accessor2 a2,
00457                          MaskImageIterator mupperleft, MaskAccessor mask,
00458                          Functor & f)
00459     }
00460     \endcode
00461 
00462 
00463     use argument objects in conjunction with \ref ArgumentObjectFactories:
00464     \code
00465     namespace vigra {
00466         template <class ImageIterator1, class Accessor1,
00467                   class ImageIterator2, class Accessor2,
00468                   class MaskImageIterator, class MaskAccessor,
00469                   class Functor>
00470         void
00471         inspectTwoImagesIf(triple<ImageIterator1, ImageIterator1, Accessor1> img1,
00472                  pair<ImageIterator2, Accessor2> img2,
00473                  pair<MaskImageIterator, MaskAccessor> mimg,
00474                  Functor & f)
00475     }
00476     \endcode
00477 
00478     <b> Usage:</b>
00479 
00480         <b>\#include</b> "<a href="inspectimage_8hxx-source.html">vigra/inspectimage.hxx</a>"<br>
00481         Namespace: vigra
00482 
00483     \code
00484     vigra::BImage image1;
00485     vigra::BImage image2;
00486     vigra::BImage maskimage;
00487 
00488     SomeStatisticsFunctor stats(...);     // init functor
00489 
00490     vigra::inspectTwoImagesIf(srcImageRange(image1), srcImage(image2),
00491                               srcImage(maskimage), region_stats);
00492 
00493     \endcode
00494 
00495     <b> Required Interface:</b>
00496 
00497     \code
00498     ImageIterator1 upperleft1, lowerright1;
00499     ImageIterator2 upperleft2;
00500     MaskImageIterator upperleftm;
00501     ImageIterator1::row_iterator ix1 = upperleft1.rowIterator();
00502     ImageIterator2::row_iterator ix2 = upperleft2.rowIterator();
00503     MaskImageIterator::row_iterator mx = mupperleft.rowIterator();
00504 
00505     Accessor1 accessor1;
00506     Accessor2 accessor2;
00507     MaskAccessor mask;
00508 
00509     Functor functor;
00510     if(mask(mx))
00511         functor(accessor1(ix1), accessor2(ix2));
00512     \endcode
00513 
00514 */
00515 template <class ImageIterator1, class Accessor1,
00516           class ImageIterator2, class Accessor2,
00517           class MaskImageIterator, class MaskAccessor,
00518       class Functor>
00519 void
00520 inspectTwoImagesIf(ImageIterator1 upperleft1, ImageIterator1 lowerright1, Accessor1 a1,
00521                  ImageIterator2 upperleft2, Accessor2 a2,
00522                  MaskImageIterator mupperleft, MaskAccessor mask,
00523                  Functor & f)
00524 {
00525     int w = lowerright1.x - upperleft1.x;
00526 
00527     for(; upperleft1.y<lowerright1.y; ++upperleft1.y, ++upperleft2.y, ++mupperleft.y)
00528     {
00529         inspectTwoLinesIf(upperleft1.rowIterator(),
00530                           upperleft1.rowIterator() + w, a1,
00531                           upperleft2.rowIterator(), a2,
00532                           mupperleft.rowIterator(), mask, f);
00533     }
00534 }
00535 
00536 template <class ImageIterator1, class Accessor1,
00537           class ImageIterator2, class Accessor2,
00538           class MaskImageIterator, class MaskAccessor,
00539           class Functor>
00540 inline
00541 void
00542 inspectTwoImagesIf(triple<ImageIterator1, ImageIterator1, Accessor1> img1,
00543          pair<ImageIterator2, Accessor2> img2,
00544          pair<MaskImageIterator, MaskAccessor> m,
00545          Functor & f)
00546 {
00547     inspectTwoImagesIf(img1.first, img1.second, img1.third,
00548                      img2.first, img2.second,
00549                      m.first, m.second,
00550                      f);
00551 }
00552 
00553 //@}
00554 
00555 /** \addtogroup InspectFunctor Functors To Inspect Images
00556     Functors which report image statistics
00557 */
00558 //@{
00559 
00560 /********************************************************/
00561 /*                                                      */
00562 /*                     FindMinMax                       */
00563 /*                                                      */
00564 /********************************************************/
00565 
00566 /** \brief Find the minimum and maximum pixel value in an image or ROI.
00567 
00568     In addition the size of the ROI is calculated.
00569     These functors can also be used in conjunction with
00570     \ref ArrayOfRegionStatistics to find the extremes of all regions in
00571     a labeled image.
00572     
00573     <b> Traits defined:</b>
00574     
00575     <tt>FunctorTraits::isUnaryAnalyser</tt> is true (<tt>VigraTrueType<tt>)
00576     
00577     <b> Usage:</b>
00578 
00579         <b>\#include</b> "<a href="inspectimage_8hxx-source.html">vigra/inspectimage.hxx</a>"<br>
00580         Namespace: vigra
00581 
00582     \code
00583     vigra::BImage img;
00584 
00585     vigra::FindMinMax<vigra::BImage::PixelType> minmax;   // init functor
00586 
00587     vigra::inspectImage(srcImageRange(img), minmax);
00588 
00589     cout << "Min: " << minmax.min << " Max: " << minmax.max;
00590 
00591     \endcode
00592 
00593     <b> Required Interface:</b>
00594 
00595     \code
00596     VALUETYPE v1, v2(v1);
00597 
00598     v1 < v2;
00599     v1 = v2;
00600     \endcode
00601 
00602 */
00603 template <class VALUETYPE>
00604 class FindMinMax
00605 {
00606    public:
00607 
00608         /** the functor's argument type
00609         */
00610     typedef VALUETYPE argument_type;
00611 
00612         /** the functor's result type
00613         */
00614     typedef VALUETYPE result_type;
00615 
00616         /** \deprecated use argument_type
00617         */
00618     typedef VALUETYPE value_type;
00619 
00620         /** init min and max
00621         */
00622     FindMinMax()
00623     : count(0)
00624     {}
00625 
00626         /** (re-)init functor (clear min, max)
00627         */
00628     void reset()
00629     {
00630         count = 0;
00631     }
00632 
00633         /** update min and max
00634         */
00635     void operator()(argument_type const & v)
00636     {
00637         if(count)
00638         {
00639             if(v < min) min = v;
00640             if(max < v) max = v;
00641         }
00642         else
00643         {
00644             min = v;
00645             max = v;
00646         }
00647         ++count;
00648     }
00649 
00650         /** update min and max with components of RGBValue<VALUETYPE>
00651         */
00652     void operator()(RGBValue<VALUETYPE> const & v)
00653     {
00654         operator()(v.red());
00655         operator()(v.green());
00656         operator()(v.blue());
00657     }
00658 
00659         /** merge two statistics
00660         */
00661     void operator()(FindMinMax const & v)
00662     {
00663         if(v.count)
00664         {
00665             if(count)
00666             {
00667                 if(v.min < min) min = v.min;
00668                 if((this->max) < v.max) max = v.max;
00669             }
00670             else
00671             {
00672                 min = v.min;
00673                 max = v.max;
00674             }
00675         }
00676         count += v.count;
00677     }
00678 
00679         /** the current min
00680         */
00681     VALUETYPE min;
00682 
00683         /** the current max
00684         */
00685     VALUETYPE max;
00686 
00687         /** the number of values processed so far
00688         */
00689     unsigned int count;
00690 
00691 };
00692 
00693 template <class VALUETYPE>
00694 class FunctorTraits<FindMinMax<VALUETYPE> >
00695 : public FunctorTraitsBase<FindMinMax<VALUETYPE> >
00696 {
00697   public:
00698     typedef VigraTrueType isUnaryAnalyser;
00699 };
00700 
00701 /********************************************************/
00702 /*                                                      */
00703 /*                    FindAverage                       */
00704 /*                                                      */
00705 /********************************************************/
00706 
00707 /** \brief  Find the average pixel value in an image or ROI.
00708 
00709     In addition the size of the ROI is calculated.
00710     This Functor can also be used in conjunction with
00711     \ref ArrayOfRegionStatistics to find the average of all regions in
00712     a labeled image.
00713 
00714     <b> Traits defined:</b>
00715     
00716     <tt>FunctorTraits::isUnaryAnalyser</tt> and <tt>FunctorTraits::isInitializer</tt>
00717     are true (<tt>VigraTrueType<tt>)
00718     
00719     <b> Usage:</b>
00720 
00721         <b>\#include</b> "<a href="inspectimage_8hxx-source.html">vigra/inspectimage.hxx</a>"<br>
00722         Namespace: vigra
00723 
00724     \code
00725     vigra::BImage img;
00726 
00727     vigra::FindAverage<vigra::BImage::PixelType> average;   // init functor
00728 
00729     vigra::inspectImage(srcImageRange(img), average);
00730 
00731     cout << "Average: " << average();
00732 
00733     \endcode
00734 
00735     <b> Required Interface:</b>
00736 
00737     \code
00738     VALUETYPE v1, v2(v1);
00739 
00740     v1 < v2;
00741     v1 = v2;
00742     \endcode
00743 
00744 */
00745 template <class VALUETYPE>
00746 class FindAverage
00747 {
00748    public:
00749 
00750         /** the functor's argument type
00751         */
00752     typedef VALUETYPE argument_type;
00753 
00754         /** the functor's result type
00755         */
00756     typedef typename NumericTraits<VALUETYPE>::RealPromote result_type;
00757 
00758         /** \deprecated use argument_type and result_type
00759         */
00760     typedef typename NumericTraits<VALUETYPE>::RealPromote value_type;
00761 
00762         /** init average
00763         */
00764     FindAverage()
00765     : count(0), sum(NumericTraits<result_type>::zero())
00766     {}
00767 
00768         /** (re-)init average
00769         */
00770     void reset()
00771     {
00772         count = 0;
00773         sum = NumericTraits<result_type>::zero();
00774     }
00775 
00776         /** update average
00777         */
00778     void operator()(argument_type const & v)
00779     {
00780         sum += v;
00781         ++count;
00782     }
00783 
00784         /** merge two statistics
00785         */
00786     void operator()(FindAverage const & v)
00787     {
00788         sum += v.sum;
00789         count += v.count;
00790     }
00791 
00792         /** return current average
00793         */
00794     result_type average() const
00795     {
00796         return sum / (double)count;
00797     }
00798 
00799         /** return current average
00800         */
00801     result_type operator()() const
00802     {
00803         return sum / (double)count;
00804     }
00805 
00806     unsigned int count;
00807     result_type sum;
00808 
00809 };
00810 
00811 template <class VALUETYPE>
00812 class FunctorTraits<FindAverage<VALUETYPE> >
00813 : public FunctorTraitsBase<FindAverage<VALUETYPE> >
00814 {
00815   public:
00816     typedef VigraTrueType isInitializer;
00817     typedef VigraTrueType isUnaryAnalyser;
00818 };
00819 
00820 /********************************************************/
00821 /*                                                      */
00822 /*                    FindROISize                       */
00823 /*                                                      */
00824 /********************************************************/
00825 
00826 /** \brief Calculate the size of an ROI in an image.
00827 
00828     This Functor is often used in conjunction with
00829     \ref ArrayOfRegionStatistics to find the sizes of all regions in
00830     a labeled image.
00831 
00832     <b> Traits defined:</b>
00833     
00834     <tt>FunctorTraits::isUnaryAnalyser</tt> and <tt>FunctorTraits::isInitializer</tt>
00835     are true (<tt>VigraTrueType<tt>)
00836     
00837     <b> Usage:</b>
00838 
00839     <b>\#include</b> "<a href="inspectimage_8hxx-source.html">vigra/inspectimage.hxx</a>"<br>
00840         Namespace: vigra
00841 
00842     \code
00843     vigra::BImage img, mask;
00844 
00845     vigra::FindROISize<vigra::BImage::PixelType> roisize;   // init functor
00846 
00847     vigra::inspectImageIf(srcImageRange(img), srcImage(mask), roisize);
00848 
00849     cout << "Size of ROI: " << roisize.count;
00850 
00851     \endcode
00852 
00853 */
00854 template <class VALUETYPE>
00855 class FindROISize
00856 {
00857    public:
00858 
00859         /** the functor's argument type
00860         */
00861     typedef VALUETYPE argument_type;
00862 
00863         /** the functor's result type
00864         */
00865     typedef unsigned int result_type;
00866 
00867         /** \deprecated use argument_type and result_type
00868         */
00869     typedef VALUETYPE value_type;
00870 
00871         /** init counter to 0
00872         */
00873     FindROISize()
00874     : count(0)
00875     {}
00876 
00877         /** (re-)init ROI size with 0
00878         */
00879     void reset()
00880     {
00881         count = 0;
00882     }
00883 
00884         /** update counter
00885         */
00886     void operator()(argument_type const &)
00887     {
00888         ++count;
00889     }
00890 
00891         /** return current size
00892         */
00893     result_type operator()() const
00894     {
00895         return count;
00896     }
00897 
00898         /** return current size
00899         */
00900     result_type size() const
00901     {
00902         return count;
00903     }
00904 
00905         /** merge two statistics
00906         */
00907     void operator()(FindROISize const & o)
00908     {
00909         count += o.count;
00910     }
00911 
00912         /** the current counter
00913         */
00914     result_type count;
00915 
00916 };
00917 
00918 template <class VALUETYPE>
00919 class FunctorTraits<FindROISize<VALUETYPE> >
00920 : public FunctorTraitsBase<FindROISize<VALUETYPE> >
00921 {
00922   public:
00923     typedef VigraTrueType isInitializer;
00924     typedef VigraTrueType isUnaryAnalyser;
00925 };
00926 
00927 /********************************************************/
00928 /*                                                      */
00929 /*                FindBoundingRectangle                 */
00930 /*                                                      */
00931 /********************************************************/
00932 
00933 /** \brief Calculate the bounding rectangle of an ROI in an image.
00934 
00935     As always in VIGRA, <TT>roiRect.lowerRight</TT> is <em> just outside the rectangle</em>.
00936     That is, the last pixel actually in the rectangle is <TT>roiRect.lowerRight - Diff2D(1,1)</TT>.
00937     This Functor is often used in conjunction with
00938     \ref ArrayOfRegionStatistics to find the bounding rectangles
00939     of all regions in a labeled image.
00940 
00941     <b> Traits defined:</b>
00942     
00943     <tt>FunctorTraits::isUnaryAnalyser</tt> and <tt>FunctorTraits::isInitializer</tt>
00944     are true (<tt>VigraTrueType<tt>)
00945     
00946     <b> Usage:</b>
00947 
00948     <b>\#include</b> "<a href="inspectimage_8hxx-source.html">vigra/inspectimage.hxx</a>"<br>
00949         Namespace: vigra
00950 
00951     \code
00952     vigra::BImage img, mask;
00953     ...
00954 
00955     vigra::FindBoundingRectangle roiRect;   // init functor
00956 
00957     // Diff2D is used as the iterator for the source image. This
00958     // simulates an image where each pixel value equals that pixel's
00959     // coordinates. Tha image 'mask' determines the ROI.
00960     vigra::inspectImageIf(srcIterRange(Diff2D(0,0), img.size()),
00961                           srcImage(mask), roiRect);
00962 
00963     cout << "Upper left of ROI: " <<
00964         roiRect.upperLeft.x << ", " << roiRect.upperLeft.y << endl;
00965     cout << "Lower right of ROI: " <<
00966         roiRect.lowerRight.x << ", " << roiRect.lowerRight.y << endl;
00967 
00968     \endcode
00969 
00970 */
00971 class FindBoundingRectangle
00972 {
00973   public:
00974 
00975         /** the functor's argument type
00976         */
00977     typedef Diff2D argument_type;
00978 
00979         /** the functors result type
00980         */
00981     typedef Rect2D result_type;
00982 
00983         /** \deprecated use argument_type
00984         */
00985     typedef Diff2D value_type;
00986 
00987         /** Upper left of the region as seen so far
00988         */
00989     Point2D upperLeft;
00990 
00991         /** Lower right of the region as seen so far
00992         */
00993     Point2D lowerRight;
00994 
00995         /** are the functors contents valid ?
00996         */
00997     bool valid;
00998 
00999         /** init rectangle to invalid values
01000         */
01001     FindBoundingRectangle()
01002     : valid(false)
01003     {}
01004 
01005         /** (re-)init functor to find other bounds
01006         */
01007     void reset()
01008     {
01009         valid = false;
01010     }
01011 
01012         /** update rectangle by including the coordinate coord
01013         */
01014     void operator()(argument_type const & coord)
01015     {
01016         if(!valid)
01017         {
01018             upperLeft = Point2D(coord);
01019             lowerRight = Point2D(coord + Diff2D(1,1));
01020             valid = true;
01021         }
01022         else
01023         {
01024             upperLeft.x = std::min(upperLeft.x, coord.x);
01025             upperLeft.y = std::min(upperLeft.y, coord.y);
01026             lowerRight.x = std::max(lowerRight.x, coord.x + 1);
01027             lowerRight.y = std::max(lowerRight.y, coord.y + 1);
01028         }
01029     }
01030 
01031         /** update rectangle by merging it with another rectangle
01032         */
01033     void operator()(FindBoundingRectangle const & otherRegion)
01034     {
01035         if(!valid)
01036         {
01037             upperLeft = otherRegion.upperLeft;
01038             lowerRight = otherRegion.lowerRight;
01039             valid = otherRegion.valid;
01040         }
01041         else if(otherRegion.valid)
01042         {
01043             upperLeft.x = std::min(upperLeft.x, otherRegion.upperLeft.x);
01044             upperLeft.y = std::min(upperLeft.y, otherRegion.upperLeft.y);
01045             lowerRight.x = std::max(lowerRight.x, otherRegion.lowerRight.x);
01046             lowerRight.y = std::max(lowerRight.y, otherRegion.lowerRight.y);
01047         }
01048     }
01049 
01050         /** Get size of current rectangle.
01051         */
01052     Size2D size() const
01053     {
01054         return lowerRight - upperLeft;
01055     }
01056 
01057         /** Get current rectangle. <TT>result_type::first</TT> is the upper
01058             left corner of the rectangle, <TT>result_type::second</TT>
01059             the lower right.
01060         */
01061     result_type operator()() const
01062     {
01063         return result_type(upperLeft, lowerRight);
01064     }
01065 };
01066 
01067 template <>
01068 class FunctorTraits<FindBoundingRectangle>
01069 : public FunctorTraitsBase<FindBoundingRectangle>
01070 {
01071   public:
01072     typedef VigraTrueType isInitializer;
01073     typedef VigraTrueType isUnaryAnalyser;
01074 };
01075 
01076 /********************************************************/
01077 /*                                                      */
01078 /*                 LastValueFunctor                     */
01079 /*                                                      */
01080 /********************************************************/
01081 
01082 /** \brief Stores and returns the last value it has seen.
01083 
01084     This Functor is best used in conjunction with
01085     \ref ArrayOfRegionStatistics to realize a look-up table.
01086 
01087     <b> Traits defined:</b>
01088     
01089     <tt>FunctorTraits::isUnaryAnalyser</tt> and <tt>FunctorTraits::isInitializer</tt>
01090     are true (<tt>VigraTrueType<tt>)
01091     
01092     <b> Usage:</b>
01093 
01094     <b>\#include</b> "<a href="inspectimage_8hxx-source.html">vigra/inspectimage.hxx</a>"<br>
01095         Namespace: vigra
01096 
01097     \code
01098     vigra::BImage img;
01099 
01100     vigra::ArrayOfRegionStatistics<LastValueFunctor<unsigned char> > lut(255);
01101 
01102     for(int i=0; i<256; ++i)
01103     {
01104         lut[i] = ...; // init look-up table
01105     }
01106 
01107     vigra::transformImage(srcImageRange(img), destImage(img), lut);
01108 
01109     \endcode
01110 
01111 */
01112 template <class VALUETYPE>
01113 class LastValueFunctor
01114 {
01115    public:
01116 
01117         /** the functor's argument type
01118         */
01119     typedef VALUETYPE argument_type;
01120 
01121         /** the functor's result type
01122         */
01123     typedef VALUETYPE result_type;
01124 
01125         /** \deprecated use argument_type and result_type
01126         */
01127     typedef VALUETYPE value_type;
01128 
01129         /** default initialization of value
01130         */
01131     LastValueFunctor()
01132     {}
01133 
01134         /** replace value
01135         */
01136     void operator=(argument_type const & v) { value = v; }
01137 
01138         /** reset to initiaö value
01139         */
01140     void reset() { value = VALUETYPE(); }
01141 
01142         /** replace value
01143         */
01144     void operator()(argument_type const & v) { value = v; }
01145 
01146         /** return current value
01147         */
01148     result_type const & operator()() const { return value; }
01149 
01150         /** the current value
01151         */
01152     VALUETYPE value;
01153 
01154 };
01155 
01156 template <class VALUETYPE>
01157 class FunctorTraits<LastValueFunctor<VALUETYPE> >
01158 : public FunctorTraitsBase<LastValueFunctor<VALUETYPE> >
01159 {
01160   public:
01161     typedef VigraTrueType isInitializer;
01162     typedef VigraTrueType isUnaryAnalyser;
01163 };
01164 
01165 /********************************************************/
01166 /*                                                      */
01167 /*                     ReduceFunctor                    */
01168 /*                                                      */
01169 /********************************************************/
01170 
01171 /** \brief Apply a functor to reduce the dimensionality of an array.
01172 
01173     This functor can be used to emulate the <tt>reduce</tt> standard function of
01174     functional programming using <tt>std::for_each()</tt> or <tt>inspectImage()</tt>
01175     and similar functions. This functor is initialized with a functor encoding
01176     the expression to be applied, and an accumulator storing the current state
01177     of the reduction. For each element of the array, the embedded functor is called
01178     with the accumulator and the current element(s) of the array. The result
01179     of the reduction is available by calling <tt>reduceFunctor()</tt>. 
01180 
01181     <b> Traits defined:</b>
01182     
01183     <tt>FunctorTraits::isUnaryAnalyser</tt>, <tt>FunctorTraits::isBinaryAnalyser</tt> 
01184     and <tt>FunctorTraits::isInitializer</tt>
01185     are true (<tt>VigraTrueType<tt>)
01186     
01187     <b> Usage:</b>
01188 
01189     <b>\#include</b> "<a href="inspectimage_8hxx-source.html">vigra/inspectimage.hxx</a>"<br>
01190         Namespace: vigra
01191 
01192     \code
01193     vigra::BImage img;
01194     ... // fill the image
01195 
01196     // create a functor to sum the elements of the image
01197     vigra::ReduceFunctor<std::plus<int>, int> sumElements(std::plus<int>, 0);
01198     
01199     vigra::inspectImage(srcImageRange(img), sumElements);
01200 
01201     cout << "The sum of the elements " << sumElements() << endl;
01202 
01203     \endcode
01204 
01205     <b> Required Interface:</b>
01206 
01207     \code
01208     FUNCTOR f;
01209     VALUETYPE accumulator, current1, current2;
01210     
01211     f(accumulator, current1); // for inspectImage()
01212     f(accumulator, current1, current2); // for inspectTwoImages()
01213     \endcode
01214 */
01215 template <class FUNCTOR, class VALUETYPE>
01216 class ReduceFunctor
01217 {
01218     FUNCTOR f_;
01219     VALUETYPE start_, accumulator_;
01220    public:
01221 
01222         /** the functor's argument type
01223             when used as a unary inspector.
01224             (This is not strictly correct since the argument type
01225             is actuall a template parameter.)
01226         */
01227     typedef VALUETYPE argument_type;
01228 
01229         /** the functor's first argument type
01230             when used as a binary inspector.
01231             (This is not strictly correct since the argument type
01232             is actuall a template parameter.)
01233         */
01234     typedef VALUETYPE first_argument_type;
01235 
01236         /** the functor's second argument type
01237             when used as a binary inspector.
01238             (This is not strictly correct since the argument type
01239             is actuall a template parameter.)
01240         */
01241     typedef VALUETYPE second_argument_type;
01242 
01243         /** the functor's result type
01244         */
01245     typedef VALUETYPE result_type;
01246 
01247         /** create with the given functor and initial value \a initial
01248             for the accumulator.
01249         */
01250     ReduceFunctor(FUNCTOR const & f, VALUETYPE const & initial)
01251     : f_(f),
01252       start_(initial),
01253       accumulator_(initial)
01254     {}
01255     
01256         /** Reset accumulator to the initial value.
01257         */
01258     void reset()
01259       { accumulator_ = start_; }
01260 
01261         /** Use binary functor to connect given value with the accumulator.
01262             The accumulator is used as the first argument, the value \a v
01263             as the second.
01264         */
01265     template <class T>
01266     void operator()(T const & v) 
01267     { 
01268         accumulator_ = f_(accumulator_, v); 
01269     }
01270 
01271         /** Use ternary functor to connect given values with accumulator.
01272             The accumulator is used as the first argument, the values \a v1
01273             ans \a v2 as the second and third.
01274         */
01275     template <class T1, class T2>
01276     void operator()(T1 const & v1, T2 const & v2) 
01277     { 
01278         accumulator_ = f_(accumulator_, v1, v2); 
01279     }
01280 
01281         /** return current value
01282         */
01283     result_type const & operator()() const 
01284       { return accumulator_; }
01285 };
01286 
01287 template <class FUNCTOR, class VALUETYPE>
01288 ReduceFunctor<FUNCTOR, VALUETYPE>
01289 reduceFunctor(FUNCTOR const & f, VALUETYPE const & initial)
01290 {
01291     return ReduceFunctor<FUNCTOR, VALUETYPE>(f, initial);
01292 }
01293 
01294 template <class FUNCTOR, class VALUETYPE>
01295 class FunctorTraits<ReduceFunctor<FUNCTOR, VALUETYPE> >
01296 : public FunctorTraitsBase<ReduceFunctor<FUNCTOR, VALUETYPE> >
01297 {
01298   public:
01299     typedef VigraTrueType isInitializer;
01300     typedef VigraTrueType isUnaryAnalyser;
01301     typedef VigraTrueType isBinaryAnalyser;
01302 };
01303 
01304 /********************************************************/
01305 /*                                                      */
01306 /*              ArrayOfRegionStatistics                 */
01307 /*                                                      */
01308 /********************************************************/
01309 
01310 /** \brief Calculate statistics for all regions of a labeled image.
01311 
01312     This Functor encapsulates an array of statistics functors, one
01313     for each label, and selects the one to be updated according to the
01314     pixel's label.
01315 
01316     <b> Traits defined:</b>
01317     
01318     <tt>FunctorTraits::isBinaryAnalyser</tt> and <tt>FunctorTraits::isUnaryFunctor</tt>
01319     are true (<tt>VigraTrueType<tt>)
01320     
01321     <b> Usage:</b>
01322 
01323     <b>\#include</b> "<a href="inspectimage_8hxx-source.html">vigra/inspectimage.hxx</a>"<br>
01324         Namespace: vigra
01325 
01326     \code
01327     vigra::BImage img;
01328     vigra::IImage labels;
01329     int max_label;
01330     ...
01331 
01332     // init functor as an array of 'max_label' FindMinMax-Functors
01333     vigra::ArrayOfRegionStatistics<vigra::FindMinMax<vigra::BImage::PixelType> >
01334                                                          minmax(max_label);
01335 
01336     vigra::inspectTwoImages(srcImageRange(img), srcImage(labels), minmax);
01337 
01338     for(int i=0; i<= max_label; ++i)
01339     {
01340         cout << "Max gray lavel of region " << i << ": "
01341              << minmax.region[i].max << endl;
01342     }
01343 
01344     // init functor as an array of 'max_label' FindAverage-Functors
01345     vigra::ArrayOfRegionStatistics<vigra::FindAverage<vigra::BImage::PixelType> >
01346                                                          average(max_label);
01347 
01348     vigra::inspectTwoImages(srcImageRange(img), srcImage(labels), average);
01349 
01350     // write back the average of each region into the original image
01351     vigra::transformImage(srcImageRange(labels), destImage(img), average);
01352 
01353     \endcode
01354 
01355     <b> Required Interface:</b>
01356 
01357     \code
01358     RegionStatistics region;
01359     RegionStatistics::argument_type a;
01360     RegionStatistics::result_type r;
01361 
01362     region(a);     // update statistics
01363     r = region();  // return statistics
01364 
01365     \endcode
01366 */
01367 template <class RegionStatistics, class LabelType = int>
01368 class ArrayOfRegionStatistics
01369 {
01370     typedef std::vector<RegionStatistics> RegionArray;
01371 
01372   public:
01373          /** argument type of the contained statistics object
01374              becomes first argument of the analyser
01375          */
01376     typedef typename RegionStatistics::argument_type first_argument_type;
01377 
01378          /** label type is used to determine the region to be updated
01379          */
01380     typedef LabelType second_argument_type;
01381 
01382          /** label type is also used to determine the region to be
01383              returned by the 1 argument operator()
01384          */
01385     typedef LabelType argument_type;
01386 
01387          /** result type of the contained statistics object
01388              becomes result type of the analyser
01389          */
01390     typedef typename RegionStatistics::result_type result_type;
01391 
01392          /** the value type of the array: the contained statistics object.
01393              <b>Note:</b> this definition was different in older
01394              VIGRA versions. The old definition was wrong.
01395          */
01396     typedef RegionStatistics value_type;
01397 
01398          /** the array's reference type
01399          */
01400     typedef RegionStatistics & reference;
01401 
01402          /** the array's const reference type
01403          */
01404     typedef RegionStatistics const & const_reference;
01405 
01406          /** type to iterate over the statistics array
01407          */
01408     typedef typename RegionArray::iterator iterator;
01409 
01410          /** type to iterate over a const statistics array
01411          */
01412     typedef typename RegionArray::const_iterator const_iterator;
01413 
01414         /** init array of RegionStatistics with default size 0.
01415         */
01416     ArrayOfRegionStatistics()
01417     {}
01418 
01419         /** init array of RegionStatistics with index domain
01420             0...max_region_label.
01421         */
01422     ArrayOfRegionStatistics(unsigned int max_region_label)
01423     : regions(max_region_label+1)
01424     {}
01425 
01426         /** resize array to new index domain 0...max_region_label.
01427             All bin are re-initialized.
01428         */
01429     void resize(unsigned int max_region_label)
01430     {
01431         RegionArray newRegions(max_region_label+1);
01432         regions.swap(newRegions);
01433     }
01434 
01435         /** reset the contained functors to their initial state.
01436         */
01437     void reset()
01438     {
01439         RegionArray newRegions(regions.size());
01440         regions.swap(newRegions);
01441     }
01442 
01443         /** update regions statistics for region <TT>label</TT>. The label type
01444             is converted to <TT>unsigned int</TT>.
01445         */
01446     void operator()(first_argument_type const & v, second_argument_type label) {
01447         regions[static_cast<unsigned int>(label)](v);
01448     }
01449 
01450         /** merge second region into first
01451         */
01452     void merge(argument_type label1, argument_type label2) {
01453         regions[static_cast<unsigned int>(label1)](regions[static_cast<unsigned int>(label2)]);
01454     }
01455 
01456         /** ask for maximal index (label) allowed
01457         */
01458     unsigned int maxRegionLabel() const
01459         { return size() - 1; }
01460 
01461         /** ask for array size (i.e. maxRegionLabel() + 1)
01462         */
01463     unsigned int size() const
01464         { return regions.size(); }
01465 
01466         /** access the statistics for a region via its label. The label type
01467             is converted to <TT>unsigned int</TT>.
01468         */
01469     result_type operator()(argument_type label) const
01470         { return regions[static_cast<unsigned int>(label)](); }
01471 
01472         /** read the statistics functor for a region via its label
01473         */
01474     const_reference operator[](argument_type label) const
01475         { return regions[static_cast<unsigned int>(label)]; }
01476 
01477         /** access the statistics functor for a region via its label
01478         */
01479     reference operator[](argument_type label)
01480         { return regions[static_cast<unsigned int>(label)]; }
01481 
01482         /** iterator to the begin of the region array
01483         */
01484     iterator begin()
01485         { return regions.begin(); }
01486 
01487         /** const iterator to the begin of the region array
01488         */
01489     const_iterator begin() const
01490         { return regions.begin(); }
01491 
01492         /** iterator to the end of the region array
01493         */
01494     iterator end()
01495         { return regions.end(); }
01496 
01497         /** const iterator to the end of the region array
01498         */
01499     const_iterator end() const
01500         { return regions.end(); }
01501 
01502   private:
01503     std::vector<RegionStatistics> regions;
01504 };
01505 
01506 template <class RegionStatistics, class LabelType>
01507 class FunctorTraits<ArrayOfRegionStatistics<RegionStatistics, LabelType> >
01508 : public FunctorTraitsBase<ArrayOfRegionStatistics<RegionStatistics, LabelType> >
01509 {
01510   public:
01511     typedef VigraTrueType isUnaryFunctor;
01512     typedef VigraTrueType isBinaryAnalyser;
01513 };
01514 
01515 //@}
01516 
01517 } // namespace vigra
01518 
01519 #endif // VIGRA_INSPECTIMAGE_HXX

© Ullrich Köthe (koethe@informatik.uni-hamburg.de)
Cognitive Systems Group, University of Hamburg, Germany

html generated using doxygen and Python
VIGRA 1.3.2 (27 Jan 2005)