00001 #include "CudaSaliency.H"
00002 #include "Util/Timer.H"
00003 #include "CUDA/CudaPyramidOps.H"
00004 #include "CUDA/CudaShapeOps.H"
00005 #include "CUDA/CudaTransforms.H"
00006 #include "CUDA/CudaPyrBuilder.H"
00007 #include "CUDA/CudaDrawOps.H"
00008 #include "CUDA/CudaNorm.H"
00009 #include "CUDA/CudaRandom.H"
00010 #include "Component/ModelOptionDef.H"
00011
00012
00013 #define IWEIGHT 0.7
00014 #define CWEIGHT 1.0
00015 #define OWEIGHT 1.0
00016 #define FWEIGHT 1.0
00017 #define SWEIGHT 0.7
00018 #define COLOR_THRESH 0.1F
00019
00020 #define delta_min 3
00021 #define delta_max 4
00022 #define level_min 0
00023 #define level_max 2
00024 #define maxdepth (level_max + delta_max + 1)
00025 #define sml 4
00026 #define normtyp VCXNORM_FANCY
00027 #define MAXNORMITERS 1
00028
00029 static const ModelOptionCateg MOC_CSM = {
00030 MOC_SORTPRI_3, "CudaSaliencyMap-related Options" };
00031
00032
00033 const ModelOptionDef OPT_CsmCudaDevice =
00034 { MODOPT_ARG(int), "CsmCudaDevice", &MOC_CSM, OPTEXP_CORE,
00035 "Number of frames in which the IOR map decays by half",
00036 "csm-cuda-device", '\0', "<int>", "0" };
00037
00038
00039 const ModelOptionDef OPT_CsmNMostSalientLoc =
00040 { MODOPT_ARG(int), "CsmNMostSalientLoc", &MOC_CSM, OPTEXP_CORE,
00041 "Return a vector with the stop n most salient locations",
00042 "csm-nmost-salient-loc", '\0', "int", "1" };
00043
00044
00045 const ModelOptionDef OPT_CsmIorHalfLife =
00046 { MODOPT_ARG(double), "CsmIorHalfLife", &MOC_CSM, OPTEXP_CORE,
00047 "Number of frames in which the IOR map decays by half",
00048 "csm-ior-halflife", '\0', "<double>", "6.5" };
00049
00050
00051 const ModelOptionDef OPT_CsmIorStrength =
00052 { MODOPT_ARG(double), "CsmIorStrength", &MOC_CSM, OPTEXP_CORE,
00053 "Magnitude of IOR (useful range 0..255)",
00054 "csm-ior-strength", '\0', "<double>", "16.0" };
00055
00056
00057 const ModelOptionDef OPT_CsmIorRadius =
00058 { MODOPT_ARG(double), "CsmIorRadius", &MOC_CSM, OPTEXP_CORE,
00059 "Radius of IOR",
00060 "csm-ior-radius", '\0', "<double>", "32.0" };
00061
00062
00063 const ModelOptionDef OPT_CsmPatchSize =
00064 { MODOPT_ARG(double), "CsmPatchSize", &MOC_CSM, OPTEXP_CORE,
00065 "Patch size",
00066 "csm-patch-size", '\0', "<double>", "72.0" };
00067
00068
00069 const ModelOptionDef OPT_CsmInertiaRadius =
00070 { MODOPT_ARG(double), "CsmInertiaRadius", &MOC_CSM, OPTEXP_CORE,
00071 "Radius of inertia blob",
00072 "csm-inertia-radius", '\0', "<double>", "32.0" };
00073
00074
00075 const ModelOptionDef OPT_CsmInertiaStrength =
00076 { MODOPT_ARG(double), "CsmInertiaStrength", &MOC_CSM, OPTEXP_CORE,
00077 "Initial strength of inertia blob",
00078 "csm-inertia-strength", '\0', "<double>", "100.0" };
00079
00080
00081 const ModelOptionDef OPT_CsmInertiaHalfLife =
00082 { MODOPT_ARG(double), "CsmInertiaHalfLife", &MOC_CSM, OPTEXP_CORE,
00083 "Number of frames in which the inertia blob decays by half",
00084 "csm-inertia-halflife", '\0', "<double>", "6.5" };
00085
00086
00087 const ModelOptionDef OPT_CsmInertiaShiftThresh =
00088 { MODOPT_ARG(double), "CsmInertiaShiftThresh", &MOC_CSM, OPTEXP_CORE,
00089 "Distance threshold for inertia shift",
00090 "csm-inertia-thresh", '\0', "<double>", "5.0" };
00091
00092
00093
00094 CudaSaliency::CudaSaliency(OptionManager& mgr,
00095 const std::string& descrName,
00096 const std::string& tagName):
00097 ModelComponent(mgr, descrName, tagName),
00098 itsCudaDevice(&OPT_CsmCudaDevice, this),
00099 itsInertiaLoc(-1,-1),
00100 itsCurrentInertiaFactor(1.0),
00101 itsInertiaMap(),
00102 itsInhibitionMap(),
00103 itsNMostSalientLoc(&OPT_CsmNMostSalientLoc, this, ALLOW_ONLINE_CHANGES),
00104 itsInertiaHalfLife(&OPT_CsmInertiaHalfLife, this, ALLOW_ONLINE_CHANGES),
00105 itsInertiaStrength(&OPT_CsmInertiaStrength, this, ALLOW_ONLINE_CHANGES),
00106 itsInertiaRadius(&OPT_CsmInertiaRadius, this, ALLOW_ONLINE_CHANGES),
00107 itsInertiaShiftThresh(&OPT_CsmInertiaShiftThresh, this, ALLOW_ONLINE_CHANGES),
00108 itsIorHalfLife(&OPT_CsmIorHalfLife, this, ALLOW_ONLINE_CHANGES),
00109 itsIorStrength(&OPT_CsmIorStrength, this, ALLOW_ONLINE_CHANGES),
00110 itsIorRadius(&OPT_CsmIorRadius, this, ALLOW_ONLINE_CHANGES),
00111 itsPatchSize(&OPT_CsmPatchSize, this, ALLOW_ONLINE_CHANGES),
00112 itsDynamicFactor(1.0)
00113
00114 {
00115 gotLum = false; gotRGBY = false; gotSaliency = false;
00116 mp = GLOBAL_DEVICE_MEMORY; dev = -1;
00117 numMotionDirs = 4;
00118 numOrientationDirs = 4;
00119 }
00120
00121 void CudaSaliency::setDevice(MemoryPolicy mp_in, int dev_in)
00122 {
00123 mp = mp_in;
00124 itsCudaDevice.setVal(dev_in);
00125 itsSalMaxLoc.resize(itsNMostSalientLoc.getVal());
00126 itsSalMax.resize(itsNMostSalientLoc.getVal());
00127 }
00128
00129
00130 void CudaSaliency::paramChanged(ModelParamBase* const param,
00131 const bool valueChanged,
00132 ParamClient::ChangeStatus* status)
00133 {
00134 if (param == &itsCudaDevice)
00135 {
00136 dev = itsCudaDevice.getVal();
00137 }
00138 if (param == &itsNMostSalientLoc)
00139 {
00140 itsSalMaxLoc.resize(itsNMostSalientLoc.getVal());
00141 itsSalMax.resize(itsNMostSalientLoc.getVal());
00142 }
00143 }
00144
00145
00146
00147 void CudaSaliency::start1()
00148 {
00149 cudaSetSeed(dev);
00150 cudaSizeRandomBuffer(randBuf,mp,dev);
00151 reichardtPyr = new CudaReichardtPyrBuilder<float>[numMotionDirs];
00152 for(int i=0;i<numMotionDirs;i++)
00153 {
00154 double direction = 360.0*double(i)/double(numMotionDirs);
00155 reichardtPyr[i] =
00156 CudaReichardtPyrBuilder<float>(cos(direction*M_PI/180.0),-sin(direction*M_PI/180.0),
00157 Gaussian5,direction+90.0);
00158 }
00159 }
00160
00161
00162 void CudaSaliency::stop2()
00163 {
00164 delete [] reichardtPyr;
00165 }
00166
00167
00168 CudaSaliency::~CudaSaliency()
00169 { }
00170
00171
00172 void CudaSaliency::doInput(const Image< PixRGB<byte> > img)
00173 {
00174 LINFO("new input.....");
00175 Image<PixRGB<float> > fimg = img;
00176 CudaImage<PixRGB<float> > tmp = CudaImage<PixRGB<float> >(fimg,mp,dev);
00177 doCudaInput(tmp);
00178 }
00179
00180 void CudaSaliency::clearMaps()
00181 {
00182 if(outmap.initialized())
00183 outmap.clear();
00184 if(intensityMap.initialized())
00185 intensityMap.clear();
00186 if(colorMap.initialized())
00187 colorMap.clear();
00188 if(orientationMap.initialized())
00189 orientationMap.clear();
00190 if(flickerMap.initialized())
00191 flickerMap.clear();
00192 if(motionMap.initialized())
00193 motionMap.clear();
00194 }
00195
00196 void CudaSaliency::doCudaInput(const CudaImage< PixRGB<float> > img)
00197 {
00198 int inDev = img.getMemoryDevice();
00199 ASSERT(inDev==dev);
00200 colima = img;
00201 clearMaps();
00202
00203 gotLum = false; gotRGBY = false;
00204
00205
00206 Timer tim;
00207
00208 tim.reset();
00209 runSaliency();
00210 LINFO("Done! %fms", tim.getSecs() * 1000.0F);
00211 }
00212
00213
00214 bool CudaSaliency::outputReady()
00215 {
00216 return gotSaliency;
00217 }
00218
00219
00220 Image<float> CudaSaliency::getOutput()
00221 {
00222 return convmap.exportToImage();
00223 }
00224
00225 CudaImage<float> CudaSaliency::getCudaOutput()
00226 {
00227 return convmap;
00228 }
00229
00230 CudaImage<float> CudaSaliency::getIMap()
00231 {
00232 return intensityMap;
00233 }
00234
00235 CudaImage<float> CudaSaliency::getCMap()
00236 {
00237 return colorMap;
00238 }
00239
00240 CudaImage<float> CudaSaliency::getOMap()
00241 {
00242 return orientationMap;
00243 }
00244
00245 CudaImage<float> CudaSaliency::getFMap()
00246 {
00247 return flickerMap;
00248 }
00249
00250 CudaImage<float> CudaSaliency::getMMap()
00251 {
00252 return motionMap;
00253 }
00254
00255 CudaImage<float> CudaSaliency::getInertiaMap()
00256 {
00257 return itsInertiaMap;
00258 }
00259
00260 CudaImage<float> CudaSaliency::getInhibitionMap()
00261 {
00262 return itsInhibitionMap;
00263 }
00264
00265 std::vector<Point2D<int> > CudaSaliency::getSalMaxLoc()
00266 {
00267 return itsSalMaxLoc;
00268 }
00269
00270 std::vector<float> CudaSaliency::getSalMax()
00271 {
00272 return itsSalMax;
00273 }
00274
00275 double CudaSaliency::getPatchSize()
00276 {
00277 return itsPatchSize.getVal();
00278 }
00279
00280 CudaImage<float> CudaSaliency::cudaPostChannel(CudaImage<float> curImage, PyramidType ptyp, float orientation, float weight, CudaImage<float>& outmap)
00281 {
00282
00283 CudaImageSet<float> pyr =
00284 cudaBuildPyrGeneric(curImage, 0, maxdepth, ptyp, orientation);
00285 CudaImage<float> cmap = processPyramid(pyr);
00286
00287
00288 if (weight != 1.0F) cmap *= weight;
00289
00290 if (outmap.initialized()) outmap += cmap;
00291 else outmap = cmap;
00292 return cmap;
00293 }
00294
00295 CudaImage<float> CudaSaliency::processPyramid(CudaImageSet<float> pyr)
00296 {
00297
00298 CudaImage<float> cmap;
00299
00300
00301 for (int delta = delta_min; delta <= delta_max; delta ++)
00302 for (int lev = level_min; lev <= level_max; lev ++)
00303 {
00304 CudaImage<float> tmp = cudaCenterSurround(pyr, lev, lev + delta, true);
00305 tmp = cudaDownSize(tmp, pyr[sml].getWidth(), pyr[sml].getHeight());
00306 tmp = cudaMaxNormalize(tmp, MAXNORMMIN, MAXNORMMAX, normtyp,MAXNORMITERS);
00307 if(cmap.initialized())
00308 cmap += tmp;
00309 else
00310 cmap = tmp;
00311 }
00312
00313 cudaInplaceAddBGnoise(cmap, 25.0F,randBuf);
00314
00315
00316 if (normtyp == VCXNORM_MAXNORM)
00317 cmap = cudaMaxNormalize(cmap, MAXNORMMIN, MAXNORMMAX, normtyp,MAXNORMITERS);
00318 else
00319 cmap = cudaMaxNormalize(cmap, 0.0f, 0.0f, normtyp,MAXNORMITERS);
00320
00321
00322 return cmap;
00323 }
00324
00325 void CudaSaliency::calcInertia(const CudaImage<float> & salMap)
00326 {
00327 const MemoryPolicy mp = salMap.getMemoryPolicy();
00328 int dev = salMap.getMemoryDevice();
00329 ASSERT(mp != HOST_MEMORY);
00330
00331 if (itsInertiaLoc.i < 0 || itsInertiaLoc.j < 0
00332 || (itsSalMaxLoc[0].squdist(itsInertiaLoc)
00333 > (itsInertiaShiftThresh.getVal()
00334 * itsInertiaShiftThresh.getVal())))
00335 {
00336 itsCurrentInertiaFactor = 1.0;
00337 LDEBUG("inertia shift to (%d,%d)",
00338 itsSalMaxLoc[0].i, itsSalMaxLoc[0].j);
00339 }
00340 else
00341 {
00342 const float factor =
00343 (itsDynamicFactor * itsInertiaHalfLife.getVal()) > 0
00344 ? pow(0.5, 1.0/(itsDynamicFactor * itsInertiaHalfLife.getVal()))
00345 : 0.0f;
00346 itsCurrentInertiaFactor *= factor;
00347 }
00348
00349 {
00350 if (itsInertiaMap.getDims() != salMap.getDims() ||
00351 itsInertiaMap.getMemoryDevice() != dev)
00352 itsInertiaMap = CudaImage<float>(salMap.getDims(), ZEROS, mp, dev);
00353
00354 itsInertiaLoc = itsSalMaxLoc[0];
00355
00356 const double s = itsInertiaStrength.getVal() * itsDynamicFactor * itsCurrentInertiaFactor;
00357 const double r_inv = itsInertiaRadius.getVal() > 0.0
00358 ? (1.0 / itsInertiaRadius.getVal()) : 0.0;
00359 Dims tile = CudaDevices::getDeviceTileSize1D(dev);
00360 int w = itsInertiaMap.getWidth();
00361 int h = itsInertiaMap.getHeight();
00362 cuda_c_inertiaMap(itsInertiaMap.getCudaArrayPtr(),s,r_inv,itsInertiaLoc.i,itsInertiaLoc.j,tile.w(),tile.h(),w,h);
00363 }
00364 }
00365
00366 void CudaSaliency::calcInhibition(const CudaImage<float> & salMap)
00367 {
00368 const MemoryPolicy mp = salMap.getMemoryPolicy();
00369 int dev = salMap.getMemoryDevice();
00370 ASSERT(mp != HOST_MEMORY);
00371 if (itsDynamicFactor * itsIorStrength.getVal() > 0.0)
00372 {
00373 if (itsInhibitionMap.getDims() != salMap.getDims() ||
00374 itsInhibitionMap.getMemoryDevice() != dev)
00375 itsInhibitionMap = CudaImage<float>(salMap.getDims(), ZEROS, mp, dev);
00376
00377 const float factor =
00378 (itsDynamicFactor * itsIorHalfLife.getVal()) > 0
00379 ? pow(0.5, 1.0/(itsDynamicFactor * itsIorHalfLife.getVal()))
00380 : 0.0f;
00381
00382 Dims tile = CudaDevices::getDeviceTileSize1D(dev);
00383 int w = itsInhibitionMap.getWidth();
00384 int h = itsInhibitionMap.getHeight();
00385
00386 cuda_c_inhibitionMap(itsInhibitionMap.getCudaArrayPtr(),factor,itsDynamicFactor*itsIorStrength.getVal(),itsIorRadius.getVal(),
00387 itsSalMaxLoc[0].i,itsSalMaxLoc[0].j,tile.w(),tile.h(),w,h);
00388 }
00389 else
00390 itsInhibitionMap.clear(0);
00391
00392 }
00393
00394
00395 void CudaSaliency::calcIntensity(const CudaImage<PixRGB<float> > & colImage, CudaImage<float>& outmap)
00396 {
00397 if(gotLum == false)
00398 {
00399 curLum = cudaLuminance(colImage);
00400
00401 curLumPyr = cudaBuildPyrGeneric(curLum, 0, maxdepth, Gaussian5, 0.0F);
00402 CudaImage<float> cmap = processPyramid(curLumPyr);
00403
00404 if (IWEIGHT != 1.0F) cmap *= IWEIGHT;
00405
00406 if (outmap.initialized()) outmap += cmap;
00407 else outmap = cmap;
00408 intensityMap=cmap;
00409 gotLum = true;
00410 }
00411 }
00412
00413
00414 void CudaSaliency::calcColor(const CudaImage<PixRGB<float> > & colImage, CudaImage<float>& outmap)
00415 {
00416 if(gotRGBY == false)
00417 {
00418 cudaGetRGBY(colImage,rg,by,COLOR_THRESH);
00419 gotRGBY = true;
00420 }
00421 CudaImage<float> col=(rg+by)/2.0F;
00422 colorMap = cudaPostChannel(col,Gaussian5,0.0F,CWEIGHT,outmap);
00423 }
00424
00425 void CudaSaliency::calcOrientation(const CudaImage<PixRGB<float> > & colImage, float orientation, CudaImage<float>& outmap)
00426 {
00427 if(gotLum == false)
00428 {
00429 curLum = cudaLuminance(colImage);
00430 gotLum = true;
00431 }
00432 CudaImage<float> o = cudaPostChannel(curLum,Oriented5,orientation,OWEIGHT,outmap);
00433 if(orientationMap.initialized())
00434 orientationMap += o;
00435 else
00436 orientationMap = o;
00437 }
00438
00439 void CudaSaliency::calcFlicker(const CudaImage<PixRGB<float> >& colImage, CudaImage<float>& outmap)
00440 {
00441 CudaImage<float> curImage;
00442 if(gotLum == false)
00443 {
00444 curLum = cudaLuminance(colima);
00445 gotLum = true;
00446 }
00447 if (prevLum.initialized() == false)
00448 {
00449 prevLum = curLum;
00450 curImage = CudaImage<float>(curLum.getDims(), ZEROS, mp, dev);
00451 }
00452 else
00453 {
00454 curImage = curLum - prevLum;
00455 prevLum = curLum;
00456 }
00457 flickerMap = cudaPostChannel(curImage,Gaussian5,0.0F,FWEIGHT,outmap);
00458 }
00459
00460 void CudaSaliency::calcMotion(const CudaImage<PixRGB<float> > & colImage, int motionIndex)
00461 {
00462 if(gotLum == false)
00463 {
00464 curLum = cudaLuminance(colImage);
00465 gotLum = true;
00466 }
00467
00468 CudaImageSet<float> motPyr = reichardtPyr[motionIndex].build(curLum,0,maxdepth);
00469 CudaImage<float> m = processPyramid(motPyr);
00470 if(motionMap.initialized())
00471 motionMap += m;
00472 else
00473 motionMap = m;
00474 }
00475
00476 void CudaSaliency::runSaliency()
00477 {
00478 Timer tim;
00479 gotSaliency = false;
00480 tim.reset();
00481 calcIntensity(colima,outmap);
00482
00483
00484 tim.reset();
00485 calcColor(colima,outmap);
00486
00487 tim.reset();
00488
00489
00490 for(int i=0;i<numOrientationDirs;i++)
00491 {
00492 calcOrientation(colima,180.0*double(i)/double(numOrientationDirs),outmap);
00493 }
00494
00495 tim.reset();
00496 calcFlicker(colima,outmap);
00497
00498
00499 for(int i=0;i<numMotionDirs;i++)
00500 {
00501 calcMotion(colima,i);
00502 }
00503
00504
00505 motionMap = cudaMaxNormalize(motionMap, MAXNORMMIN, MAXNORMMAX, normtyp,MAXNORMITERS);
00506 motionMap *=10;
00507
00508 if (outmap.initialized()) outmap += motionMap;
00509 else outmap = motionMap;
00510
00511 if(itsInhibitionMap.initialized())
00512 outmap -= itsInhibitionMap;
00513 cudaInplaceClamp(outmap,0,255);
00514 convmap = outmap;
00515 double w_ratio = outmap.getWidth()/double(colima.getWidth());
00516 double h_ratio = outmap.getHeight()/double(colima.getHeight());
00517 int smallPatchWidth = itsPatchSize.getVal()*w_ratio;
00518 int smallPatchHeight = itsPatchSize.getVal()*h_ratio;
00519 Dims rectDims = Dims(smallPatchHeight,smallPatchHeight);
00520 CudaImage<float> tmpmap = outmap;
00521
00522
00523 for(int i=0;i<itsNMostSalientLoc.getVal();i++)
00524 {
00525 cudaFindMax(tmpmap,itsSalMaxLoc[i],itsSalMax[i]);
00526 int modI = std::max(0,std::min(itsSalMaxLoc[i].i-smallPatchWidth/2,int(outmap.getWidth()-smallPatchWidth/2)));
00527 int modJ = std::max(0,std::min(itsSalMaxLoc[i].j-smallPatchHeight/2,int(outmap.getHeight()-smallPatchHeight/2)));
00528
00529 Rectangle tmprect = Rectangle(Point2D<int>(modI,modJ),rectDims);
00530 if(i+1<itsNMostSalientLoc.getVal())
00531 cudaDrawFilledRect(tmpmap,tmprect,0);
00532 }
00533
00534 calcInhibition(outmap);
00535 if(!itsInhibitionMap.initialized())
00536 itsInhibitionMap = CudaImage<float>(outmap.getDims(), ZEROS, mp, dev);
00537
00538 gotSaliency = true;
00539 }