00001 /*!@file Surprise/SurpriseControl.C attempt to control surprise in 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: T. Nathan Mundhenk <mundhenk@usc.edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Surprise/SurpriseControl.C $ 00035 // $Id: SurpriseControl.C 14376 2011-01-11 02:44:34Z pez $ 00036 // 00037 00038 #ifndef SURPRISE_CONTROL_C_DEFINED 00039 #define SURPRISE_CONTROL_C_DEFINED 00040 00041 #include "Surprise/SurpriseControl.H" 00042 00043 #include <typeinfo> 00044 #include <climits> 00045 #include <cfloat> 00046 00047 /*************************************************************************/ 00048 00049 template <class PIXTYPE, class BETATYPE, class FLOAT> 00050 SurpriseControl<PIXTYPE,BETATYPE,FLOAT>::SurpriseControl(const ushort sizeX, 00051 const ushort sizeY) 00052 { 00053 LINFO("Creating SurpriseControl Object"); 00054 00055 00056 SCinit(sizeX,sizeY); 00057 SCuseMaxLevel(false); 00058 00059 if(typeid(BETATYPE).name() != typeid(itsHyper).name()) 00060 { 00061 LFATAL("Run time type error. Type: %s is not supported", 00062 typeid(BETATYPE).name()); 00063 } 00064 } 00065 00066 /*************************************************************************/ 00067 00068 template <class PIXTYPE, class BETATYPE, class FLOAT> 00069 SurpriseControl<PIXTYPE,BETATYPE,FLOAT>::SurpriseControl() 00070 { 00071 LINFO("Creating SurpriseControl Object NOTE: Call init()"); 00072 00073 if(typeid(BETATYPE).name() != typeid(itsHyper).name()) 00074 { 00075 LFATAL("Run time type error. Type: %s is not supported", 00076 typeid(BETATYPE).name()); 00077 } 00078 } 00079 00080 /*************************************************************************/ 00081 00082 template <class PIXTYPE, class BETATYPE, class FLOAT> 00083 SurpriseControl<PIXTYPE,BETATYPE,FLOAT>::~SurpriseControl() 00084 {} 00085 00086 /*************************************************************************/ 00087 00088 template <class PIXTYPE, class BETATYPE, class FLOAT> inline 00089 void SurpriseControl<PIXTYPE,BETATYPE,FLOAT>::SCuseMaxLevel(const bool useML) 00090 { 00091 LINFO("Setting itsUseMaxLevel"); 00092 itsUseMaxLevel = useML; 00093 } 00094 00095 /*************************************************************************/ 00096 template <class PIXTYPE, class BETATYPE, class FLOAT> inline 00097 void SurpriseControl<PIXTYPE,BETATYPE,FLOAT>::SCuseTemporal(const bool useTMP) 00098 { 00099 LINFO("Setting itsUseTemporal"); 00100 itsUseTemporal = useTMP; 00101 } 00102 00103 /*************************************************************************/ 00104 template <class PIXTYPE, class BETATYPE, class FLOAT> inline 00105 void SurpriseControl<PIXTYPE,BETATYPE,FLOAT>:: SCnormalizeBiasWithScale( 00106 const bool useNBS) 00107 { 00108 LINFO("Setting itsNormalizeBiasWithScale"); 00109 itsNormalizeBiasWithScale = useNBS; 00110 } 00111 00112 /*************************************************************************/ 00113 template <class PIXTYPE, class BETATYPE, class FLOAT> inline 00114 void SurpriseControl<PIXTYPE,BETATYPE,FLOAT>::SCsetMasterConspicBias( 00115 const FLOAT bias) 00116 { 00117 itsMasterConspicBias = bias; 00118 } 00119 00120 /*************************************************************************/ 00121 template <class PIXTYPE, class BETATYPE, class FLOAT> inline 00122 void SurpriseControl<PIXTYPE,BETATYPE,FLOAT>::SCsetConspicBias( 00123 const FLOAT chan, 00124 const int chan_enum) 00125 { 00126 //LINFO("Using %s map - bias %f",sc_channel_name[chan_enum].c_str(),chan); 00127 itsConspicMapBias[chan_enum] = chan; 00128 itsUseConspicMap[chan_enum] = true; 00129 } 00130 /*************************************************************************/ 00131 template <class PIXTYPE, class BETATYPE, class FLOAT> inline 00132 void SurpriseControl<PIXTYPE,BETATYPE,FLOAT>::SCsetMyScale(const ushort scale) 00133 { 00134 itsScale = scale; 00135 } 00136 00137 /*************************************************************************/ 00138 00139 template <class PIXTYPE, class BETATYPE, class FLOAT> inline 00140 void SurpriseControl<PIXTYPE,BETATYPE,FLOAT>::SCsetAxisBias(const FLOAT X, 00141 const FLOAT Y, 00142 const FLOAT Z) 00143 { 00144 itsXBias = X; itsYBias = Y; itsZBias = Z; 00145 } 00146 /*************************************************************************/ 00147 00148 template <class PIXTYPE, class BETATYPE, class FLOAT> inline 00149 void SurpriseControl<PIXTYPE,BETATYPE,FLOAT>::SCsetH2SVBias(const FLOAT H1, 00150 const FLOAT H2, 00151 const FLOAT S, 00152 const FLOAT V) 00153 { 00154 itsH1Bias = H1; itsH2Bias = H2; itsSBias = S; itsVBias = V; 00155 } 00156 00157 /*************************************************************************/ 00158 00159 template <class PIXTYPE, class BETATYPE, class FLOAT> inline 00160 void SurpriseControl<PIXTYPE,BETATYPE,FLOAT>::SCinit(const ushort sizeX, 00161 const ushort sizeY) 00162 { 00163 LINFO("INIT: image size %d x %d",sizeX,sizeY); 00164 00165 for(ushort i = 0; i < SC_MAX_CHANNELS; i++) 00166 { 00167 itsConspicMapBias[i] = 1.0F; 00168 itsUseConspicMap[i] = false; 00169 } 00170 00171 itsIterCounter = 0; 00172 itsScale = 0; 00173 00174 itsXBias = 1.0F; itsYBias = 1.0F; itsZBias = 1.0F; 00175 00176 itsLambda = 0.1; 00177 itsInitBuffer = false; 00178 itsUseCorrMatrixSet = false; 00179 itsUseBayesWeightImage = false; 00180 itsUseMaskImage = false; 00181 itsUseTargetFrame = false; 00182 itsUseTemporal = true; 00183 itsBufferFull = false; 00184 itsNormalizeBiasWithScale = false; 00185 itsImageSizeX = sizeX; 00186 itsImageSizeY = sizeY; 00187 00188 itsTargetFrame = 0; 00189 00190 itsInImage.resize(sizeX,sizeY); 00191 itsOutImage.resize(sizeX,sizeY); 00192 itsFinalImage.resize(sizeX,sizeY); 00193 itsLocalBiasH1.resize(sizeX,sizeY); 00194 itsLocalBiasH2.resize(sizeX,sizeY); 00195 itsLocalBiasS.resize(sizeX,sizeY); 00196 itsLocalBiasV.resize(sizeX,sizeY); 00197 itsSmallSaliency.resize(sizeX,sizeY); 00198 BETATYPE blank(0.0F); 00199 PIXTYPE blank2(0.0F); 00200 00201 Image<BETATYPE> initBeta; initBeta.resize(sizeX,sizeY); 00202 typename Image<BETATYPE>::iterator betaImageItr = initBeta.beginw(); 00203 Image<PIXTYPE> tempImage; 00204 tempImage.resize(sizeX,sizeY); 00205 typename Image<PIXTYPE>::iterator tempImageItr = tempImage.beginw(); 00206 while(betaImageItr != initBeta.endw()) 00207 { 00208 *betaImageItr = blank; 00209 *tempImageItr = blank2; 00210 ++betaImageItr; ++tempImageItr; 00211 } 00212 00213 itsBetaImage.push_front(initBeta); 00214 00215 // resize intermediate images, set equal to the blank beta image 00216 00217 itsInterImage.resize(2,tempImage); 00218 } 00219 00220 /*************************************************************************/ 00221 00222 template <class PIXTYPE, class BETATYPE, class FLOAT> inline 00223 void SurpriseControl<PIXTYPE,BETATYPE,FLOAT>::SCsetLambda(const FLOAT lambda) 00224 { 00225 itsLambda = lambda; 00226 } 00227 // 1. create a guassian filtered frame of the current movie 00228 /*************************************************************************/ 00229 00230 template <class PIXTYPE, class BETATYPE, class FLOAT> inline 00231 void SurpriseControl<PIXTYPE,BETATYPE,FLOAT>::SCsetTargetFrame(const uint frame) 00232 { 00233 itsTargetFrame = frame; 00234 itsUseTargetFrame = true; 00235 } 00236 // 2. merge the guassian filtered frame with the current frame giving more 00237 // weight to filtered pixels if the surprise is higher. 00238 00239 /*************************************************************************/ 00240 00241 template <class PIXTYPE, class BETATYPE, class FLOAT> inline 00242 void SurpriseControl<PIXTYPE,BETATYPE,FLOAT>::SCsetOriginalImageWeight( 00243 const FLOAT origImageWeight) 00244 { 00245 itsOriginalImageWeight = origImageWeight; 00246 } 00247 00248 /*************************************************************************/ 00249 00250 template <class PIXTYPE, class BETATYPE, class FLOAT> 00251 void SurpriseControl<PIXTYPE,BETATYPE,FLOAT>::SCcreateAndersonSepFilters( 00252 const ushort size) 00253 { 00254 const ushort basesize = 5; 00255 00256 if(size%basesize != 0) 00257 LFATAL("This kernel size must be evenly divisable by 5 got %d",size); 00258 00259 const FLOAT anderson[basesize] = {1.0/16.0, 4.0/16.0, 6.0/16.0, 00260 4.0/16.0, 1.0/16.0}; 00261 for(ushort i = 0; i < basesize; i++) 00262 { 00263 LINFO("%f",anderson[i]); 00264 } 00265 const short div = size/basesize; 00266 00267 bool evensize; 00268 00269 if(size%2 == 0) 00270 { 00271 evensize = true; 00272 itsKernelSizeX = size + 1; 00273 itsKernelSizeY = size + 1; 00274 } 00275 else 00276 { 00277 itsKernelSizeX = size; 00278 itsKernelSizeY = size; 00279 evensize = false; 00280 } 00281 itsKernelSizeZ = basesize; 00282 00283 itsKalmanKernelX.resize(itsKernelSizeX,0.0F); 00284 itsKalmanKernelY.resize(itsKernelSizeY,0.0F); 00285 itsKalmanKernelZ.resize(itsKernelSizeZ,0.0F); 00286 00287 const FLOAT centerX = floor((FLOAT)itsKernelSizeX/2.0F); 00288 00289 ushort offset = 0; 00290 LINFO("Kernel (Anderson Variant) size %d",itsKernelSizeX); 00291 for(ushort i = 0; i < itsKernelSizeX; i++) 00292 { 00293 if((i < centerX) || (evensize == false)) 00294 { 00295 if((i%div == 0) && (i != 0)) 00296 offset++; 00297 } 00298 else 00299 { 00300 if((i - 1)%div == 0) 00301 offset++; 00302 } 00303 00304 itsKalmanKernelX[i] = anderson[offset]; 00305 itsKalmanKernelY[i] = anderson[offset]; 00306 std::cerr << i << " : " << itsKalmanKernelX[i] << "\n"; 00307 } 00308 00309 for(ushort i = 0; i < itsKernelSizeZ; i++) 00310 { 00311 itsKalmanKernelZ[i] = anderson[i]; 00312 } 00313 00314 itsImageSizeZ = itsKernelSizeZ; 00315 itsTemporalOffset = (ushort)floor(itsKernelSizeZ/2.0); 00316 } 00317 00318 /*************************************************************************/ 00319 template <class PIXTYPE, class BETATYPE, class FLOAT> 00320 void SurpriseControl<PIXTYPE,BETATYPE,FLOAT>::SCcreateSepFilters( 00321 const FLOAT spatSigma, 00322 const FLOAT tempSigma, 00323 const FLOAT stdDevSize) 00324 { 00325 LINFO("ASAC SETTING UP KERNELS"); 00326 // create three components for a std seperable guassian kernel 00327 ushort rs1 = (ushort)ceil(spatSigma*stdDevSize*2.0F); 00328 ushort rs2 = (ushort)floor(spatSigma*stdDevSize*2.0F); 00329 // make sure the kernel is odd sized spatial 00330 if(rs1%2 == 0) 00331 { 00332 if(rs2%2 == 0) 00333 { 00334 itsKernelSizeX = rs2 + 1; 00335 itsKernelSizeY = rs2 + 1; 00336 } 00337 else 00338 { 00339 itsKernelSizeX = rs2; 00340 itsKernelSizeY = rs2; 00341 } 00342 } 00343 else 00344 { 00345 itsKernelSizeX = rs1; 00346 itsKernelSizeY = rs1; 00347 } 00348 itsKalmanKernelX.resize(itsKernelSizeX,0.0F); 00349 itsKalmanKernelY.resize(itsKernelSizeY,0.0F); 00350 00351 rs1 = (ushort)ceil((tempSigma*stdDevSize*2.0F)); 00352 rs2 = (ushort)floor((tempSigma*stdDevSize*2.0F)); 00353 // make sure the kernel is odd sized temporal 00354 if(rs1%2 == 0) 00355 { 00356 if(rs2%2 == 0) 00357 { 00358 itsKernelSizeZ = rs2 + 1; 00359 } 00360 else 00361 { 00362 itsKernelSizeZ = rs2; 00363 } 00364 } 00365 else 00366 { 00367 itsKernelSizeZ = rs1; 00368 } 00369 itsKalmanKernelZ.resize(itsKernelSizeZ,0.0F); 00370 00371 itsImageSizeZ = itsKernelSizeZ; 00372 00373 // find the kernel center 00374 00375 const FLOAT centerX = floor((FLOAT)itsKernelSizeX/2.0F); 00376 const FLOAT centerY = floor((FLOAT)itsKernelSizeY/2.0F); 00377 const FLOAT centerZ = floor((FLOAT)itsKernelSizeZ/2.0F); 00378 00379 FLOAT gmod = 1.0F/sqrt(2.0F*M_PI*pow(spatSigma,2)); 00380 00381 LINFO("Kernel X size %d",itsKernelSizeX); 00382 for(ushort i = 0; i < itsKernelSizeX; i++) 00383 { 00384 const FLOAT dist = pow((i - centerX),2); 00385 itsKalmanKernelX[i] = 00386 (gmod*exp((-1.0F*dist)/pow(2*spatSigma,2))); 00387 std::cerr << i << " : " << itsKalmanKernelX[i] << "\n"; 00388 } 00389 LINFO("Kernel Y size %d",itsKernelSizeY); 00390 for(ushort i = 0; i < itsKernelSizeY; i++) 00391 { 00392 const FLOAT dist = pow((i - centerY),2); 00393 itsKalmanKernelY[i] = 00394 (gmod*exp((-1.0F*dist)/pow(2*spatSigma,2))); 00395 std::cerr << i << " : " << itsKalmanKernelY[i] << "\n"; 00396 } 00397 00398 gmod = 1.0F/sqrt(2.0F*M_PI*pow(tempSigma,2)); 00399 LINFO("Kernel Z size %d",itsKernelSizeZ); 00400 for(ushort i = 0; i < itsKernelSizeZ; i++) 00401 { 00402 const FLOAT dist = pow((i - centerZ),2); 00403 itsKalmanKernelZ[i] = 00404 (gmod*exp((-1.0F*dist)/pow(2*tempSigma,2))); 00405 std::cerr << i << " : " << itsKalmanKernelZ[i] << "\n"; 00406 } 00407 00408 itsTemporalOffset = (ushort)floor(itsKernelSizeZ/2.0); 00409 } 00410 00411 /*************************************************************************/ 00412 template <class PIXTYPE, class BETATYPE, class FLOAT> 00413 void SurpriseControl<PIXTYPE,BETATYPE,FLOAT>::SCfindConvolutionEndPoints() 00414 { 00415 LINFO("SETTING UP CONVOLUTION END POINTS"); 00416 00417 itsXStart.resize(itsImageSizeX,itsImageSizeY); 00418 itsYStart.resize(itsImageSizeX,itsImageSizeY); 00419 itsZStart.resize(itsImageSizeX,itsImageSizeY); 00420 itsXStop.resize( itsImageSizeX,itsImageSizeY); 00421 itsYStop.resize( itsImageSizeX,itsImageSizeY); 00422 itsZStop.resize( itsImageSizeX,itsImageSizeY); 00423 itsKXStart.resize(itsImageSizeX,itsImageSizeY); 00424 itsKYStart.resize(itsImageSizeX,itsImageSizeY); 00425 itsKZStart.resize(itsImageSizeX,itsImageSizeY); 00426 00427 Image<ushort>::iterator itsZStartItr = itsZStart.beginw(); 00428 Image<ushort>::iterator itsZStopItr = itsZStop.beginw(); 00429 Image<ushort>::iterator itsKZStartItr = itsKZStart.beginw(); 00430 00431 Image<ushort>::iterator itsYStartItr = itsYStart.beginw(); 00432 Image<ushort>::iterator itsYStopItr = itsYStop.beginw(); 00433 Image<ushort>::iterator itsKYStartItr = itsKYStart.beginw(); 00434 00435 Image<ushort>::iterator itsXStartItr = itsXStart.beginw(); 00436 Image<ushort>::iterator itsXStopItr = itsXStop.beginw(); 00437 Image<ushort>::iterator itsKXStartItr = itsKXStart.beginw(); 00438 00439 for(ushort y = 0; y < itsImageSizeY; y++) 00440 { 00441 for(ushort x = 0; x < itsImageSizeX; x++) 00442 { 00443 // Z is not interesting, its starts at the current frame and 00444 // runs the size of the deque 00445 00446 *itsKZStartItr = 0; 00447 *itsZStartItr = 0; 00448 *itsZStopItr = itsKernelSizeZ; 00449 00450 const ushort yhalf = (ushort)floor((FLOAT)itsKernelSizeY/2.0F); 00451 const ushort yend = itsImageSizeY - yhalf; 00452 if(y < yhalf + 1) 00453 { 00454 *itsYStartItr = 0; 00455 *itsKYStartItr = yhalf - y; 00456 *itsYStopItr = y + yhalf; 00457 } 00458 else if(y > yend) 00459 { 00460 *itsYStartItr = y - yhalf; 00461 *itsKYStartItr = 0; 00462 *itsYStopItr = itsImageSizeY; 00463 } 00464 else 00465 { 00466 *itsYStartItr = y - yhalf; 00467 *itsKYStartItr = 0; 00468 *itsYStopItr = y + yhalf; 00469 } 00470 00471 const ushort xhalf = (ushort)floor((FLOAT)itsKernelSizeX/2.0F); 00472 const ushort xend = itsImageSizeX - xhalf; 00473 if(x < xhalf + 1) 00474 { 00475 *itsXStartItr = 0; 00476 *itsKXStartItr = xhalf - x; 00477 *itsXStopItr = x + xhalf; 00478 } 00479 else if(x > xend) 00480 { 00481 *itsXStartItr = x - xhalf; 00482 *itsKXStartItr = 0; 00483 *itsXStopItr = itsImageSizeX; 00484 } 00485 else 00486 { 00487 *itsXStartItr = x - xhalf; 00488 *itsKXStartItr = 0; 00489 *itsXStopItr = x + xhalf; 00490 } 00491 00492 ++itsZStartItr; ++itsZStopItr; ++itsKZStartItr; 00493 ++itsYStartItr; ++itsYStopItr; ++itsKYStartItr; 00494 ++itsXStartItr; ++itsXStopItr; ++itsKXStartItr; 00495 } 00496 } 00497 } 00498 00499 00500 /*************************************************************************/ 00501 template <class PIXTYPE, class BETATYPE, class FLOAT> inline 00502 void SurpriseControl<PIXTYPE,BETATYPE,FLOAT>::SCinputRawImage( 00503 const Image<PixRGB<FLOAT> >& rawImage) 00504 { 00505 //LINFO("INPUT RAW IMAGE"); 00506 00507 if(rawImage.getHeight() != itsImageSizeY) 00508 { 00509 LINFO("Input raw image is not the correct size"); 00510 LFATAL("Raw %d != sizeY %d",rawImage.getHeight(),itsImageSizeY); 00511 } 00512 if(rawImage.getWidth() != itsImageSizeX) 00513 { 00514 LINFO("Input raw image is not the correct size"); 00515 LFATAL("Raw %d != sizeX %d",rawImage.getWidth(),itsImageSizeX); 00516 } 00517 00518 typename Image<PIXTYPE >::iterator inImageItr = 00519 itsInImage.beginw(); 00520 typename Image<PixRGB<FLOAT> >::const_iterator rawImageItr = 00521 rawImage.begin(); 00522 00523 // convert the input image to H2SV2 00524 while(inImageItr != itsInImage.endw()) 00525 { 00526 *inImageItr = PIXTYPE(*rawImageItr); 00527 ++inImageItr; ++rawImageItr; 00528 } 00529 00530 itsFrameBuffer.push_front(itsInImage); 00531 itsInitBuffer = true; 00532 00533 //if we get to big, pop off the back image 00534 if(itsFrameBuffer.size() > (unsigned)(itsImageSizeZ + 1)) 00535 { 00536 itsFrameBuffer.pop_back(); 00537 itsBufferFull = true; 00538 } 00539 } 00540 00541 /*************************************************************************/ 00542 00543 template <class PIXTYPE, class BETATYPE, class FLOAT> inline 00544 void SurpriseControl<PIXTYPE,BETATYPE,FLOAT>::SCinputSalMap( 00545 const Image<FLOAT>& salMap) 00546 { 00547 if(itsInImage.getWidth() != salMap.getWidth()) 00548 { 00549 LINFO("Saliency map is the wrong size or raw image not initalized"); 00550 LFATAL("Sal Map Width %d != Raw Image Width %d",salMap.getWidth(), 00551 itsInImage.getWidth()); 00552 } 00553 if(itsInImage.getHeight() != salMap.getHeight()) 00554 { 00555 LINFO("Saliency map is the wrong size or raw image not initalized"); 00556 LFATAL("Sal Map Height %d != Raw Image Height %d",salMap.getHeight(), 00557 itsInImage.getHeight()); 00558 } 00559 00560 // normalize from 0 to 1 00561 itsSalMap = salMap/255.0F; 00562 } 00563 00564 /*************************************************************************/ 00565 00566 template <class PIXTYPE, class BETATYPE, class FLOAT> inline 00567 void SurpriseControl<PIXTYPE,BETATYPE,FLOAT>::SCinputConspicMap( 00568 const Image<FLOAT>& cmap, 00569 const int cmap_enum) 00570 { 00571 if(itsUseConspicMap[cmap_enum] != true) 00572 { 00573 LINFO("Called to input %s image, but did not expect it", 00574 sc_channel_name[cmap_enum].c_str()); 00575 LFATAL("Be sure to set the bias first!"); 00576 } 00577 if(itsInImage.getWidth() != cmap.getWidth()) 00578 { 00579 LINFO("Saliency map is the wrong size or raw image not initalized"); 00580 LFATAL("Conspic Width %d != Raw Width %d",cmap.getWidth(), 00581 itsInImage.getWidth()); 00582 } 00583 if(itsInImage.getHeight() != cmap.getHeight()) 00584 { 00585 LINFO("Saliency map is the wrong size or raw image not initalized"); 00586 LFATAL("Conspic Height %d != Raw Height %d",cmap.getHeight(), 00587 itsInImage.getHeight()); 00588 } 00589 // normalize from 0 to 1 00590 itsConspicMap[cmap_enum] = cmap/255.0F; 00591 itsConspicMap[cmap_enum] = itsConspicMap[cmap_enum] * 00592 itsConspicMapBias[cmap_enum]; 00593 00594 itsConspicMap[cmap_enum] = itsConspicMap[cmap_enum] * itsMasterConspicBias; 00595 00596 00597 // if we use a bayes image, weight here 00598 if(itsUseBayesWeightImage) 00599 { 00600 if(itsConspicMap[cmap_enum].getWidth() != itsBayesWeightImage.getWidth()) 00601 LFATAL("Bayes image must be same width as conspicuity maps"); 00602 if(itsConspicMap[cmap_enum].getHeight() != itsBayesWeightImage.getHeight()) 00603 LFATAL("Bayes image must be same height as conspicuity maps"); 00604 00605 typename Image<FLOAT>::iterator icmap = itsConspicMap[cmap_enum].beginw(); 00606 typename Image<FLOAT>::const_iterator bayes = itsBayesWeightImage.begin(); 00607 while(icmap != itsConspicMap[cmap_enum].endw()) 00608 { 00609 *icmap = (*icmap) * (*bayes); 00610 ++icmap; ++bayes; 00611 } 00612 } 00613 // if we use a mask, modify conspic maps here 00614 if(itsUseMaskImage) 00615 { 00616 if(itsConspicMap[cmap_enum].getWidth() != itsMaskImage.getWidth()) 00617 LFATAL("Mask image must be same width as conspicuity maps"); 00618 if(itsConspicMap[cmap_enum].getHeight() != itsMaskImage.getHeight()) 00619 LFATAL("Mask image must be same height as conspicuity maps"); 00620 00621 typename Image<FLOAT>::iterator icmap = itsConspicMap[cmap_enum].beginw(); 00622 typename Image<FLOAT>::const_iterator mask = itsMaskImage.begin(); 00623 while(icmap != itsConspicMap[cmap_enum].endw()) 00624 { 00625 *icmap = (*icmap) * (*mask); 00626 00627 ++icmap; ++mask; 00628 } 00629 } 00630 00631 if(SC_DEBUG) 00632 { 00633 char name[100]; 00634 sprintf(name,"debug-conspic-%d-%d-%d.png",itsScale,itsIterCounter,cmap_enum); 00635 std::string prefix = name; 00636 Image<PixRGB<FLOAT> > temp = 00637 normalizeScaleRainbow(itsConspicMap[cmap_enum],0,5); 00638 Raster::WriteRGB(temp, prefix); 00639 } 00640 00641 } 00642 00643 /*************************************************************************/ 00644 00645 template <class PIXTYPE, class BETATYPE, class FLOAT> inline 00646 void SurpriseControl<PIXTYPE,BETATYPE,FLOAT>::SCinputBayesWeightImage( 00647 const Image<FLOAT> &bayesImage) 00648 { 00649 LINFO("INPUT Bayes Weight Image"); 00650 itsUseBayesWeightImage = true; 00651 itsBayesWeightImage = bayesImage; 00652 } 00653 /*************************************************************************/ 00654 00655 template <class PIXTYPE, class BETATYPE, class FLOAT> inline 00656 void SurpriseControl<PIXTYPE,BETATYPE,FLOAT>::SCinputMaskImage( 00657 const Image<FLOAT> &maskImage) 00658 00659 { 00660 FLOAT mi, ma; 00661 getMinMax(maskImage,mi,ma); 00662 if(mi < 0) 00663 { 00664 LINFO("Mask Image value too low = %f",mi); 00665 LFATAL("Mask Image pixel values must be from 0 to 1"); 00666 } 00667 if(ma > 1) 00668 { 00669 LINFO("Mask Image value too high = %f",ma); 00670 LFATAL("Mask Image pixel values must be from 0 to 1"); 00671 } 00672 LINFO("INPUT independant mask image"); 00673 itsUseMaskImage = true; 00674 itsMaskImage = maskImage; 00675 } 00676 /*************************************************************************/ 00677 00678 template <class PIXTYPE, class BETATYPE, class FLOAT> inline 00679 void SurpriseControl<PIXTYPE,BETATYPE,FLOAT>::SCcomputeNewBeta() 00680 { 00681 00682 00683 // Go through each conspicuity map and if we are using it, compute 00684 // beta as a kalman smoothed set of frames. 00685 // buffer beta so that it can align with the temporal components 00686 00687 Image<BETATYPE> betaImage; betaImage.resize(itsImageSizeX,itsImageSizeY); 00688 for(ushort i = 0; i < SC_MAX_CHANNELS; i++) 00689 { 00690 if(itsUseConspicMap[i]) 00691 { 00692 typename Image<BETATYPE>::iterator betaImageItr; 00693 typename Image<FLOAT>::iterator consMapItr = 00694 itsConspicMap[i].beginw(); 00695 typename Image<BETATYPE>::const_iterator betaImageOldItr = 00696 itsBetaImage[0].begin(); 00697 typename Image<FLOAT>::const_iterator itsBayesWeightItr = 00698 itsBayesWeightImage.begin(); 00699 00700 for(betaImageItr = betaImage.beginw(); 00701 betaImageItr != betaImage.endw(); 00702 ++betaImageItr, ++consMapItr, 00703 ++itsBayesWeightItr, ++betaImageOldItr) 00704 { 00705 if(itsUseBayesWeightImage) 00706 { 00707 *consMapItr = *consMapItr * (*itsBayesWeightItr); 00708 } 00709 00710 betaImageItr->p[i] = 00711 (betaImageOldItr->p[i] * itsLambda + *consMapItr)/ 00712 (1 + 1 * itsLambda); 00713 } 00714 00715 if(SC_DEBUG) 00716 { 00717 Image<FLOAT> ftemp; ftemp.resize(betaImage.getWidth(), 00718 betaImage.getHeight()); 00719 00720 typename Image<FLOAT>::iterator itmp = ftemp.beginw(); 00721 00722 for(betaImageItr = betaImage.beginw(); 00723 betaImageItr != betaImage.endw(); 00724 ++betaImageItr, ++itmp) 00725 *itmp = betaImageItr->p[i]; 00726 00727 char name[100]; 00728 sprintf(name,"debug-beta-%d-%d-%d.png",itsScale,itsIterCounter,i); 00729 std::string prefix = name; 00730 Image<PixRGB<FLOAT> > temp = 00731 normalizeScaleRainbow(ftemp,0,5); 00732 Raster::WriteRGB(temp, prefix); 00733 } 00734 } 00735 } 00736 itsBetaImage.push_front(betaImage); 00737 00738 //if we get to big, pop off the back image 00739 if(itsBetaImage.size() > (unsigned)(itsImageSizeZ + 1)) 00740 itsBetaImage.pop_back(); 00741 } 00742 00743 /*************************************************************************/ 00744 00745 template <class PIXTYPE, class BETATYPE, class FLOAT> 00746 void SurpriseControl<PIXTYPE,BETATYPE,FLOAT>::SCprocessFrameSeperable() 00747 { 00748 LINFO("PROCESSING FRAME Kernel Size X - %d Y - %d Z - %d", 00749 itsKernelSizeX, 00750 itsKernelSizeY, 00751 itsKernelSizeZ); 00752 00753 typename Image<PixRGB<FLOAT> >::iterator finalImageItr = 00754 itsFinalImage.beginw(); 00755 00756 // copy itsInImage to itsOutImage so we can take the conspicuity weighted 00757 // average of the two 00758 00759 // Derive the new bias with low pass smoothing 00760 00761 SCcomputeNewBeta(); 00762 00763 LINFO("Buffer %"ZU" ksize %d",itsFrameBuffer.size(),itsKernelSizeZ); 00764 if(itsFrameBuffer.size() > (uint)itsTemporalOffset) 00765 { 00766 itsOutputReady = true; 00767 itsFrameCurrent = &itsFrameBuffer[(uint)itsTemporalOffset]; 00768 itsBetaCurrent = &itsBetaImage[(uint)itsTemporalOffset]; 00769 00770 SCcomputeLocalBias(); 00771 00772 if(itsUseTemporal) 00773 { 00774 LINFO("Convolving image x,y,z"); 00775 SCseperateConvXYZ(); 00776 } 00777 else 00778 { 00779 LINFO("Convolving image x,y"); 00780 SCseperateConvXY(); 00781 } 00782 00783 LINFO("FINISHING image"); 00784 typename Image<PIXTYPE >::const_iterator outImageItr = itsOutImage.begin(); 00785 for(finalImageItr = itsFinalImage.beginw(); 00786 finalImageItr != itsFinalImage.endw(); 00787 ++finalImageItr, ++outImageItr) 00788 { 00789 *finalImageItr = PixRGB<FLOAT>(*outImageItr); 00790 } 00791 LINFO("DONE"); 00792 } 00793 else 00794 { 00795 LINFO("FRAME BUFFER NOT YET HALF FULL"); 00796 itsOutputReady = false; 00797 for(finalImageItr = itsFinalImage.beginw(); 00798 finalImageItr != itsFinalImage.endw(); 00799 ++finalImageItr) 00800 { 00801 *finalImageItr = PixRGB<FLOAT>(0,0,0); 00802 } 00803 } 00804 itsIterCounter++; 00805 } 00806 00807 /*************************************************************************/ 00808 template <class PIXTYPE, class BETATYPE, class FLOAT> 00809 void SurpriseControl<PIXTYPE,BETATYPE,FLOAT>::SCcomputeLocalBias() 00810 { 00811 00812 if(!(itsUseConspicMap[SC_DR0] == itsUseConspicMap[SC_DR1] && 00813 itsUseConspicMap[SC_DR0] == itsUseConspicMap[SC_DR2] && 00814 itsUseConspicMap[SC_DR0] == itsUseConspicMap[SC_DR3])) 00815 LFATAL("You must use all four direction channels or none!"); 00816 00817 if(!(itsUseConspicMap[SC_GA0] == itsUseConspicMap[SC_GA1] && 00818 itsUseConspicMap[SC_GA0] == itsUseConspicMap[SC_GA2] && 00819 itsUseConspicMap[SC_GA0] == itsUseConspicMap[SC_GA3])) 00820 LFATAL("You must use all four orientation channels or none!"); 00821 00822 if(!(itsUseConspicMap[SC_H1] == itsUseConspicMap[SC_H2] && 00823 itsUseConspicMap[SC_H1] == itsUseConspicMap[SC_HS] && 00824 itsUseConspicMap[SC_H1] == itsUseConspicMap[SC_HV])) 00825 LFATAL("You must use all four H2SV channels or none!"); 00826 00827 if(!(itsUseConspicMap[SC_RG] == itsUseConspicMap[SC_BY])) 00828 LFATAL("You must use both RG and BY channels or none!"); 00829 Image<bool>::iterator iSmallS; 00830 00831 // find if any parts have a very small surprise 00832 iSmallS = itsSmallSaliency.beginw(); 00833 for(typename Image<BETATYPE>::const_iterator betaImageItr = 00834 itsBetaCurrent->begin(); betaImageItr != itsBetaCurrent->end(); 00835 ++betaImageItr, ++iSmallS) 00836 { 00837 // get the surprise biases smoothed 00838 //*iSmallS = false; 00839 *iSmallS = true; 00840 00841 for(ushort i = 0; i < SC_MAX_CHANNELS; i++) 00842 { 00843 if(betaImageItr->p[i] > SMALL_SALIENCY) 00844 *iSmallS = false; 00845 } 00846 } 00847 00848 // reset all localbias maps, set to zero 00849 typename Image<FLOAT>::iterator iBiasH1 = itsLocalBiasH1.beginw(); 00850 typename Image<FLOAT>::iterator iBiasH2 = itsLocalBiasH2.beginw(); 00851 typename Image<FLOAT>::iterator iBiasS = itsLocalBiasS.beginw(); 00852 typename Image<FLOAT>::iterator iBiasV = itsLocalBiasV.beginw(); 00853 00854 for(typename Image<BETATYPE>::const_iterator betaImageItr = 00855 itsBetaCurrent->begin(); betaImageItr != itsBetaCurrent->end(); 00856 ++betaImageItr, 00857 ++iBiasH1, ++iBiasH2, ++iBiasS, ++iBiasV, ++iSmallS) 00858 { 00859 *iBiasH1 = 0; *iBiasH2 = 0; *iBiasS = 0; *iBiasV = 0; 00860 } 00861 00862 // compute bias using maximum saliency value 00863 if(itsUseMaxLevel) 00864 { 00865 00866 iBiasH1 = itsLocalBiasH1.beginw(); 00867 iBiasH2 = itsLocalBiasH2.beginw(); 00868 iBiasS = itsLocalBiasS.beginw(); 00869 iBiasV = itsLocalBiasV.beginw(); 00870 00871 for(typename Image<BETATYPE>::const_iterator betaImageItr = 00872 itsBetaCurrent->begin(); betaImageItr != itsBetaCurrent->end(); 00873 ++betaImageItr, 00874 ++iBiasH1, ++iBiasH2, ++iBiasS, ++iBiasV) 00875 { 00876 // compute the surprise bias combinations with the axis bias 00877 /* If we use max level then surprise removal is scaled by the max 00878 level of all conspicuity maps, this limits reduction to be no more 00879 than the highest conspicuity map and prevents to much application 00880 at certian locations. However, it may not scale properly 00881 */ 00882 00883 // Bias color by RG/BY or H2SV 00884 00885 const FLOAT *betaImg = betaImageItr->p; 00886 00887 if(itsUseConspicMap[SC_H1]) 00888 { 00889 *iBiasH1 = betaImg[SC_H1]; 00890 *iBiasH2 = betaImg[SC_H2]; 00891 *iBiasS = betaImg[SC_HS]; 00892 *iBiasV = betaImg[SC_HV]; 00893 } 00894 else 00895 { 00896 if(itsUseConspicMap[SC_BY]) 00897 { 00898 if(betaImageItr->p[SC_BY] > betaImageItr->p[SC_RG]) 00899 { 00900 *iBiasH1 = betaImg[SC_BY]; 00901 *iBiasH2 = betaImg[SC_BY]; 00902 *iBiasS = betaImg[SC_BY]; 00903 } 00904 else 00905 { 00906 *iBiasH1 = betaImg[SC_RG]; 00907 *iBiasH2 = betaImg[SC_RG]; 00908 *iBiasS = betaImg[SC_RG]; 00909 } 00910 } 00911 } 00912 // Bias Value by the max of all feature types 00913 FLOAT newVal = 0; 00914 for(ushort i = 0; i < SC_MAX_CHANNELS; i++) 00915 { 00916 if(betaImg[i] > newVal && itsUseConspicMap[i]) 00917 newVal = betaImg[i]; 00918 } 00919 *iBiasV = newVal; 00920 } 00921 } 00922 else 00923 { 00924 iBiasH1 = itsLocalBiasH1.beginw(); 00925 iBiasH2 = itsLocalBiasH2.beginw(); 00926 iBiasS = itsLocalBiasS.beginw(); 00927 iBiasV = itsLocalBiasV.beginw(); 00928 00929 for(typename Image<BETATYPE>::const_iterator betaImageItr = 00930 itsBetaCurrent->begin(); betaImageItr != itsBetaCurrent->end(); 00931 ++betaImageItr, 00932 ++iBiasH1, ++iBiasH2, ++iBiasS, ++iBiasV) 00933 { 00934 // compute the surprise bias combinations with the axis bias 00935 /* If we use max level then surprise removal is scaled by the max 00936 level of all conspicuity maps, this limits reduction to be no more 00937 than the highest conspicuity map and prevents to much application 00938 at certian locations. However, it may not scale properly 00939 */ 00940 00941 const FLOAT *betaImg = betaImageItr->p; 00942 // get the surprise biases smoothed 00943 // First bias by each feature type if we have it 00944 if(itsUseConspicMap[SC_H1]) 00945 { 00946 *iBiasH1 = betaImg[SC_H1]; 00947 *iBiasH2 = betaImg[SC_H2]; 00948 *iBiasS = betaImg[SC_HS]; 00949 *iBiasV = betaImg[SC_HV]; 00950 } 00951 else 00952 { 00953 if(itsUseConspicMap[SC_BY]) 00954 { 00955 *iBiasH1 = (betaImg[SC_BY] + betaImg[SC_RG]); 00956 *iBiasH2 = (betaImg[SC_BY] + betaImg[SC_RG]); 00957 *iBiasS = (betaImg[SC_BY] + betaImg[SC_RG]); 00958 *iBiasV = (betaImg[SC_BY] + betaImg[SC_RG]); 00959 } 00960 00961 if(itsUseConspicMap[SC_IN]) 00962 *iBiasV += betaImg[SC_IN]; 00963 } 00964 00965 if(itsUseConspicMap[SC_FL]) 00966 *iBiasV += betaImg[SC_FL]; 00967 if(itsUseConspicMap[SC_DR0]) 00968 *iBiasV += betaImg[SC_DR0] + betaImg[SC_DR1] + 00969 betaImg[SC_DR2] + betaImg[SC_DR3]; 00970 if(itsUseConspicMap[SC_GA0]) 00971 *iBiasV += betaImg[SC_GA0] + betaImg[SC_GA1] + 00972 betaImg[SC_GA2] + betaImg[SC_GA3]; 00973 } 00974 } 00975 00976 if(itsNormalizeBiasWithScale) 00977 { 00978 FLOAT miH1, maH1, miH2, maH2, miS, maS, miV, maV; 00979 FLOAT fmaxH1, fmaxH2, fmaxS, fmaxV; 00980 getMinMax(itsLocalBiasH1,miH1,maH1); 00981 getMinMax(itsLocalBiasH2,miH2,maH2); 00982 getMinMax(itsLocalBiasS, miS, maS); 00983 getMinMax(itsLocalBiasV, miV, maV); 00984 00985 // normalize but maintain relative scale between H1,H2,S and V 00986 00987 if((maH1 > maH2) && (maH1 > maS) && (maH1 > maV)) 00988 { 00989 const FLOAT adj = 1.0 / maH1; 00990 fmaxH1 = 1.0; 00991 fmaxH2 = maH2 * adj; 00992 fmaxS = maS * adj; 00993 fmaxV = maV * adj; 00994 } 00995 else if((maH2 > maS) && (maH2 > maV)) 00996 { 00997 const FLOAT adj = 1.0 / maH2; 00998 fmaxH2 = 1.0; 00999 fmaxH1 = maH1 * adj; 01000 fmaxS = maS * adj; 01001 fmaxV = maV * adj; 01002 } 01003 else if(maS > maV) 01004 { 01005 const FLOAT adj = 1.0 / maS; 01006 fmaxS = 1.0; 01007 fmaxH1 = maH1 * adj; 01008 fmaxH2 = maH2 * adj; 01009 fmaxV = maV * adj; 01010 } 01011 else 01012 { 01013 const FLOAT adj = 1.0 / maV; 01014 fmaxV = 1.0; 01015 fmaxH1 = maH1 * adj; 01016 fmaxH2 = maH2 * adj; 01017 fmaxS = maS * adj; 01018 } 01019 01020 for(iBiasH1 = itsLocalBiasH1.beginw(); iBiasH1 != itsLocalBiasH1.endw(); 01021 ++iBiasH1) 01022 { 01023 *iBiasH1 = ((*iBiasH1 - miH1) / (maH1 - miH1)) * fmaxH1; 01024 } 01025 01026 for(iBiasH2 = itsLocalBiasH2.beginw(); iBiasH2 != itsLocalBiasH2.endw(); 01027 ++iBiasH2) 01028 { 01029 *iBiasH2 = ((*iBiasH2 - miH2) / (maH2 - miH2)) * fmaxH2; 01030 } 01031 01032 for(iBiasS = itsLocalBiasS.beginw(); iBiasS != itsLocalBiasS.endw(); 01033 ++iBiasS) 01034 { 01035 *iBiasS = ((*iBiasS - miS) / (maS - miS)) * fmaxS; 01036 } 01037 01038 for(iBiasV = itsLocalBiasV.beginw(); iBiasV != itsLocalBiasV.endw(); 01039 ++iBiasV) 01040 { 01041 *iBiasV = ((*iBiasV - miV) / (maV - miV)) * fmaxV; 01042 } 01043 } 01044 01045 // put in the final bias over each channel 01046 01047 for(iBiasH1 = itsLocalBiasH1.beginw(); iBiasH1 != itsLocalBiasH1.endw(); 01048 ++iBiasH1) 01049 { 01050 *iBiasH1 = itsH1Bias * *iBiasH1; 01051 } 01052 01053 for(iBiasH2 = itsLocalBiasH2.beginw(); iBiasH2 != itsLocalBiasH2.endw(); 01054 ++iBiasH2) 01055 { 01056 *iBiasH2 = itsH2Bias * *iBiasH2; 01057 } 01058 01059 for(iBiasS = itsLocalBiasS.beginw(); iBiasS != itsLocalBiasS.endw(); 01060 ++iBiasS) 01061 { 01062 *iBiasS = itsSBias * *iBiasS; 01063 } 01064 01065 for(iBiasV = itsLocalBiasV.beginw(); iBiasV != itsLocalBiasV.endw(); 01066 ++iBiasV) 01067 { 01068 *iBiasV = itsVBias * *iBiasV; 01069 } 01070 01071 if(SC_DEBUG) 01072 { 01073 char name[100]; 01074 sprintf(name,"debug-biasParts-H1-%d-%d.png",itsScale,itsIterCounter); 01075 std::string prefix = name; 01076 Image<PixRGB<FLOAT> > temp = 01077 normalizeScaleRainbow(itsLocalBiasH1,0,5); 01078 Raster::WriteRGB(temp, prefix); 01079 01080 sprintf(name,"debug-biasParts-H2-%d-%d.png",itsScale,itsIterCounter); 01081 prefix = name; 01082 temp = normalizeScaleRainbow(itsLocalBiasH2,0,5); 01083 Raster::WriteRGB(temp, prefix); 01084 01085 sprintf(name,"debug-biasParts-S-%d-%d.png",itsScale,itsIterCounter); 01086 prefix = name; 01087 temp = normalizeScaleRainbow(itsLocalBiasS,0,5); 01088 Raster::WriteRGB(temp, prefix); 01089 01090 sprintf(name,"debug-biasParts-V-%d-%d.png",itsScale,itsIterCounter); 01091 prefix = name; 01092 temp = normalizeScaleRainbow(itsLocalBiasV,0,5); 01093 Raster::WriteRGB(temp, prefix); 01094 } 01095 } 01096 01097 /*************************************************************************/ 01098 01099 template <class PIXTYPE, class BETATYPE, class FLOAT> 01100 void SurpriseControl<PIXTYPE,BETATYPE,FLOAT>::SCseperateConvXYZ() 01101 { 01102 SCseperateConv('z'); 01103 SCseperateConv('y'); 01104 SCseperateConv('x'); 01105 } 01106 01107 /*************************************************************************/ 01108 01109 template <class PIXTYPE, class BETATYPE, class FLOAT> 01110 void SurpriseControl<PIXTYPE,BETATYPE,FLOAT>::SCseperateConvXY() 01111 { 01112 // skip over the z layer convolution and start at y 01113 // we need to set the starting point where z would have left off 01114 itsInterImage[0] = *itsFrameCurrent; 01115 SCseperateConv('y'); 01116 SCseperateConv('x'); 01117 } 01118 01119 /*************************************************************************/ 01120 01121 template <class PIXTYPE, class BETATYPE, class FLOAT> 01122 void SurpriseControl<PIXTYPE,BETATYPE,FLOAT>::SCseperateConv(const char axis) 01123 { 01124 const typename std::deque<Image<PIXTYPE > >::const_iterator 01125 frameBufferBegin = itsFrameBuffer.begin(); 01126 //const typename std::deque<Image<PIXTYPE > >::const_iterator 01127 // frameBufferEnd = itsFrameBuffer.end(); 01128 01129 typename Image<PIXTYPE >::iterator outImageItr; 01130 typename Image<PIXTYPE >::iterator outImageBegin; 01131 typename Image<PIXTYPE >::iterator outImageEnd; 01132 typename Image<PIXTYPE >::const_iterator inImageItr; 01133 typename Image<PIXTYPE >::const_iterator inImageTrueItr; 01134 01135 Image<ushort>::const_iterator itsStartItr; 01136 Image<ushort>::const_iterator itsStopItr; 01137 Image<ushort>::const_iterator itsKStartItr; 01138 01139 typename std::deque<Image<PIXTYPE > >::const_iterator frameBufferItr; 01140 typename std::vector<FLOAT>::const_iterator kalmanKernelbegin; 01141 FLOAT axisBias; 01142 01143 if(axis == 'z') 01144 { 01145 //inImageItr = itsInImage.beginw(); 01146 // Pick the image in the middle of the frame buffer 01147 // We use floor so that it points to an array index which starts at 0 01148 inImageItr = itsFrameCurrent->begin(); 01149 outImageBegin = itsInterImage[0].beginw(); 01150 outImageEnd = itsInterImage[0].endw(); 01151 itsStartItr = itsZStart.begin(); 01152 itsStopItr = itsZStop.begin(); 01153 itsKStartItr = itsKZStart.begin(); 01154 kalmanKernelbegin = itsKalmanKernelZ.begin(); 01155 axisBias = itsZBias; 01156 } 01157 else if(axis == 'y') 01158 { 01159 // blank the output image 01160 inImageItr = itsInterImage[0].begin(); 01161 outImageBegin = itsInterImage[1].beginw(); 01162 outImageEnd = itsInterImage[1].endw(); 01163 itsStartItr = itsYStart.begin(); 01164 itsStopItr = itsYStop.begin(); 01165 itsKStartItr = itsKYStart.begin(); 01166 kalmanKernelbegin = itsKalmanKernelY.begin(); 01167 axisBias = itsYBias; 01168 } 01169 else if(axis == 'x') 01170 { 01171 inImageItr = itsInterImage[1].begin(); 01172 outImageBegin = itsOutImage.beginw(); 01173 outImageEnd = itsOutImage.endw(); 01174 itsStartItr = itsXStart.begin(); 01175 itsStopItr = itsXStop.begin(); 01176 itsKStartItr = itsKXStart.begin(); 01177 kalmanKernelbegin = itsKalmanKernelX.begin(); 01178 axisBias = itsXBias; 01179 } 01180 else 01181 { 01182 LINFO("Must use axis as z,x then y in that order"); 01183 LFATAL("Unknown axis specified %c",axis); 01184 // put values here to make to compiler shut the %*&! up 01185 inImageItr = itsInterImage[1].begin(); 01186 outImageBegin = itsOutImage.beginw(); 01187 outImageEnd = itsOutImage.endw(); 01188 itsStartItr = itsXStart.begin(); 01189 itsStopItr = itsXStop.begin(); 01190 itsKStartItr = itsKXStart.begin(); 01191 kalmanKernelbegin = itsKalmanKernelX.begin(); 01192 axisBias = itsXBias; 01193 } 01194 01195 // blank the output image and the norm image 01196 for(outImageItr = outImageBegin; outImageItr != outImageEnd; ++outImageItr) 01197 { 01198 outImageItr->p[0] = 0.0F; 01199 outImageItr->p[1] = 0.0F; 01200 outImageItr->p[2] = 0.0F; 01201 outImageItr->p[3] = 0.0F; 01202 } 01203 01204 typename Image<FLOAT>::const_iterator iBiasH1 = itsLocalBiasH1.begin(); 01205 typename Image<FLOAT>::const_iterator iBiasH2 = itsLocalBiasH2.begin(); 01206 typename Image<FLOAT>::const_iterator iBiasS = itsLocalBiasS.begin(); 01207 typename Image<FLOAT>::const_iterator iBiasV = itsLocalBiasV.begin(); 01208 01209 inImageTrueItr = itsFrameCurrent->begin(); 01210 // We have the biases now convolve by the biases 01211 01212 int pos = 0; 01213 ushort Zstop = 0; 01214 01215 if(axis == 'z') 01216 { 01217 if(itsFrameBuffer.size() > itsKernelSizeZ) 01218 Zstop = itsKernelSizeZ; 01219 else 01220 Zstop = itsFrameBuffer.size(); 01221 } 01222 01223 for(outImageItr = outImageBegin; 01224 outImageItr != outImageEnd; pos++, 01225 ++outImageItr, ++inImageItr, 01226 ++itsStartItr, ++itsStopItr, ++itsKStartItr, ++inImageTrueItr, 01227 ++iBiasH1, ++iBiasH2, ++iBiasS, ++iBiasV) 01228 { 01229 01230 //LINFO("POS %d",pos); 01231 FLOAT npixH1 = 0.0F; 01232 FLOAT npixH2 = 0.0F; 01233 FLOAT npixS = 0.0F; 01234 FLOAT npixV = 0.0F; 01235 01236 const FLOAT H1bias = *iBiasH1 * axisBias; 01237 const FLOAT H2bias = *iBiasH2 * axisBias; 01238 const FLOAT Sbias = *iBiasS * axisBias; 01239 const FLOAT Vbias = *iBiasV * axisBias; 01240 01241 ushort start,stop; 01242 01243 if(axis == 'z') 01244 { 01245 start = 0; 01246 stop = Zstop; 01247 } 01248 else 01249 { 01250 start = *itsStartItr; 01251 stop = *itsStopItr; 01252 } 01253 01254 // figure out where we are in the image and the kernel 01255 frameBufferItr = frameBufferBegin; 01256 01257 int posMod = 0; 01258 if(axis == 'y') 01259 posMod = pos%itsImageSizeX; 01260 else if(axis == 'x') 01261 posMod = pos/itsImageSizeX; 01262 01263 typename std::vector<FLOAT>::const_iterator k = kalmanKernelbegin + 01264 (*itsKStartItr); 01265 01266 // iterate over the kernel 01267 for(ushort i = start; i < stop; i++, ++k) 01268 { 01269 // get the current other pixel x,y,z 01270 PIXTYPE curr; 01271 if(axis == 'z') 01272 { 01273 curr = frameBufferItr->getVal(pos); 01274 frameBufferItr++; 01275 } 01276 else if(axis == 'y') 01277 curr = itsInterImage[0].getVal(posMod,i); 01278 else 01279 curr = itsInterImage[1].getVal(i,posMod); 01280 01281 // if other pixel is to dim, don't use its color 01282 // this avoids H2SV (and HSV) singularities at black for hue 01283 01284 if(curr.p[3] > SC_NEAR_BLACK) 01285 { 01286 const FLOAT H1 = (*k) * H1bias * curr.p[2]; 01287 outImageItr->p[0] += curr.p[0] * H1; 01288 npixH1 += H1; 01289 01290 const FLOAT H2 = (*k) * H2bias * curr.p[2]; 01291 outImageItr->p[1] += curr.p[1] * H2; 01292 npixH2 += H2; 01293 } 01294 01295 // saturation is biased by color, intensity, 01296 // orientation and motion 01297 const FLOAT S = (*k) * Sbias; 01298 outImageItr->p[2] += curr.p[2] * S; 01299 npixS += S; 01300 01301 const FLOAT V = (*k) * Vbias; 01302 outImageItr->p[3] += curr.p[3] * V; 01303 npixV += V; 01304 } 01305 01306 // accumulate the normalization 01307 01308 // at x, the final iteration normalize the final image 01309 if(axis == 'x') 01310 { 01311 // add in the original image to average (in a sense) with the 01312 // blurred image 01313 outImageItr->p[0] += inImageTrueItr->p[0] * itsOriginalImageWeight; 01314 outImageItr->p[1] += inImageTrueItr->p[1] * itsOriginalImageWeight; 01315 outImageItr->p[2] += inImageTrueItr->p[2] * itsOriginalImageWeight; 01316 outImageItr->p[3] += inImageTrueItr->p[3] * itsOriginalImageWeight; 01317 01318 npixH1 += itsOriginalImageWeight; 01319 npixH2 += itsOriginalImageWeight; 01320 npixS += itsOriginalImageWeight; 01321 npixV += itsOriginalImageWeight; 01322 } 01323 if(npixH1 != 0) 01324 outImageItr->p[0] = outImageItr->p[0]/npixH1; 01325 if(npixH2 != 0) 01326 outImageItr->p[1] = outImageItr->p[1]/npixH2; 01327 if(npixS != 0) 01328 outImageItr->p[2] = outImageItr->p[2]/npixS; 01329 if(npixV != 0) 01330 outImageItr->p[3] = outImageItr->p[3]/npixV; 01331 } 01332 01333 // clamp just in case to at least 0 01334 if(axis == 'x') 01335 { 01336 if(outImageItr->p[0] < 0) 01337 outImageItr->p[0] = 0; 01338 if(outImageItr->p[1] < 0) 01339 outImageItr->p[1] = 0; 01340 if(outImageItr->p[2] < 0) 01341 outImageItr->p[2] = 0; 01342 if(outImageItr->p[3] < 0) 01343 outImageItr->p[3] = 0; 01344 } 01345 } 01346 01347 01348 /*************************************************************************/ 01349 01350 template <class PIXTYPE, class BETATYPE, class FLOAT> inline 01351 Image<PixRGB<FLOAT> > SurpriseControl<PIXTYPE,BETATYPE,FLOAT>::SCgetSharpened( 01352 const PIXTYPE scale_factor) 01353 const 01354 { 01355 if(itsOutputReady) 01356 { 01357 const Image<PIXTYPE> fbuffer = *itsFrameCurrent; 01358 01359 // get img 1 - img 2 as a difference image 01360 const Image<PIXTYPE> diffimg = fbuffer - itsOutImage; 01361 01362 // add back the original with a scaling factor 01363 Image<PIXTYPE> finalimg; 01364 finalimg.resize(fbuffer.getWidth(), fbuffer.getHeight()); 01365 01366 01367 // clamp values just in case 01368 typename Image<PIXTYPE>::const_iterator dimg = diffimg.begin(); 01369 typename Image<PIXTYPE>::const_iterator fimg = fbuffer.begin(); 01370 01371 typename Image<FLOAT>::const_iterator iBiasH1 = itsLocalBiasH1.begin(); 01372 typename Image<FLOAT>::const_iterator iBiasH2 = itsLocalBiasH2.begin(); 01373 typename Image<FLOAT>::const_iterator iBiasS = itsLocalBiasS.begin(); 01374 typename Image<FLOAT>::const_iterator iBiasV = itsLocalBiasV.begin(); 01375 01376 for(typename Image<PIXTYPE>::iterator aptr = finalimg.beginw(); 01377 aptr != finalimg.endw(); 01378 ++aptr, ++dimg, ++fimg , ++iBiasH1, ++iBiasH2, ++iBiasS, ++iBiasV) 01379 { 01380 aptr->p[0] = ((dimg->p[0] * scale_factor.p[0] * *iBiasH1) + fimg->p[0]); 01381 if(aptr->p[0] > 1) aptr->p[0] = 1; 01382 aptr->p[1] = ((dimg->p[1] * scale_factor.p[1] * *iBiasH2) + fimg->p[1]); 01383 if(aptr->p[1] > 1) aptr->p[1] = 1; 01384 aptr->p[2] = ((dimg->p[2] * scale_factor.p[2] * *iBiasS) + fimg->p[2]); 01385 if(aptr->p[2] > 1) aptr->p[2] = 1; 01386 aptr->p[3] = ((dimg->p[3] * scale_factor.p[3] * *iBiasV) + fimg->p[3]); 01387 if(aptr->p[3] > 1) aptr->p[3] = 1; 01388 } 01389 01390 return static_cast<Image<PixRGB<FLOAT> > >(finalimg); 01391 } 01392 else 01393 { 01394 Image<PixRGB<FLOAT> > blank; blank.resize(itsImageSizeX,itsImageSizeY); 01395 typename Image<PixRGB<FLOAT> >::iterator ib = blank.beginw(); 01396 01397 PixRGB<FLOAT>bp = PixRGB<FLOAT>(0,0,0); 01398 01399 while(ib != blank.endw()) {*ib = bp; ++ib;} 01400 01401 return blank; 01402 } 01403 } 01404 01405 /*************************************************************************/ 01406 01407 template <class PIXTYPE, class BETATYPE, class FLOAT> inline 01408 Image<PixRGB<FLOAT> > SurpriseControl<PIXTYPE,BETATYPE,FLOAT>::SCgetFrame() 01409 const 01410 { 01411 if(itsOutputReady) 01412 { 01413 return itsFinalImage; 01414 } 01415 else 01416 { 01417 Image<PixRGB<FLOAT> > blank; blank.resize(itsImageSizeX,itsImageSizeY); 01418 typename Image<PixRGB<FLOAT> >::iterator ib = blank.beginw(); 01419 01420 PixRGB<FLOAT>bp = PixRGB<FLOAT>(0,0,0); 01421 01422 while(ib != blank.endw()) {*ib = bp; ++ib;} 01423 01424 return blank; 01425 } 01426 } 01427 01428 /*************************************************************************/ 01429 01430 template <class PIXTYPE, class BETATYPE, class FLOAT> inline 01431 Image<PixRGB<FLOAT> > SurpriseControl<PIXTYPE,BETATYPE,FLOAT>::SCgetOutImage() 01432 const 01433 { 01434 Image<PixRGB<FLOAT> > returnImage; 01435 returnImage.resize(itsOutImage.getWidth(),itsOutImage.getHeight()); 01436 typename Image<PixRGB<FLOAT> >::iterator returnImageItr = 01437 returnImage.beginw(); 01438 typename Image<PIXTYPE>::const_iterator outImageItr = 01439 itsOutImage.begin(); 01440 while(returnImageItr != returnImage.endw()) 01441 { 01442 *returnImageItr = PixRGB<FLOAT>(*outImageItr); 01443 ++returnImageItr; ++outImageItr; 01444 } 01445 01446 return returnImage; 01447 } 01448 01449 /*************************************************************************/ 01450 01451 template <class PIXTYPE, class BETATYPE, class FLOAT> inline 01452 Image<PixRGB<FLOAT> > SurpriseControl<PIXTYPE,BETATYPE,FLOAT>::SCgetInImage() 01453 const 01454 { 01455 if(itsOutputReady) 01456 { 01457 Image<PixRGB<FLOAT> > returnImage; 01458 const Image<PIXTYPE> fbuffer = *itsFrameCurrent; 01459 returnImage.resize(itsFrameCurrent->getWidth(), 01460 itsFrameCurrent->getHeight()); 01461 typename Image<PixRGB<FLOAT> >::iterator returnImageItr = 01462 returnImage.beginw(); 01463 typename Image<PIXTYPE>::const_iterator inImageItr = fbuffer.begin(); 01464 01465 while(returnImageItr != returnImage.endw()) 01466 { 01467 *returnImageItr = PixRGB<FLOAT>(*inImageItr); 01468 ++returnImageItr; ++inImageItr; 01469 } 01470 return returnImage; 01471 } 01472 else 01473 { 01474 Image<PixRGB<FLOAT> > blank; blank.resize(itsImageSizeX,itsImageSizeY); 01475 typename Image<PixRGB<FLOAT> >::iterator ib = blank.beginw(); 01476 01477 PixRGB<FLOAT>bp = PixRGB<FLOAT>(0,0,0); 01478 01479 while(ib != blank.endw()) {*ib = bp; ++ib;} 01480 01481 return blank; 01482 } 01483 } 01484 /*************************************************************************/ 01485 01486 template <class PIXTYPE, class BETATYPE, class FLOAT> inline 01487 Image<PIXTYPE> SurpriseControl<PIXTYPE,BETATYPE,FLOAT>::SCgetRawOutImage() const 01488 { 01489 return itsOutImage; 01490 } 01491 01492 /*************************************************************************/ 01493 01494 template <class PIXTYPE, class BETATYPE, class FLOAT> inline 01495 Image<PIXTYPE> SurpriseControl<PIXTYPE,BETATYPE,FLOAT>::SCgetRawInImage() const 01496 { 01497 if(itsOutputReady) 01498 { 01499 return *itsFrameCurrent; 01500 } 01501 else 01502 { 01503 Image<PIXTYPE> blank; blank.resize(itsImageSizeX,itsImageSizeY); 01504 typename Image<PIXTYPE>::iterator ib = blank.beginw(); 01505 01506 PIXTYPE bp = PIXTYPE(0,0,0,0); 01507 while(ib != blank.endw()) {*ib = bp; ++ib;} 01508 01509 return blank; 01510 } 01511 } 01512 01513 /*************************************************************************/ 01514 01515 template <class PIXTYPE, class BETATYPE, class FLOAT> inline 01516 Image<BETATYPE> SurpriseControl<PIXTYPE,BETATYPE,FLOAT>::SCgetBetaImage() const 01517 { 01518 if(itsOutputReady) 01519 { 01520 return *itsBetaCurrent; 01521 } 01522 else 01523 { 01524 Image<BETATYPE> blank; blank.resize(itsImageSizeX,itsImageSizeY); 01525 typename Image<BETATYPE>::iterator ib = blank.beginw(); 01526 01527 PixHyper<FLOAT,SC_MAX_CHANNELS> bp = PixHyper<FLOAT,SC_MAX_CHANNELS>(0); 01528 01529 while(ib != blank.endw()) {*ib = bp; ++ib;} 01530 01531 return blank; 01532 } 01533 } 01534 01535 /*************************************************************************/ 01536 01537 template <class PIXTYPE, class BETATYPE, class FLOAT> inline 01538 ushort SurpriseControl<PIXTYPE,BETATYPE,FLOAT>::SCgetTemporalOffset() const 01539 { 01540 return itsTemporalOffset; 01541 } 01542 01543 /*************************************************************************/ 01544 01545 template <class PIXTYPE, class BETATYPE, class FLOAT> inline 01546 bool SurpriseControl<PIXTYPE,BETATYPE,FLOAT>::SCisOutputReady() const 01547 { 01548 return itsOutputReady; 01549 } 01550 01551 /*************************************************************************/ 01552 01553 template <class PIXTYPE, class BETATYPE, class FLOAT> inline 01554 void SurpriseControl<PIXTYPE,BETATYPE,FLOAT>::SCgetLocalBiasImages( 01555 Image<FLOAT> &H1, Image<FLOAT> &H2, 01556 Image<FLOAT> &S, Image<FLOAT> &V) const 01557 { 01558 if(itsOutputReady) 01559 { 01560 H1 = itsLocalBiasH1; H2 = itsLocalBiasH2; 01561 S = itsLocalBiasS; V = itsLocalBiasV; 01562 } 01563 else 01564 { 01565 Image<FLOAT> blank; blank.resize(itsImageSizeX,itsImageSizeY); 01566 typename Image<FLOAT>::iterator ib = blank.beginw(); 01567 FLOAT bp = 0; 01568 01569 while(ib != blank.endw()) {*ib = bp; ++ib;} 01570 01571 H1 = blank; H2 = blank; S = blank; V = blank; 01572 } 01573 } 01574 01575 /*************************************************************************/ 01576 01577 template <class PIXTYPE, class BETATYPE, class FLOAT> inline 01578 void SurpriseControl<PIXTYPE,BETATYPE,FLOAT>::SCgetSeperableParts( 01579 Image<PIXTYPE> &Zimg, 01580 Image<PIXTYPE> &Yimg) const 01581 { 01582 if(itsOutputReady) 01583 { 01584 Zimg = itsInterImage[0]; 01585 Yimg = itsInterImage[1]; 01586 } 01587 else 01588 { 01589 Image<PIXTYPE> blank; blank.resize(itsImageSizeX,itsImageSizeY); 01590 typename Image<PIXTYPE>::iterator ib = blank.beginw(); 01591 01592 PIXTYPE bp = PIXTYPE(0,0,0,0); 01593 while(ib != blank.endw()) {*ib = bp; ++ib;} 01594 01595 Zimg = blank; Yimg = blank; 01596 } 01597 } 01598 01599 /*************************************************************************/ 01600 01601 template class SurpriseControl<PixH2SV1<float>, 01602 PixHyper<float,SC_MAX_CHANNELS>,float>; 01603 template class SurpriseControl<PixH2SV2<float>, 01604 PixHyper<float,SC_MAX_CHANNELS>,float>; 01605 01606 #endif