LTI-Lib latest version v1.9 - last update 10 Apr 2010

ltiSOFM2DVisualizer.h

00001 /*
00002  * Copyright (C) 2002, 2003, 2004, 2005, 2006
00003  * Lehrstuhl fuer Technische Informatik, RWTH-Aachen, Germany
00004  *
00005  * This file is part of the LTI-Computer Vision Library (LTI-Lib)
00006  *
00007  * The LTI-Lib is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License (LGPL)
00009  * as published by the Free Software Foundation; either version 2.1 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * The LTI-Lib is distributed in the hope that it will be
00013  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
00014  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with the LTI-Lib; see the file LICENSE.  If
00019  * not, write to the Free Software Foundation, Inc., 59 Temple Place -
00020  * Suite 330, Boston, MA 02111-1307, USA.
00021  */
00022 
00023 
00024 /*--------------------------------------------------------------------
00025  * project ....: LTI-Lib: Image Processing and Computer Vision Library
00026  * file .......: ltiSOFM2DVisualizer.h
00027  * authors ....: Jens Paustenbach
00028  * organization: LTI, RWTH Aachen
00029  * creation ...: 31.10.2002
00030  * revisions ..: $Id: ltiSOFM2DVisualizer.h,v 1.9 2006/02/07 18:24:27 ltilib Exp $
00031  */
00032 
00033 #ifndef _LTI_S_O_F_M_2D_VISUALIZER_H_
00034 #define _LTI_S_O_F_M_2D_VISUALIZER_H_
00035 
00036 #include "ltiDrawBase.h"
00037 #include "ltiFunctor.h"
00038 #include "ltiSOFM2D.h"
00039 #include "ltiSammonsMapping.h"
00040 #include "ltiL1Distance.h"
00041 #include "ltiL2Distance.h"
00042 #include "ltiBoundsFunctor.h"
00043 
00044 namespace lti {
00045   /**
00046    *  This class provides some possibilites to visualize the
00047    *  given SOFM.
00048    *  If the drawer is an instance of ltiDraw<T>, you have to set
00049    *  the background color of the image that is used to a value
00050    *  that is different from the drawing colors in the colormap.
00051    */
00052   class SOFM2DVisualizer : public functor {
00053   public:
00054     /**
00055      * the parameters for the class SOFM2DVisualizer
00056      */
00057     class parameters : public functor::parameters {
00058     public:
00059       /**
00060        * default constructor
00061        */
00062       parameters();
00063 
00064       /**
00065        * copy constructor
00066        * @param other the parameters object to be copied
00067        */
00068       parameters(const parameters& other);
00069 
00070       /**
00071        * destructor
00072        */
00073       ~parameters();
00074 
00075       /**
00076        * returns name of this type
00077        */
00078       const char* getTypeName() const;
00079 
00080       /**
00081        * copy the contents of a parameters object
00082        * @param other the parameters object to be copied
00083        * @return a reference to this parameters object
00084        */
00085       parameters& copy(const parameters& other);
00086 
00087       /**
00088        * copy the contents of a parameters object
00089        * @param other the parameters object to be copied
00090        * @return a reference to this parameters object
00091        */
00092       parameters& operator=(const parameters& other);
00093 
00094 
00095       /**
00096        * returns a pointer to a clone of the parameters
00097        */
00098       virtual functor::parameters* clone() const;
00099 
00100       /**
00101        * write the parameters in the given ioHandler
00102        * @param handler the ioHandler to be used
00103        * @param complete if true (the default) the enclosing begin/end will
00104        *        be also written, otherwise only the data block will be written.
00105        * @return true if write was successful
00106        */
00107       virtual bool write(ioHandler& handler,const bool complete=true) const;
00108 
00109       /**
00110        * read the parameters from the given ioHandler
00111        * @param handler the ioHandler to be used
00112        * @param complete if true (the default) the enclosing begin/end will
00113        *        be also written, otherwise only the data block will be written.
00114        * @return true if write was successful
00115        */
00116       virtual bool read(ioHandler& handler,const bool complete=true);
00117 
00118 #     ifdef _LTI_MSC_6
00119       /**
00120        * this function is required by MSVC only, as a workaround for a
00121        * very awful bug, which exists since MSVC V.4.0, and still by
00122        * V.6.0 with all bugfixes (so called "service packs") remains
00123        * there...  This method is also public due to another bug, so please
00124        * NEVER EVER call this method directly: use read() instead
00125        */
00126       bool readMS(ioHandler& handler,const bool complete=true);
00127 
00128       /**
00129        * this function is required by MSVC only, as a workaround for a
00130        * very awful bug, which exists since MSVC V.4.0, and still by
00131        * V.6.0 with all bugfixes (so called "service packs") remains
00132        * there...  This method is also public due to another bug, so please
00133        * NEVER EVER call this method directly: use write() instead
00134        */
00135       bool writeMS(ioHandler& handler,const bool complete=true) const;
00136 #     endif
00137 
00138       // ------------------------------------------------
00139       // the parameters
00140       // ------------------------------------------------
00141 
00142       /**
00143        *  a list of colors, that is used for visualization
00144        */
00145       vector<rgbPixel> colorMap;
00146 
00147       /**
00148        *  the size of the symbols in the visualization
00149        */
00150       int symbolSize;
00151 
00152       /**
00153        *  the parameters for the Sammons Mapper. You have to set this parameter
00154        *  only if you use sammonsMapping and want to use other parameters for
00155        *  the Sammons Mapper than the default.
00156        */
00157       sammonsMapping::parameters smP;
00158 
00159 
00160     protected:
00161       static const vector<rgbPixel> defaultColors;
00162 
00163 
00164     };
00165 
00166     /**
00167      * default constructor
00168      */
00169     SOFM2DVisualizer();
00170 
00171     /**
00172      * Construct a functor using the given parameters
00173      */
00174     SOFM2DVisualizer(const parameters& par);
00175 
00176     /**
00177      * copy constructor
00178      * @param other the object to be copied
00179      */
00180     SOFM2DVisualizer(const SOFM2DVisualizer& other);
00181 
00182     /**
00183      * destructor
00184      */
00185     virtual ~SOFM2DVisualizer();
00186 
00187     /**
00188      * returns the name of this type ("SOFM2DVisualizer")
00189      */
00190     virtual const char* getTypeName() const;
00191 
00192     /**
00193      * Draws the unified distane matrix of the given som.
00194      */
00195     template<typename T>
00196     bool uMatrix(drawBase<T>& drawer,const SOFM2D& som) const {
00197       // collect information from the som that is used for visualisation
00198 
00199       bool ok=true;
00200       int sizeX=som.xSize();
00201       int sizeY=som.ySize();
00202       dmatrix grid(som.getPrototypes());
00203 
00204       dmatrix dist(sizeY,sizeX,0.);
00205       l2Distance<double> dFunc;
00206 
00207       dmatrix region;
00208       dvector tmp;
00209       ivector idx(3);
00210       int i,j;
00211 
00212       //corners
00213       idx[0]=1;
00214       idx[1]=sizeX;
00215       idx[2]=sizeX+1;
00216       region.copy(grid,idx);
00217       dFunc.apply(region,grid.getRow(0),tmp);
00218       dist.at(0,0)=tmp.sumOfElements()/3.;
00219 
00220       idx[0]=sizeX-2;
00221       idx[1]=2*sizeX-1;
00222       idx[2]=2*sizeX-2;
00223       region.copy(grid,idx);
00224       dFunc.apply(region,grid.getRow(sizeX-1),tmp);
00225       dist.at(0,sizeX-1)=tmp.sumOfElements()/3.;
00226 
00227       idx[0]=sizeX*(sizeY-1)+1;
00228       idx[1]=sizeX*(sizeY-2);
00229       idx[2]=sizeX*(sizeY-2)+1;
00230       region.copy(grid,idx);
00231       dFunc.apply(region,grid.getRow(sizeX*(sizeY-1)),tmp);
00232       dist.at(sizeY-1,0)=tmp.sumOfElements()/3.;
00233 
00234       idx[0]=sizeX*sizeY-2;
00235       idx[1]=sizeX*(sizeY-1)-1;
00236       idx[2]=sizeX*(sizeY-1)-2;
00237       region.copy(grid,idx);
00238       dFunc.apply(region,grid.getRow(sizeX*sizeY-1),tmp);
00239       dist.at(sizeY-1,sizeX-1)=tmp.sumOfElements()/3.;
00240 
00241       //egdes
00242       idx.resize(5);
00243       for (i=1; i<sizeX-1; i++) {
00244         idx[0]=i-1;
00245         idx[1]=i+1;
00246         idx[2]=i+sizeX-1;
00247         idx[3]=i+sizeX;
00248         idx[4]=i+sizeX+1;
00249         region.copy(grid,idx);
00250         dFunc.apply(region,grid.getRow(i),tmp);
00251         dist.at(0,i)=tmp.sumOfElements()/5.;
00252       }
00253       for (i=1; i<sizeX-1; i++) {
00254         idx[0]=(sizeY-1)*sizeX+i-1;
00255         idx[1]=(sizeY-1)*sizeX+i+1;
00256         idx[2]=(sizeY-2)*sizeX+i-1;
00257         idx[3]=(sizeY-2)*sizeX+i;
00258         idx[4]=(sizeY-2)*sizeX+i+1;
00259         region.copy(grid,idx);
00260         dFunc.apply(region,grid.getRow((sizeY-1)*sizeX+i),tmp);
00261         dist.at(sizeY-1,i)=tmp.sumOfElements()/5.;
00262       }
00263       for (i=1; i<sizeY-1; i++) {
00264         idx[0]=(i-1)*sizeX;
00265         idx[1]=(i+1)*sizeX;
00266         idx[2]=(i-1)*sizeX+1;
00267         idx[3]=i*sizeX+1;
00268         idx[4]=(i+1)*sizeX+1;
00269         region.copy(grid,idx);
00270         dFunc.apply(region,grid.getRow(i*sizeX),tmp);
00271         dist.at(i,0)=tmp.sumOfElements()/5.;
00272       }
00273       for (i=1; i<sizeY-1; i++) {
00274         idx[0]=i*sizeX-1;
00275         idx[1]=(i+2)*sizeX-1;
00276         idx[2]=i*sizeX-2;
00277         idx[3]=(i+1)*sizeX-2;
00278         idx[4]=(i+2)*sizeX-2;
00279         region.copy(grid,idx);
00280         dFunc.apply(region,grid.getRow((i+1)*sizeX-1),tmp);
00281         dist.at(i,sizeX-1)=tmp.sumOfElements()/5.;
00282       }
00283 
00284       //rest
00285       idx.resize(8);
00286       for (i=1; i<sizeY-1; i++) {
00287         for (j=1; j<sizeX-1; j++) {
00288           idx[0]=(i-1)*sizeX+j-1;
00289           idx[1]=(i-1)*sizeX+j;
00290           idx[2]=(i-1)*sizeX+j+1;
00291           idx[3]=i*sizeX+j-1;
00292           idx[4]=i*sizeX+j+1;
00293           idx[5]=(i+1)*sizeX+j-1;
00294           idx[6]=(i+1)*sizeX+j;
00295           idx[7]=(i+1)*sizeX+j+1;
00296           region.copy(grid,idx);
00297           dFunc.apply(region,grid.getRow(i*sizeX+j),tmp);
00298           dist.at(i,j)=tmp.sumOfElements()/8.;
00299         }
00300       }
00301 
00302       double maxDist=dist.maximum();
00303       dist.divide(-1.*maxDist);
00304       dist.add(1.);
00305 
00306       int f=getParameters().symbolSize;;
00307       //    const point size=drawer.getCanvasSize();
00308       //      if (f*sizeX>point.y || f*sizeY>point.X) { // not for epsDraw because
00309       //                                                // canvas size is mutable
00310       //          ok=false;
00311       //          setStatusString("the image is to small");
00312       //      }
00313       //      channel img(f*sizeY,f*sizeX);
00314       //      lti::draw<float> drawer;
00315       //      drawer.use(img);
00316 
00317       for (i=0; i<sizeY; i++) {
00318         for (j=0; j<sizeX; j++) {
00319           drawer.setGray(dist.at(i,j));
00320           drawer.rectangle(j*f,i*f,(j+1)*f-1,(i+1)*f-1,true);
00321         }
00322       }
00323 
00324       return ok;
00325     };
00326 
00327 
00328 
00329     /**
00330      * draws distribution of data colored according to ids.
00331      * @param drawer the drawing object
00332      * @param som the som to draw
00333      * @param data the
00334      * @param ids the ids according to the data
00335      * @return true if apply successful or false otherwise.
00336      */
00337     template<typename T>
00338     bool drawClasses(drawBase<T>& drawer,const SOFM2D& som,
00339                      const dmatrix& data,const ivector& ids) const {
00340       bool ok=true;
00341       dmatrix grid(som.getPrototypes());
00342       int sizeX=som.xSize();
00343       int sizeY=som.ySize();
00344       parameters p=getParameters();
00345 
00346 
00347       std::map<int,int> realToIntern;
00348       int rows=grid.rows();
00349       int nextId=0;
00350 
00351       ivector r(rows,0); //red
00352       ivector g(rows,0); //green
00353       ivector b(rows,0); //blue
00354       ivector n(rows,0); //count hits
00355 
00356       int i,j,w,currId;
00357       classifier::outputVector iv;
00358       for (i=0; i<data.rows(); i++) {
00359         som.classify(data.getRow(i), iv);
00360         currId=ids.at(i);
00361         if (realToIntern.find(currId)==realToIntern.end()) {
00362           realToIntern[currId]=nextId++;
00363         }
00364         w=iv.getWinnerUnit();
00365         n[w]++;
00366         r[w]+=p.colorMap[realToIntern[currId]].getRed();
00367         g[w]+=p.colorMap[realToIntern[currId]].getGreen();
00368         b[w]+=p.colorMap[realToIntern[currId]].getBlue();
00369       }
00370 
00371       image img(sizeY,sizeX);
00372       int nMax=n.maximum();
00373       for (i=0; i<sizeY; i++) {
00374         for (j=0; j<sizeX; j++) {
00375           w=i*sizeX+j;
00376           img.at(i,j).setRed(ubyte(r[w]/nMax));
00377           img.at(i,j).setGreen(ubyte(g[w]/nMax));
00378           img.at(i,j).setBlue(ubyte(b[w]/nMax));
00379         }
00380       }
00381       int f=p.symbolSize;
00382       //      image realImg(f*sizeY,f*sizeX);
00383       //      lti::draw<rgbPixel> drawer;
00384       //      drawer.use(realImg);
00385 
00386 
00387       for (i=0; i<sizeY; i++) {
00388         for (j=0; j<sizeX; j++) {
00389           drawer.setColor(img.at(i,j));
00390           drawer.rectangle(j*f,i*f,(j+1)*f-1,(i+1)*f-1,true);
00391         }
00392       }
00393 
00394 
00395       return ok;
00396     };
00397 
00398     /**
00399      * Classifies the given data with the som and draws the distribution
00400      * of the hits where the data points were classified in the som.
00401      */
00402     template<typename T>
00403     bool drawHits(drawBase<T>& drawer,const SOFM2D& som,
00404                   const dmatrix& data) const {
00405 
00406       bool ok=true;
00407       int sizeX=som.xSize();
00408       int sizeY=som.ySize();
00409 
00410       fmatrix count(sizeY,sizeX,0.);
00411 
00412       int i,j,w,x,y;
00413       classifier::outputVector iv;
00414       for (i=0; i<data.rows(); i++) {
00415         som.classify(data.getRow(i), iv);
00416         w=iv.getWinnerUnit();
00417         y=w/sizeX;
00418         x=w%sizeX;
00419         count.at(y,x)+=1.0f;
00420       }
00421 
00422       float chMax=count.maximum();
00423       count.divide(chMax);
00424 
00425       int f=getParameters().symbolSize;
00426 
00427       for (i=0; i<sizeY; i++) {
00428         for (j=0; j<sizeX; j++) {
00429           drawer.setGray(count.at(i,j));
00430           drawer.rectangle(j*f,i*f,(j+1)*f-1,(i+1)*f-1,true);
00431         }
00432       }
00433 
00434       return ok;
00435     }
00436 
00437 
00438     /**
00439      * Draws one component of the given som.
00440      */
00441     template<typename T>
00442     bool componentPlane(drawBase<T>& drawer,const SOFM2D& som,
00443                         const int& comp) const {
00444       bool ok=true;
00445       dvector grid(som.getPrototypes().getColumnCopy(comp));
00446       int sizeX=som.xSize();
00447       int sizeY=som.ySize();
00448       int i,j;
00449 
00450       int f=getParameters().symbolSize;
00451       double minimum=grid.minimum();
00452       if (minimum<0)
00453         grid.add(-1.*minimum);
00454       grid.divide(grid.maximum());
00455 
00456       for (i=0; i<sizeY; i++) {
00457         for (j=0; j<sizeX; j++) {
00458           drawer.setGray(grid.at(i*sizeX+j));
00459           drawer.rectangle(j*f,i*f,(j+1)*f-1,(i+1)*f-1,true);
00460         }
00461       }
00462       return ok;
00463     }
00464 
00465     /**
00466      * Applies a sammons mapping to the given som and draws the
00467      * resulting grid. Please not that the sammonsMapping does not
00468      * respect the orientation in the image plane. Thus, the result
00469      * might be rotated by an arbitrary angle.
00470      */
00471     template<typename T>
00472     bool sammonsMapper(drawBase<T>& drawer,const SOFM2D& som) const {
00473 
00474       bool ok=true;
00475       int i;
00476 
00477       sammonsMapping mapper;
00478       mapper.setParameters(getParameters().smP);
00479 
00480       dmatrix res;
00481       double error;
00482       ok = ok && mapper.apply(som.getPrototypes(),res,error);
00483 
00484       boundsFunctor<double> bounds;
00485       dvector mx, mn;
00486       bounds.boundsOfRows(res,mn,mx);
00487 
00488       const ipoint canvasSize=drawer.getCanvasSize();
00489 
00490       const double facX=(canvasSize.x-10)/(mx[0]-mn[0]);
00491       const double facY=(canvasSize.y-10)/(mx[1]-mn[1]);
00492       const double fac=min(facX,facY);
00493 
00494       drawer.setStyle("bo");
00495       for (i=0; i<res.rows(); i++) {
00496         drawer.marker(int(fac*(res.at(i,0)-mn[0])+5),
00497                       int(fac*(res.at(i,1)-mn[1])+5));
00498       }
00499       drawer.setStyle("r.");
00500       int x=som.xSize();
00501       int y=som.ySize();
00502       int j;
00503       for (i=0; i<y; i++) {
00504         drawer.set(int(fac*(res.at(i*x,0)-mn[0])+5),
00505                    int(fac*(res.at(i*x,1)-mn[1])+5));
00506         for(j=1; j<x; j++) {
00507           drawer.lineTo(int(fac*(res.at(i*x+j,0)-mn[0])+5),
00508                         int(fac*(res.at(i*x+j,1)-mn[1])+5));
00509         }
00510       }
00511       drawer.setStyle("g.");
00512       for (i=0; i<x; i++) {
00513         drawer.set(int(fac*(res.at(i,0)-mn[0])+5),
00514                    int(fac*(res.at(i,1)-mn[1])+5));
00515         for(j=1; j<y; j++) {
00516           drawer.lineTo(int(fac*(res.at(i+j*x,0)-mn[0])+5),
00517                         int(fac*(res.at(i+j*x,1)-mn[1])+5));
00518         }
00519       }
00520 
00521       return ok;
00522     }
00523 
00524     //  template<typename T>
00525     //     bool plotIds(drawBase<T>& drawer,const dmatrix& data,
00526     //                  const ivector& ids) const {
00527 
00528     //     int f=getParameters().symbolSize;
00529 
00530     //     int outsize=sizeX*sizeY;
00531 
00532     //     bool allOk=true;
00533     //     int i, j, k;
00534     //     matrix<int> clCount(outSize,outSize,0);
00535     //     classifier::outputVector outV;
00536 
00537     //     //map the actual ids to numbers between 0 and n-1
00538     //     std::map<int, int> realToIntern;
00539     //     ivector internToReal(outSize);
00540     //     j=0;
00541     //     for (i=0; i<ids.size(); i++) {
00542     //       if (realToIntern.find(ids.at(i))==realToIntern.end()) {
00543     //         realToIntern[ids.at(i)]=j;
00544     //         internToReal.at(j)=ids.at(i);
00545     //         j++;
00546     //       }
00547     //     }
00548 
00549     //     //initialize outTemplate with values from 0 to n-1 matching the
00550     //     //positions in the outTemplate
00551     //     ivector ideez(outSize);
00552     //     for (i=0; i<outSize; i++) {
00553     //       ideez.at(i)=i;
00554     //     }
00555     //     outTemplate=outputTemplate(ideez);
00556 
00557     //     //classify all data and count 'hits' for each position
00558     //     for(i=0;i<data.rows();i++) {
00559     //       allOk = classify(data[i], outV) && allOk;
00560     //       clCount[outV.getWinnerUnit()][realToIntern[ids[i]]]++;
00561     //     }
00562 
00563     //     double rowsum;
00564     //     int rowsize;
00565     //     outTemplate=outputTemplate(outSize);
00566     //     for(i=0;i<outSize;i++) {
00567     //       rowsum=clCount[i].sumOfElements();
00568     //       classifier::outputVector rowV;
00569     //       if (rowsum!=0) {
00570     //         rowsize=0;
00571     //         for (j=0;j<outSize;j++) {
00572     //           if (clCount[i][j]!=0) {
00573     //             rowsize++;
00574     //           }
00575     //         }
00576     //         rowV=outputVector(rowsize);
00577     //         for(j=0,k=0;j<outSize;j++) {
00578     //           if (clCount[i][j]!=0) {
00579     //             rowV.setPair(k++, internToReal[j], clCount[i][j]/rowsum);
00580     //           }
00581     //         }
00582     //       } else {
00583     //         allOk=false;
00584     //       }
00585     //       outTemplate.setProbs(i, rowV);
00586     //     }
00587     //     return allOk;
00588     //   }
00589 
00590     /**
00591      * copy data of "other" functor.
00592      * @param other the functor to be copied
00593      * @return a reference to this functor object
00594      */
00595     SOFM2DVisualizer& copy(const SOFM2DVisualizer& other);
00596 
00597     /**
00598      * alias for copy member
00599      * @param other the functor to be copied
00600      * @return a reference to this functor object
00601      */
00602     SOFM2DVisualizer& operator=(const SOFM2DVisualizer& other);
00603 
00604     /**
00605      * returns a pointer to a clone of this functor.
00606      */
00607     virtual functor* clone() const;
00608 
00609     /**
00610      * returns used parameters
00611      */
00612     const parameters& getParameters() const;
00613 
00614   };
00615 }
00616 
00617 #endif

Generated on Sat Apr 10 15:26:13 2010 for LTI-Lib by Doxygen 1.6.1