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

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