00001 /*!@file BeoSub/test-EdgeDetect.C */ 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: 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/BeoSub/test-EdgeDetect.C $ 00035 // $Id: test-EdgeDetect.C 7452 2006-11-15 22:49:56Z ilab13 $ 00036 // 00037 00038 #include "GUI/XWindow.H" 00039 //CAMERA STUFF 00040 #include "Image/Image.H" 00041 #include "Image/Pixels.H" 00042 00043 #include "Component/ModelManager.H" 00044 #include "Devices/FrameGrabberFactory.H" 00045 #include "Util/Timer.H" 00046 #include "Util/Types.H" 00047 #include "Util/log.H" 00048 #include "Image/ColorOps.H" 00049 #include "Image/Image.H" 00050 #include "Image/MathOps.H" 00051 #include "Image/DrawOps.H" 00052 #include "Image/FilterOps.H" 00053 #include "Image/Transforms.H" 00054 #include "Raster/Raster.H" 00055 #include "BeoSub/hysteresis.H" 00056 #include "VFAT/segmentImageTrackMC.H" 00057 #include "rutz/shared_ptr.h" 00058 #include <cstdio> 00059 #include <cstdlib> 00060 #include <cstring> 00061 #include <iostream> //needed for segmentImageTrackMC! 00062 #include <math.h> 00063 00064 #include "Image/Convolver.H" 00065 //END CAMERA STUFF 00066 00067 //////////////////////////////////////////////////// 00068 // Canny Edge Detection 00069 // Randolph Voorhies 00070 // 11/15/05 00071 /////////////////////////////////////////////////// 00072 00073 00074 #define PI 3.14159265 00075 #define TRACE_CONTOUR_DEPTH_LIMIT 3 00076 00077 00078 //Depth limited search to trace contours 00079 bool traceContour(const Image<float> &magnitudeImage, const int x, const int y, const int loThresh, const int hiThresh, const int from, const int steps) { 00080 if(magnitudeImage.getVal(x,y) >= hiThresh) 00081 return true; 00082 if(magnitudeImage.getVal(x,y) < loThresh) 00083 return false; 00084 if(x == 0 || x >= magnitudeImage.getWidth() - 1 || y == 0 || y >= magnitudeImage.getHeight() - 1) 00085 return false; 00086 00087 if(steps >= TRACE_CONTOUR_DEPTH_LIMIT) 00088 return false; 00089 00090 if(magnitudeImage.getVal(x-1,y) > loThresh && from != 1) 00091 if(traceContour(magnitudeImage, x-1, y, loThresh, hiThresh, 5, steps+1)) 00092 return true; 00093 if(magnitudeImage.getVal(x-1,y-1) > loThresh && from != 2) 00094 if(traceContour(magnitudeImage, x-1, y-1, loThresh, hiThresh, 6, steps+1)) 00095 return true; 00096 if(magnitudeImage.getVal(x-1,y+1) > loThresh && from != 8) 00097 if(traceContour(magnitudeImage, x-1, y+1, loThresh, hiThresh, 4, steps+1)) 00098 return true; 00099 if(magnitudeImage.getVal(x,y-1) > loThresh && from != 3) 00100 if(traceContour(magnitudeImage, x, y-1, loThresh, hiThresh, 7, steps+1)) 00101 return true; 00102 if(magnitudeImage.getVal(x,y+1) > loThresh && from != 7) 00103 if(traceContour(magnitudeImage, x, y+1, loThresh, hiThresh, 3, steps+1)) 00104 return true; 00105 if(magnitudeImage.getVal(x+1,y-1) > loThresh && from != 4) 00106 if(traceContour(magnitudeImage, x+1, y-1, loThresh, hiThresh, 8, steps+1)) 00107 return true; 00108 if(magnitudeImage.getVal(x+1,y) > loThresh && from != 5) 00109 if(traceContour(magnitudeImage, x+1, y, loThresh, hiThresh, 1, steps+1)) 00110 return true; 00111 if(magnitudeImage.getVal(x+1,y+1) > loThresh && from != 6) 00112 if(traceContour(magnitudeImage, x+1, y+1, loThresh, hiThresh, 2, steps+1)) 00113 return true; 00114 00115 return false; 00116 } 00117 00118 void nonMaxSuppressAndContTrace(Image<byte> &edgeImage, const Image<float> magnitudeImage, const Image<float> orientationImage, const int loThresh, const int hiThresh) { 00119 float mag, pa=0, pb=0, orientDeg; 00120 00121 for(int x = 1; x < magnitudeImage.getWidth() - 1; x++) 00122 for(int y = 1; y < magnitudeImage.getHeight() - 1; y++) { 00123 mag = magnitudeImage.getVal(x,y); 00124 orientDeg = orientationImage.getVal(x,y)*(180/PI); 00125 00126 if((orientDeg >= 0 && orientDeg <= 45) || (orientDeg > -180 && orientDeg <= -135)) { 00127 pa = (magnitudeImage.getVal(x+1,y) + magnitudeImage.getVal(x+1,y-1))/2; 00128 pb = (magnitudeImage.getVal(x-1,y) + magnitudeImage.getVal(x-1,y+1))/2; 00129 } 00130 else if((orientDeg > 45 && orientDeg <= 90) || (orientDeg > -135 && orientDeg <= -90)) { 00131 pa = (magnitudeImage.getVal(x+1,y-1) + magnitudeImage.getVal(x,y-1))/2; 00132 pb = (magnitudeImage.getVal(x-1,y+1) + magnitudeImage.getVal(x,y+1))/2; 00133 } 00134 else if((orientDeg > 90 && orientDeg <= 135) || (orientDeg > -90 && orientDeg <= -45)) { 00135 pa = (magnitudeImage.getVal(x,y-1) + magnitudeImage.getVal(x-1,y-1))/2; 00136 pb = (magnitudeImage.getVal(x,y+1) + magnitudeImage.getVal(x+1,y+1))/2; 00137 } 00138 else if((orientDeg > 135 && orientDeg <= 180) || (orientDeg > -45 && orientDeg < 0)) { 00139 pa = (magnitudeImage.getVal(x-1,y-1) + magnitudeImage.getVal(x-1,y))/2; 00140 pb = (magnitudeImage.getVal(x+1,y+1) + magnitudeImage.getVal(x+1,y))/2; 00141 } 00142 00143 if(mag > pa && mag > pb) { 00144 if(mag < loThresh) 00145 continue; 00146 else if(mag > hiThresh) 00147 edgeImage.setVal(x,y,255); 00148 else if(traceContour(magnitudeImage,x,y,loThresh,hiThresh, -1, 0)) { 00149 edgeImage.setVal(x,y,255); 00150 } 00151 } 00152 } 00153 } 00154 00155 //TODO: Templates not working correctly: sending a Image<float> as a source breaks it. 00156 template <class T_or_RGB> 00157 Image<byte> cannyEdgeDetect(const Image<T_or_RGB> source, const float sigma, const int loThresh, const int hiThresh) { 00158 00159 Image<byte> edgeImage(source.getDims(), ZEROS); //Image to return 00160 Image<float> magnitudeImage(source.getDims(), ZEROS); //First Derivative Magnitude Image 00161 Image<float> orientationImage(source.getDims(), ZEROS); //First Derivative Orientation Image 00162 00163 //gaussian blurred image -- to reduce noise 00164 Image<float> fblurImage = luminance(convGauss(source, sigma, sigma,10)); 00165 00166 //Find the magnitude and orientation 00167 gradient(fblurImage, magnitudeImage, orientationImage); 00168 00169 //Perform non-maximul suppression and contour tracing to determine edges 00170 nonMaxSuppressAndContTrace(edgeImage, magnitudeImage, orientationImage, loThresh, hiThresh); 00171 00172 return edgeImage; 00173 } 00174 00175 00176 00177 //good tlo and thi values are 10, 16, with a sigma of 2 00178 int main(int argc, char* argv[]) { 00179 00180 int loThresh, hiThresh; 00181 float sigma; 00182 Image< PixRGB<byte> > cameraImage; 00183 Image<float> floatImage; 00184 00185 if(argc != 4) { 00186 std::cout << "USAGE: bin/EdgeDetect sigma Tlow Thigh " << std::endl; 00187 std::cout << " *Thigh and Tlow are thresholds for the canny algorithm" << std::endl; 00188 std::cout << " *sigma is used in gaussian mask" << std::endl; 00189 exit(0); 00190 } 00191 00192 sigma = (float)atoi(argv[1]); 00193 loThresh = atoi(argv[2]); 00194 hiThresh = atoi(argv[3]); 00195 00196 XWindow* xwin; 00197 XWindow* xwin2; 00198 00199 ModelManager camManager("ColorTracker Tester"); 00200 nub::soft_ref<FrameIstream> gb(makeIEEE1394grabber(camManager, "colorcam", "cocam")); 00201 camManager.addSubComponent(gb); 00202 //camManager.loadConfig("camconfig.pmap"); 00203 gb->setModelParamVal("FrameGrabberSubChan", 0); 00204 camManager.start(); 00205 00206 cameraImage = gb->readRGB(); 00207 00208 xwin = new XWindow(cameraImage.getDims()); 00209 xwin2 = new XWindow(cameraImage.getDims()); 00210 00211 while(1) { 00212 cameraImage = gb->readRGB(); 00213 //floatImage = cameraImage; 00214 xwin->drawImage(cameraImage); 00215 //xwin2->drawImage(cannyEdgeDetect(floatImage, sigma, loThresh, hiThresh)); 00216 xwin2->drawImage(cannyEdgeDetect(cameraImage, sigma, loThresh, hiThresh)); 00217 } 00218 return 0; 00219 } 00220 00221 // ###################################################################### 00222 /* So things look consistent in everyone's emacs... */ 00223 /* Local Variables: */ 00224 /* indent-tabs-mode: nil */ 00225 /* End: */