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 | The implementation of the hysteresis algorithm is strongly inspired | 00030 | by that made by Simon A.J. Winder in the IMG* package. Here is his | 00031 | copyright notice: | 00032 | | 00033 | IMG* Image Processing Toolset and C Library | 00034 | | 00035 | Copyright 1994 Simon A.J. Winder | 00036 | All Rights Reserved | 00037 | | 00038 | Permission to use, copy, and modify this software and its | 00039 | documentation is hereby granted only under the following terms and | 00040 | conditions. Both the above copyright notice and this permission | 00041 | notice must be included along with all copies of the software, | 00042 | derivative works or modified versions, and any portions thereof, | 00043 | and both notices must appear in supporting documentation. | 00044 | | 00045 | This software may be distributed (but not offered for sale or | 00046 | transferred for compensation) to third parties, provided such third | 00047 | parties agree to abide by the terms and conditions of this notice. | 00048 | | 00049 | The software is provided "as is" and the author disclaims all | 00050 | warranties with regard to this software, including all implied | 00051 | warranties of merchantability and fitness. In no event shall the | 00052 | author be liable for any special, direct, indirect, or | 00053 | consequential damages or any damages whatsoever resulting from loss | 00054 | of use, data or profits, whether in an action of contract, | 00055 | negligence or other tortious action, arising out of or in | 00056 | connection with the use or performance of this software. | 00057 *---------------------------------------------------------------------*/ 00058 00059 00060 /** 00061 * @file HysteresisBinaryImage.C 00062 * @brief Implementation of class qgar::HysteresisBinaryImage. 00063 * 00064 * See file HysteresisBinaryImage.H for the interface. 00065 * 00066 * @author <a href="mailto:qgar-develop@loria.fr?subject=Qgar fwd Karl Tombre">Karl Tombre</a> 00067 * @date July 3, 2001 16:30 00068 * @since Qgar 1.0 00069 */ 00070 00071 00072 00073 // STD 00074 #include <stack> 00075 #include <vector> 00076 // QGAR 00077 #include <qgarlib/GradientLocalMaxImage.H> 00078 #include <qgarlib/HysteresisBinaryImage.H> 00079 #include <qgarlib/primitives.H> 00080 00081 00082 00083 using namespace std; 00084 00085 00086 00087 namespace qgar 00088 { 00089 00090 // ------------------------------------------------------------------- 00091 // C O N S T R U C T O R 00092 // ------------------------------------------------------------------- 00093 HysteresisBinaryImage::HysteresisBinaryImage 00094 (const GradientLocalMaxImage& aGradImg, 00095 unsigned int aLowThrsl, 00096 unsigned int aHighThrsl) 00097 00098 : BinaryImage(aGradImg.width(), aGradImg.height()) // Allocate binary image 00099 00100 { 00101 // Stack of points 00102 stack< Point, vector<Point> > stackPt; 00103 00104 // Create two images for low and high thresholded images 00105 BinaryImage lowImg (_width, _height); 00106 BinaryImage highImg(_width, _height); 00107 00108 // Fill them with 1's and 0's 00109 int size = _width * _height; 00110 BinaryImage::value_type* pMapLow = lowImg.pPixMap(); 00111 BinaryImage::value_type* pMapHigh = highImg.pPixMap(); 00112 float* pMapGrad = aGradImg.pPixMap(); 00113 00114 for (int iCnt = 0 ; 00115 iCnt < size ; 00116 ++iCnt, ++pMapLow, ++pMapHigh, ++pMapGrad) 00117 { 00118 float pix = *pMapGrad; 00119 00120 if ((pix == 0.0) || (pix < aLowThrsl)) 00121 { 00122 (*pMapLow) = QGE_BW_WHITE; 00123 } 00124 else 00125 { 00126 (*pMapLow) = QGE_BW_BLACK; 00127 } 00128 00129 if ((pix == 0.0) || (pix < aHighThrsl)) 00130 { 00131 (*pMapHigh) = QGE_BW_WHITE; 00132 } 00133 else 00134 { 00135 (*pMapHigh) = QGE_BW_BLACK; 00136 } 00137 } 00138 00139 // highImg is seed of final result 00140 BinaryImage::operator=(highImg); 00141 00142 // Add all points on edges with a gradient lower than high but 00143 // higher than low that are connected to strong edges 00144 for (int y = 0 ; y < _height ; ++y) 00145 { 00146 for (int x = 0; x < _width ; ++x) 00147 { 00148 00149 // if we have a seed 00150 if (highImg.pixel(x, y) != QGE_BW_WHITE) 00151 { 00152 // Push starting point and clear from lowImg 00153 Point pt(x, y); 00154 stackPt.push(pt); 00155 lowImg.setPixel(x, y, QGE_BW_WHITE); 00156 00157 // Trace the line from this point 00158 while (! stackPt.empty()) 00159 { 00160 pt = stackPt.top(); 00161 stackPt.pop(); 00162 // write point to output and delete from highImg 00163 int ptX = pt.x(); 00164 int ptY = pt.y(); 00165 setPixel(ptX, ptY, QGE_BW_BLACK); 00166 00167 highImg.setPixel(ptX, ptY, QGE_BW_WHITE); 00168 00169 // Stack and delete points we want to go to next 00170 for (int yCnt = ptY - 1 ; yCnt < (ptY + 2) ; ++yCnt) 00171 { 00172 for (int xCnt = ptX - 1 ; xCnt < (ptX + 2) ; ++xCnt) 00173 { 00174 if ( (yCnt >= 0) 00175 && (yCnt < _height) 00176 && (xCnt >= 0) 00177 && (xCnt < _width) 00178 && (lowImg.pixel(xCnt, yCnt) != QGE_BW_WHITE)) 00179 { 00180 pt.setXY(xCnt, yCnt); 00181 stackPt.push(pt); 00182 lowImg.setPixel(xCnt, yCnt, QGE_BW_WHITE); 00183 } 00184 } // END for xCnt 00185 } // END for yCnt 00186 } // END while 00187 } // END if 00188 00189 } // END for x 00190 } // END for y 00191 } 00192 // ------------------------------------------------------------------- 00193 00194 } // namespace qgar