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

LinErodedBinaryImage.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  LinErodedBinaryImage.C
00030  * @brief Implementation of class qgar::LinErodedBinaryImage.
00031  *
00032  *        See file LinErodedBinaryImage.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 5, 2002  16:08
00036  * @since  Qgar 2.0
00037  */
00038 
00039 
00040 
00041 // STD
00042 #include <sstream>
00043 // STL
00044 #include <qgarlib/GenImage.H>
00045 #include <qgarlib/LinErodedBinaryImage.H>
00046 #include <qgarlib/QgarErrorDomain.H>
00047 
00048 
00049 
00050 namespace qgar
00051 {
00052 
00053 // -------------------------------------------------------------------
00054 // C O N S T R U C T O R
00055 // -------------------------------------------------------------------
00056 
00057 LinErodedBinaryImage::LinErodedBinaryImage(const BinaryImage& anImg,
00058                                            QGEorientation anOrient,
00059                                            unsigned int anEroSize)
00060 
00061   throw(QgarErrorDomain)
00062 
00063   : BinaryImage(anImg)
00064 
00065 {
00066   perform(this, anOrient, anEroSize);
00067 }
00068 
00069 
00070 // -------------------------------------------------------------------
00071 // O R I E N T E D    E R O S I O N S
00072 // -------------------------------------------------------------------
00073 
00074 // DISPATCHING
00075 
00076 void LinErodedBinaryImage::perform(BinaryImage* anImg,
00077                                    QGEorientation anOrient,
00078                                    unsigned int anEroSize)
00079 {
00080   switch (anOrient)
00081     {
00082     case QGE_ORIENTATION_HOR:
00083       erodeHor(anImg, anEroSize);
00084       break;
00085     case QGE_ORIENTATION_VER:
00086       erodeVer(anImg, anEroSize);
00087       break;
00088     case QGE_ORIENTATION_DIAG_POS:
00089       erodePdiag(anImg, anEroSize);
00090       break;
00091     case QGE_ORIENTATION_DIAG_NEG:
00092       erodeNdiag(anImg, anEroSize);
00093       break;
00094     case QGE_ORIENTATION_ALL:
00095       erodeAll(anImg, anEroSize);
00096     }
00097 }
00098 
00099 // -------------------------------------------------------------------
00100 // HORIZONTAL EROSION
00101 
00102 void LinErodedBinaryImage::erodeHor(BinaryImage* anImg,
00103                                     unsigned int anEroSize)
00104 
00105   throw(QgarErrorDomain)
00106 
00107 {
00108   int linsize = (2 * anEroSize) + 1;  // Size of erosion segment
00109   int width   = anImg->width();
00110   int height  = anImg->height();
00111   
00112   if (linsize > width)
00113     {
00114       std::ostringstream os;
00115       os << "Horizontal erosion size ["
00116          << anEroSize
00117          << " -> "
00118          << linsize
00119          << "] too large for image ["
00120          << width
00121          << " X "
00122          << height
00123          << "]";
00124       throw QgarErrorDomain(__FILE__, __LINE__,
00125                             "void qgar::LinErodedBinaryImage::erodeHor(qgar::BinaryImage*, unsigned int)",
00126                             os.str());
00127     }
00128   
00129   // pointers on current row
00130   BinaryImage::value_type* behind;
00131   BinaryImage::value_type* ahead;
00132 
00133   int mask, i, j;
00134 
00135   for (i = 0; i < height ; ++i)
00136     {
00137       behind = anImg->pRow(i);
00138       
00139       for (j = mask = 0; j < (int)anEroSize; ++j, ++behind)
00140         {
00141           if (!*behind)
00142             {
00143               mask = j + 1;
00144             }
00145         }
00146 
00147       for (ahead = behind; 
00148            (j < linsize - 1) && (j < width - (int)anEroSize - 1);
00149            ++j, ++ahead)
00150         {
00151           if (!*ahead)
00152             {
00153               mask = anEroSize + 1;
00154             }
00155           if (mask)
00156             {
00157               *ahead = 0;
00158               --mask;
00159             }
00160         }
00161         
00162       for (/* VOID */ ; j < width - (int)anEroSize ; ++j)
00163         {
00164           if (!*ahead)
00165             {
00166               mask = anEroSize + 1;
00167             }
00168 
00169           if (mask)
00170             {
00171               *behind = 0;
00172               *ahead = 0;
00173               --mask;
00174             }
00175           ++behind;
00176           ++ahead;
00177         }
00178 
00179       for (/* VOID */ ; j < width; ++j)
00180         {
00181           if (!*ahead)
00182             {
00183               mask = anEroSize + 1;
00184             }
00185 
00186           if (mask)
00187             {
00188               *behind = 0;
00189               --mask;
00190             }
00191           ++behind;
00192           ++ahead;
00193         }
00194     }
00195 }
00196 
00197 // -------------------------------------------------------------------
00198 // VERTICAL EROSION
00199 
00200 void LinErodedBinaryImage::erodeVer(BinaryImage* anImg,
00201                                       unsigned int anEroSize)
00202 
00203   throw(QgarErrorDomain)
00204 
00205 {
00206   int linsize = 2*anEroSize + 1;  // size of segment
00207   int width   = anImg->width();
00208   int height  = anImg->height();
00209   
00210   if (linsize > height)
00211     {
00212       std::ostringstream os;
00213       os << "Vertical erosion size ["
00214          << anEroSize
00215          << " -> "
00216          << linsize
00217          << "] too large for image ["
00218          << width
00219          << " X "
00220          << height
00221          << "]";
00222       throw QgarErrorDomain(__FILE__, __LINE__,
00223                             "void qgar::LinErodedBinaryImage::erodeVer(qgar::BinaryImage*, unsigned int)",
00224                             os.str());
00225     }
00226   
00227   // pointers on current row
00228   BinaryImage::value_type* behind;
00229   BinaryImage::value_type* ahead;
00230 
00231   int mask, i, j;
00232 
00233   for (i = 0; i < width; ++i)
00234     {
00235       behind = anImg->pColumn(i);
00236 
00237       for (j = mask = 0; j < (int)anEroSize; ++j, behind += width)
00238         {
00239           if (!*behind)
00240             {
00241               mask = j + 1;
00242             }
00243         }
00244 
00245     for (ahead = behind; 
00246          (j < linsize - 1) && (j < height - (int)anEroSize - 1);
00247           ++j, ahead += width)
00248       {
00249       if (!*ahead)
00250         {
00251           mask = anEroSize + 1;
00252         }
00253       if (mask)
00254         {
00255           *ahead = 0;
00256           --mask;
00257         }
00258       }
00259         
00260     for (; j < height - (int)anEroSize; ++j)
00261       {
00262         if (!*ahead)
00263           {
00264             mask = anEroSize + 1;
00265           }
00266 
00267         if (mask)
00268           {
00269             *behind = 0;
00270             *ahead = 0;
00271             --mask;
00272           }
00273         behind += width;
00274         ahead += width;
00275       }
00276 
00277     for (; j < height ; ++j)
00278       {
00279         if (!*ahead)
00280           {
00281             mask = anEroSize + 1;
00282           }
00283 
00284         if (mask)
00285           {
00286             *behind = 0;
00287             --mask;
00288           }
00289         behind += width;
00290         ahead += width;
00291       }
00292     }
00293 }
00294 
00295 // -------------------------------------------------------------------
00296 // NE-SW EROSION
00297 
00298 void
00299 LinErodedBinaryImage::erodePdiag(BinaryImage* anImg,
00300                                  unsigned int anEroSize)
00301 
00302   throw(QgarErrorDomain)
00303 
00304 {
00305   int linsize = (2 * anEroSize) + 1;  // size of segment
00306   int width   = anImg->width();
00307   int height  = anImg->height();
00308   
00309   int diagSize = (2 * linsize) / 3;
00310   if ((diagSize > height) || (diagSize > width))
00311     {
00312       std::ostringstream os;
00313       os << "NE-SW erosion size ["
00314          << anEroSize
00315          << " -> "
00316          << linsize
00317          << "] too large for image ["
00318          << width
00319          << " X "
00320          << height
00321          << "]";
00322       throw QgarErrorDomain(__FILE__, __LINE__,
00323                             "void qgar::LinErodedBinaryImage::erodePDiag(qgar::BinaryImage*, unsigned int)",
00324                             os.str());
00325     }
00326 
00327   // pointers on current row
00328   BinaryImage::value_type* behind;
00329   BinaryImage::value_type* ahead;
00330 
00331   // the last line of image
00332   BinaryImage::value_type* end = anImg->pRow(height - 1) + 1;
00333 
00334   int mask; // number of pixels to dilate
00335   int i; // current line number
00336   int j; // current pixel number in the line
00337 
00338   int length; // current line size
00339 
00340   // loop on all possible lines
00341 
00342   for (i = linsize; i < height + width - 1 - linsize; ++i)
00343     {
00344       // work directly on the line
00345     
00346       if (i < height)
00347         {
00348           behind = anImg->pRow(i);
00349           length = (width > i + 1 ? i + 1 : width);
00350         }
00351       else
00352         {
00353           behind = ++end;
00354           length = (width - i + height - 1> height ? height : width - i + height - 1);
00355         }
00356 
00357     // the first anEroSize pixels
00358       for (j = mask = 0; j < (int)anEroSize; j++, behind -= (width - 1))
00359         {
00360           // the next anEroSize pixels are function of these
00361           if (!*behind)
00362             {
00363               mask = j + 1;
00364             }
00365         }
00366 
00367       // the next anEroSize pixels
00368       for ( ahead = behind; 
00369             (j < linsize - 1) && (j < length - (int)anEroSize - 1);
00370             ++j, ahead -= (width - 1))
00371         {
00372           // a non zero implies a dilatation
00373           if (!*ahead)
00374             {
00375               mask = anEroSize + 1;
00376             }
00377           if (mask)
00378             {
00379               *ahead = 0; // dilatation at right
00380               --mask;
00381             }
00382         }
00383         
00384     // the rest of the line exect the last anEroSize
00385     for (/* VOID */ ; j < length - (int)anEroSize; ++j)
00386       {
00387         if (!*ahead)
00388           {
00389             mask = anEroSize + 1;
00390           }
00391 
00392         if (mask)
00393           {
00394             *behind = 0; // dilatation at left
00395             *ahead = 0;
00396             --mask;
00397           }
00398         behind -= (width - 1);
00399         ahead -= (width - 1);
00400       }
00401 
00402     // the last pixels
00403     for (/* VOID */ ; j < length ; ++j)
00404       {
00405         if (!*ahead)
00406           {
00407             mask = anEroSize + 1;
00408           }
00409 
00410         if (mask)
00411           {
00412             *behind = 0;
00413             --mask;
00414           }
00415         behind -= (width - 1);
00416         ahead -= (width - 1);
00417       }
00418 
00419     }
00420   
00421 }
00422 
00423 // -------------------------------------------------------------------
00424 // NW-SE EROSION
00425 
00426 void LinErodedBinaryImage::erodeNdiag(BinaryImage* anImg,
00427                                       unsigned int anEroSize)
00428 
00429   throw(QgarErrorDomain)
00430 
00431 {
00432   int linsize = 2*anEroSize + 1;  // size of segment
00433   int width   = anImg->width();
00434   int height  = anImg->height();
00435   
00436   int diagSize = (2 * linsize) / 3;
00437   if ((diagSize > height) || (diagSize > width))
00438     {
00439       std::ostringstream os;
00440       os << "NW-SE erosion size ["
00441          << anEroSize
00442          << " -> "
00443          << linsize
00444          << "] too large for image ["
00445          << width
00446          << " X "
00447          << height
00448          << "]";
00449       throw QgarErrorDomain(__FILE__, __LINE__,
00450                             "void qgar::LinErodedBinaryImage::erodeNDiag(qgar::BinaryImage*, unsigned int)",
00451                             os.str());
00452     }
00453 
00454   // pointers on current row
00455   BinaryImage::value_type* behind;
00456   BinaryImage::value_type* ahead;
00457 
00458   // the first line of image
00459   BinaryImage::value_type* first = anImg->pRow(1) - linsize;
00460 
00461   int mask; // number of pixels to dilate
00462   int i; // current line number
00463   int j; // current pixel number in the line
00464 
00465   int length; // current line size
00466 
00467   // loop on all possible lines
00468 
00469   for (i = linsize; i < height + width - 1 - linsize; ++i)
00470     {
00471       // work directly on the line
00472     
00473       if (i < width)
00474         {
00475           behind = --first;
00476           length = (i + 1 > height ? height : i + 1);
00477         }
00478       else
00479         {
00480           behind = anImg->pRow(i - width + 1);
00481           length = (height - (i - width + 1) > width ? width : height - (i - width + 1));
00482         }
00483 
00484       // the first anEroSize pixels
00485       for (j = mask = 0; j < (int)anEroSize; ++j, behind += (width + 1))
00486         {
00487           // the next anEroSize pixels are function of these
00488           if (!*behind)
00489             {
00490               mask = j + 1;
00491             }
00492         }
00493 
00494     // the next anEroSize pixels
00495       for (ahead = behind; 
00496            (j < linsize - 1) && (j < length - (int)anEroSize - 1);
00497            ++j, ahead += (width + 1))
00498         {
00499       
00500           // a non zero implies a dilatation
00501           if (!*ahead)
00502             {
00503               mask = anEroSize + 1;
00504             }
00505           if (mask)
00506             {
00507               *ahead = 0; // dilatation at right
00508               --mask;
00509             }
00510         }
00511         
00512       // the rest of the line exect the last anEroSize
00513       for (/* VOID */ ; j < length - (int)anEroSize; ++j)
00514         {
00515           if (!*ahead)
00516             {
00517               mask = anEroSize + 1;
00518             }
00519           
00520           if (mask)
00521             {
00522               *behind = 0; // dilatation at left
00523               *ahead = 0;
00524               --mask;
00525             }
00526           behind += (width + 1);
00527           ahead += (width + 1);
00528         }
00529 
00530       // the last pixels
00531       for (/* VOID */ ; j < length ; ++j)
00532         {
00533           
00534           if (!*ahead)
00535             {
00536               mask = anEroSize + 1;
00537             }
00538           
00539           if (mask)
00540             {
00541               *behind = 0;
00542               --mask;
00543             }
00544           behind += (width + 1);
00545           ahead += (width + 1);
00546         }
00547       
00548     }
00549 
00550 }
00551 
00552 // -------------------------------------------------------------------
00553 // ALL-ORIENTATIONS DILATION
00554 
00555 void
00556 LinErodedBinaryImage::erodeAll(BinaryImage* anImg,
00557                                unsigned int anEroSize)
00558 
00559   throw(QgarErrorDomain)
00560 
00561 {
00562   int linsize =  (2 * anEroSize) + 1;  // size of segment
00563   int diagSize = (2 * linsize) / 3;
00564   int width   = anImg->width();
00565   int height  = anImg->height();
00566 
00567   if ((diagSize > height) || (diagSize > width))
00568     {
00569       std::ostringstream os;
00570       os << "All-orientations erosion size ["
00571          << anEroSize
00572          << " -> "
00573          << linsize
00574          << "] too large for image ["
00575          << width
00576          << " X "
00577          << height
00578          << "]";
00579       throw QgarErrorDomain(__FILE__, __LINE__,
00580                             "void qgar::LinErodedBinaryImage::erodeAll(qgar::BinaryImage*, unsigned int)",
00581                             os.str());
00582     }
00583 
00584   BinaryImage img2(*anImg);
00585 
00586   // Allocate a table for current input rows
00587   BinaryImage::value_type* crow = new BinaryImage::value_type [width * linsize];
00588 
00589   // Allocate a table for current output row
00590   BinaryImage::value_type* orow = new BinaryImage::value_type [width];
00591   
00592   BinaryImage::value_type* p;
00593   BinaryImage::value_type* q;
00594   
00595   // Now loop on all possible lines
00596 
00597   int i = 0;   // current line number in input image
00598   int l = anEroSize; // current line number in output image
00599 
00600   for (/* VOID */ ; l < height - (int)anEroSize ; ++l, ++i)
00601     {
00602       int ii = i; // current line number while loading current rows
00603 
00604       for (q = crow ; ii < i + linsize ; ++ii, q += width)
00605         {
00606           anImg->row(ii, q); // load rows into crow
00607         }
00608 
00609       int j = anEroSize;
00610       anImg->row(l, orow); // initialize orow with old values
00611       
00612       for (p = orow + anEroSize, q = crow + anEroSize ;
00613            j < width - (int)anEroSize ; ++j, ++q)
00614         {              // On all columns which can be processed
00615           BinaryImage::value_type curhoriz = 1; // start with minimum for all
00616           BinaryImage::value_type curverti = 1;
00617           BinaryImage::value_type curpdiag = 1;
00618           BinaryImage::value_type curndiag = 1;
00619 
00620           BinaryImage::value_type* sl = q;
00621           int k = 0;
00622           
00623           for (/* VOID */ ; k < linsize ; ++k, sl += width)
00624             {
00625               if (*(sl - anEroSize + k) == 0)
00626                 {
00627                   curndiag = 0;
00628                 }
00629               if (*sl == 0)
00630                 {
00631                   curverti = 0;
00632                 }
00633               if (*(sl + anEroSize -k) == 0)
00634                 {
00635                   curpdiag = 0;
00636                 }
00637               if (k == (int)anEroSize) // if we are on the medium line
00638                 {
00639                   BinaryImage::value_type* ssl = sl - anEroSize;
00640                   int kk = 0;
00641                   for (/* VOID */ ; kk < linsize ; ++kk, ++ssl)
00642                     {
00643                       if (*ssl == 0)
00644                         {
00645                           curhoriz = 0; // found a zero
00646                           break; // no need to continue
00647                         }
00648                     } // END for kk
00649                 }
00650             } // END for k
00651 
00652           // Write result
00653           *p++ = ((curndiag == 0) && (curpdiag == 0) &&
00654                   (curhoriz == 0) && (curverti == 0)) ? 0 : 1;
00655         }
00656 
00657       // Write result
00658       img2.setRow(l, orow);
00659     }
00660 
00661   for (i = 0; i < height; ++i)
00662     {
00663       img2.row(i, orow);
00664       anImg->setRow(i, orow);
00665     }
00666 
00667   // Clean up
00668   delete [] crow;
00669   delete [] orow;
00670 }
00671 
00672 // -------------------------------------------------------------------
00673 
00674 } // namespace qgar