00001 /*!@file Corba/Objects/CMapServer.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/Objects/CMapServer.C $ 00035 // $Id: CMapServer.C 9412 2008-03-10 23:10:15Z farhan $ 00036 // 00037 00038 #include <stdlib.h> 00039 #include <time.h> 00040 #include <iostream> 00041 #include <unistd.h> 00042 #include <fcntl.h> 00043 #include <sys/types.h> 00044 #include <sys/stat.h> 00045 #include <signal.h> 00046 #include "Image/ColorOps.H" 00047 #include "Image/MathOps.H" 00048 #include "Image/Image.H" 00049 #include "Image/ImageSet.H" 00050 #include "Image/Pixels.H" 00051 #include "Image/PyramidOps.H" 00052 #include "Image/ShapeOps.H" 00053 #include "Image/Transforms.H" 00054 #include "Image/fancynorm.H" 00055 #include "Util/Assert.H" 00056 #include "Util/Timer.H" 00057 #include "Util/Types.H" 00058 #include "Component/ModelManager.H" 00059 #include "Corba/Objects/CMapSK.hh" 00060 #include "Corba/ImageOrbUtil.H" 00061 #include "Corba/Objects/CMapServer.H" 00062 #include "Corba/CorbaUtil.H" 00063 //#include "GUI/XWinManaged.H" 00064 //XWinManaged xwin(Dims(256, 256), -1, -1, "CMap Debug"); 00065 00066 // ###################################################################### 00067 // ##### Global options: 00068 // ###################################################################### 00069 #define delta_min 3 00070 #define delta_max 4 00071 #define level_min 0 00072 #define level_max 2 00073 #define maxdepth (level_max + delta_max + 1) 00074 #define normtyp (VCXNORM_MAXNORM) 00075 //#define normtyp (VCXNORM_FANCYWEAK) 00076 //#define normtyp (VCXNORM_FANCYONE) 00077 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 bool Debug = false; 00087 00088 #ifndef LocalCMapServer 00089 //! Signal handler (e.g., for control-C) 00090 void terminate(int s) 00091 { 00092 LERROR("*** INTERRUPT ***"); 00093 unbindObject(orb, "saliency", "CMapServers", objectName); 00094 orb->shutdown(0); 00095 } 00096 #endif 00097 00098 static omni_mutex BiasCenterSurroundMutex; 00099 00100 class BiasCenterSurroundThread : public omni_thread { 00101 00102 public: 00103 BiasCenterSurroundThread(Image<float> &cmap, ImageSet<float> &pyr, 00104 int lev1, int lev2, float bias): 00105 th_cmap(cmap), th_pyr(pyr), th_lev1(lev1), th_lev2(lev2), th_bias(bias){ 00106 00107 start_undetached(); 00108 } 00109 00110 private: 00111 Image<float> &th_cmap; 00112 ImageSet<float> &th_pyr; 00113 int th_lev1, th_lev2; 00114 float th_bias; 00115 00116 void* run_undetached(void *ptr){ 00117 00118 Image<float> tmp = centerSurround(th_pyr, th_lev1, th_lev2, true); 00119 inplaceNormalize(tmp, 0.0F, 255.0F); 00120 00121 //bias this level 00122 for (Image<float>::iterator itr = tmp.beginw(), stop = tmp.endw(); 00123 itr != stop; ++itr) { 00124 *itr = 255.0F - fabs((*itr) - th_bias); //corelate the bias 00125 } 00126 00127 tmp = downSize(tmp, th_cmap.getWidth(), th_cmap.getHeight()); 00128 //tmp = rescale(tmp, cmap->getWidth(), cmap->getHeight()); 00129 //inplaceAddBGnoise(tmp, 255.0); 00130 tmp = maxNormalize(tmp, MAXNORMMIN, MAXNORMMAX, normtyp); 00131 BiasCenterSurroundMutex.lock(); 00132 th_cmap += tmp; 00133 BiasCenterSurroundMutex.unlock(); 00134 00135 return NULL; 00136 } 00137 }; 00138 00139 class CenterSurroundThread : public omni_thread { 00140 00141 public: 00142 CenterSurroundThread(Image<float> &cmap, ImageSet<float> &pyr, int lev1, int lev2): 00143 th_cmap(cmap), th_pyr(pyr), th_lev1(lev1), th_lev2(lev2){ 00144 00145 start_undetached(); 00146 } 00147 00148 private: 00149 Image<float> &th_cmap; 00150 ImageSet<float> &th_pyr; 00151 int th_lev1, th_lev2; 00152 00153 void* run_undetached(void *ptr){ 00154 00155 Image<float> tmp = centerSurround(th_pyr, th_lev1, th_lev2, true); 00156 inplaceNormalize(tmp, 0.0F, 255.0F); 00157 00158 if (tmp.getWidth() >= th_cmap.getWidth()) 00159 tmp = downSize(tmp, th_cmap.getWidth(), th_cmap.getHeight()); 00160 else 00161 tmp = quickInterpolate(tmp, th_cmap.getWidth()/tmp.getWidth()); 00162 00163 tmp = maxNormalize(tmp, MAXNORMMIN, MAXNORMMAX, normtyp); 00164 00165 BiasCenterSurroundMutex.lock(); 00166 th_cmap += tmp; 00167 BiasCenterSurroundMutex.unlock(); 00168 00169 return NULL; 00170 } 00171 }; 00172 00173 void CMap_i::shutdown() { 00174 // Shutdown the ORB 00175 unbindObject(orb,"saliency", "CMapServers", objectName); 00176 orb->shutdown(0); 00177 } 00178 00179 void CMap_i::setSaliencyMapLevel(const short sml){ 00180 saliencyMapLevel = sml; 00181 } 00182 00183 00184 00185 // ###################################################################### 00186 CMap::BiasSeq* CMap_i::getBiasCMAP(const ImageOrb& img, const short ptyp, 00187 const float ori, const float coeff, 00188 const Point2DOrb& loc) 00189 { 00190 //convert to an image 00191 Image<byte> image; 00192 orb2Image(img, image); 00193 00194 //compute the cmap 00195 Image<float> fimg = image; 00196 // compute pyramid: 00197 ImageSet<float> pyr = buildPyrGeneric(fimg, 0, maxdepth, 00198 (PyramidType)ptyp, ori); 00199 00200 00201 // alloc conspicuity map and clear it: 00202 00203 CMap::BiasSeq *bias = new CMap::BiasSeq; 00204 bias->length(6); //TODO: compute from delta_min etc.. 00205 00206 // intensities is the max-normalized weighted sum of IntensCS: 00207 int ii=0; 00208 for (int delta = delta_min; delta <= delta_max; delta ++) 00209 for (int lev = level_min; lev <= level_max; lev ++) 00210 { 00211 Image<float> tmp = centerSurround(pyr, lev, lev + delta, true); 00212 inplaceNormalize(tmp, 0.0F, 255.0F); 00213 00214 if (loc.i >= 0 && loc.j >=0){ 00215 //get the bias points 00216 //Map the pooint to the current point in the pyramid level 00217 Point2D<int> newp((int)((float)loc.i * ((float)tmp.getWidth() / (float)fimg.getWidth())), 00218 (int)((float)loc.j * ((float)tmp.getHeight() / (float)fimg.getHeight())) ); 00219 (*bias)[ii] = (float)tmp.getVal(newp); 00220 //tmp.setVal(newp, 255); 00221 //xwin.drawImage(rescale(tmp, 256, 256)); 00222 //sleep(2); 00223 00224 } 00225 00226 ii++; 00227 } 00228 00229 00230 return bias; 00231 } 00232 00233 ImageOrb* CMap_i::computeCMAP(const ImageOrb& img, const short ptyp, const float ori, const float coeff){ 00234 00235 00236 00237 static double avrtime = 0; 00238 static int avgn = 0; 00239 double time_taken; 00240 Timer time(1000000); 00241 if (Debug) { 00242 time.reset(); 00243 } 00244 00245 //convert to an image 00246 Image<byte> image; 00247 orb2Image(img, image); 00248 Image<float> fimg = image; 00249 00250 // compute pyramid: 00251 ImageSet<float> pyr = buildPyrGeneric(fimg, 0, maxdepth, 00252 (PyramidType)ptyp, ori); 00253 00254 // alloc conspicuity map and clear it: 00255 Image<float> cmap(pyr[saliencyMapLevel].getDims(), ZEROS); 00256 00257 int ii=0; 00258 00259 CenterSurroundThread *workth[25]; //TODO: should be computed 00260 00261 // intensities is the max-normalized weighted sum of IntensCS: 00262 for (int delta = delta_min; delta <= delta_max; delta ++) 00263 for (int lev = level_min; lev <= level_max; lev ++) 00264 { 00265 //spawn a new thread for each centersurround computation 00266 workth[ii] = new CenterSurroundThread(cmap,pyr, lev, lev + delta); 00267 ii++; 00268 } 00269 00270 //wait for thread to finish 00271 for (int i=0; i<ii; i++) 00272 workth[i]->join(NULL); 00273 00274 // inplaceAddBGnoise(cmap, 25.0F); 00275 00276 if (normtyp == VCXNORM_MAXNORM) 00277 cmap = maxNormalize(cmap, MAXNORMMIN, MAXNORMMAX, normtyp); 00278 else 00279 cmap = maxNormalize(cmap, 0.0f, 0.0f, normtyp); 00280 00281 // multiply by conspicuity coefficient: 00282 if (coeff != 1.0F) cmap *= coeff; 00283 00284 if (Debug) { 00285 time_taken = time.getSecs(); 00286 avrtime += time_taken; 00287 ++avgn; 00288 LINFO("CMap stats: agvn=%i avgtime=%0.4f time_taken=%f ptype=%i ori=%f coeff=%f", 00289 avgn, avrtime/(double)avgn, time_taken, (int)ptyp, ori, coeff); 00290 } 00291 00292 return image2Orb(cmap); 00293 00294 00295 } 00296 00297 00298 ImageOrb* CMap_i::computeCMAP2(const ImageOrb& img1, const ImageOrb& img2, 00299 const short ptyp, const float ori, const float coeff){ 00300 00301 static double avrtime = 0; 00302 static int avgn = 0; 00303 double time_taken; 00304 Timer time(1000000); 00305 if (Debug) { 00306 00307 time.reset(); 00308 } 00309 //convert to an image 00310 Image<byte> image1; 00311 orb2Image(img1, image1); 00312 00313 Image<byte> image2; 00314 orb2Image(img2, image2); 00315 00316 //compute the cmap 00317 Image<float> fimg = image1-image2; 00318 00319 Image<float> *cmap = computeCMAP(fimg, (PyramidType)ptyp, ori, coeff); 00320 Image<byte> cmap_byte = *cmap; 00321 delete cmap; 00322 00323 if (Debug) { 00324 time_taken = time.getSecs(); 00325 avrtime += time_taken; 00326 ++avgn; 00327 LINFO("CMap2 stats: agvn=%i avgtime=%0.4f time_taken=%f ptype=%i ori=%f coeff=%f", 00328 avgn, avrtime/(double)avgn, time_taken, (int)ptyp, ori, coeff); 00329 } 00330 return image2Orb(cmap_byte); 00331 } 00332 00333 ImageOrb* CMap_i::computeFlickerCMAP(const ImageOrb& img, const short ptyp, const float ori, const float coeff){ 00334 00335 static double avrtime = 0; 00336 static int avgn = 0; 00337 double time_taken; 00338 Timer time(1000000); 00339 if (Debug) { 00340 time.reset(); 00341 } 00342 static Image<float> previmg; 00343 00344 //convert to an image 00345 Image<byte> image; 00346 orb2Image(img, image); 00347 00348 //compute the cmap 00349 Image<float> fimg = image; 00350 if (previmg.initialized() == false) previmg = fimg; 00351 00352 previmg -= fimg; 00353 Image<float> *cmap = computeCMAP(previmg, (PyramidType)ptyp, ori, coeff); 00354 previmg = fimg; 00355 Image<byte> cmap_byte = *cmap; 00356 00357 delete cmap; 00358 00359 if (Debug) { 00360 time_taken = time.getSecs(); 00361 avrtime += time_taken; 00362 ++avgn; 00363 LINFO("FilckerCmap stats: agvn=%i avgtime=%0.4f time_taken=%f ptype=%i ori=%f coeff=%f", 00364 avgn, avrtime/(double)avgn, time_taken, (int)ptyp, ori, coeff); 00365 } 00366 00367 return image2Orb(cmap_byte); 00368 } 00369 00370 ImageOrb* CMap_i::computeBiasCMAP(const ImageOrb& img, const short ptyp, 00371 const float ori, const float coeff, 00372 const CMap::BiasSeq& bias){ 00373 00374 static double avrtime = 0; 00375 static int avgn = 0; 00376 double time_taken; 00377 Timer time(1000000); 00378 if (Debug) { 00379 time.reset(); 00380 } 00381 00382 //convert to an image 00383 Image<byte> image; 00384 orb2Image(img, image); 00385 Image<float> fimg = image; 00386 00387 // compute pyramid: 00388 ImageSet<float> pyr = buildPyrGeneric(fimg, 0, maxdepth, 00389 (PyramidType)ptyp, ori); 00390 00391 // alloc conspicuity map and clear it: 00392 Image<float> cmap(pyr[saliencyMapLevel].getDims(), ZEROS); 00393 00394 if (Debug) { 00395 LINFO("Bias map with: "); 00396 for (uint i=0; i<bias.length(); i++) 00397 printf("%f ", bias[i]); 00398 printf("\n"); 00399 } 00400 00401 00402 // intensities is the max-normalized weighted sum of IntensCS: 00403 int ii=0; 00404 00405 BiasCenterSurroundThread *workth[25]; //TODO: should be computed 00406 00407 for (int delta = delta_min; delta <= delta_max; delta ++) 00408 for (int lev = level_min; lev <= level_max; lev ++) 00409 { 00410 /* Image<float> tmp = centerSurround(pyr, lev, lev + delta, true); 00411 inplaceNormalize(tmp, 0.0F, 255.0F); 00412 00413 //bias this level 00414 for (Image<float>::iterator itr = tmp.beginw(), stop = tmp.endw(); 00415 itr != stop; ++itr) { 00416 *itr = 255.0F - fabs((*itr) - bias[ii]); //corelate the bias 00417 } 00418 00419 tmp = downSize(tmp, cmap.getWidth(), cmap.getHeight()); 00420 //tmp = rescale(tmp, cmap->getWidth(), cmap->getHeight()); 00421 //inplaceAddBGnoise(tmp, 255.0); 00422 tmp = maxNormalize(tmp, MAXNORMMIN, MAXNORMMAX, normtyp); 00423 cmap += tmp; 00424 ii++; */ 00425 00426 //spawn a new thread for each centersurround computation 00427 workth[ii] = new BiasCenterSurroundThread(cmap,pyr, lev, lev + delta, bias[ii]); 00428 ii++; 00429 00430 } 00431 00432 //wait for thread to finish 00433 for (int i=0; i<ii; i++) 00434 workth[i]->join(NULL); 00435 00436 if (normtyp == VCXNORM_MAXNORM) 00437 cmap = maxNormalize(cmap, MAXNORMMIN, MAXNORMMAX, normtyp); 00438 else 00439 cmap = maxNormalize(cmap, 0.0f, 0.0f, normtyp); 00440 00441 // multiply by conspicuity coefficient: 00442 if (coeff != 1.0F) cmap *= coeff; 00443 00444 if (Debug) { 00445 time_taken = time.getSecs(); 00446 avrtime += time_taken; 00447 ++avgn; 00448 LINFO("CMap stats: agvn=%i avgtime=%0.4f time_taken=%f ptype=%i ori=%f coeff=%f", 00449 avgn, avrtime/(double)avgn, time_taken, (int)ptyp, ori, coeff); 00450 } 00451 00452 return image2Orb(cmap); 00453 } 00454 00455 00456 // ###################################################################### 00457 Image<float> *CMap_i::computeCMAP(const Image<float>& fimg, const PyramidType ptyp, const float ori, const float coeff) 00458 { 00459 00460 // compute pyramid: 00461 ImageSet<float> pyr = buildPyrGeneric(fimg, 0, maxdepth, 00462 ptyp, ori); 00463 00464 // alloc conspicuity map and clear it: 00465 Image<float> *cmap = new Image<float>(pyr[saliencyMapLevel].getDims(), ZEROS); 00466 00467 00468 // intensities is the max-normalized weighted sum of IntensCS: 00469 for (int delta = delta_min; delta <= delta_max; delta ++) 00470 for (int lev = level_min; lev <= level_max; lev ++) 00471 { 00472 Image<float> tmp = centerSurround(pyr, lev, lev + delta, true); 00473 tmp = downSize(tmp, cmap->getWidth(), cmap->getHeight()); 00474 //tmp = rescale(tmp, cmap->getWidth(), cmap->getHeight()); 00475 inplaceAddBGnoise(tmp, 255.0); 00476 tmp = maxNormalize(tmp, MAXNORMMIN, MAXNORMMAX, normtyp); 00477 *cmap += tmp; 00478 } 00479 if (normtyp == VCXNORM_MAXNORM) 00480 *cmap = maxNormalize(*cmap, MAXNORMMIN, MAXNORMMAX, normtyp); 00481 else 00482 *cmap = maxNormalize(*cmap, 0.0f, 0.0f, normtyp); 00483 00484 // multiply by conspicuity coefficient: 00485 if (coeff != 1.0F) *cmap *= coeff; 00486 00487 00488 return cmap; 00489 } 00490 00491 // ###################################################################### 00492 Image<float> *CMap_i::computeBiasCMAP(const Image<float>& fimg, const PyramidType ptyp, 00493 const float ori, const float coeff, 00494 const CMap::BiasSeq& bias) 00495 { 00496 // compute pyramid: 00497 ImageSet<float> pyr = buildPyrGeneric(fimg, 0, maxdepth, 00498 ptyp, ori); 00499 00500 // alloc conspicuity map and clear it: 00501 Image<float> *cmap = new Image<float>(pyr[saliencyMapLevel].getDims(), ZEROS); 00502 00503 if (Debug) { 00504 LINFO("Bias map with: "); 00505 for (uint i=0; i<bias.length(); i++) 00506 printf("%f ", bias[i]); 00507 printf("\n"); 00508 } 00509 00510 00511 // intensities is the max-normalized weighted sum of IntensCS: 00512 int ii=0; 00513 for (int delta = delta_min; delta <= delta_max; delta ++) 00514 for (int lev = level_min; lev <= level_max; lev ++) 00515 { 00516 Image<float> tmp = centerSurround(pyr, lev, lev + delta, true); 00517 inplaceNormalize(tmp, 0.0F, 255.0F); 00518 00519 //bias this level 00520 for (Image<float>::iterator itr = tmp.beginw(), stop = tmp.endw(); 00521 itr != stop; ++itr) { 00522 *itr = 255.0F - fabs((*itr) - bias[ii]); //corelate the bias 00523 } 00524 00525 tmp = downSize(tmp, cmap->getWidth(), cmap->getHeight()); 00526 //tmp = rescale(tmp, cmap->getWidth(), cmap->getHeight()); 00527 //inplaceAddBGnoise(tmp, 255.0); 00528 tmp = maxNormalize(tmp, MAXNORMMIN, MAXNORMMAX, normtyp); 00529 *cmap += tmp; 00530 ii++; 00531 } 00532 if (normtyp == VCXNORM_MAXNORM) 00533 *cmap = maxNormalize(*cmap, MAXNORMMIN, MAXNORMMAX, normtyp); 00534 else 00535 *cmap = maxNormalize(*cmap, 0.0f, 0.0f, normtyp); 00536 00537 // multiply by conspicuity coefficient: 00538 *cmap *= coeff; 00539 00540 return cmap; 00541 } 00542 00543 //start the class server 00544 int main(int argc, char **argv){ 00545 00546 MYLOGVERB = LOG_INFO; 00547 00548 // Instantiate a ModelManager: 00549 ModelManager manager("CMap Object"); 00550 00551 if (manager.parseCommandLine((const int)argc, (const char**)argv, "", 0, 0) == false) 00552 return(1); 00553 00554 00555 if (manager.debugMode()){ 00556 Debug = true; 00557 } else { 00558 LINFO("Running as a daemon. Set --debug to see any errors."); 00559 //Become a daemon 00560 // fork off the parent process 00561 pid_t pid = fork(); 00562 if (pid < 0) 00563 LFATAL("Can not fork"); 00564 00565 if (pid > 0) 00566 exit(0); //exit the parent process 00567 00568 // Change the file mask 00569 umask(0); 00570 00571 //Create a new system id so that the kernel wont think we are an orphan. 00572 pid_t sid = setsid(); 00573 if (sid < 0) 00574 LFATAL("Can not become independent"); 00575 00576 fclose(stdin); 00577 fclose(stdout); 00578 fclose(stderr); 00579 00580 } 00581 // catch signals and redirect them to terminate for clean exit: 00582 signal(SIGHUP, terminate); signal(SIGINT, terminate); 00583 signal(SIGQUIT, terminate); signal(SIGTERM, terminate); 00584 signal(SIGALRM, terminate); 00585 00586 //Create the object and run in 00587 orb = CORBA::ORB_init(argc, argv); 00588 00589 CORBA::Object_var obj = orb->resolve_initial_references("RootPOA"); 00590 PortableServer::POA_var poa = PortableServer::POA::_narrow(obj); 00591 00592 CMap_i* cmap = new CMap_i(); 00593 00594 PortableServer::ObjectId_var cmapid = poa->activate_object(cmap); 00595 00596 //get a ref string 00597 obj = cmap->_this(); 00598 CORBA::String_var sior(orb->object_to_string(obj)); 00599 std::cerr << "'" << (char*)sior << "'" << "\n"; 00600 00601 if( !bindObjectToName(orb, obj, "saliency", "CMapServers", "CMap", objectName) ){ 00602 LFATAL("Can not bind to name service"); 00603 return 1; 00604 } 00605 cmap->_remove_ref(); 00606 00607 PortableServer::POAManager_var pman = poa->the_POAManager(); 00608 pman->activate(); 00609 00610 try { 00611 manager.start(); 00612 //run the object untill shutdown or killed 00613 orb->run(); 00614 } catch (...) { 00615 LINFO("Error starting server"); 00616 } 00617 00618 LINFO("Shutting down"); 00619 unbindObject(orb, "saliency", "CMapServers", objectName); 00620 00621 manager.stop(); 00622 return 0; 00623 } 00624