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

LinErodedImage.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  LinErodedImage.C
00030  * @brief Implementation of class qgar::LinErodedImage.
00031  *
00032  *        See file LinErodedImage.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  17:16
00036  * @since  Qgar 2.0
00037  */
00038 
00039 
00040 
00041 // STD
00042 #include <algorithm>
00043 #include <sstream>
00044 // QGAR
00045 #include <qgarlib/GenImage.H>
00046 #include <qgarlib/LinErodedImage.H>
00047 #include <qgarlib/QgarErrorDomain.H>
00048 
00049 
00050 
00051 using namespace std;
00052 
00053 
00054 namespace qgar
00055 {
00056 
00057 // -------------------------------------------------------------------
00058 // C O N S T R U C T O R
00059 // -------------------------------------------------------------------
00060 
00061 LinErodedImage::LinErodedImage(GreyLevelImage& anImg,
00062                                QGEorientation anOrient,
00063                                unsigned int anEroSize)
00064 
00065   throw(QgarErrorDomain)
00066 
00067   : GreyLevelImage(anImg)
00068 
00069 {
00070   perform(this, anOrient, anEroSize);
00071 }
00072 
00073 // -------------------------------------------------------------------
00074 // O R I E N T E D    E R O S I O N S
00075 // -------------------------------------------------------------------
00076 
00077 // DISPATCHING
00078 
00079 void LinErodedImage::perform(GreyLevelImage* anImg,
00080                              QGEorientation anOrient,
00081                              unsigned int anEroSize)
00082 {
00083   switch (anOrient)
00084     {
00085     case QGE_ORIENTATION_HOR:
00086       erodeHor(anImg, anEroSize);
00087       break;
00088     case QGE_ORIENTATION_VER:
00089       erodeVer(anImg, anEroSize);
00090       break;
00091     case QGE_ORIENTATION_DIAG_POS:
00092       erodePdiag(anImg, anEroSize);
00093       break;
00094     case QGE_ORIENTATION_DIAG_NEG:
00095       erodeNdiag(anImg, anEroSize);
00096       break;
00097     case QGE_ORIENTATION_ALL:
00098       erodeAll(anImg, anEroSize);
00099     }
00100 }
00101 
00102 // -------------------------------------------------------------------
00103 // HORIZONTAL EROSION
00104 
00105 void LinErodedImage::erodeHor(GreyLevelImage* anImg,
00106                               unsigned int anEroSize)
00107 
00108   throw(QgarErrorDomain)
00109 
00110 {
00111   int linsize = (2 * anEroSize) + 1;  // Size of erosion segment
00112   int width   = anImg->width();
00113   int height  = anImg->height();
00114   
00115   if (linsize > width)
00116     {
00117       std::ostringstream os;
00118       os << "Horizontal erosion size ["
00119          << anEroSize
00120          << " -> "
00121          << linsize
00122          << "] too large for image ["
00123          << width
00124          << " X "
00125          << height
00126          << "]";
00127       throw QgarErrorDomain(__FILE__, __LINE__,
00128                             "void qgar::LinErodedImage::erodeHor(qgar::GreyLevelImage*, unsigned int)",
00129                             os.str());
00130     }
00131   
00132   // Allocate a table for left propagated minimums
00133   GreyLevelImage::value_type* outRow = new GreyLevelImage::value_type [width];
00134   
00135   GreyLevelImage::value_type* pOutRow; // pointer on minimum's table
00136   GreyLevelImage::value_type* inRow;   // pointers on current row
00137   GreyLevelImage::value_type* pInRow;
00138 
00139   int l = 0;   // current line number
00140  
00141   // if width % linsize isn't equal to zero, we have to
00142   // simulate missing pixels at the end of each line
00143 
00144   int overPixels = width % linsize; // pixels in excess
00145 
00146   // and now we can process through each line
00147 
00148   for (; l < height; l++) {
00149       
00150     GreyLevelImage::value_type minimum = 0; // current local minimum
00151     int firstPixel; // first pixel number in current window
00152     int window; // the window of linsize pixels
00153       
00154     
00155     /*** propagation of minimums to the left ***/
00156     
00157     pInRow = anImg->pRow(l) + width - 1 - overPixels;
00158     pOutRow = outRow + width - 1 - overPixels;
00159     
00160     for ( firstPixel = overPixels; 
00161           firstPixel < width;
00162           firstPixel += linsize)
00163       {
00164         *pOutRow = *pInRow--;
00165         minimum = *pOutRow--;
00166 
00167         for (window = 1; 
00168              window < linsize ; 
00169              window++, pInRow--)
00170           {
00171             if (minimum > *pInRow)
00172               {
00173                 minimum = *pInRow;
00174               }
00175             *pOutRow-- = minimum;
00176           }
00177       }
00178 
00179     // correction of the last overPixels if needed
00180     
00181     if (overPixels)
00182       {      
00183         pInRow = anImg->pRow(l) + width - 1;
00184         pOutRow = outRow + width - 1;
00185         *pOutRow = *pInRow--;
00186         minimum = *pOutRow--;
00187       
00188         for (firstPixel = 1; 
00189              firstPixel < linsize; 
00190              firstPixel++, pInRow--)
00191           {
00192             if (minimum > *pInRow)
00193               {
00194                 minimum = *pInRow;
00195               }
00196             *pOutRow-- = minimum;
00197           }
00198     }
00199       
00200     /*** propagation of minimums to the right, ***/ 
00201     /***   with direct computation of result.  ***/
00202 
00203     // first sequence:
00204 
00205     // we keep the first anEroSize pixels
00206     pInRow = anImg->pRow(l);
00207     inRow = pInRow + anEroSize;
00208 
00209     pOutRow = outRow;
00210 
00211     for ( firstPixel = 0, minimum = *pInRow; 
00212           firstPixel < (int)anEroSize; 
00213           firstPixel++, pInRow++) {
00214       if (minimum > *pInRow) minimum = *pInRow;
00215     }
00216 
00217     for ( firstPixel++; 
00218           firstPixel < linsize;
00219           firstPixel++, pInRow++) {
00220       if (minimum > *pInRow) minimum = *pInRow;
00221     }
00222 
00223     // the first result...
00224     if (minimum > *pInRow) minimum = *pInRow;
00225     pOutRow++;
00226     pInRow++;
00227     *inRow++ = minimum;
00228            
00229       
00230     // first sequence complete, now we can run the process
00231     for ( ;
00232           firstPixel < width - overPixels;
00233           firstPixel += linsize) {
00234       minimum = *pInRow++;
00235       *inRow = (*pOutRow > minimum ? minimum : *pOutRow);
00236       inRow++;
00237       pOutRow++;
00238         
00239       for ( window = 1; 
00240             window < linsize; 
00241             window++, pInRow++, pOutRow++, inRow++){
00242         if (minimum > *pInRow) minimum = *pInRow;
00243         *inRow = (*pOutRow > minimum ? minimum : *pOutRow);
00244       }
00245     }
00246       
00247     // we have to do the overPixels...
00248       
00249     if (overPixels) {
00250         
00251       for ( minimum = *pInRow;
00252             firstPixel < width;
00253             firstPixel++, pInRow++, pOutRow++, inRow++) {
00254         if (minimum > *pInRow) minimum = *pInRow;
00255         *inRow = (*pOutRow > minimum ? minimum : *pOutRow);
00256       }
00257     }
00258   }
00259   
00260   // Clean up
00261   delete [] outRow;
00262 
00263 }
00264 
00265 // -------------------------------------------------------------------
00266 // VERTICAL EROSION
00267 
00268 void LinErodedImage::erodeVer(GreyLevelImage* anImg,
00269                               unsigned int anEroSize)
00270 
00271   throw(QgarErrorDomain)
00272 
00273 {
00274   int linsize = 2*anEroSize + 1;  // size of segment
00275   int width   = anImg->width();
00276   int height  = anImg->height();
00277   
00278   if (linsize > height)
00279     {
00280       std::ostringstream os;
00281       os << "Vertical erosion size ["
00282          << anEroSize
00283          << " -> "
00284          << linsize
00285          << "] too large for image ["
00286          << width
00287          << " X "
00288          << height
00289          << "]";
00290       throw QgarErrorDomain(__FILE__, __LINE__,
00291                             "void qgar::LinErodedImage::erodeVer(qgar::GreyLevelImage*, unsigned int)",
00292                             os.str());
00293     }
00294 
00295   // Allocate a table for left propagated minimums
00296   GreyLevelImage::value_type* outRow = new GreyLevelImage::value_type [height];
00297   
00298   GreyLevelImage::value_type* pOutRow; // pointer on minimum's table
00299 
00300   GreyLevelImage::value_type* inRow;
00301   GreyLevelImage::value_type* pInRow; // pointers on current row
00302 
00303   int l = 0;   // current line number
00304  
00305   // if width % linsize isn't equal to zero, we have to
00306   // simulate missing pixels at the end of each line
00307 
00308   int overPixels = height % linsize; // pixels in excess
00309   
00310   // and now we can process through each line
00311 
00312   for (; l < width ; l++) {
00313       
00314     GreyLevelImage::value_type minimum = 0; // current local minimum
00315     int firstPixel; // first pixel number in current window
00316     int window; // the window of linsize pixels
00317          
00318  
00319     /*** propagation of minimums to the left ***/
00320     
00321     pInRow = anImg->pColumn(l) + width * (height - 1 - overPixels);
00322     pOutRow = outRow + height - 1 - overPixels;
00323     
00324     for ( firstPixel = overPixels; 
00325           firstPixel < height;
00326           firstPixel += linsize) {    
00327 
00328       *pOutRow = *pInRow;
00329       pInRow -= width;
00330       minimum = *pOutRow--;
00331 
00332       for ( window = 1; 
00333             window < linsize; 
00334             window++, pInRow -= width) {
00335         if (minimum > *pInRow) minimum = *pInRow;
00336         *pOutRow-- = minimum;
00337       }
00338     }
00339 
00340     // correction of the last overPixels if needed
00341     
00342     if (overPixels) {
00343       
00344       pInRow = anImg->pColumn(l) + width * (height - 1);
00345       pOutRow = outRow + height - 1;
00346       *pOutRow = *pInRow;
00347       pInRow -= width;
00348       minimum = *pOutRow--;
00349       
00350       for ( firstPixel = 1; 
00351             firstPixel < linsize; 
00352             firstPixel++, pInRow -= width) {
00353         if (minimum > *pInRow) minimum = *pInRow;
00354         *pOutRow-- = minimum;
00355       }
00356     }
00357       
00358 
00359     /*** propagation of minimums to the right, ***/ 
00360     /***   with direct computation of result.  ***/
00361 
00362     
00363     // first sequence:
00364 
00365     // we keep the first anEroSize pixels
00366     pInRow = anImg->pColumn(l);
00367     inRow = pInRow + anEroSize * width;
00368 
00369     pOutRow = outRow;
00370 
00371     for ( firstPixel = 0, minimum = *pInRow; 
00372           firstPixel < (int)anEroSize; 
00373           firstPixel++, pInRow += width) {
00374       if (minimum > *pInRow) minimum = *pInRow;
00375     }    
00376     
00377     for ( firstPixel++; 
00378           firstPixel < linsize;
00379           firstPixel++, pInRow += width) {
00380       if (minimum > *pInRow) minimum = *pInRow;
00381     }    
00382 
00383     
00384     // the first result...
00385     if (minimum > *pInRow) minimum = *pInRow;
00386     pOutRow++;
00387     pInRow += width;
00388     *inRow = minimum;
00389     inRow += width;
00390   
00391     
00392   
00393     // first sequence complete, now we can run the process
00394     for ( ;
00395           firstPixel < height - overPixels;
00396           firstPixel += linsize) {
00397       
00398       minimum = *pInRow;
00399       pInRow += width;
00400       *inRow = (*pOutRow > minimum ? minimum : *pOutRow);
00401       inRow += width;
00402       *pOutRow++;
00403 
00404       for ( window = 1; 
00405             window < linsize; 
00406             window++, pInRow += width, pOutRow++, inRow += width){
00407         if (minimum > *pInRow) minimum = *pInRow;
00408         *inRow = (*pOutRow > minimum ? minimum : *pOutRow);
00409       }
00410     }
00411     
00412     // we have to do the overPixels...
00413     
00414     if (overPixels) {
00415 
00416       for ( minimum = *pInRow;
00417             firstPixel < height;
00418             firstPixel++, pInRow += width, pOutRow++, inRow += width) {
00419         if (minimum > *pInRow) minimum = *pInRow;
00420         *inRow = (*pOutRow > minimum ? minimum : *pOutRow);
00421       }
00422     }
00423   }
00424 
00425   // Clean up
00426   delete [] outRow;
00427    
00428 }
00429 
00430 // -------------------------------------------------------------------
00431 // NE-SW EROSION
00432 
00433 void LinErodedImage::erodePdiag(GreyLevelImage* anImg,
00434                                 unsigned int anEroSize)
00435 
00436   throw(QgarErrorDomain)
00437 
00438 {
00439   int linsize = (2 * anEroSize) + 1;  // size of segment
00440   int width   = anImg->width();
00441   int height  = anImg->height();
00442   
00443   int diagSize = (2 * linsize) / 3;
00444   if ((diagSize > height) || (diagSize > width))
00445     {
00446       std::ostringstream os;
00447       os << "NE-SW erosion size ["
00448          << anEroSize
00449          << " -> "
00450          << linsize
00451          << "] too large for image ["
00452          << width
00453          << " X "
00454          << height
00455          << "]";
00456       throw QgarErrorDomain(__FILE__, __LINE__,
00457                             "void qgar::LinErodedImage::erodePDiag(qgar::GreyLevelImage*, unsigned int)",
00458                             os.str());
00459     }
00460   
00461   int i = (width > height ? width : height);
00462 
00463   // Allocate a table for left propagated maximums
00464   GreyLevelImage::value_type* outRow = new GreyLevelImage::value_type [i];
00465 
00466   // Allocate a table for current line
00467   GreyLevelImage::value_type* diagRow = new GreyLevelImage::value_type [i];
00468   
00469   GreyLevelImage::value_type* pOutRow; // pointer on maximum's table
00470 
00471   GreyLevelImage::value_type* inRow;
00472   GreyLevelImage::value_type* pInRow;  // pointers on current row
00473 
00474   // the last line of image
00475   GreyLevelImage::value_type* end = anImg->pRow(height - 1) + 1;
00476 
00477   int l = linsize;   // current line number
00478 
00479   int length; // current line size
00480  
00481   // if width % linsize isn't equal to zero, we have to
00482   // simulate missing pixels at the end of each line
00483 
00484   int overPixels;
00485       
00486   GreyLevelImage::value_type minimum = 0; // current local minimum
00487   int firstPixel; // first pixel number in current window
00488   int window; // the window of linsize pixels
00489 
00490   // and now we can process through each line
00491 
00492   for (; l < height + width - 1 - linsize; l++) {
00493     
00494     if (l < height) {
00495       inRow = anImg->pRow(l);
00496       length = (width > l + 1 ? l + 1 : width);
00497     }
00498     else {
00499       inRow = end;
00500       i = width - l + height - 1;
00501       length = (i > height ? height : i);
00502     }
00503 
00504     pInRow = diagRow;
00505 
00506     // load the current line
00507     for (i = 0 ; i < length; i++) {
00508       *pInRow++ = *inRow;
00509       inRow -= (width - 1);
00510     }
00511 
00512 
00513     overPixels = length % linsize; // pixels in excess
00514       
00515     
00516     /*** propagation of minimums to the left ***/
00517     
00518     pInRow = diagRow + length - 1 - overPixels;
00519     pOutRow = outRow + length - 1 - overPixels;
00520     
00521     for ( firstPixel = overPixels; 
00522           firstPixel < length;
00523           firstPixel += linsize) {
00524 
00525       *pOutRow = *pInRow--;
00526       minimum = *pOutRow--;
00527 
00528       for (window = 1; 
00529            window < linsize ; 
00530            window++, pInRow--) {
00531         if (minimum > *pInRow) minimum = *pInRow;
00532         *pOutRow-- = minimum;
00533       }
00534     }
00535 
00536     // correction of the last overPixels if needed
00537     
00538     if (overPixels) {
00539       
00540       pInRow = diagRow + length - 1;
00541       pOutRow = outRow + length - 1;
00542       *pOutRow = *pInRow--;
00543       minimum = *pOutRow--;
00544       
00545       for ( firstPixel = 1; 
00546             firstPixel < linsize; 
00547             firstPixel++, pInRow--) {
00548         if (minimum > *pInRow) minimum = *pInRow;
00549         *pOutRow-- = minimum;
00550       }
00551     }
00552       
00553 
00554     /*** propagation of minimums to the right, ***/ 
00555     /***   with direct computation of result.  ***/
00556 
00557 
00558     // first sequence:
00559 
00560     // we keep the first anEroSize pixels
00561     pInRow = diagRow;
00562     inRow = pInRow + anEroSize;
00563 
00564     pOutRow = outRow;
00565 
00566     for ( firstPixel = 0, minimum = *pInRow; 
00567           firstPixel < (int)anEroSize; 
00568           firstPixel++, pInRow++) {
00569       if (minimum > *pInRow) minimum = *pInRow;
00570     }
00571 
00572     for ( firstPixel++; 
00573           firstPixel < linsize;
00574           firstPixel++, pInRow++) {
00575       if (minimum > *pInRow) minimum = *pInRow;
00576     }
00577 
00578     // the first result...
00579     if (minimum > *pInRow) minimum = *pInRow;
00580     pOutRow++;
00581     pInRow++;
00582     *inRow++ = minimum;
00583            
00584       
00585     // first sequence complete, now we can run the process
00586     for ( ;
00587           firstPixel < length - overPixels;
00588           firstPixel += linsize) {
00589       minimum = *pInRow++;
00590       *inRow = (*pOutRow > minimum ? minimum : *pOutRow);
00591       inRow++;
00592       pOutRow++;
00593         
00594       for ( window = 1; 
00595             window < linsize; 
00596             window++, pInRow++, pOutRow++, inRow++){
00597         if (minimum > *pInRow) minimum = *pInRow;
00598         *inRow = (*pOutRow > minimum ? minimum : *pOutRow);
00599       }
00600     }
00601       
00602     // we have to do the overPixels...
00603       
00604     if (overPixels) {
00605         
00606       for ( minimum = *pInRow;
00607             firstPixel < length;
00608             firstPixel++, pInRow++, pOutRow++, inRow++) {
00609         if (minimum > *pInRow) minimum = *pInRow;
00610         *inRow = (*pOutRow > minimum ? minimum : *pOutRow);
00611       }
00612     }
00613 
00614     // save the current line
00615     if (l < height) inRow = anImg->pRow(l);
00616     else inRow = end++;
00617 
00618     pInRow = diagRow;
00619  
00620     for (i = 0 ; i < length ; i++) {
00621       *inRow = *pInRow++;
00622       inRow -= (width - 1);
00623     }
00624     
00625 
00626   }
00627   
00628   // Clean up
00629   delete [] outRow;
00630   delete [] diagRow;
00631 }
00632 
00633 // -------------------------------------------------------------------
00634 // NW-SE EROSION
00635 
00636 void LinErodedImage::erodeNdiag(GreyLevelImage* anImg,
00637                                 unsigned int anEroSize)
00638 
00639   throw(QgarErrorDomain)
00640 
00641 {
00642   int linsize = 2*anEroSize + 1;  // size of segment
00643   int width   = anImg->width();
00644   int height  = anImg->height();
00645   
00646   int diagSize = (2 * linsize) / 3;
00647   if ((diagSize > height) || (diagSize > width))
00648     {
00649       std::ostringstream os;
00650       os << "NW-SE erosion size ["
00651          << anEroSize
00652          << " -> "
00653          << linsize
00654          << "] too large for image ["
00655          << width
00656          << " X "
00657          << height
00658          << "]";
00659       throw QgarErrorDomain(__FILE__, __LINE__,
00660                             "void qgar::LinErodedImage::erodeNDiag(qgar::GreyLevelImage*, unsigned int)",
00661                             os.str());
00662     }
00663   
00664   int i = (width > height ? width : height);
00665 
00666   // Allocate a table for left propagated minimums
00667   GreyLevelImage::value_type* outRow = new GreyLevelImage::value_type [i];
00668 
00669   // Allocate a table for current line
00670   GreyLevelImage::value_type* diagRow = new GreyLevelImage::value_type [i];
00671   
00672   GreyLevelImage::value_type* pOutRow; // pointer on minimum's table
00673 
00674   GreyLevelImage::value_type* inRow;
00675   GreyLevelImage::value_type* pInRow;  // pointers on current row
00676 
00677   // the first line of image
00678   GreyLevelImage::value_type* first = anImg->pRow(1) - linsize - 1;
00679 
00680   int l = linsize;   // current line number
00681 
00682   int length; // current line size
00683  
00684   // if width % linsize isn't equal to zero, we have to
00685   // simulate missing pixels at the end of each line
00686 
00687   int overPixels;
00688       
00689   GreyLevelImage::value_type minimum = 0; // current local minimum
00690   int firstPixel; // first pixel number in current window
00691   int window; // the window of linsize pixels
00692 
00693   // and now we can process through each line
00694 
00695   for (; l < height + width - 1 - linsize; l++) {
00696     
00697     if (l < width) {
00698       inRow = first;
00699       length = (l + 1 > height ? height : l + 1);
00700     }
00701     else {
00702       inRow = anImg->pRow(l - width + 1);
00703       i = height - (l - width + 1);
00704       length = (i > width ? width : i);
00705     }
00706 
00707     pInRow = diagRow;
00708 
00709     // load the current line
00710     for (i = 0 ; i < length; i++) {
00711       *pInRow++ = *inRow;
00712       inRow += (width + 1);
00713     }
00714   
00715     overPixels = length % linsize; // pixels in excess
00716       
00717     
00718     /*** propagation of minimums to the left ***/
00719     
00720     pInRow = diagRow + length - 1 - overPixels;
00721     pOutRow = outRow + length - 1 - overPixels;
00722     
00723     for ( firstPixel = overPixels; 
00724           firstPixel < length;
00725           firstPixel += linsize) {
00726 
00727       *pOutRow = *pInRow--;
00728       minimum = *pOutRow--;
00729 
00730       for (window = 1; 
00731            window < linsize ; 
00732            window++, pInRow--) {
00733         if (minimum > *pInRow) minimum = *pInRow;
00734         *pOutRow-- = minimum;
00735       }
00736     }
00737 
00738     // correction of the last overPixels if needed
00739     
00740     if (overPixels) {
00741       
00742       pInRow = diagRow + length - 1;
00743       pOutRow = outRow + length - 1;
00744       *pOutRow = *pInRow--;
00745       minimum = *pOutRow--;
00746       
00747       for ( firstPixel = 1; 
00748             firstPixel < linsize; 
00749             firstPixel++, pInRow--) {
00750         if (minimum > *pInRow) minimum = *pInRow;
00751         *pOutRow-- = minimum;
00752       }
00753     }
00754       
00755 
00756     /*** propagation of minimums to the right, ***/ 
00757     /***   with direct computation of result.  ***/
00758 
00759 
00760     // first sequence:
00761 
00762     // we keep the first anEroSize pixels
00763     pInRow = diagRow;
00764     inRow = pInRow + anEroSize;
00765 
00766     pOutRow = outRow;
00767 
00768     for ( firstPixel = 0, minimum = *pInRow; 
00769           firstPixel < (int)anEroSize; 
00770           firstPixel++, pInRow++) {
00771       if (minimum > *pInRow) minimum = *pInRow;
00772     }
00773 
00774     for ( firstPixel++; 
00775           firstPixel < linsize;
00776           firstPixel++, pInRow++) {
00777       if (minimum > *pInRow) minimum = *pInRow;
00778     }
00779 
00780     // the first result...
00781     if (minimum > *pInRow) minimum = *pInRow;
00782     pOutRow++;
00783     pInRow++;
00784     *inRow++ = minimum;
00785            
00786       
00787     // first sequence complete, now we can run the process
00788     for ( ;
00789           firstPixel < length - overPixels;
00790           firstPixel += linsize) {
00791       minimum = *pInRow++;
00792       *inRow = (*pOutRow > minimum ? minimum : *pOutRow);
00793       inRow++;
00794       pOutRow++;
00795         
00796       for ( window = 1; 
00797             window < linsize; 
00798             window++, pInRow++, pOutRow++, inRow++){
00799         if (minimum > *pInRow) minimum = *pInRow;
00800         *inRow = (*pOutRow > minimum ? minimum : *pOutRow);
00801       }
00802     }
00803       
00804     // we have to do the overPixels...
00805       
00806     if (overPixels) {
00807         
00808       for ( minimum = *pInRow;
00809             firstPixel < length;
00810             firstPixel++, pInRow++, pOutRow++, inRow++) {
00811         if (minimum > *pInRow) minimum = *pInRow;
00812         *inRow = (*pOutRow > minimum ? minimum : *pOutRow);
00813       }
00814     }
00815 
00816     // save the current line
00817     
00818     if (l < width) inRow = first--;
00819     else inRow = anImg->pRow(l - width + 1);
00820    
00821     pInRow = diagRow;
00822 
00823     for (i = 0 ; i < length ; i++) {
00824       *inRow = *pInRow++;
00825       inRow += (width + 1);
00826     }
00827 
00828   }
00829 
00830   // Clean up
00831   delete [] outRow;
00832   delete [] diagRow;
00833 }
00834 
00835 // -------------------------------------------------------------------
00836 // ALL-ORIENTATIONS DILATION
00837 
00838 void LinErodedImage::erodeAll(GreyLevelImage* anImg,
00839                                  unsigned int anEroSize)
00840 
00841   throw(QgarErrorDomain)
00842 
00843 {
00844   int linsize =  (2 * anEroSize) + 1;  // size of segment
00845   int diagSize = (2 * linsize) / 3;
00846   int width   = anImg->width();
00847   int height  = anImg->height();
00848 
00849   if ((diagSize > height) || (diagSize > width))
00850     {
00851       std::ostringstream os;
00852       os << "All-orientations erosion size ["
00853          << anEroSize
00854          << " -> "
00855          << linsize
00856          << "] too large for image ["
00857          << width
00858          << " X "
00859          << height
00860          << "]";
00861       throw QgarErrorDomain(__FILE__, __LINE__,
00862                             "void qgar::LinErodedImage::erodeAll(qgar::GreyLevelImage*, unsigned int)",
00863                             os.str());
00864     }
00865 
00866   GreyLevelImage work(*anImg);
00867 
00868   // Allocate a table for current input rows
00869   GreyLevelImage::value_type* crow = new GreyLevelImage::value_type [width * linsize];
00870 
00871   // Allocate a table for current output row
00872   GreyLevelImage::value_type* orow = new GreyLevelImage::value_type [width];
00873   
00874   GreyLevelImage::value_type* p;
00875   GreyLevelImage::value_type* q;
00876   
00877   // Now loop on all possible lines
00878 
00879   int i = 0;   // current line number in input image
00880   int l = anEroSize; // current line number in output image
00881 
00882   for ( ; l < height - (int)anEroSize ; l++, i++)
00883     {
00884       int ii = i; // current line number while loading current rows
00885 
00886       for (q = crow ; ii < i + linsize ; ii++, q += width)
00887         anImg->row(ii, q); // load rows into crow
00888 
00889       int j = anEroSize;
00890       anImg->row(l, orow); // initialize orow with old values
00891       
00892       for (p = orow + anEroSize, q = crow + anEroSize ;
00893            j < width - (int)anEroSize ; j++, q++)
00894         {
00895           // On all columns which can be processed
00896           // start with minimum for all
00897           GreyLevelImage::value_type curhoriz = 255;
00898           GreyLevelImage::value_type curverti = 255;
00899           GreyLevelImage::value_type curpdiag = 255;
00900           GreyLevelImage::value_type curndiag = 255;
00901 
00902           GreyLevelImage::value_type* sl = q;
00903           int k = 0;
00904           
00905           for ( ; k < linsize ; k++, sl += width)
00906             {
00907               if (*(sl - anEroSize + k) < curndiag)
00908                 {
00909                   curndiag = *(sl - anEroSize + k);
00910                 }
00911               if (*sl < curverti)
00912                 {
00913                   curverti = *sl;
00914                 }
00915               if (*(sl + anEroSize - k) < curpdiag)
00916                 {
00917                   curpdiag = *(sl + anEroSize - k);
00918                 }
00919               if (k == (int)anEroSize) // if we are on the medium line
00920                 {
00921                   GreyLevelImage::value_type* ssl = sl - anEroSize;
00922                   int kk = 0;
00923                   for ( ; kk < linsize ; kk++, ssl++)
00924                     {
00925                       if (*ssl < curhoriz)
00926                         {
00927                           curhoriz = *ssl;      // new minimum
00928                         }
00929                     }
00930                 }
00931             }
00932 
00933           // write result
00934           *p++ = max(max(curndiag, curpdiag), max(curhoriz, curverti));
00935         }
00936 
00937       // Save result
00938       work.setRow(l, orow);
00939     }
00940   
00941   for (i = 0; i < height; i++) {
00942     work.row(i, crow);
00943     anImg->setRow(i, crow);
00944   }
00945 
00946   // Clean up
00947   delete [] crow;
00948   delete [] orow;
00949 }
00950 
00951 // -------------------------------------------------------------------
00952 
00953 } // namespace qgar