Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

GeodesicRecImage.C

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------*
00002  | Library QgarLib, graphics analysis and recognition                  |
00003  | Copyright (C) 2002  Qgar Project, LORIA                             |
00004  |                                                                     |
00005  | This library is free software; you can redistribute it and/or       |
00006  | modify it under the terms of the GNU Lesser General Public          |
00007  | License version 2.1, as published by the 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.                |
00012  | See the GNU Lesser General Public License for more details.         |
00013  |                                                                     |
00014  | The GNU Lesser General Public License is included in the file       |
00015  | LICENSE.LGPL, in the root directory of the Qgar packaging. See      |
00016  | http://www.gnu.org/licenses/lgpl.html for the terms of the licence. |
00017  | To receive a paper copy, write to the Free Software Foundation,     |
00018  | Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.       |
00019  |                                                                     |
00020  | Contact Project Qgar for any information:                           |
00021  |   LORIA - équipe Qgar                                               |
00022  |   B.P. 239, 54506 Vandoeuvre-lès-Nancy Cedex, France                |
00023  |   email: qgar-contact@loria.fr                                      |
00024  |   http://www.qgar.org/                                              |
00025  *---------------------------------------------------------------------*/
00026 
00027 
00028 /**
00029  * @file  GeodesicRecImage.C
00030  * @brief Implementation of class qgar::GeodesicRecImage.
00031  *
00032  *        See file GeodesicRecImage.H for the interface.
00033  *
00034  * @author <a href="mailto:qgar-develop@loria.fr?subject=Qgar fwd Mathieu Baeumler">Mathieu Baeumler</a>
00035  * @date   August 7, 2002  16:22
00036  * @since  Qgar 2.0
00037  */
00038 
00039 
00040 
00041 // STD
00042 #include <queue>
00043 #include <sstream>
00044 // QGAR
00045 #include <qgarlib/DilatedImage.H>
00046 #include <qgarlib/GenImage.H>
00047 #include <qgarlib/GeodesicRecImage.H>
00048 #include <qgarlib/QgarErrorDomain.H>
00049 
00050 
00051 
00052 using namespace std;
00053 
00054 
00055 namespace qgar
00056 {
00057 
00058 // ---------------------------------------------------------------------
00059 // C O N S T R U C T O R S
00060 // ---------------------------------------------------------------------
00061 
00062 // Default constructor
00063 GeodesicRecImage::GeodesicRecImage(GreyLevelImage& aMarkImg,
00064                                    GreyLevelImage& aResImg)
00065   throw(QgarErrorDomain)
00066   : GreyLevelImage(aMarkImg)
00067 {
00068   if (   (aMarkImg.width()  != aResImg.width())
00069       || (aMarkImg.height() != aResImg.height()))
00070     {
00071       std::ostringstream os;
00072       os << "Marker image size ["
00073          << aMarkImg.width()
00074          << " X "
00075          << aMarkImg.height()
00076          << "] does not match result image size ["
00077          << aResImg.width()
00078          << " X "
00079          << aResImg.height()
00080          << "]";
00081       throw QgarErrorDomain(__FILE__, __LINE__,
00082                             "qgar::GeodesicRecImage::GeodesicRecImage(qgar::GreyLevelImage&, qgar::GreyLevelImage&)",
00083                             os.str());
00084     }
00085 
00086   perform(this, &aResImg);
00087 }
00088 
00089 // -------------------------------------------------------------------
00090 // G E O D E S I C   R E C O N S T R U C T I O N
00091 // -------------------------------------------------------------------
00092 
00093 void GeodesicRecImage::perform(GreyLevelImage* aMarkImg,
00094                                GreyLevelImage* aResImg)
00095 {
00096   int width  = aMarkImg->width(); // just some shortcuts
00097   int height = aMarkImg->height();
00098 
00099   // first enqueue the boundaries of marker image.
00100 
00101   // as we have to compare marker and goal image in the same time,
00102   // we won't enqueue the pointers on marker's pixels, but their
00103   // indice in pixMap (which are the same in goal's pixMap)
00104   queue< long > boundary;
00105   
00106   long indice; // indice in the queue
00107   GreyLevelImage::value_type maximum; // local maximum
00108 
00109   GreyLevelImage::value_type* Jp; // pointer on marker image
00110   GreyLevelImage::value_type* Ip; // pointer on goal image
00111   GreyLevelImage::value_type* Jq; // pointer on current marker boundary pixel
00112   GreyLevelImage::value_type* Iq; // pointer on current goal boundary pixel
00113 
00114   GreyLevelImage::value_type* markerPixMap = aMarkImg->pPixMap(); // just some shortcuts
00115   GreyLevelImage::value_type* goalPixMap   = aResImg->pPixMap();
00116 
00117   int minK, minL; // limits of current pixel's neighborhood
00118   int maxK, maxL;
00119  
00120   /*** scan in raster order: ***/
00121 
00122   Jp = markerPixMap;
00123   Ip = goalPixMap;
00124 
00125   for (int i = 0; i < height; ++i)
00126     {
00127       for (int j = 0; j < width; ++j, ++Jp, ++Ip)
00128         {
00129           // point-wise minimum between max(p U Ng+(p)) and Ip
00130           maximum = *Jp;
00131 
00132           // after the first line
00133           if (i != 0)
00134             {
00135               // first pixel
00136               if (j == 0)
00137                 {
00138                   Jq = Jp - width;
00139                   if (maximum < *Jq)
00140                     {
00141                       maximum = *Jq;
00142                     }
00143                   ++Jq;
00144                   if (maximum < *Jq)
00145                     {
00146                       maximum = *Jq;    
00147                     }
00148                 }
00149               // last pixel
00150               else if (j == width - 1)
00151                 {
00152                   Jq = Jp - 1;
00153                   if (maximum < *Jq)
00154                     {
00155                       maximum = *Jq;
00156                     }
00157 
00158                   Jq -= width;
00159                   if (maximum < *Jq)
00160                     {
00161                       maximum = *Jq;
00162                     }
00163 
00164                   ++Jq;
00165                   if (maximum < *Jq)
00166                     {
00167                       maximum = *Jq;   
00168                     }
00169                 }
00170               // between these two pixels
00171               else
00172                 {
00173                   for (int k = -1; k < 1; ++k)
00174                     {
00175                       for (int l = -1 ; l < 1 - k; ++l)
00176                         {
00177                           Jq = Jp + k*width + l;
00178                           if (maximum < *Jq)
00179                             {
00180                               maximum = *Jq;
00181                             }
00182                         } // END for l
00183                     } // END for k
00184                 }
00185             }
00186           else if (j > 0)
00187             {
00188               Jq = Jp - 1;
00189               if (maximum < *Jq)
00190                 {
00191                   maximum = *Jq;
00192                 }
00193             }
00194       
00195           *Jp = (maximum < *Ip ? maximum : *Ip);
00196         } // END for j
00197     } // END for i
00198 
00199   /*** scan in anti-raster order: ***/
00200 
00201   --Jp;
00202   --Ip;
00203   for (int i = 0 ; i < height ; ++i)
00204     {
00205       for (int j = 0; j < width; ++j, --Jp, --Ip)
00206         {
00207           // point-wise minimum between max(p U Ng-(p)) and Ip
00208           maximum = *Jp;
00209 
00210           // after the first line
00211           if (i != 0)
00212             {
00213               // first pixel
00214               if (j == 0)
00215                 {
00216                   Jq = Jp + width;
00217                   if (maximum < *Jq)
00218                     {
00219                       maximum = *Jq;
00220                     }
00221 
00222                   --Jq;
00223                   if (maximum < *Jq)
00224                     {
00225                       maximum = *Jq;
00226                     }
00227 
00228                   *Jp = (maximum < *Ip ? maximum : *Ip);
00229                   Jq = Jp + width;
00230                   Iq = Ip + width;
00231                   if ((*Jq < *Jp) && (*Jq < *Iq))
00232                     {
00233                       boundary.push(Jp - markerPixMap);
00234                     }
00235                   else
00236                     {
00237                       --Iq;
00238                       --Iq;
00239                       if ((*Jq < *Jp) && (*Jq < *Iq))
00240                         {
00241                           boundary.push(Jp - markerPixMap);
00242                         }
00243                     }
00244                 } // END first pixel
00245 
00246               // last pixel
00247               else if (j == width - 1)
00248                 {
00249                   Jq = Jp + 1;
00250                   if (maximum < *Jq)
00251                     {
00252                       maximum = *Jq;
00253                     }
00254 
00255                   Jq += width;
00256                   if (maximum < *Jq)
00257                     {
00258                       maximum = *Jq;
00259                     }
00260 
00261                   --Jq;
00262                   if (maximum < *Jq)
00263                     {
00264                       maximum = *Jq; 
00265                     }
00266 
00267                   *Jp = (maximum < *Ip ? maximum : *Ip);
00268                   Jq = Jp + 1;
00269                   Iq = Ip + 1;
00270                   if ((*Jq < *Jp) && (*Jq < *Iq))
00271                     {
00272                       boundary.push(Jp - markerPixMap);
00273                     }
00274                   else
00275                     {
00276                       Iq += width;
00277                       Iq += width;
00278                       if ((*Jq < *Jp) && (*Jq < *Iq))
00279                         {
00280                           boundary.push(Jp - markerPixMap);
00281                         }
00282                       else
00283                         {
00284                           Iq--;
00285                           Iq--;
00286                           if ((*Jq < *Jp) && (*Jq < *Iq))
00287                             {
00288                               boundary.push(Jp - markerPixMap);
00289                             }
00290                         }
00291                     }
00292                 } // END last pixel
00293 
00294               // between these two pixels
00295               else
00296                 {
00297                   for (int k = 1; k > -1; --k)
00298                     {
00299                       for (int l = 1 ; l > -(1 + k); --l)
00300                         {
00301                           Jq = Jp + k*width + l;
00302                           if (maximum < *Jq)
00303                             {
00304                               maximum = *Jq;
00305                             }
00306                         } // END for l
00307                     } // END for k
00308 
00309                   *Jp = (maximum < *Ip ? maximum : *Ip);
00310                   for (int k = 1; k > -1; --k)
00311                     {
00312                       for (int l = 1 ; l > -(1 + k); --l)
00313                         {
00314                           indice = k*width + l;
00315                           Jq = Jp + indice;
00316                           Iq = Ip + indice;
00317                           if ((*Jq < *Jp) && (*Jq < *Iq))
00318                             {
00319                               boundary.push(Jp - markerPixMap);
00320                               // -------------------------------------------
00321                               // HORROR!  HORROR!  HORROR!  HORROR!  HORROR!
00322                               // -------------------------------------------
00323                               k = -1;
00324                               break;
00325                               // -------------------------------------------
00326                             }
00327                         } // END for l
00328                     } // END for k
00329                 }
00330             } // END if i
00331 
00332           else if (j > 0)
00333             {
00334               Jq = Jp + 1;
00335               if (maximum < *Jq) maximum = *Jq;
00336               *Jp = (maximum < *Ip ? maximum : *Ip);
00337               Iq = Ip + 1;
00338               if ((*Jq < *Jp) && (*Jq < *Iq))
00339                 {
00340                   boundary.push(Jp - markerPixMap);
00341                 }
00342             }
00343           else
00344             {
00345               *Jp = (maximum < *Ip ? maximum : *Ip);
00346             }
00347         } // END for j
00348     } // END for i (end of scan)
00349   
00350   /*** propagation ***/
00351 
00352   while (!boundary.empty())
00353     {
00354       indice = boundary.front();
00355       boundary.pop();
00356 
00357       Jp = markerPixMap + indice;
00358       Ip = goalPixMap + indice;
00359 
00360       /*** definition of current pixel's neighborhood ***/
00361 
00362       // between the first and the last line
00363       if ( (Jp > markerPixMap + width - 1) && 
00364            (Jp < markerPixMap + (height - 1)*width) )
00365         {
00366           minK = -1;
00367           maxK = 2;
00368 
00369           // first pixel
00370           if ((Jp - markerPixMap) % width == 0)
00371             {
00372               minL = 0;
00373               maxL = 2;
00374             }
00375           // last pixel
00376           else if ((Jp - markerPixMap) % width == width - 1)
00377             {
00378               minL = -1;
00379               maxL = 1;
00380             }
00381           // between these two pixels
00382           else
00383             {
00384               minL = -1;
00385               maxL = 2;
00386             }
00387         }
00388 
00389       // first pixel
00390       else if (Jp == markerPixMap)
00391         {
00392           minK = minL = 0;
00393           maxK = maxL = 2;
00394         }
00395 
00396       // before last pixel of first line
00397       else if (Jp < markerPixMap + width - 1)
00398         {
00399           minK = 0;
00400           minL = -1;
00401           maxK = maxL = 2;
00402         }
00403 
00404       // last pixel of first line
00405       else if (Jp ==  markerPixMap + width - 1)
00406         {
00407           minK = 0;
00408           minL = -1;
00409           maxK = 2;
00410           maxL = 1;
00411         }
00412 
00413       // first pixel of last line
00414       else if (Jp == markerPixMap + (height - 1)*width)
00415         {
00416           minK = -1;
00417           minL = 0;
00418           maxK = 1;
00419           maxL = 2;
00420         }
00421 
00422       // before last pixel of last line
00423       else if (Jp < markerPixMap + height*width - 1)
00424         {
00425           minK = minL = -1;
00426           maxL = 2;
00427           maxK = 1;
00428         }
00429 
00430       // last pixel
00431       else
00432         {
00433           minL = minK = -1;
00434           maxL = maxK = 1;
00435         }
00436         
00437       for (int k = minK; k < maxK; ++k)
00438         {
00439           for (int l = minL ; l < maxL; ++l)
00440             {
00441               indice = k*width + l;
00442               Jq = Jp + indice;
00443               Iq = Ip + indice;
00444               if ( (*Jq < *Jp) && (*Iq != *Jq) )
00445                 {
00446                   *Jq = (*Jp < *Iq ? *Jp : *Iq);
00447                   boundary.push(Jq - markerPixMap);
00448                 }
00449             } // END for l
00450         } // END for k
00451 
00452   } // END while (end of propagation)
00453 }
00454 
00455 // ----------------------------------------------------------------------
00456 
00457 } // namespace qgar