00001 /*!@file Corba/Parallel/CMap.C a compute a conspicuity map from an image */ 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: Lior Elazary <lelazary@yahoo.com> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Corba/Parallel/CMap.C $ 00035 // $Id: CMap.C 14125 2010-10-12 06:29:08Z itti $ 00036 // 00037 00038 00039 #include <stdlib.h> 00040 #include <time.h> 00041 #include <iostream> 00042 #include <unistd.h> 00043 #include <fcntl.h> 00044 #include <sys/types.h> 00045 #include <sys/stat.h> 00046 #include "Image/ColorOps.H" 00047 #include "Image/Image.H" 00048 #include "Image/ImageSet.H" 00049 #include "Image/Pixels.H" 00050 #include "Image/PyramidOps.H" 00051 #include "Image/ShapeOps.H" 00052 #include "Image/Transforms.H" 00053 #include "Image/fancynorm.H" 00054 #include "Util/Assert.H" 00055 #include "Util/Timer.H" 00056 #include "Util/Types.H" 00057 #include <cstdio> // for sprintf 00058 00059 #include "Corba/Parallel/CMapSK.hh" 00060 #include "Corba/ImageOrbUtil.H" 00061 00062 // ###################################################################### 00063 // ##### Global options: 00064 // ###################################################################### 00065 #define sml 2 00066 #define delta_min 3 00067 #define delta_max 4 00068 #define level_min 0 00069 #define level_max 2 00070 #define maxdepth (level_max + delta_max + 1) 00071 #define normtyp (VCXNORM_MAXNORM) 00072 00073 // relative feature weights: 00074 #define IWEIGHT 1.0 00075 #define CWEIGHT 1.0 00076 #define OWEIGHT 1.0 00077 #define FWEIGHT 1.5 00078 00079 #define NBCMAP2 7 00080 //! prescale level by which we downsize images before sending them off 00081 #define PRESCALE 2 00082 00083 CORBA::ORB_var orb; 00084 CosNaming::Name objectName; 00085 00086 static CORBA::Boolean bindObjectToName(CORBA::ORB_ptr, CORBA::Object_ptr); 00087 void unbindObject (); 00088 00089 //Define STAT_CMAP to show camp statisitc and timing 00090 #define STAT_CMAP 00091 00092 00093 //The cmap object implimentation 00094 class CMap_i : public POA_CMap , 00095 public PortableServer::RefCountServantBase 00096 { 00097 public: 00098 inline CMap_i(){} 00099 virtual ~CMap_i(){} 00100 virtual ImageOrb* computeCMAP(const ImageOrb& img, 00101 const short ptyp, const float ori, const float coeff); 00102 virtual ImageOrb* computeCMAP2(const ImageOrb& img1, const ImageOrb& img2, 00103 const short ptyp, const float ori, const float coeff); 00104 virtual ImageOrb* computeFlickerCMAP(const ImageOrb& img, 00105 const short ptyp, const float ori, const float coeff); 00106 00107 virtual void shutdown(); 00108 00109 private: 00110 Image<float>* computeCMAP(const Image<float>& fimg, 00111 const PyramidType ptyp, const float ori, const float coeff); 00112 }; 00113 00114 void CMap_i::shutdown() { 00115 // Shutdown the ORB 00116 unbindObject(); 00117 orb->shutdown(0); 00118 } 00119 00120 ImageOrb* CMap_i::computeCMAP(const ImageOrb& img, const short ptyp, const float ori, const float coeff){ 00121 00122 00123 #ifdef STAT_CMAP 00124 static double avrtime = 0; 00125 static int avgn = 0; 00126 double time_taken; 00127 Timer time(1000000); 00128 time.reset(); 00129 #endif 00130 00131 00132 //convert to an image 00133 Image<byte> image; 00134 orb2Image(img, image); 00135 00136 //compute the cmap 00137 Image<float> fimg = image; 00138 Image<float> *cmap = computeCMAP(fimg, (PyramidType)ptyp, ori, coeff); 00139 Image<byte> cmap_byte = *cmap; 00140 00141 delete cmap; 00142 00143 #ifdef STAT_CMAP 00144 time_taken = time.getSecs(); 00145 avrtime += time_taken; 00146 ++avgn; 00147 LINFO("CMap stats: agvn=%i avgtime=%0.4f time_taken=%f ptype=%i ori=%f coeff=%f", 00148 avgn, avrtime/(double)avgn, time_taken, (int)ptyp, ori, coeff); 00149 #endif 00150 00151 return image2Orb(cmap_byte); 00152 } 00153 00154 00155 ImageOrb* CMap_i::computeCMAP2(const ImageOrb& img1, const ImageOrb& img2, 00156 const short ptyp, const float ori, const float coeff){ 00157 00158 #ifdef STAT_CMAP 00159 static double avrtime = 0; 00160 static int avgn = 0; 00161 double time_taken; 00162 00163 Timer time(1000000); 00164 time.reset(); 00165 #endif 00166 //convert to an image 00167 Image<byte> image1; 00168 orb2Image(img1, image1); 00169 00170 Image<byte> image2; 00171 orb2Image(img2, image2); 00172 00173 //compute the cmap 00174 Image<float> fimg = image1-image2; 00175 00176 Image<float> *cmap = computeCMAP(fimg, (PyramidType)ptyp, ori, coeff); 00177 Image<byte> cmap_byte = *cmap; 00178 delete cmap; 00179 00180 #ifdef STAT_CMAP 00181 time_taken = time.getSecs(); 00182 avrtime += time_taken; 00183 ++avgn; 00184 LINFO("CMap2 stats: agvn=%i avgtime=%0.4f time_taken=%f ptype=%i ori=%f coeff=%f", 00185 avgn, avrtime/(double)avgn, time_taken, (int)ptyp, ori, coeff); 00186 #endif 00187 return image2Orb(cmap_byte); 00188 } 00189 00190 ImageOrb* CMap_i::computeFlickerCMAP(const ImageOrb& img, const short ptyp, const float ori, const float coeff){ 00191 00192 #ifdef STAT_CMAP 00193 static double avrtime = 0; 00194 static int avgn = 0; 00195 double time_taken; 00196 Timer time(1000000); 00197 time.reset(); 00198 #endif 00199 static Image<float> previmg; 00200 00201 //convert to an image 00202 Image<byte> image; 00203 orb2Image(img, image); 00204 00205 //compute the cmap 00206 Image<float> fimg = image; 00207 if (previmg.initialized() == false) previmg = fimg; 00208 00209 previmg -= fimg; 00210 Image<float> *cmap = computeCMAP(previmg, (PyramidType)ptyp, ori, coeff); 00211 previmg = fimg; 00212 Image<byte> cmap_byte = *cmap; 00213 00214 delete cmap; 00215 00216 #ifdef STAT_CMAP 00217 time_taken = time.getSecs(); 00218 avrtime += time_taken; 00219 ++avgn; 00220 LINFO("FilckerCmap stats: agvn=%i avgtime=%0.4f time_taken=%f ptype=%i ori=%f coeff=%f", 00221 avgn, avrtime/(double)avgn, time_taken, (int)ptyp, ori, coeff); 00222 #endif 00223 return image2Orb(cmap_byte); 00224 } 00225 00226 00227 // ###################################################################### 00228 Image<float> *CMap_i::computeCMAP(const Image<float>& fimg, const PyramidType ptyp, const float ori, const float coeff) 00229 { 00230 // compute pyramid: 00231 ImageSet<float> pyr = buildPyrGeneric(fimg, 0, maxdepth, 00232 ptyp, ori); 00233 00234 // alloc conspicuity map and clear it: 00235 Image<float> *cmap = new Image<float>(pyr[sml].getDims(), ZEROS); 00236 00237 00238 // intensities is the max-normalized weighted sum of IntensCS: 00239 for (int delta = delta_min; delta <= delta_max; delta ++) 00240 for (int lev = level_min; lev <= level_max; lev ++) 00241 { 00242 Image<float> tmp = centerSurround(pyr, lev, lev + delta, true); 00243 tmp = downSize(tmp, cmap->getWidth(), cmap->getHeight()); 00244 inplaceAddBGnoise(tmp, 255.0); 00245 tmp = maxNormalize(tmp, MAXNORMMIN, MAXNORMMAX, normtyp); 00246 *cmap += tmp; 00247 } 00248 if (normtyp == VCXNORM_MAXNORM) 00249 *cmap = maxNormalize(*cmap, MAXNORMMIN, MAXNORMMAX, normtyp); 00250 else 00251 *cmap = maxNormalize(*cmap, 0.0f, 0.0f, normtyp); 00252 00253 // multiply by conspicuity coefficient: 00254 *cmap *= coeff; 00255 00256 return cmap; 00257 } 00258 00259 00260 //start the class server 00261 int main(int argc, char **argv){ 00262 00263 LINFO("Running as a daemon"); 00264 //Become a daemon 00265 // fork off the parent process 00266 pid_t pid = fork(); 00267 if (pid < 0){ 00268 LFATAL("Can not fork"); 00269 } 00270 00271 if (pid > 0){ 00272 exit(0); //exit the parent process 00273 } 00274 00275 // Chnage the file mask 00276 umask(0); 00277 00278 //Create a new system id so that the kernel wont think we are an orphan. 00279 00280 pid_t sid = setsid(); 00281 00282 if (sid < 0){ 00283 LFATAL("Can not become independent"); 00284 } 00285 00286 //Create the object and run in 00287 orb = CORBA::ORB_init(argc, argv); 00288 00289 CORBA::Object_var obj = orb->resolve_initial_references("RootPOA"); 00290 PortableServer::POA_var poa = PortableServer::POA::_narrow(obj); 00291 00292 CMap_i* cmap = new CMap_i(); 00293 00294 PortableServer::ObjectId_var cmapid = poa->activate_object(cmap); 00295 00296 //get a ref string 00297 obj = cmap->_this(); 00298 CORBA::String_var sior(orb->object_to_string(obj)); 00299 std::cerr << "'" << (char*)sior << "'" << "\n"; 00300 00301 if( !bindObjectToName(orb, obj) ) 00302 return 1; 00303 cmap->_remove_ref(); 00304 00305 PortableServer::POAManager_var pman = poa->the_POAManager(); 00306 pman->activate(); 00307 00308 00309 00310 //run the object untill shutdown or killed 00311 orb->run(); 00312 00313 LINFO("Shutting down"); 00314 return 0; 00315 } 00316 00317 ////////////////////////////////////////////////////////////////////// 00318 00319 static CORBA::Boolean 00320 bindObjectToName(CORBA::ORB_ptr orb, CORBA::Object_ptr objref) 00321 { 00322 CosNaming::NamingContext_var rootContext; 00323 00324 try { 00325 // Obtain a reference to the root context of the Name service: 00326 CORBA::Object_var obj; 00327 obj = orb->resolve_initial_references("NameService"); 00328 00329 if( CORBA::is_nil(obj) ) { 00330 std::cerr << "Obj is null." << std::endl; 00331 return 0; 00332 } 00333 00334 // Narrow the reference returned. 00335 rootContext = CosNaming::NamingContext::_narrow(obj); 00336 if( CORBA::is_nil(rootContext) ) { 00337 std::cerr << "Failed to narrow the root naming context." << std::endl; 00338 return 0; 00339 } 00340 } 00341 catch(CORBA::ORB::InvalidName& ex) { 00342 // This should not happen! 00343 std::cerr << "Service required is invalid [does not exist]." << std::endl; 00344 return 0; 00345 } 00346 00347 try { 00348 // Bind a context called "test" to the root context: 00349 00350 CosNaming::Name contextName; 00351 contextName.length(1); 00352 contextName[0].id = (const char*) "test"; // string copied 00353 contextName[0].kind = (const char*) "saliency"; // string copied 00354 // Note on kind: The kind field is used to indicate the type 00355 // of the object. This is to avoid conventions such as that used 00356 // by files (name.type -- e.g. test.ps = postscript etc.) 00357 CosNaming::NamingContext_var testContext; 00358 try { 00359 // Bind the context to root. 00360 testContext = rootContext->bind_new_context(contextName); 00361 } 00362 catch(CosNaming::NamingContext::AlreadyBound& ex) { 00363 // If the context already exists, this exception will be raised. 00364 // In this case, just resolve the name and assign testContext 00365 // to the object returned: 00366 CORBA::Object_var obj; 00367 obj = rootContext->resolve(contextName); 00368 testContext = CosNaming::NamingContext::_narrow(obj); 00369 if( CORBA::is_nil(testContext) ) { 00370 std::cerr << "Failed to narrow naming context." << std::endl; 00371 return 0; 00372 } 00373 } 00374 00375 // Bind objref with name Echo to the testContext: 00376 objectName.length(1); 00377 00378 00379 bool bound = false; 00380 char CmapID[100]; 00381 for (int i=0; i<100 && !bound; i++) { 00382 sprintf(CmapID, "CMap_%i", i); 00383 std::cout << "Binding object " << CmapID << std::endl; 00384 objectName[0].id = (const char *) CmapID; // string copied 00385 objectName[0].kind = (const char*) "Object"; // string copied 00386 00387 bound = true; 00388 try { 00389 testContext->bind(objectName, objref); 00390 } 00391 catch(CosNaming::NamingContext::AlreadyBound& ex) { 00392 //testContext->rebind(objectName, objref); 00393 bound = false; 00394 } 00395 00396 } 00397 if (!bound){ 00398 LFATAL("Can not bind object"); 00399 return 0; 00400 } else { 00401 } 00402 00403 00404 // Amendment: When using OrbixNames, it is necessary to first try bind 00405 // and then rebind, as rebind on it's own will throw a NotFoundexception if 00406 // the Name has not already been bound. [This is incorrect behaviour - 00407 // it should just bind]. 00408 } 00409 catch(CORBA::COMM_FAILURE& ex) { 00410 std::cerr << "Caught system exception COMM_FAILURE -- unable to contact the " 00411 << "naming service." << std::endl; 00412 return 0; 00413 } 00414 catch(CORBA::SystemException&) { 00415 std::cerr << "Caught a CORBA::SystemException while using the naming service." 00416 << std::endl; 00417 return 0; 00418 } 00419 00420 return 1; 00421 } 00422 00423 // unbind the object from the name server 00424 void unbindObject (){ 00425 CosNaming::NamingContext_var rootContext; 00426 00427 try { 00428 // Obtain a reference to the root context of the Name service: 00429 CORBA::Object_var obj; 00430 obj = orb->resolve_initial_references("NameService"); 00431 00432 if( CORBA::is_nil(obj) ) { 00433 std::cerr << "Obj is null." << std::endl; 00434 return; 00435 } 00436 00437 // Narrow the reference returned. 00438 rootContext = CosNaming::NamingContext::_narrow(obj); 00439 if( CORBA::is_nil(rootContext) ) { 00440 std::cerr << "Failed to narrow the root naming context." << std::endl; 00441 return; 00442 } 00443 } 00444 catch(CORBA::ORB::InvalidName& ex) { 00445 // This should not happen! 00446 std::cerr << "Service required is invalid [does not exist]." << std::endl; 00447 return; 00448 } 00449 00450 CosNaming::Name contextName; 00451 contextName.length(2); 00452 contextName[0].id = (const char*) "test"; // string copied 00453 contextName[0].kind = (const char*) "saliency"; // string copied 00454 contextName[1] = objectName[0]; 00455 00456 rootContext->unbind(contextName); 00457 } 00458 00459 00460