00001 /*!@file Image/MorphOps.C functions for binary morphology (dilate, erode, open, close) */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005 // 00005 // by the University of Southern California (USC) and the iLab at USC. // 00006 // See http://iLab.usc.edu for information about this project. // 00007 // //////////////////////////////////////////////////////////////////// // 00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00010 // in Visual Environments, and Applications'' by Christof Koch and // 00011 // Laurent Itti, California Institute of Technology, 2001 (patent // 00012 // pending; application number 09/912,225 filed July 23, 2001; see // 00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00014 // //////////////////////////////////////////////////////////////////// // 00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00016 // // 00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00018 // redistribute it and/or modify it under the terms of the GNU General // 00019 // Public License as published by the Free Software Foundation; either // 00020 // version 2 of the License, or (at your option) any later version. // 00021 // // 00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00025 // PURPOSE. See the GNU General Public License for more details. // 00026 // // 00027 // You should have received a copy of the GNU General Public License // 00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00030 // Boston, MA 02111-1307 USA. // 00031 // //////////////////////////////////////////////////////////////////// // 00032 // 00033 // Primary maintainer for this file: Rob Peters <rjpeters at usc dot edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Image/MorphOps.C $ 00035 // $Id: MorphOps.C 9412 2008-03-10 23:10:15Z farhan $ 00036 // 00037 00038 #ifndef IMAGE_MORPHOPS_C_DEFINED 00039 #define IMAGE_MORPHOPS_C_DEFINED 00040 00041 #include "Image/MorphOps.H" 00042 00043 #include "Image/Image.H" 00044 #include "rutz/trace.h" 00045 00046 // ###################################################################### 00047 template <class T> 00048 Image<T> dilateImg(const Image<T>& img, const Image<T>& se, Point2D<int> origin) 00049 { 00050 GVX_TRACE(__PRETTY_FUNCTION__); 00051 ASSERT(img.initialized() && se.initialized()); 00052 00053 int iw = img.getWidth(); int ih = img.getHeight(); 00054 int sw = se.getWidth(); int sh = se.getHeight(); 00055 00056 if (origin == Point2D<int>(-1,-1)) 00057 { 00058 origin.i = (sw - 1) / 2; 00059 origin.j = (sh - 1) / 2; 00060 } 00061 ASSERT((origin.i < sw) && (origin.j < sh)); 00062 00063 Image<T> result(iw,ih,ZEROS); 00064 00065 typename Image<T>::const_iterator iptr, sptr1, sptr2; 00066 typename Image<T>::iterator rptr1, rptr2; 00067 iptr = img.begin(); 00068 00069 for (int iy = 0; iy < ih; ++iy) 00070 { 00071 // initialize height 00072 int rYstart = iy - origin.j; 00073 int rYend = rYstart + sh; 00074 int sYstart = 0; 00075 if (rYstart < 0) 00076 { 00077 sYstart -= rYstart; 00078 rYstart = 0; 00079 } 00080 if (rYend > ih) rYend = ih; 00081 00082 for (int ix = 0; ix < iw; ++ix) 00083 { 00084 // do we have to do anything? 00085 if (*iptr != T()) 00086 { 00087 //initialize pointers and width 00088 int rXstart = ix - origin.i; 00089 int rXend = rXstart + sw; 00090 int sXstart = 0; 00091 if (rXstart < 0) 00092 { 00093 sXstart -= rXstart; 00094 rXstart = 0; 00095 } 00096 if (rXend > iw) rXend = iw; 00097 00098 rptr1 = result.beginw() + rYstart * iw + rXstart; 00099 sptr1 = se.begin() + sYstart * sw + sXstart; 00100 00101 for (int ry = rYstart; ry < rYend; ++ry) 00102 { 00103 rptr2 = rptr1; sptr2 = sptr1; 00104 for (int rx = rXstart; rx < rXend; ++rx) 00105 { 00106 *rptr2 = std::max(*rptr2,*sptr2); 00107 ++rptr2; ++sptr2; 00108 } 00109 rptr1 += iw; sptr1 += sw; 00110 } 00111 } // end: we have to do something 00112 ++iptr; 00113 } // end: for ix 00114 } // end: for iy 00115 return result; 00116 } 00117 00118 // ###################################################################### 00119 template <class T> 00120 Image<T> erodeImg(const Image<T>& img, const Image<T>& se, Point2D<int> origin) 00121 { 00122 GVX_TRACE(__PRETTY_FUNCTION__); 00123 ASSERT(img.initialized() && se.initialized()); 00124 00125 int iw = img.getWidth(); int ih = img.getHeight(); 00126 int sw = se.getWidth(); int sh = se.getHeight(); 00127 00128 if (origin == Point2D<int>(-1,-1)) 00129 { 00130 origin.i = (sw - 1) / 2; 00131 origin.j = (sh - 1) / 2; 00132 } 00133 ASSERT((origin.i < sw) && (origin.j < sh)); 00134 00135 Image<T> result(iw,ih,ZEROS); 00136 00137 typename Image<T>::const_iterator iptr1, iptr2, sptr1, sptr2; 00138 typename Image<T>::iterator rptr = result.beginw(); 00139 T se_orig_val = se.getVal(origin); 00140 00141 //loop over result X 00142 for (int ry = 0; ry < ih; ++ry) 00143 { 00144 // initialize height 00145 int iYstart = ry - origin.j; 00146 int iYend = iYstart + sh; 00147 int sYstart = 0; 00148 if (iYstart < 0) 00149 { 00150 sYstart -= iYstart; 00151 iYstart = 0; 00152 } 00153 if (iYend > ih) iYend = ih; 00154 00155 00156 // loop over result Y 00157 for (int rx = 0; rx < iw; ++rx) 00158 { 00159 int iXstart = rx - origin.i; 00160 int iXend = iXstart + sw; 00161 int sXstart = 0; 00162 if (iXstart < 0) 00163 { 00164 sXstart -= iXstart; 00165 iXstart = 0; 00166 } 00167 if (iXend > iw) iXend = iw; 00168 00169 bool flag = true; // reset the flag 00170 iptr1 = img.begin() + iYstart * iw + iXstart; 00171 sptr1 = se.begin() + sYstart * sw + sXstart; 00172 00173 //loop over the image covered by the structuring element 00174 for (int iy = iYstart; iy < iYend; ++iy) 00175 { 00176 00177 iptr2 = iptr1; sptr2 = sptr1; 00178 for (int ix = iXstart; ix < iXend; ++ ix) 00179 { 00180 if ((*sptr2 != 0) && (*iptr2 == 0)) 00181 { 00182 flag = false; 00183 break; 00184 } // end: if (*iptr2 == 0) 00185 ++iptr2; ++sptr2; 00186 } // end: for ix 00187 00188 if (!flag) break; 00189 iptr1 += iw; sptr1 += sw; 00190 00191 } // end: for iy 00192 00193 // should we set the pixel? 00194 if (flag) *rptr = std::max(*rptr, se_orig_val); 00195 00196 ++rptr; 00197 00198 } // end: for rx 00199 } // end: for ry 00200 return result; 00201 } 00202 00203 // ###################################################################### 00204 template <class T> 00205 Image<T> openImg(const Image<T>& img, const Image<T>& se, Point2D<int> origin) 00206 { 00207 return dilateImg(erodeImg(img,se,origin),se,origin); 00208 } 00209 00210 // ###################################################################### 00211 template <class T> 00212 Image<T> closeImg(const Image<T>& img, const Image<T>& se, Point2D<int> origin) 00213 { 00214 return erodeImg(dilateImg(img,se,origin),se,origin); 00215 } 00216 00217 // Include the explicit instantiations 00218 #include "inst/Image/MorphOps.I" 00219 00220 // ###################################################################### 00221 /* So things look consistent in everyone's emacs... */ 00222 /* Local Variables: */ 00223 /* mode: c++ */ 00224 /* indent-tabs-mode: nil */ 00225 /* End: */ 00226 00227 #endif // IMAGE_MORPHOPS_C_DEFINED