00001 /*!@file BeoSub/CannyModel.C Simple shape models */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the // 00005 // 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: Zack Gossman <gossman@usc.edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/BeoSub/CannyModel.C $ 00035 // $Id: CannyModel.C 9412 2008-03-10 23:10:15Z farhan $ 00036 // 00037 00038 #include "CannyModel.H" 00039 #include "Image/DrawOps.H" 00040 #include "Image/ColorOps.H" 00041 #include "GUI/XWindow.H" 00042 #include <cmath> 00043 00044 // ###################################################################### 00045 ShapeModel::ShapeModel(const int ndims, const double thresh, 00046 double* dims, const bool debug) : 00047 itsNumDims(ndims), itsThreshold(thresh), 00048 itsDebugMode(debug), itsWindow() 00049 { 00050 00051 itsDimensions = (double*)calloc(ndims+1, sizeof(double)); 00052 for(int i = 0; i <=ndims; i++){ 00053 00054 itsDimensions[i] = dims[i]; 00055 } 00056 00057 } 00058 00059 // ###################################################################### 00060 ShapeModel::~ShapeModel() 00061 { 00062 itsWindow.reset(NULL); 00063 } 00064 00065 // ###################################################################### 00066 double ShapeModel::getThreshold() const 00067 { return itsThreshold; } 00068 00069 // ###################################################################### 00070 int ShapeModel::getNumDims() const 00071 { return itsNumDims; } 00072 00073 double* ShapeModel::getDimensions() const 00074 { 00075 double* tempDims = (double*)calloc(itsNumDims+1, sizeof(double)); 00076 for(int i = 0; i < itsNumDims; i++){ 00077 tempDims[i] = itsDimensions[i]; 00078 } 00079 00080 return itsDimensions; 00081 } 00082 00083 void ShapeModel::setDimensions(double* in) 00084 { 00085 for(int i = 0; i <=itsNumDims; i++){ 00086 itsDimensions[i] = in[i]; 00087 } 00088 } 00089 00090 // ###################################################################### 00091 float ShapeModel::getDistVal(const double x, const double y, 00092 const Image<float>& distMap, 00093 Image< PixRGB<byte> >& xdisp) const 00094 { 00095 int xx = int(x + 0.5), yy = int(y + 0.5); 00096 00097 // if we are inside the image, just get the distance from the 00098 // distance map: 00099 if (distMap.coordsOk(int(x), int(y))) 00100 { 00101 if (xdisp.initialized()) 00102 drawDisk(xdisp, Point2D<int>(xx, yy), 3, PixRGB<byte>(255, 0, 0)); 00103 float d = distMap.getValInterp(x, y); 00104 return d * d; 00105 } 00106 else 00107 { 00108 // we are outside the distance map; return an error that depends 00109 // on how far outside we are: 00110 int xerror = 0, yerror = 0; 00111 if (xx < 0) xerror = -xx; 00112 else if (xx >= distMap.getWidth()) xerror = xx - distMap.getWidth(); 00113 00114 if (yy < 0) yerror = -yy; 00115 else if (yy > distMap.getHeight()) yerror = yy - distMap.getHeight(); 00116 00117 return 10.0f * ((xerror + yerror) * (xerror + yerror));//May need a higher penalty than 10. FIX? 00118 } 00119 } 00120 00121 // ###################################################################### 00122 double ShapeModel::calcDist(double p[], const Image<float>& distMap) const 00123 { 00124 00125 // Prepare an image to draw into: 00126 Image< PixRGB<byte> > xdisp; 00127 xdisp = toRGB(Image<byte>(distMap)); 00128 00129 // if this is the first time we are called and we are in debug mode, 00130 // open an XWindow of the size of the distMap: 00131 if (itsWindow.get() == NULL && itsDebugMode == true){ 00132 const_cast<ShapeModel *>(this)-> 00133 itsWindow.reset(new XWindow(distMap.getDims())); 00134 const_cast<ShapeModel *>(this)-> 00135 itsWindow->setPosition((xdisp.getWidth()*2)+20, 0); 00136 } 00137 00138 // get the distance: 00139 double dist = getDist(p, distMap, xdisp); 00140 00141 // if we have a window, show shape and distance map: 00142 if (itsWindow.get()){ 00143 itsWindow->drawImage(xdisp); 00144 } 00145 return dist; 00146 } 00147 00148 // ###################################################################### 00149 RectangleShape::RectangleShape(const double thresh, double* dims, const bool debug) : 00150 ShapeModel(5, thresh, dims, debug) 00151 { } 00152 00153 // ###################################################################### 00154 RectangleShape::~RectangleShape() 00155 { } 00156 00157 // ###################################################################### 00158 float RectangleShape::getDist(double p[], const Image<float>& distMap, 00159 Image< PixRGB<byte> >& xdisp) const 00160 { 00161 //NEED to put in limitations keeping shape from becoming too small and keeping any part of the shape from leaving the scope of the image! FIX!! 00162 00163 // ########## Parse the parameters into human form: 00164 double x_center = p[1]; 00165 double y_center = p[2]; 00166 double alpha = p[3]; 00167 00168 double width = p[4]; 00169 double height = p[5]; 00170 00171 // ########## Trace the shape and accumulate distances: 00172 float sina = sin(alpha/10.0); 00173 float cosa = cos(alpha/10.0); 00174 int numPts = 0; 00175 float dist = 0.0; 00176 00177 // The following is code for a free-form rectangle. 00178 for (int i = -5; i < 5; i++) { 00179 // (-w/2,-h/2) -> (-w/2, h/2) 00180 float tempValX = x_center - width*cosa/2.0 - (i+1)*height*sina/10.0; 00181 float tempValY = y_center - width*sina/2.0 + (i+1)*height*cosa/10.0; 00182 dist += getDistVal(tempValX, tempValY, distMap, xdisp); 00183 numPts++; 00184 00185 // (w/2, -h/2) -> (w/2, h/2) 00186 tempValX = x_center + width*cosa/2.0 - (i+1)*height*sina/10.0; 00187 tempValY = y_center + width*sina/2.0 + (i+1)*height*cosa/10.0; 00188 dist += getDistVal(tempValX, tempValY, distMap, xdisp); 00189 numPts++; 00190 00191 // (-w/2, -h/2) -> (w/2, -h/2) 00192 tempValX = x_center + height*sina/2.0 + (i+1)*width*cosa/10.0; 00193 tempValY = y_center - height*cosa/2.0 + (i+1)*width*sina/10.0; 00194 dist += getDistVal(tempValX, tempValY, distMap, xdisp); 00195 numPts++; 00196 00197 // (-w/2, h/2) -> (w/2, h/2) 00198 tempValX = x_center - height*sina/2.0 + (i+1)*width*cosa/10.0; 00199 tempValY = y_center + height*cosa/2.0 + (i+1)*width*sina/10.0; 00200 dist += getDistVal(tempValX, tempValY, distMap, xdisp); 00201 numPts++; 00202 } 00203 00204 dist = dist / numPts; 00205 00206 // ########## Add a distance penalty if shape too small: 00207 if (width < 40) dist += (10.0*((40 - width) * (40 - width))); 00208 if (height < 30) dist += (10.0*((30 - height) * (30-height))); 00209 00210 return dist; 00211 } 00212 00213 00214 // ###################################################################### 00215 SquareShape::SquareShape(const double thresh, double* dims, const bool debug) : 00216 ShapeModel(4, thresh, dims, debug) 00217 { } 00218 00219 // ###################################################################### 00220 SquareShape::~SquareShape() 00221 { } 00222 00223 // ###################################################################### 00224 float SquareShape::getDist(double p[], const Image<float>& distMap, 00225 Image< PixRGB<byte> >& xdisp) const 00226 { 00227 // ########## Parse the parameters into human form: 00228 double x_center = p[1]; 00229 double y_center = p[2]; 00230 double alpha = p[4]; 00231 double height = p[3]; 00232 00233 // ########## Trace the shape and accumulate distances: 00234 float sina = sin(alpha/10.0); 00235 float cosa = cos(alpha/10.0); 00236 int numPts = 0; 00237 float dist = 0.0; 00238 00239 //Following is the mathematical representation of a square 00240 for(int i=-5; i<5; i++) { 00241 // (-h/2,-h/2) -> (-h/2, h/2) 00242 float tempValX = x_center - height*cosa/2 - (i+1)*height*sina/10; 00243 float tempValY = y_center - height*sina/2 + (i+1)*height*cosa/10; 00244 dist += getDistVal(tempValX, tempValY, distMap, xdisp); 00245 numPts++; 00246 00247 // (h/2, -h/2) -> (h/2, h/2) 00248 tempValX = x_center + height*cosa/2 - (i+1)*height*sina/10; 00249 tempValY = y_center + height*sina/2 + (i+1)*height*cosa/10; 00250 dist += getDistVal(tempValX, tempValY, distMap, xdisp); 00251 numPts++; 00252 00253 // (-h/2, -h/2) -> (h/2, -h/2) 00254 tempValX = x_center + height*sina/2 + (i+1)*height*cosa/10; 00255 tempValY = y_center - height*cosa/2 + (i+1)*height*sina/10; 00256 dist += getDistVal(tempValX, tempValY, distMap, xdisp); 00257 numPts++; 00258 00259 // (-h/2, h/2) -> (h/2, h/2) 00260 tempValX = x_center - height*sina/2 + (i+1)*height*cosa/10; 00261 tempValY = y_center + height*cosa/2 + (i+1)*height*sina/10; 00262 dist += getDistVal(tempValX, tempValY, distMap, xdisp); 00263 numPts++; 00264 } 00265 00266 dist = dist / numPts; 00267 00268 // ########## Add a distance penalty if shape too small: 00269 if (height < 30) dist += (10.0 * ((30 - height)*(30 - height))); 00270 00271 return dist; 00272 } 00273 00274 00275 00276 // ###################################################################### 00277 OctagonShape::OctagonShape(const double thresh, double* dims, const bool debug) : 00278 ShapeModel(4, thresh, dims, debug) 00279 { } 00280 00281 // ###################################################################### 00282 OctagonShape::~OctagonShape() 00283 { } 00284 00285 // ###################################################################### 00286 float OctagonShape::getDist(double p[], const Image<float>& distMap, 00287 Image< PixRGB<byte> >& xdisp) const 00288 { 00289 // ########## Parse the parameters into human form: 00290 double x_center = p[1]; 00291 double y_center = p[2]; 00292 double alpha = p[4]; 00293 double height = p[3]; //note that "height" may not be quite the correct label here 00294 00295 // ########## Trace the shape and accumulate distances: 00296 float sina = sin(alpha/10.0); 00297 float cosa = cos(alpha/10.0); 00298 //funky angles for diagonal edges in octagon 00299 float sinb = sin((alpha+40.00)/10.0); 00300 float cosb = cos((alpha+40.00)/10.0); 00301 int numPts = 0; 00302 float dist = 0.0; 00303 00304 00305 //Following is the mathematical representation of an octagon 00306 for(int i=-5; i<5; i++) { 00307 //Diagonal edges are even-numbered 00308 // edge 1 00309 float tempValX = x_center - height*cosa/2 - ((i+1)*height*sina/10)/2.2; 00310 float tempValY = y_center - height*sina/2 + ((i+1)*height*cosa/10)/2.2; 00311 dist += getDistVal(tempValX, tempValY, distMap, xdisp); 00312 numPts++; 00313 00314 //edge 2 00315 tempValX = x_center - height*cosb/2 - ((i+1)*height*sinb/10)/2.2; 00316 tempValY = y_center - height*sinb/2 + ((i+1)*height*cosb/10)/2.2; 00317 dist += getDistVal(tempValX, tempValY, distMap, xdisp); 00318 numPts++; 00319 00320 // edge 3 00321 tempValX = x_center + height*cosa/2 - ((i+1)*height*sina/10)/2.2; 00322 tempValY = y_center + height*sina/2 + ((i+1)*height*cosa/10)/2.2; 00323 dist += getDistVal(tempValX, tempValY, distMap, xdisp); 00324 numPts++; 00325 00326 // edge 4 00327 tempValX = x_center + height*cosb/2 - ((i+1)*height*sinb/10)/2.2; 00328 tempValY = y_center + height*sinb/2 + ((i+1)*height*cosb/10)/2.2; 00329 dist += getDistVal(tempValX, tempValY, distMap, xdisp); 00330 numPts++; 00331 00332 // edge 5 00333 tempValX = x_center + height*sina/2 + ((i+1)*height*cosa/10)/2.2; 00334 tempValY = y_center - height*cosa/2 + ((i+1)*height*sina/10)/2.2; 00335 dist += getDistVal(tempValX, tempValY, distMap, xdisp); 00336 numPts++; 00337 00338 // edge 6 00339 tempValX = x_center + height*sinb/2 + ((i+1)*height*cosb/10)/2.2; 00340 tempValY = y_center - height*cosb/2 + ((i+1)*height*sinb/10)/2.2; 00341 dist += getDistVal(tempValX, tempValY, distMap, xdisp); 00342 numPts++; 00343 00344 // edge 7 00345 tempValX = x_center - height*sina/2 + ((i+1)*height*cosa/10)/2.2; 00346 tempValY = y_center + height*cosa/2 + ((i+1)*height*sina/10)/2.2; 00347 dist += getDistVal(tempValX, tempValY, distMap, xdisp); 00348 numPts++; 00349 00350 // edge 8 00351 tempValX = x_center - height*sinb/2 + ((i+1)*height*cosb/10)/2.2; 00352 tempValY = y_center + height*cosb/2 + ((i+1)*height*sinb/10)/2.2; 00353 dist += getDistVal(tempValX, tempValY, distMap, xdisp); 00354 numPts++; 00355 } 00356 00357 dist = dist / numPts; 00358 00359 // ########## Add a distance penalty if shape too small: 00360 if (height < 20) dist += (10.0 * ((20 - height) * (20 - height))); 00361 00362 return dist; 00363 } 00364 00365 00366 00367 // ###################################################################### 00368 CircleShape::CircleShape(const double thresh, double* dims, const bool debug) : 00369 ShapeModel(3, thresh, dims, debug) 00370 { } 00371 00372 // ###################################################################### 00373 CircleShape::~CircleShape() 00374 { } 00375 00376 // ###################################################################### 00377 float CircleShape::getDist(double p[], const Image<float>& distMap, 00378 Image< PixRGB<byte> >& xdisp) const 00379 { 00380 // ########## Parse the parameters into human form: 00381 double x_center = p[1]; 00382 double y_center = p[2]; 00383 double radius = p[3]; 00384 00385 // ########## Trace the shape and accumulate distances: 00386 int numPts = 0; 00387 float dist = 0.0; 00388 00389 00390 //Following is the mathematical representation of a circle 00391 for(int i=-7; i<7; i++) { 00392 // The following is code for a circle 00393 float tempValX = x_center + radius * cos(i*2*M_PI/14); 00394 float tempValY = y_center + radius * sin(i*2*M_PI/14); 00395 dist += getDistVal(tempValX, tempValY, distMap, xdisp); 00396 numPts++; 00397 } 00398 00399 dist = dist / numPts; 00400 00401 // ########## Add a distance penalty if shape too small: 00402 if (radius < 20) dist += (10.0 * ((20 - radius) * (20 - radius))); 00403 00404 return dist; 00405 } 00406 00407 00408 00409 // ###################################################################### 00410 ParallelShape::ParallelShape(const double thresh, double* dims, const bool debug) : 00411 ShapeModel(5, thresh, dims, debug) 00412 { } 00413 00414 // ###################################################################### 00415 ParallelShape::~ParallelShape() 00416 { } 00417 00418 // ###################################################################### 00419 float ParallelShape::getDist(double p[], const Image<float>& distMap, 00420 Image< PixRGB<byte> >& xdisp) const 00421 { 00422 00423 // ########## Parse the parameters into human form: 00424 double x_center = p[1]; 00425 double y_center = p[2]; 00426 double alpha = p[3]; 00427 00428 double width = p[4]; 00429 double height = p[5]; 00430 00431 // ########## Trace the shape and accumulate distances: 00432 float sina = sin(alpha/10.0); 00433 float cosa = cos(alpha/10.0); 00434 int numPts = 0; 00435 float dist = 0.0; 00436 00437 // The following is code for a free-form rectangle. 00438 for (int i = -5; i < 5; i++) { 00439 00440 // (-w/2, -h/2) -> (w/2, -h/2) 00441 float tempValX = x_center + height*sina/2.0 + (i+1)*width*cosa/10.0; 00442 float tempValY = y_center - height*cosa/2.0 + (i+1)*width*sina/10.0; 00443 dist += getDistVal(tempValX, tempValY, distMap, xdisp); 00444 numPts++; 00445 00446 // (-w/2, h/2) -> (w/2, h/2) 00447 tempValX = x_center - height*sina/2.0 + (i+1)*width*cosa/10.0; 00448 tempValY = y_center + height*cosa/2.0 + (i+1)*width*sina/10.0; 00449 dist += getDistVal(tempValX, tempValY, distMap, xdisp); 00450 numPts++; 00451 } 00452 00453 dist = dist / numPts; 00454 00455 // ########## Add a distance penalty if shape too small: 00456 if (width < 70) dist += (10.0 * ((70 - width) * (70-width))); 00457 if (height < 30) dist += (10.0 * ((30 - height) * (30 - height))); 00458 00459 return dist; 00460 } 00461 // ###################################################################### 00462 /* So things look consistent in everyone's emacs... */ 00463 /* Local Variables: */ 00464 /* indent-tabs-mode: nil */ 00465 /* End: */