00001 /*!@file FeatureMatching/OriChamferMatching.C Oriented chamfer matching algs */ 00002 00003 00004 // //////////////////////////////////////////////////////////////////// // 00005 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005 // 00006 // by the University of Southern California (USC) and the iLab at USC. // 00007 // See http://iLab.usc.edu for information about this project. // 00008 // //////////////////////////////////////////////////////////////////// // 00009 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00010 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00011 // in Visual Environments, and Applications'' by Christof Koch and // 00012 // Laurent Itti, California Institute of Technology, 2001 (patent // 00013 // pending; application number 09/912,225 filed July 23, 2001; see // 00014 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00015 // //////////////////////////////////////////////////////////////////// // 00016 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00017 // // 00018 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00019 // redistribute it and/or modify it under the terms of the GNU General // 00020 // Public License as published by the Free Software Foundation; either // 00021 // version 2 of the License, or (at your option) any later version. // 00022 // // 00023 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00024 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00025 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00026 // PURPOSE. See the GNU General Public License for more details. // 00027 // // 00028 // You should have received a copy of the GNU General Public License // 00029 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00030 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00031 // Boston, MA 02111-1307 USA. // 00032 // //////////////////////////////////////////////////////////////////// // 00033 // 00034 // Primary maintainer for this file: Lior Elazary <elazary@usc.edu> 00035 // $HeadURL: $ 00036 // $Id: $ 00037 // 00038 00039 #ifndef ORICHAMFERMATCHING_C_DEFINED 00040 #define ORICHAMFERMATCHING_C_DEFINED 00041 00042 #include "FeatureMatching/OriChamferMatching.H" 00043 #include "Image/DrawOps.H" 00044 #include "Image/MathOps.H" 00045 #include "GUI/DebugWin.H" 00046 #include "Util/FastMathFunctions.H" 00047 00048 #include <stdio.h> 00049 00050 // ###################################################################### 00051 OriChamferMatching::OriChamferMatching() : 00052 itsUseOpenCV(false), 00053 itsMaxCost(100) 00054 { 00055 } 00056 00057 // ###################################################################### 00058 OriChamferMatching::OriChamferMatching(const std::vector<Line>& inLines, 00059 const int numDirections, 00060 const double oriCost, 00061 const Dims dims) : 00062 itsUseOpenCV(false), 00063 itsMaxCost(100) 00064 { 00065 setLines(inLines, numDirections, oriCost, dims); 00066 }; 00067 00068 // ###################################################################### 00069 void OriChamferMatching::setLines(const std::vector<Line>& inLines, 00070 const int numDirections, 00071 const double oriCost, 00072 const Dims dims) 00073 { 00074 itsLines = inLines; 00075 //Construct the distance transform image 00076 00077 //Build an image set with all the lines that fall in the quantized region 00078 itsOriDistImages = ImageSet<float>(numDirections, dims); 00079 00080 for(uint i=0; i<inLines.size(); i++) 00081 { 00082 Line l = inLines[i]; 00083 l.quantize(numDirections); 00084 00085 int oriIdx = l.getDirectionIdx(); 00086 if (oriIdx < 0 || oriIdx > numDirections) 00087 LFATAL("OriIdx %i is out of range %i", oriIdx, numDirections); 00088 //drawLine(itsOriDistImages[oriIdx], (Point2D<int>)l.getP1(), 00089 // (Point2D<int>)l.getP2(), (float)l.getLength()); 00090 drawLine(itsOriDistImages[oriIdx], (Point2D<int>)l.getP1(), 00091 (Point2D<int>)l.getP2(), 255.0F); 00092 } 00093 00094 //Construct the distance images 00095 for(int oriIdx = 0; oriIdx < numDirections; oriIdx++) 00096 { 00097 if (itsUseOpenCV) 00098 { 00099 Image<byte> linesImg = binaryReverse(itsOriDistImages[oriIdx], 255.0F); 00100 linesImg.deepcopy(); 00101 cvDistTransform(img2ipl(linesImg), img2ipl(itsOriDistImages[oriIdx]), CV_DIST_L2, 5); 00102 } else { 00103 //itsOriDistImages[oriIdx] = saliencyChamfer34(itsOriDistImages[oriIdx]); 00104 itsOriDistImages[oriIdx] = chamfer34(itsOriDistImages[oriIdx]); 00105 } 00106 00107 } 00108 00109 //Update the orientation costs 00110 updateOriCost(oriCost); 00111 buildIntegralDistances(); 00112 00113 //for(int oriIdx = 0; oriIdx < numDirections; oriIdx++) 00114 //{ 00115 // LINFO("oriIdx %i", oriIdx); 00116 // SHOWIMG(itsOriDistImages[oriIdx]); 00117 //} 00118 00119 }; 00120 00121 void OriChamferMatching::updateOriCost(const double oriCost) 00122 { 00123 Dims d = itsOriDistImages[0].getDims(); 00124 00125 int size=d.w()*d.h(); 00126 const int numDirections = itsOriDistImages.size(); 00127 00128 for(int k=0; k<size; k++) //For each pixel in the set 00129 { 00130 std::vector<float> costs(numDirections); 00131 //Assign the cost vector and Clamp all costs to maxCost 00132 for(uint i=0; i<costs.size(); i++) 00133 { 00134 costs[i] = itsOriDistImages[i][k]; 00135 if (costs[i] > itsMaxCost) 00136 costs[i] = itsMaxCost; 00137 } 00138 00139 //forward pass 00140 if (costs[0] > costs[numDirections-1] + oriCost) 00141 costs[0] = costs[numDirections-1] + oriCost; 00142 00143 for (int i=1 ; i<numDirections; i++) 00144 { 00145 if (costs[i] > costs[i-1] + oriCost) 00146 costs[i] = costs[i-1] + oriCost; 00147 } 00148 00149 if (costs[0] > costs[numDirections-1] + oriCost) 00150 costs[0] = costs[numDirections-1] + oriCost; 00151 00152 for (int i=1 ; i<numDirections ; i++) 00153 { 00154 if (costs[i] > costs[i-1] + oriCost) 00155 costs[i] = costs[i-1] + oriCost; 00156 else 00157 break; 00158 } 00159 00160 ////backward pass 00161 if (costs[numDirections-1] > costs[0] + oriCost) 00162 costs[numDirections-1] = costs[0] + oriCost; 00163 for (int i=numDirections-1 ; i>0 ; i--) 00164 { 00165 if (costs[i-1] > costs[i] + oriCost) 00166 costs[i-1] = costs[i] + oriCost; 00167 } 00168 00169 if (costs[numDirections-1] > costs[0] + oriCost) 00170 costs[numDirections-1] = costs[0] + oriCost; 00171 for (int i=numDirections-1 ; i>0 ; i--) 00172 { 00173 if (costs[i-1] > costs[i] + oriCost) 00174 costs[i-1] = costs[i] + oriCost; 00175 else 00176 break; 00177 } 00178 00179 //Assign the cost 00180 for (int i=0 ; i<numDirections ; i++) 00181 itsOriDistImages[i][k] = costs[i]; 00182 00183 } 00184 } 00185 00186 00187 void OriChamferMatching::buildIntegralDistances() 00188 { 00189 int numDirections = itsOriDistImages.size(); 00190 itsOriIntDistImages.resize(numDirections); 00191 00192 for(int i=0; i<numDirections; i++) 00193 { 00194 double theta = (i*M_PI)/numDirections + M_PI/(2*numDirections); 00195 //printf("Theta %f\n", theta*180/M_PI); 00196 00197 itsOriIntDistImages[i] = OriIntegralImage(itsOriDistImages[i], cos(theta), sin(theta)); 00198 } 00199 } 00200 00201 00202 OriIntegralImage::OriIntegralImage(const Image<float>& distImage, float dx, float dy) 00203 { 00204 if (fabs(dx) > fabs(dy)) 00205 { 00206 itsDS = dy / (dx + 1e-9f); 00207 itsXindexed = 1; 00208 } 00209 else 00210 { 00211 itsDS = dx / (dy + 1e-9f); 00212 itsXindexed = 0; 00213 } 00214 // Compute secant 00215 itsFactor = sqrt(itsDS*itsDS + 1); 00216 00217 //Build the indecies used to find the pixel location 00218 int width = distImage.getWidth(); 00219 int height = distImage.getHeight(); 00220 00221 if (itsXindexed) 00222 itsIndices.resize(width); 00223 else 00224 itsIndices.resize(height); 00225 00226 for(uint i=0; i<itsIndices.size(); i++) 00227 itsIndices[i] = (int)ceil(i*itsDS - 0.5); 00228 00229 itsIntegralImage = Image<float>(width, height, NO_INIT); 00230 00231 //Build the integral image 00232 for(int x=0; x<width; x++) 00233 itsIntegralImage.setVal(x,0, 0.0F); 00234 00235 for(int y=0; y<height; y++) 00236 itsIntegralImage.setVal(0,y, 0.0F); 00237 00238 00239 if (itsXindexed) 00240 { 00241 int miny=0, maxy=0; 00242 //Find the miny and maxy 00243 if (itsIndices[width-1] > 0) 00244 { 00245 miny = -itsIndices[width-1]; 00246 maxy = height; 00247 } else { 00248 miny = 0; 00249 maxy = height - itsIndices[width-1]; 00250 } 00251 00252 //Build the integral image 00253 for(int y=miny; y<=maxy; y++) 00254 for(int x=1; x<width; x++) 00255 { 00256 int py = y + itsIndices[x-1]; 00257 int cy = y + itsIndices[x]; 00258 00259 if (cy > 0 && cy < height - 1) 00260 itsIntegralImage.setVal(x, cy, 00261 itsIntegralImage.getVal(x-1,py) + itsIntegralImage.getVal(x,cy)); 00262 } 00263 } else { 00264 int minx =0, maxx = 0; 00265 //Find the minx and maxx 00266 if(itsIndices[height-1]>0) 00267 { 00268 minx = -itsIndices[height-1]; 00269 maxx = width; 00270 } else { 00271 minx = 0; 00272 maxx = width - itsIndices[height-1]; 00273 } 00274 00275 //Build the integral image 00276 for(int x=minx; x<=maxx; x++) 00277 for(int y=1; y<height; y++) 00278 { 00279 int px = x + itsIndices[y-1]; 00280 int cx = x + itsIndices[y]; 00281 00282 if (cx > 0 && cx < width - 1) 00283 itsIntegralImage.setVal(cx, y, 00284 itsIntegralImage.getVal(px, y-1) + itsIntegralImage.getVal(cx,y)); 00285 } 00286 00287 } 00288 00289 } 00290 00291 00292 00293 // ###################################################################### 00294 /* So things look consistent in everyone's emacs... */ 00295 /* Local Variables: */ 00296 /* indent-tabs-mode: nil */ 00297 /* End: */ 00298 00299 #endif 00300