00001 /*!@file Surprise/RemoveSurprise.C attempt to remove surprise from 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/RemoveSurprise.C $ 00035 // $Id: RemoveSurprise.C 14376 2011-01-11 02:44:34Z pez $ 00036 // 00037 00038 #ifndef REMOVE_SURPRISE_C_DEFINED 00039 #define REMOVE_SURPRISE_C_DEFINED 00040 00041 #include "Surprise/RemoveSurprise.H" 00042 #include <typeinfo> 00043 00044 /*************************************************************************/ 00045 00046 template <class PIXTYPE, class BETATYPE, class FLOAT> 00047 RemoveSurprise<PIXTYPE,BETATYPE,FLOAT>::RemoveSurprise(const ushort sizeX, 00048 const ushort sizeY) 00049 { 00050 LINFO("Creating RemoveSurprise Object"); 00051 00052 itsINbias = 1.0F; itsDRbias = 1.0F; itsFLbias = 1.0F; itsGAbias = 1.0F; 00053 itsRGbias = 1.0F; itsBYbias = 1.0F; 00054 00055 itsCObias = 1.0F; itsMObias = 1.0F; itsORbias = 1.0F; itsINbias = 1.0F; 00056 00057 RSinit(sizeX,sizeY); 00058 RSuseTrueKalman(false); 00059 RSuseMaxLevel(false); 00060 00061 if((typeid(BETATYPE).name() != typeid(itsHyper4).name()) && 00062 (typeid(BETATYPE).name() != typeid(itsHyper6).name())) 00063 { 00064 LFATAL("Run time type error. Type: %s is not supported", 00065 typeid(BETATYPE).name()); 00066 } 00067 } 00068 00069 /*************************************************************************/ 00070 00071 template <class PIXTYPE, class BETATYPE, class FLOAT> 00072 RemoveSurprise<PIXTYPE,BETATYPE,FLOAT>::RemoveSurprise() 00073 { 00074 LINFO("Creating RemoveSurprise Object NOTE: Call init()"); 00075 00076 itsINbias = 1.0F; itsDRbias = 1.0F; itsFLbias = 1.0F; itsGAbias = 1.0F; 00077 itsRGbias = 1.0F; itsBYbias = 1.0F; 00078 00079 itsCObias = 1.0F; itsMObias = 1.0F; itsORbias = 1.0F; itsINbias = 1.0F; 00080 RSuseTrueKalman(false); 00081 if((typeid(BETATYPE).name() != typeid(itsHyper4).name()) && 00082 (typeid(BETATYPE).name() != typeid(itsHyper6).name())) 00083 { 00084 LFATAL("Run time type error. Type: %s is not supported", 00085 typeid(BETATYPE).name()); 00086 } 00087 } 00088 00089 /*************************************************************************/ 00090 00091 template <class PIXTYPE, class BETATYPE, class FLOAT> 00092 RemoveSurprise<PIXTYPE,BETATYPE,FLOAT>::~RemoveSurprise() 00093 {} 00094 00095 /*************************************************************************/ 00096 00097 template <class PIXTYPE, class BETATYPE, class FLOAT> 00098 void RemoveSurprise<PIXTYPE,BETATYPE,FLOAT>::RSuseTrueKalman(const bool useTK) 00099 { 00100 LINFO("Setting itsUseTrueKalman"); 00101 itsUseTrueKalman = useTK; 00102 } 00103 00104 /*************************************************************************/ 00105 00106 template <class PIXTYPE, class BETATYPE, class FLOAT> 00107 void RemoveSurprise<PIXTYPE,BETATYPE,FLOAT>::RSuseMaxLevel(const bool useML) 00108 { 00109 LINFO("Setting itsUseMaxLevel"); 00110 itsUseMaxLevel = useML; 00111 } 00112 00113 /*************************************************************************/ 00114 00115 template <class PIXTYPE, class BETATYPE, class FLOAT> 00116 void RemoveSurprise<PIXTYPE,BETATYPE,FLOAT>::RSsetConspicBias(const FLOAT CO, 00117 const FLOAT MO, 00118 const FLOAT OR, 00119 const FLOAT IN) 00120 { 00121 LINFO("Setting new biases with 4 maps"); 00122 if(typeid(BETATYPE).name() != typeid(itsHyper4).name()) 00123 { 00124 LFATAL("Run time type error, expected %s got %s", 00125 typeid(itsHyper4).name(),typeid(BETATYPE).name()); 00126 } 00127 itsCObias = CO; itsMObias = MO; itsORbias = OR; itsINbias = IN; 00128 } 00129 00130 /*************************************************************************/ 00131 00132 template <class PIXTYPE, class BETATYPE, class FLOAT> 00133 void RemoveSurprise<PIXTYPE,BETATYPE,FLOAT>::RSsetConspicBias(const FLOAT IN, 00134 const FLOAT DR, 00135 const FLOAT FL, 00136 const FLOAT GA, 00137 const FLOAT RG, 00138 const FLOAT BY) 00139 { 00140 LINFO("Setting new biases with 6 maps"); 00141 if(typeid(BETATYPE).name() != typeid(itsHyper6).name()) 00142 { 00143 LFATAL("Run time type error, expected %s got %s", 00144 typeid(itsHyper6).name(), typeid(BETATYPE).name()); 00145 } 00146 itsINbias = IN; itsDRbias = DR; itsFLbias = FL; itsGAbias = GA; 00147 itsRGbias = RG; itsBYbias = BY; 00148 } 00149 00150 /*************************************************************************/ 00151 00152 template <class PIXTYPE, class BETATYPE, class FLOAT> 00153 void RemoveSurprise<PIXTYPE,BETATYPE,FLOAT>::RSsetAxisBias(const FLOAT X, 00154 const FLOAT Y, 00155 const FLOAT Z) 00156 { 00157 itsXbias = X; itsYbias = Y; itsZbias = Z; 00158 } 00159 /*************************************************************************/ 00160 00161 template <class PIXTYPE, class BETATYPE, class FLOAT> 00162 void RemoveSurprise<PIXTYPE,BETATYPE,FLOAT>::RSsetH2SVBias(const FLOAT H1, 00163 const FLOAT H2, 00164 const FLOAT S, 00165 const FLOAT V) 00166 { 00167 itsH1bias = H1; itsH2bias = H2; itsSbias = S; itsVbias = V; 00168 } 00169 00170 /*************************************************************************/ 00171 00172 template <class PIXTYPE, class BETATYPE, class FLOAT> 00173 void RemoveSurprise<PIXTYPE,BETATYPE,FLOAT>::RSinit(const ushort sizeX, 00174 const ushort sizeY) 00175 { 00176 LINFO("INIT"); 00177 itsLambda = 0.1; 00178 itsInitBuffer = false; 00179 itsUseCorrMatrixSet = false; 00180 itsUseBayesWeightImage = false; 00181 itsImageSizeX = sizeX; 00182 itsImageSizeY = sizeY; 00183 itsXbias = 1.0F; itsYbias = 1.0F; itsZbias = 1.0F; 00184 itsInImage.resize(sizeX,sizeY); 00185 itsOutImage.resize(sizeX,sizeY); 00186 itsFinalImage.resize(sizeX,sizeY); 00187 00188 itsBetaImage.resize(sizeX,sizeY); 00189 BETATYPE blank(0.0F); 00190 PIXTYPE blank2(0.0F); 00191 typename Image<BETATYPE>::iterator betaImageItr = itsBetaImage.beginw(); 00192 Image<PIXTYPE> tempImage; 00193 tempImage.resize(sizeX,sizeY); 00194 typename Image<PIXTYPE>::iterator tempImageItr = tempImage.beginw(); 00195 while(betaImageItr != itsBetaImage.endw()) 00196 { 00197 *betaImageItr = blank; 00198 *tempImageItr = blank2; 00199 ++betaImageItr; ++tempImageItr; 00200 } 00201 00202 // resize intermediate images, set equal to the blank beta image 00203 00204 itsInterImage.resize(2,tempImage); 00205 itsInterImageNorm.resize(1,tempImage); 00206 00207 if(typeid(BETATYPE).name() == typeid(itsHyper4).name()) 00208 { 00209 itsInit.resize(8,false); 00210 itsInitMessage.resize(8,""); 00211 itsInitMessage[0] = "Input Raw Image at method RSinputRawImage"; 00212 itsInitMessage[1] = "Input Sal Map at method RSinputSalMap"; 00213 itsInitMessage[2] = "Input conspicuity map for color at method RSinputConspicCO"; 00214 itsInitMessage[3] = "Input conspicuity map for motion at method RSinputConspicMO"; 00215 itsInitMessage[4] = "Input conspicuity map for orientation at method RSinputConspicOR"; 00216 itsInitMessage[5] = "Input conspicuity map for intensity at method RSinputConspicIN"; 00217 itsInitMessage[6] = "Set up filters at RScreateSepFilters"; 00218 itsInitMessage[7] = "Set up convolution bounds at RSfindConvolutionEndPoints"; 00219 } 00220 } 00221 00222 /*************************************************************************/ 00223 00224 template <class PIXTYPE, class BETATYPE, class FLOAT> 00225 void RemoveSurprise<PIXTYPE,BETATYPE,FLOAT>::RSsetLambda(const FLOAT lambda) 00226 { 00227 itsLambda = lambda; 00228 } 00229 // 1. create a guassian filtered frame of the current movie 00230 /*************************************************************************/ 00231 00232 template <class PIXTYPE, class BETATYPE, class FLOAT> 00233 void RemoveSurprise<PIXTYPE,BETATYPE,FLOAT>::RSsetDesatBias(const FLOAT desat) 00234 { 00235 itsDesatbias = desat; 00236 } 00237 00238 // 2. merge the guassian filtered frame with the current frame giving more 00239 // weight to filtered pixels if the surprise is higher. 00240 00241 /*************************************************************************/ 00242 00243 template <class PIXTYPE, class BETATYPE, class FLOAT> 00244 void RemoveSurprise<PIXTYPE,BETATYPE,FLOAT>::RSinputRawImage( 00245 const Image<PixRGB<FLOAT> >& rawImage, 00246 const uint frame) 00247 { 00248 LINFO("INPUT RAW IMAGE"); 00249 itsInit[0] = true; 00250 itsFrameNumber = frame; 00251 if(rawImage.getHeight() != itsImageSizeY) 00252 { 00253 LINFO("Input raw image is not the correct size"); 00254 LFATAL("Raw %d != sizeY %d",rawImage.getHeight(),itsImageSizeY); 00255 } 00256 if(rawImage.getWidth() != itsImageSizeX) 00257 { 00258 LINFO("Input raw image is not the correct size"); 00259 LFATAL("Raw %d != sizeX %d",rawImage.getWidth(),itsImageSizeX); 00260 } 00261 00262 typename Image<PIXTYPE >::iterator inImageItr = 00263 itsInImage.beginw(); 00264 typename Image<PixRGB<FLOAT> >::const_iterator rawImageItr = 00265 rawImage.begin(); 00266 00267 00268 // convert the input image to H2SV2 00269 while(inImageItr != itsInImage.endw()) 00270 { 00271 *inImageItr = PIXTYPE(*rawImageItr); 00272 ++inImageItr; ++rawImageItr; 00273 } 00274 00275 // If we wish to use a more proper kalman filter then store the new image 00276 // else just buffer the raw images 00277 if((itsUseTrueKalman) && (itsInitBuffer)) 00278 { 00279 itsFrameBuffer.push_front(itsOutImage); 00280 } 00281 else 00282 { 00283 itsFrameBuffer.push_front(itsInImage); 00284 itsInitBuffer = true; 00285 } 00286 00287 //if we get to big, pop off the back image 00288 if(itsFrameBuffer.size() > itsKernelSizeZ) 00289 { 00290 itsFrameBuffer.pop_back(); 00291 } 00292 } 00293 00294 /*************************************************************************/ 00295 00296 template <class PIXTYPE, class BETATYPE, class FLOAT> 00297 void RemoveSurprise<PIXTYPE,BETATYPE,FLOAT>::RSinputSalMap(const Image<FLOAT>& salMap) 00298 { 00299 LINFO("INPUT Salmap IMAGE"); 00300 itsInit[1] = true; 00301 if(itsInImage.getWidth() != salMap.getWidth()) 00302 { 00303 LINFO("Saliency map is the wrong size or raw image not initalized"); 00304 LFATAL("Sal Width %d != Raw Width %d",salMap.getWidth(), 00305 itsInImage.getWidth()); 00306 } 00307 if(itsInImage.getHeight() != salMap.getHeight()) 00308 { 00309 LINFO("Saliency map is the wrong size or raw image not initalized"); 00310 LFATAL("Sal Height %d != Raw Height %d",salMap.getHeight(), 00311 itsInImage.getHeight()); 00312 } 00313 00314 // normalize from 0 to 1 00315 itsSalMap = salMap/255.0F; 00316 } 00317 00318 /*************************************************************************/ 00319 00320 template <class PIXTYPE, class BETATYPE, class FLOAT> 00321 void RemoveSurprise<PIXTYPE,BETATYPE,FLOAT>::RSinputConspicCO(const Image<FLOAT>& conspicCO) 00322 { 00323 LINFO("INPUT CO IMAGE"); 00324 itsInit[2] = true; 00325 if(itsInImage.getWidth() != conspicCO.getWidth()) 00326 { 00327 LINFO("Saliency map is the wrong size or raw image not initalized"); 00328 LFATAL("Conspic Width %d != Raw Width %d",conspicCO.getWidth(), 00329 itsInImage.getWidth()); 00330 } 00331 if(itsInImage.getHeight() != conspicCO.getHeight()) 00332 { 00333 LINFO("Saliency map is the wrong size or raw image not initalized"); 00334 LFATAL("Conspic Height %d != Raw Height %d",conspicCO.getHeight(), 00335 itsInImage.getHeight()); 00336 } 00337 // normalize from 0 to 1 00338 itsConspicCO = conspicCO/255.0F; 00339 itsConspicCO = itsConspicCO*itsCObias; 00340 } 00341 00342 /*************************************************************************/ 00343 00344 template <class PIXTYPE, class BETATYPE, class FLOAT> 00345 void RemoveSurprise<PIXTYPE,BETATYPE,FLOAT>::RSinputConspicMO(const Image<FLOAT>& conspicMO) 00346 { 00347 LINFO("INPUT MO IMAGE"); 00348 itsInit[3] = true; 00349 if(itsInImage.getWidth() != conspicMO.getWidth()) 00350 { 00351 LINFO("Saliency map is the wrong size or raw image not initalized"); 00352 LFATAL("Conspic Width %d != Raw Width %d",conspicMO.getWidth(), 00353 itsInImage.getWidth()); 00354 } 00355 if(itsInImage.getHeight() != conspicMO.getHeight()) 00356 { 00357 LINFO("Saliency map is the wrong size or raw image not initalized"); 00358 LFATAL("Conspic Height %d != Raw Height %d",conspicMO.getHeight(), 00359 itsInImage.getHeight()); 00360 } 00361 // normalize from 0 to 1 00362 itsConspicMO = conspicMO/255.0F; 00363 itsConspicMO = itsConspicMO*itsMObias; 00364 } 00365 00366 /*************************************************************************/ 00367 00368 template <class PIXTYPE, class BETATYPE, class FLOAT> 00369 void RemoveSurprise<PIXTYPE,BETATYPE,FLOAT>::RSinputConspicOR(const Image<FLOAT>& conspicOR) 00370 { 00371 LINFO("INPUT OR IMAGE"); 00372 itsInit[4] = true; 00373 if(itsInImage.getWidth() != conspicOR.getWidth()) 00374 { 00375 LINFO("Saliency map is the wrong size or raw image not initalized"); 00376 LFATAL("Conspic Width %d != Raw Width %d",conspicOR.getWidth(), 00377 itsInImage.getWidth()); 00378 } 00379 if(itsInImage.getHeight() != conspicOR.getHeight()) 00380 { 00381 LINFO("Saliency map is the wrong size or raw image not initalized"); 00382 LFATAL("Conspic Height %d != Raw Height %d",conspicOR.getHeight(), 00383 itsInImage.getHeight()); 00384 } 00385 // normalize from 0 to 1 00386 itsConspicOR = conspicOR/255.0F; 00387 itsConspicOR = itsConspicOR*itsORbias; 00388 } 00389 00390 /*************************************************************************/ 00391 00392 template <class PIXTYPE, class BETATYPE, class FLOAT> 00393 void RemoveSurprise<PIXTYPE,BETATYPE,FLOAT>::RSinputConspicIN(const Image<FLOAT>& conspicIN) 00394 { 00395 LINFO("INPUT IN IMAGE"); 00396 itsInit[5] = true; 00397 if(itsInImage.getWidth() != conspicIN.getWidth()) 00398 { 00399 LINFO("Saliency map is the wrong size or raw image not initalized"); 00400 LFATAL("Conspic Width %d != Raw Width %d",conspicIN.getWidth(), 00401 itsInImage.getWidth()); 00402 } 00403 if(itsInImage.getHeight() != conspicIN.getHeight()) 00404 { 00405 LINFO("Saliency map is the wrong size or raw image not initalized"); 00406 LFATAL("Conspic Height %d != Raw Height %d",conspicIN.getHeight(), 00407 itsInImage.getHeight()); 00408 } 00409 // normalize from 0 to 1 00410 //itsConspicIN = conspicIN/255.0F; 00411 itsConspicIN = conspicIN; 00412 itsConspicIN = itsConspicIN*itsINbias; 00413 } 00414 00415 /*************************************************************************/ 00416 00417 template <class PIXTYPE, class BETATYPE, class FLOAT> 00418 void RemoveSurprise<PIXTYPE,BETATYPE,FLOAT>::RSinputConspicDR(const Image<FLOAT>& conspicDR) 00419 { 00420 LINFO("INPUT DR IMAGE"); 00421 00422 if(itsInImage.getWidth() != conspicDR.getWidth()) 00423 { 00424 LINFO("Saliency map is the wrong size or raw image not initalized"); 00425 LFATAL("Conspic Width %d != Raw Width %d",conspicDR.getWidth(), 00426 itsInImage.getWidth()); 00427 } 00428 if(itsInImage.getHeight() != conspicDR.getHeight()) 00429 { 00430 LINFO("Saliency map is the wrong size or raw image not initalized"); 00431 LFATAL("Conspic Height %d != Raw Height %d",conspicDR.getHeight(), 00432 itsInImage.getHeight()); 00433 } 00434 // normalize from 0 to 1 00435 //itsConspicDR = conspicDR/255.0F; 00436 itsConspicDR = conspicDR; 00437 itsConspicDR = itsConspicDR*itsDRbias; 00438 } 00439 00440 /*************************************************************************/ 00441 00442 template <class PIXTYPE, class BETATYPE, class FLOAT> 00443 void RemoveSurprise<PIXTYPE,BETATYPE,FLOAT>::RSinputConspicFL(const Image<FLOAT>& conspicFL) 00444 { 00445 LINFO("INPUT FL IMAGE"); 00446 itsInit[5] = true; 00447 if(itsInImage.getWidth() != conspicFL.getWidth()) 00448 { 00449 LINFO("Saliency map is the wrong size or raw image not initalized"); 00450 LFATAL("Conspic Width %d != Raw Width %d",conspicFL.getWidth(), 00451 itsInImage.getWidth()); 00452 } 00453 if(itsInImage.getHeight() != conspicFL.getHeight()) 00454 { 00455 LINFO("Saliency map is the wrong size or raw image not initalized"); 00456 LFATAL("Conspic Height %d != Raw Height %d",conspicFL.getHeight(), 00457 itsInImage.getHeight()); 00458 } 00459 // normalize from 0 to 1 00460 //itsConspicFL = conspicFL/255.0F; 00461 itsConspicFL = conspicFL; 00462 itsConspicFL = itsConspicFL*itsFLbias; 00463 } 00464 00465 /*************************************************************************/ 00466 00467 template <class PIXTYPE, class BETATYPE, class FLOAT> 00468 void RemoveSurprise<PIXTYPE,BETATYPE,FLOAT>::RSinputConspicGA(const Image<FLOAT>& conspicGA) 00469 { 00470 LINFO("INPUT GA IMAGE"); 00471 itsInit[5] = true; 00472 if(itsInImage.getWidth() != conspicGA.getWidth()) 00473 { 00474 LINFO("Saliency map is the wrong size or raw image not initalized"); 00475 LFATAL("Conspic Width %d != Raw Width %d",conspicGA.getWidth(), 00476 itsInImage.getWidth()); 00477 } 00478 if(itsInImage.getHeight() != conspicGA.getHeight()) 00479 { 00480 LINFO("Saliency map is the wrong size or raw image not initalized"); 00481 LFATAL("Conspic Height %d != Raw Height %d",conspicGA.getHeight(), 00482 itsInImage.getHeight()); 00483 } 00484 // normalize from 0 to 1 00485 //itsConspicGA = conspicGA/255.0F; 00486 itsConspicGA = conspicGA; 00487 itsConspicGA = itsConspicGA*itsGAbias; 00488 } 00489 00490 /*************************************************************************/ 00491 00492 template <class PIXTYPE, class BETATYPE, class FLOAT> 00493 void RemoveSurprise<PIXTYPE,BETATYPE,FLOAT>::RSinputConspicRG(const Image<FLOAT>& conspicRG) 00494 { 00495 LINFO("INPUT RG IMAGE"); 00496 itsInit[5] = true; 00497 if(itsInImage.getWidth() != conspicRG.getWidth()) 00498 { 00499 LINFO("Saliency map is the wrong size or raw image not initalized"); 00500 LFATAL("Conspic Width %d != Raw Width %d",conspicRG.getWidth(), 00501 itsInImage.getWidth()); 00502 } 00503 if(itsInImage.getHeight() != conspicRG.getHeight()) 00504 { 00505 LINFO("Saliency map is the wrong size or raw image not initalized"); 00506 LFATAL("Conspic Height %d != Raw Height %d",conspicRG.getHeight(), 00507 itsInImage.getHeight()); 00508 } 00509 // normalize from 0 to 1 00510 //itsConspicRG = conspicRG/255.0F; 00511 itsConspicRG = conspicRG; 00512 itsConspicRG = itsConspicRG*itsRGbias; 00513 } 00514 00515 /*************************************************************************/ 00516 00517 template <class PIXTYPE, class BETATYPE, class FLOAT> 00518 void RemoveSurprise<PIXTYPE,BETATYPE,FLOAT>::RSinputConspicBY(const Image<FLOAT>& conspicBY) 00519 { 00520 LINFO("INPUT BY IMAGE"); 00521 itsInit[5] = true; 00522 if(itsInImage.getWidth() != conspicBY.getWidth()) 00523 { 00524 LINFO("Saliency map is the wrong size or raw image not initalized"); 00525 LFATAL("Conspic Width %d != Raw Width %d",conspicBY.getWidth(), 00526 itsInImage.getWidth()); 00527 } 00528 if(itsInImage.getHeight() != conspicBY.getHeight()) 00529 { 00530 LINFO("Saliency map is the wrong size or raw image not initalized"); 00531 LFATAL("Conspic Height %d != Raw Height %d",conspicBY.getHeight(), 00532 itsInImage.getHeight()); 00533 } 00534 // normalize from 0 to 1 00535 //itsConspicBY = conspicBY/255.0F; 00536 itsConspicBY = conspicBY; 00537 itsConspicBY = itsConspicBY*itsBYbias; 00538 } 00539 00540 /*************************************************************************/ 00541 00542 template <class PIXTYPE, class BETATYPE, class FLOAT> 00543 void RemoveSurprise<PIXTYPE,BETATYPE,FLOAT>::RSinputBayesWeightImage( 00544 const Image<FLOAT> &bayesImage) 00545 { 00546 LINFO("INPUT Bayes Weight Image"); 00547 itsUseBayesWeightImage = true; 00548 itsBayesWeightImage = bayesImage; 00549 } 00550 00551 /*************************************************************************/ 00552 00553 template <class PIXTYPE, class BETATYPE, class FLOAT> 00554 void RemoveSurprise<PIXTYPE,BETATYPE,FLOAT>::RSsetCorrWeightMat( 00555 const std::vector<std::vector<FLOAT> > corAnti, 00556 const std::vector<std::vector<FLOAT> > corBase) 00557 { 00558 LINFO("INPUT Corr Weight Matrix"); 00559 itsUseCorrMatrixSet = true; 00560 itsAntiCorrelationMat = corAnti; 00561 itsBaseCorrelationMat = corBase; 00562 } 00563 00564 /*************************************************************************/ 00565 00566 template <class PIXTYPE, class BETATYPE, class FLOAT> 00567 void RemoveSurprise<PIXTYPE,BETATYPE,FLOAT>::RScreateSepFilters(const FLOAT spatSigma, 00568 const FLOAT tempSigma, 00569 const FLOAT stdDevSize) 00570 { 00571 LINFO("SETTING UP FILTERS"); 00572 itsInit[6] = true; 00573 // create three components for a std seperable guassian kernel 00574 ushort rs1 = (ushort)ceil(spatSigma*stdDevSize*2.0F); 00575 ushort rs2 = (ushort)floor(spatSigma*stdDevSize*2.0F); 00576 // make sure the kernel is odd sized spatial 00577 if(rs1%2 == 0) 00578 { 00579 if(rs2%2 == 0) 00580 { 00581 itsKernelSizeX = rs2 + 1; 00582 itsKernelSizeY = rs2 + 1; 00583 } 00584 else 00585 { 00586 itsKernelSizeX = rs2; 00587 itsKernelSizeY = rs2; 00588 } 00589 } 00590 else 00591 { 00592 itsKernelSizeX = rs1; 00593 itsKernelSizeY = rs1; 00594 } 00595 itsKalmanKernelX.resize(itsKernelSizeX,0.0F); 00596 itsKalmanKernelY.resize(itsKernelSizeY,0.0F); 00597 00598 // the temporal filter is one tailed (we can't smooth into the future) 00599 rs1 = (uint)ceil((tempSigma*stdDevSize)); 00600 rs2 = (uint)floor((tempSigma*stdDevSize)); 00601 // make sure the kernel is odd sized temporal 00602 if(rs1%2 == 0) 00603 { 00604 if(rs2%2 == 0) 00605 { 00606 itsKernelSizeZ = (ushort)rs2 + 1; 00607 } 00608 else 00609 { 00610 itsKernelSizeZ = (ushort)rs2; 00611 } 00612 } 00613 else 00614 { 00615 itsKernelSizeZ = (ushort)rs1; 00616 } 00617 itsKalmanKernelZ.resize(itsKernelSizeZ,0.0F); 00618 00619 // find the kernel center 00620 00621 const FLOAT centerX = floor((FLOAT)itsKernelSizeX/2.0F); 00622 const FLOAT centerY = floor((FLOAT)itsKernelSizeY/2.0F); 00623 00624 FLOAT gmod = 1.0F/sqrt(2.0F*M_PI*pow(spatSigma,2)); 00625 00626 LINFO("Kernel X size %d",itsKernelSizeX); 00627 for(ushort i = 0; i < itsKernelSizeX; i++) 00628 { 00629 const FLOAT dist = pow((i - centerX),2); 00630 itsKalmanKernelX[i] = 00631 (gmod*exp((-1.0F*dist)/pow(2*spatSigma,2))); 00632 std::cerr << i << " : " << itsKalmanKernelX[i] << "\n"; 00633 } 00634 LINFO("Kernel Y size %d",itsKernelSizeY); 00635 for(ushort i = 0; i < itsKernelSizeY; i++) 00636 { 00637 const FLOAT dist = pow((i - centerY),2); 00638 itsKalmanKernelY[i] = 00639 (gmod*exp((-1.0F*dist)/pow(2*spatSigma,2))); 00640 std::cerr << i << " : " << itsKalmanKernelY[i] << "\n"; 00641 } 00642 00643 gmod = 2.0F/sqrt(2.0F*M_PI*pow(spatSigma,2)); 00644 LINFO("Kernel Z size %d",itsKernelSizeZ); 00645 for(ushort i = 0; i < itsKernelSizeZ; i++) 00646 { 00647 const FLOAT dist = pow((FLOAT)i,2.0F); 00648 itsKalmanKernelZ[i] = 00649 (gmod*exp((-1.0F*dist)/pow(2*spatSigma,2))); 00650 std::cerr << i << " : " << itsKalmanKernelZ[i] << "\n"; 00651 } 00652 } 00653 00654 /*************************************************************************/ 00655 00656 template <class PIXTYPE, class BETATYPE, class FLOAT> 00657 void RemoveSurprise<PIXTYPE,BETATYPE,FLOAT>::RSfindConvolutionEndPoints() 00658 { 00659 LINFO("SETTING UP CONVOLUTION END POINTS"); 00660 itsInit[7] = true; 00661 itsXStart.resize(itsImageSizeX,itsImageSizeY); 00662 itsYStart.resize(itsImageSizeX,itsImageSizeY); 00663 itsZStart.resize(itsImageSizeX,itsImageSizeY); 00664 itsXStop.resize( itsImageSizeX,itsImageSizeY); 00665 itsYStop.resize( itsImageSizeX,itsImageSizeY); 00666 itsZStop.resize( itsImageSizeX,itsImageSizeY); 00667 itsKXStart.resize(itsImageSizeX,itsImageSizeY); 00668 itsKYStart.resize(itsImageSizeX,itsImageSizeY); 00669 itsKZStart.resize(itsImageSizeX,itsImageSizeY); 00670 00671 Image<ushort>::iterator itsXStartItr = itsXStart.beginw(); 00672 Image<ushort>::iterator itsXStopItr = itsXStop.beginw(); 00673 Image<ushort>::iterator itsKXStartItr = itsKXStart.beginw(); 00674 Image<ushort>::iterator itsYStartItr = itsYStart.beginw(); 00675 Image<ushort>::iterator itsYStopItr = itsYStop.beginw(); 00676 Image<ushort>::iterator itsKYStartItr = itsKYStart.beginw(); 00677 Image<ushort>::iterator itsZStartItr = itsZStart.beginw(); 00678 Image<ushort>::iterator itsZStopItr = itsZStop.beginw(); 00679 Image<ushort>::iterator itsKZStartItr = itsKZStart.beginw(); 00680 00681 // foo 00682 00683 for(ushort y = 0; y < itsImageSizeY; y++) 00684 { 00685 for(ushort x = 0; x < itsImageSizeX; x++) 00686 { 00687 const ushort yhalf = (ushort)floor(itsKernelSizeY/2); 00688 const ushort yend = itsImageSizeY - yhalf; 00689 if(y < yhalf + 1) 00690 { 00691 *itsYStartItr = 0; 00692 *itsKYStartItr = yhalf - y; 00693 *itsYStopItr = y + yhalf; 00694 } 00695 else if(y > yend) 00696 { 00697 *itsYStartItr = y - yhalf; 00698 *itsKYStartItr = 0; 00699 *itsYStopItr = itsImageSizeY; 00700 } 00701 else 00702 { 00703 *itsYStartItr = y - yhalf; 00704 *itsKYStartItr = 0; 00705 *itsYStopItr = y + yhalf; 00706 } 00707 00708 const ushort xhalf = (ushort)floor(itsKernelSizeX/2); 00709 const ushort xend = itsImageSizeX - xhalf; 00710 if(x < xhalf + 1) 00711 { 00712 *itsXStartItr = 0; 00713 *itsKXStartItr = xhalf - x; 00714 *itsXStopItr = x + xhalf; 00715 } 00716 else if(x > xend) 00717 { 00718 *itsXStartItr = x - xhalf; 00719 *itsKXStartItr = 0; 00720 *itsXStopItr = itsImageSizeX; 00721 } 00722 else 00723 { 00724 *itsXStartItr = x - xhalf; 00725 *itsKXStartItr = 0; 00726 *itsXStopItr = x + xhalf; 00727 } 00728 00729 // Z is not interesting, its starts at the current frame and 00730 // runs the size of the deque 00731 *itsKZStartItr = 0; 00732 *itsZStartItr = 0; 00733 *itsZStopItr = itsKernelSizeZ; 00734 00735 //LINFO("X %d - %d K %d",*itsXStartItr,*itsXStopItr,*itsKXStartItr); 00736 //LINFO("Y %d - %d K %d",*itsYStartItr,*itsYStopItr,*itsKYStartItr); 00737 ++itsXStartItr; ++itsXStopItr; ++itsKXStartItr; 00738 ++itsYStartItr; ++itsYStopItr; ++itsKYStartItr; 00739 ++itsZStartItr; ++itsZStopItr; ++itsKZStartItr; 00740 } 00741 } 00742 } 00743 00744 /*************************************************************************/ 00745 00746 template <class PIXTYPE, class BETATYPE, class FLOAT> 00747 void RemoveSurprise<PIXTYPE,BETATYPE,FLOAT>::RSprocessFrame() 00748 { 00749 LINFO("PROCESSING FRAME %d",itsFrameNumber); 00750 for(uint i = 0; i < itsInit.size(); i++) 00751 { 00752 if(!itsInit[i]) 00753 { 00754 std::cerr << itsInitMessage[i] << "\n"; 00755 LFATAL("One or more nessesary methods not run"); 00756 } 00757 } 00758 if(typeid(BETATYPE).name() != typeid(itsHyper4).name()) 00759 { 00760 LFATAL("Run time type mismatch. Expected %s got %s", 00761 typeid(itsHyper4).name(),typeid(BETATYPE).name()); 00762 } 00763 00764 00765 Image<ushort>::iterator itsXStartItr = itsXStart.beginw(); 00766 Image<ushort>::iterator itsYStartItr = itsYStart.beginw(); 00767 Image<ushort>::iterator itsXStopItr = itsXStop.beginw(); 00768 Image<ushort>::iterator itsYStopItr = itsYStop.beginw(); 00769 Image<ushort>::iterator itsKXStartItr = itsKXStart.beginw(); 00770 Image<ushort>::iterator itsKYStartItr = itsKYStart.beginw(); 00771 00772 typename Image<PIXTYPE >::iterator outImageItr; 00773 typename Image<PIXTYPE >::iterator inImageItr = itsInImage.beginw(); 00774 typename Image<BETATYPE>::iterator betaImageItr = itsBetaImage.beginw(); 00775 00776 typename Image<FLOAT>::iterator itsConsCOItr = itsConspicCO.beginw(); 00777 typename Image<FLOAT>::iterator itsConsMOItr = itsConspicMO.beginw(); 00778 typename Image<FLOAT>::iterator itsConsORItr = itsConspicOR.beginw(); 00779 typename Image<FLOAT>::iterator itsConsINItr = itsConspicIN.beginw(); 00780 00781 typename Image<PixRGB<FLOAT> >::iterator finalImageItr = 00782 itsFinalImage.beginw(); 00783 typename std::deque<Image<PIXTYPE > >::iterator frameBufferItr; 00784 00785 const typename std::deque<Image<PIXTYPE > >::iterator frameBufferEnd = 00786 itsFrameBuffer.end(); 00787 const typename std::deque<Image<PIXTYPE > >::iterator frameBufferBegin = 00788 itsFrameBuffer.begin(); 00789 00790 const typename std::vector<FLOAT>::iterator kalmanKernelXbegin = 00791 itsKalmanKernelX.begin(); 00792 const typename std::vector<FLOAT>::iterator kalmanKernelYbegin = 00793 itsKalmanKernelY.begin(); 00794 const typename std::vector<FLOAT>::iterator kalmanKernelZbegin = 00795 itsKalmanKernelZ.begin(); 00796 00797 // copy itsInImage to itsOutImage so we can take the conspicuity weighted 00798 // average of the two 00799 00800 // for the output image pixels 00801 for(outImageItr = itsOutImage.beginw(); 00802 outImageItr != itsOutImage.endw(); 00803 ++outImageItr, ++finalImageItr, ++inImageItr, ++betaImageItr, 00804 ++itsYStartItr, ++itsXStartItr, 00805 ++itsYStopItr, ++itsXStopItr, 00806 ++itsKYStartItr, ++itsKXStartItr, 00807 ++itsConsCOItr, ++itsConsMOItr, 00808 ++itsConsORItr, ++itsConsINItr) 00809 { 00810 00811 PIXTYPE normal(0.0F); 00812 00813 // reset this pixel 00814 *outImageItr = normal; 00815 00816 const FLOAT CO = *itsConsCOItr; 00817 const FLOAT MO = *itsConsMOItr; 00818 const FLOAT OR = *itsConsORItr; 00819 const FLOAT IN = *itsConsINItr; 00820 const ushort XStart = *itsXStartItr; 00821 const ushort YStart = *itsYStartItr; 00822 const ushort KXStart = *itsKXStartItr; 00823 const ushort KYStart = *itsKYStartItr; 00824 const ushort XStop = *itsXStopItr; 00825 const ushort YStop = *itsYStopItr; 00826 00827 // copy these variables into a more register friendly data structure 00828 00829 FLOAT outH1 = inImageItr->H1(); 00830 FLOAT outH2 = inImageItr->H2(); 00831 FLOAT outS = inImageItr->S(); 00832 FLOAT outV = inImageItr->V(); 00833 00834 // use normal to hold the final divisor for the convolution 00835 00836 FLOAT npixS = normal.p[2]; npixS++; 00837 FLOAT npixV = normal.p[3]; npixV++; 00838 FLOAT npixH1 = normal.p[0]; npixH1++; 00839 FLOAT npixH2 = normal.p[1]; npixH2++; 00840 00841 // smooth bias over iterations with a decay term 00842 00843 00844 const FLOAT betaCO = 00845 (betaImageItr->p[0] * itsLambda + CO)/(1 + 1 * itsLambda); 00846 00847 betaImageItr->p[0] = betaCO; 00848 00849 const FLOAT betaMO = 00850 (betaImageItr->p[1] * itsLambda + MO)/(1 + 1 * itsLambda); 00851 betaImageItr->p[1] = betaMO; 00852 00853 const FLOAT betaOR = 00854 (betaImageItr->p[2] * itsLambda + OR)/(1 + 1 * itsLambda); 00855 betaImageItr->p[2] = betaOR; 00856 00857 const FLOAT betaIN = 00858 (betaImageItr->p[3] * itsLambda + IN)/(1 + 1 * itsLambda); 00859 betaImageItr->p[3] = betaIN; 00860 00861 00862 if((betaCO > SMALL_SALIENCY) || (betaMO > SMALL_SALIENCY) || 00863 (betaOR > SMALL_SALIENCY) || (betaIN > SMALL_SALIENCY)) 00864 { 00865 // iterate over Y 00866 const typename std::vector<FLOAT>::iterator kalmanKernelXbeginLoc = 00867 kalmanKernelXbegin + KXStart; 00868 00869 00870 00871 typename std::vector<FLOAT>::iterator ky = kalmanKernelYbegin + KYStart; 00872 00873 for(ushort j = YStart; j < YStop; j++, ++ky) 00874 { 00875 const FLOAT COky = betaCO * (*ky); 00876 const FLOAT MOky = betaMO * (*ky); 00877 const FLOAT ORky = betaOR * (*ky); 00878 const FLOAT INky = betaIN * (*ky); 00879 const int posy = j * itsImageSizeX; 00880 // iterate over X 00881 typename std::vector<FLOAT>::iterator kx = kalmanKernelXbeginLoc; 00882 for(ushort i = XStart; i < XStop; i++, ++kx) 00883 { 00884 const FLOAT COkx = (*kx) * COky; 00885 const FLOAT MOkx = (*kx) * MOky; 00886 const FLOAT ORkx = (*kx) * ORky; 00887 const FLOAT INkx = (*kx) * INky; 00888 const FLOAT COMO = COkx + MOkx; 00889 const FLOAT COINORMO = COMO + ORkx + INkx; 00890 const int posx = posy + i; 00891 // iterate through each frame in the buffer Z 00892 typename std::vector<FLOAT>::iterator kz = kalmanKernelZbegin; 00893 00894 for(frameBufferItr = frameBufferBegin; 00895 frameBufferItr != frameBufferEnd; 00896 ++frameBufferItr, ++kz) 00897 { 00898 const PIXTYPE *curr = &frameBufferItr->getVal(posx); 00899 00900 // Hue is biased by color and motion 00901 // if intensity is very low, don't bother with color since 00902 // HSV is singular for hue if color is black 00903 if(curr->p[3] > 0.15F) 00904 { 00905 const FLOAT COMOkz = (*kz) * COMO; 00906 outH1 += curr->p[0] * COMOkz; 00907 outH2 += curr->p[1] * COMOkz; 00908 npixH1 += COMOkz; 00909 } 00910 00911 // saturation is biased by color, intensity, 00912 // orientation and motion 00913 const FLOAT COINORMOkz = (*kz) * COINORMO; 00914 outS += curr->p[2] * COINORMOkz; 00915 npixS += COINORMOkz; 00916 00917 // intensity is biased by color, intensity, 00918 // orientation and motion 00919 outV += curr->p[3] * COINORMOkz; 00920 } 00921 } 00922 } 00923 } 00924 00925 outImageItr->p[0] = outH1/npixH1; 00926 outImageItr->p[1] = outH2/npixH1; 00927 outImageItr->p[2] = outS /npixS; 00928 outImageItr->p[3] = outV /npixS; 00929 00930 *finalImageItr = PixRGB<FLOAT>(*outImageItr); 00931 // final image is a combination of the current image and 00932 // the convolved image weighted by surprise 00933 } 00934 } 00935 00936 00937 /*************************************************************************/ 00938 00939 template <class PIXTYPE, class BETATYPE, class FLOAT> 00940 void RemoveSurprise<PIXTYPE,BETATYPE,FLOAT>::RSprocessFrameSeperable() 00941 { 00942 LINFO("PROCESSING FRAME %d",itsFrameNumber); 00943 typename Image<BETATYPE>::iterator betaImageItr; 00944 typename Image<PixRGB<FLOAT> >::iterator finalImageItr = 00945 itsFinalImage.beginw(); 00946 00947 if(typeid(BETATYPE).name() == typeid(itsHyper4).name()) 00948 { 00949 LINFO("Non-Scale 4 Channel Model"); 00950 typename Image<FLOAT>::iterator itsConsCOItr = itsConspicCO.beginw(); 00951 typename Image<FLOAT>::iterator itsConsMOItr = itsConspicMO.beginw(); 00952 typename Image<FLOAT>::iterator itsConsORItr = itsConspicOR.beginw(); 00953 typename Image<FLOAT>::iterator itsConsINItr = itsConspicIN.beginw(); 00954 00955 const PIXTYPE ZERO(0.0F); 00956 PIXTYPE normal; 00957 // copy itsInImage to itsOutImage so we can take the conspicuity weighted 00958 // average of the two 00959 // Derive the new bias with low pass smoothing 00960 for(betaImageItr = itsBetaImage.beginw(); 00961 betaImageItr != itsBetaImage.endw(); 00962 ++betaImageItr, 00963 ++itsConsCOItr, ++itsConsMOItr, 00964 ++itsConsORItr, ++itsConsINItr) 00965 { 00966 const FLOAT CO = *itsConsCOItr; 00967 const FLOAT MO = *itsConsMOItr; 00968 const FLOAT OR = *itsConsORItr; 00969 const FLOAT IN = *itsConsINItr; 00970 00971 betaImageItr->p[0] = 00972 (betaImageItr->p[0] * itsLambda + CO)/(1 + 1 * itsLambda); 00973 00974 betaImageItr->p[1] = 00975 (betaImageItr->p[1] * itsLambda + MO)/(1 + 1 * itsLambda); 00976 00977 betaImageItr->p[2] = 00978 (betaImageItr->p[2] * itsLambda + OR)/(1 + 1 * itsLambda); 00979 00980 betaImageItr->p[3] = 00981 (betaImageItr->p[3] * itsLambda + IN)/(1 + 1 * itsLambda); 00982 } 00983 } 00984 else 00985 { 00986 LINFO("Scale 6 Channel Model"); 00987 typename Image<FLOAT>::iterator itsConsINItr = itsConspicIN.beginw(); 00988 typename Image<FLOAT>::iterator itsConsDRItr = itsConspicDR.beginw(); 00989 typename Image<FLOAT>::iterator itsConsFLItr = itsConspicFL.beginw(); 00990 typename Image<FLOAT>::iterator itsConsGAItr = itsConspicGA.beginw(); 00991 typename Image<FLOAT>::iterator itsConsRGItr = itsConspicRG.beginw(); 00992 typename Image<FLOAT>::iterator itsConsBYItr = itsConspicBY.beginw(); 00993 typename Image<FLOAT>::iterator itsBayesWeightItr = 00994 itsBayesWeightImage.beginw(); 00995 00996 const PIXTYPE ZERO(0.0F); 00997 PIXTYPE normal; 00998 // copy itsInImage to itsOutImage so we can take the conspicuity weighted 00999 // average of the two 01000 01001 // Derive the new bias with low pass smoothing 01002 for(betaImageItr = itsBetaImage.beginw(); 01003 betaImageItr != itsBetaImage.endw(); 01004 ++betaImageItr, 01005 ++itsConsINItr, ++itsConsDRItr, 01006 ++itsConsFLItr, ++itsConsGAItr, 01007 ++itsConsRGItr, ++itsConsBYItr, 01008 ++itsBayesWeightItr) 01009 { 01010 if(itsUseBayesWeightImage) 01011 { 01012 *itsConsINItr = *itsConsINItr * *itsBayesWeightItr; 01013 *itsConsDRItr = *itsConsDRItr * *itsBayesWeightItr; 01014 *itsConsFLItr = *itsConsFLItr * *itsBayesWeightItr; 01015 *itsConsGAItr = *itsConsGAItr * *itsBayesWeightItr; 01016 *itsConsRGItr = *itsConsRGItr * *itsBayesWeightItr; 01017 *itsConsBYItr = *itsConsBYItr * *itsBayesWeightItr; 01018 } 01019 if(itsUseCorrMatrixSet) 01020 { 01021 const FLOAT IN = *itsConsINItr; 01022 const FLOAT DR = *itsConsDRItr; 01023 const FLOAT FL = *itsConsFLItr; 01024 const FLOAT GA = *itsConsGAItr; 01025 const FLOAT RG = *itsConsRGItr; 01026 const FLOAT BY = *itsConsBYItr; 01027 01028 const FLOAT INnew = pow(RScomputeCor(IN,DR,FL,GA,RG,BY,0),20) * IN; 01029 //LINFO("IN old %f new %f",IN,INnew); 01030 betaImageItr->p[0] = 01031 (betaImageItr->p[0] * itsLambda + INnew)/ 01032 (1 + 1 * itsLambda); 01033 01034 const FLOAT DRnew = pow(RScomputeCor(IN,DR,FL,GA,RG,BY,1),20) * DR; 01035 //LINFO("DR old %f new %f",DR,DRnew); 01036 betaImageItr->p[1] = 01037 (betaImageItr->p[1] * itsLambda + DRnew)/ 01038 (1 + 1 * itsLambda); 01039 01040 const FLOAT FLnew = pow(RScomputeCor(IN,DR,FL,GA,RG,BY,2),20) * FL; 01041 //LINFO("FL old %f new %f",FL,FLnew); 01042 betaImageItr->p[2] = 01043 (betaImageItr->p[2] * itsLambda + FLnew)/ 01044 (1 + 1 * itsLambda); 01045 01046 const FLOAT GAnew = pow(RScomputeCor(IN,DR,FL,GA,RG,BY,3),20) * GA; 01047 //LINFO("GA old %f new %f",GA,GAnew); 01048 betaImageItr->p[3] = 01049 (betaImageItr->p[3] * itsLambda + GAnew)/ 01050 (1 + 1 * itsLambda); 01051 01052 const FLOAT RGnew = pow(RScomputeCor(IN,DR,FL,GA,RG,BY,4),20) * RG; 01053 //LINFO("RG old %f new %f",RG,RGnew); 01054 betaImageItr->p[4] = 01055 (betaImageItr->p[4] * itsLambda + RGnew)/ 01056 (1 + 1 * itsLambda); 01057 01058 const FLOAT BYnew = pow(RScomputeCor(IN,DR,FL,GA,RG,BY,5),20) * BY; 01059 //LINFO("BY old %f new %f",BY,BYnew); 01060 betaImageItr->p[5] = 01061 (betaImageItr->p[5] * itsLambda + BYnew)/ 01062 (1 + 1 * itsLambda); 01063 } 01064 else 01065 { 01066 betaImageItr->p[0] = 01067 (betaImageItr->p[0] * itsLambda + *itsConsINItr)/ 01068 (1 + 1 * itsLambda); 01069 01070 betaImageItr->p[1] = 01071 (betaImageItr->p[1] * itsLambda + *itsConsDRItr)/ 01072 (1 + 1 * itsLambda); 01073 01074 betaImageItr->p[2] = 01075 (betaImageItr->p[2] * itsLambda + *itsConsFLItr)/ 01076 (1 + 1 * itsLambda); 01077 01078 betaImageItr->p[3] = 01079 (betaImageItr->p[3] * itsLambda + *itsConsGAItr)/ 01080 (1 + 1 * itsLambda); 01081 01082 betaImageItr->p[4] = 01083 (betaImageItr->p[4] * itsLambda + *itsConsRGItr)/ 01084 (1 + 1 * itsLambda); 01085 01086 betaImageItr->p[5] = 01087 (betaImageItr->p[5] * itsLambda + *itsConsBYItr)/ 01088 (1 + 1 * itsLambda); 01089 } 01090 } 01091 } 01092 LINFO("BETA done"); 01093 // do x,y and z seperate convolutions 01094 RSseperateConv('z'); RSseperateConv('y'); RSseperateConv('x'); 01095 LINFO("FINISHING image"); 01096 typename Image<PIXTYPE >::iterator outImageItr = itsOutImage.beginw(); 01097 for(finalImageItr = itsFinalImage.beginw(); 01098 finalImageItr != itsFinalImage.endw(); 01099 ++finalImageItr, ++outImageItr) 01100 { 01101 *finalImageItr = PixRGB<FLOAT>(*outImageItr); 01102 } 01103 LINFO("DONE"); 01104 } 01105 01106 01107 /*************************************************************************/ 01108 01109 template <class PIXTYPE, class BETATYPE, class FLOAT> 01110 void RemoveSurprise<PIXTYPE,BETATYPE,FLOAT>::RSseperateConv(const char axis) 01111 { 01112 typename Image<BETATYPE>::iterator betaImageItr = itsBetaImage.beginw(); 01113 01114 const typename std::deque<Image<PIXTYPE > >::iterator frameBufferBegin = 01115 itsFrameBuffer.begin(); 01116 // const typename std::deque<Image<PIXTYPE > >::iterator frameBufferEnd = 01117 // itsFrameBuffer.end(); 01118 01119 typename Image<PIXTYPE >::iterator outImageItr; 01120 typename Image<PIXTYPE >::iterator outImageBegin; 01121 typename Image<PIXTYPE >::iterator outImageEnd; 01122 //typename Image<PIXTYPE >::iterator outImageNormItr; 01123 typename Image<PIXTYPE >::iterator inImageItr; 01124 typename Image<PIXTYPE >::iterator inImageTrueItr; 01125 01126 Image<ushort>::iterator itsStartItr; 01127 Image<ushort>::iterator itsStopItr; 01128 Image<ushort>::iterator itsKStartItr; 01129 01130 typename std::deque<Image<PIXTYPE > >::iterator frameBufferItr; 01131 typename std::vector<FLOAT>::iterator kalmanKernelbegin; 01132 FLOAT axisBias; 01133 01134 if(axis == 'z') 01135 { 01136 inImageItr = itsInImage.beginw(); 01137 outImageBegin = itsInterImage[0].beginw(); 01138 outImageEnd = itsInterImage[0].endw(); 01139 //outImageNormItr = itsInterImageNorm[0].beginw(); 01140 itsStartItr = itsZStart.beginw(); 01141 itsStopItr = itsZStop.beginw(); 01142 itsKStartItr = itsKZStart.beginw(); 01143 kalmanKernelbegin = itsKalmanKernelZ.begin(); 01144 axisBias = itsZbias; 01145 01146 // blank the output image and the norm image 01147 for(outImageItr = outImageBegin; 01148 outImageItr != outImageEnd; 01149 ++outImageItr) 01150 { 01151 outImageItr->p[0] = 0.0F; 01152 outImageItr->p[1] = 0.0F; 01153 outImageItr->p[2] = 0.0F; 01154 outImageItr->p[3] = 0.0F; 01155 /* 01156 outImageNormItr->p[0] = 0.0F; 01157 outImageNormItr->p[1] = 0.0F; 01158 outImageNormItr->p[2] = 0.0F; 01159 outImageNormItr->p[3] = 0.0F; 01160 */ 01161 } 01162 //outImageNormItr = itsInterImageNorm[0].beginw(); 01163 01164 } 01165 else if(axis == 'y') 01166 { 01167 // blank the output image 01168 inImageItr = itsInterImage[0].beginw(); 01169 outImageBegin = itsInterImage[1].beginw(); 01170 outImageEnd = itsInterImage[1].endw(); 01171 //outImageNormItr = itsInterImageNorm[0].beginw(); 01172 itsStartItr = itsYStart.beginw(); 01173 itsStopItr = itsYStop.beginw(); 01174 itsKStartItr = itsKYStart.beginw(); 01175 kalmanKernelbegin = itsKalmanKernelY.begin(); 01176 axisBias = itsYbias; 01177 01178 // blank the output image 01179 for(outImageItr = outImageBegin; outImageItr != outImageEnd; ++outImageItr) 01180 { 01181 outImageItr->p[0] = 0.0F; 01182 outImageItr->p[1] = 0.0F; 01183 outImageItr->p[2] = 0.0F; 01184 outImageItr->p[3] = 0.0F; 01185 } 01186 } 01187 else if(axis == 'x') 01188 { 01189 inImageItr = itsInterImage[1].beginw(); 01190 outImageBegin = itsOutImage.beginw(); 01191 outImageEnd = itsOutImage.endw(); 01192 //outImageNormItr = itsInterImageNorm[0].beginw(); 01193 itsStartItr = itsXStart.beginw(); 01194 itsStopItr = itsXStop.beginw(); 01195 itsKStartItr = itsKXStart.beginw(); 01196 kalmanKernelbegin = itsKalmanKernelX.begin(); 01197 axisBias = itsXbias; 01198 01199 // blank the output image 01200 for(outImageItr = outImageBegin; outImageItr != outImageEnd; ++outImageItr) 01201 { 01202 outImageItr->p[0] = 0.0F; 01203 outImageItr->p[1] = 0.0F; 01204 outImageItr->p[2] = 0.0F; 01205 outImageItr->p[3] = 0.0F; 01206 } 01207 } 01208 else 01209 { 01210 LINFO("Must use axis as z,x then y in that order"); 01211 LFATAL("Unknown axis specified %c",axis); 01212 // put values here to make to compiler shut the %*&! up 01213 inImageItr = itsInterImage[1].beginw(); 01214 outImageBegin = itsOutImage.beginw(); 01215 outImageEnd = itsOutImage.endw(); 01216 //outImageNormItr = itsInterImageNorm[0].beginw(); 01217 itsStartItr = itsXStart.beginw(); 01218 itsStopItr = itsXStop.beginw(); 01219 itsKStartItr = itsKXStart.beginw(); 01220 kalmanKernelbegin = itsKalmanKernelX.begin(); 01221 axisBias = itsXbias; 01222 } 01223 01224 int pos = 0; 01225 FLOAT localBiasH1 = 0.0F; 01226 FLOAT localBiasH2 = 0.0F; 01227 FLOAT localBiasS = 0.0F; 01228 FLOAT localBiasV = 0.0F; 01229 01230 const bool hyper6 = (typeid(BETATYPE).name() == typeid(itsHyper6).name()); 01231 inImageTrueItr = itsInImage.beginw(); 01232 01233 for(outImageItr = outImageBegin; 01234 outImageItr != outImageEnd; pos++, 01235 ++outImageItr, ++inImageItr, ++betaImageItr, 01236 ++itsStartItr, ++itsStopItr, ++itsKStartItr, ++inImageTrueItr) 01237 { 01238 FLOAT npixH1 = 0.0F; 01239 FLOAT npixH2 = 0.0F; 01240 FLOAT npixS = 0.0F; 01241 FLOAT npixV = 0.0F; 01242 01243 if(hyper6) 01244 { 01245 // get the surprise biases smoothed 01246 const FLOAT betaIN = betaImageItr->p[0]; 01247 const FLOAT betaDR = betaImageItr->p[1]; 01248 const FLOAT betaFL = betaImageItr->p[2]; 01249 const FLOAT betaGA = betaImageItr->p[3]; 01250 01251 LFATAL("two lines following this message do not compile. FIXME"); 01252 const FLOAT betaRG = 0; ///////betaImageItr->p[4]; 01253 const FLOAT betaBY = 0; ///////betaImageItr->p[5]; 01254 01255 // compute the surprise bias combinations with the axis bias 01256 /* If we use max level then surprise removal is scaled by the max 01257 level of all conspicuity maps, this limits reduction to be no more 01258 than the highest conspicuity map and prevents to much application 01259 at certian locations. However, it may not scale properly 01260 */ 01261 01262 if(itsUseMaxLevel) 01263 { 01264 if(betaBY > betaRG) 01265 { 01266 localBiasH1 = betaBY * axisBias * itsH1bias; 01267 localBiasH2 = betaBY * axisBias * itsH2bias; 01268 localBiasS = betaBY * axisBias * itsSbias; 01269 } 01270 else 01271 { 01272 localBiasH1 = betaRG * axisBias * itsH1bias; 01273 localBiasH2 = betaRG * axisBias * itsH2bias; 01274 localBiasS = betaRG * axisBias * itsSbias; 01275 } 01276 FLOAT newVal = betaBY; 01277 if(betaRG > newVal) newVal = betaRG; 01278 if(betaDR > newVal) newVal = betaDR; 01279 if(betaIN > newVal) newVal = betaIN; 01280 if(betaFL > newVal) newVal = betaFL; 01281 if(betaGA > newVal) newVal = betaGA; 01282 localBiasV = newVal * axisBias * itsVbias; 01283 } 01284 else 01285 { 01286 localBiasH1 = (betaBY + betaRG) * axisBias * itsH1bias; 01287 localBiasH2 = (betaBY + betaRG) * axisBias * itsH2bias; 01288 localBiasS = (betaBY + betaRG) * axisBias * itsSbias; 01289 localBiasV = (betaDR + betaBY + betaRG + 01290 betaIN + betaFL + betaGA) * axisBias * 01291 itsVbias; 01292 } 01293 01294 const FLOAT colorBias = (betaRG * betaBY) / (itsBYbias * itsRGbias); 01295 FLOAT desat = 1.0F - (colorBias * itsDesatbias); 01296 01297 //make sure desat stays normal positive 01298 if(desat < 0.0F) 01299 desat = 0.0F; 01300 01301 // Make sure that the values here are not sooo small as to not matter 01302 if((betaIN > SMALL_SALIENCY) || (betaDR > SMALL_SALIENCY) || 01303 (betaFL > SMALL_SALIENCY) || (betaGA > SMALL_SALIENCY) || 01304 (betaBY > SMALL_SALIENCY) || (betaRG > SMALL_SALIENCY)) 01305 { 01306 // figure out where we are in the image and the kernel 01307 frameBufferItr = frameBufferBegin; 01308 typename std::vector<FLOAT>::iterator k = kalmanKernelbegin + 01309 (*itsKStartItr); 01310 int posMod = 0; 01311 if(axis == 'y') 01312 posMod = pos%itsImageSizeX; 01313 else if(axis == 'x') 01314 posMod = pos/itsImageSizeX; 01315 else if(axis == 'z') 01316 *itsStopItr = itsFrameBuffer.size(); 01317 // iterate over the kernel 01318 for(ushort i = *itsStartItr; i < *itsStopItr; i++, ++k) 01319 { 01320 // get the current other pixel x,y,z 01321 PIXTYPE curr; 01322 if(axis == 'z') 01323 { 01324 curr = frameBufferItr->getVal(pos); 01325 frameBufferItr++; 01326 } 01327 else if(axis == 'y') 01328 curr = itsInterImage[0].getVal(posMod,i); 01329 else 01330 curr = itsInterImage[1].getVal(i,posMod); 01331 01332 // if other pixel is to dim, don't use its color 01333 // this avoids H2SV (and HSV) singularities at black for hue 01334 if(curr.p[3] > NEAR_BLACK) 01335 { 01336 const FLOAT H1 = (*k) * localBiasH1; 01337 outImageItr->p[0] += curr.p[0] * H1; 01338 npixH1 += H1; 01339 01340 const FLOAT H2 = (*k) * localBiasH2; 01341 outImageItr->p[1] += curr.p[1] * H2; 01342 npixH2 += H2; 01343 } 01344 01345 // saturation is biased by color, intensity, 01346 // orientation and motion 01347 const FLOAT S = (*k) * localBiasS; 01348 outImageItr->p[2] += (curr.p[2] * desat) * S; 01349 npixS += S; 01350 01351 const FLOAT V = (*k) * localBiasV; 01352 // simple desaturation can increase intensity so we compensate 01353 // V' = (V - V*S)/(1 - S') 01354 const FLOAT newV = (curr.p[3] - curr.p[3]*curr.p[2])/ 01355 (1 - (curr.p[2] * desat)); 01356 //outImageItr->p[3] += curr.p[3] * V; 01357 outImageItr->p[3] += newV * V; 01358 npixV += V; 01359 } 01360 } 01361 } 01362 else 01363 { 01364 // get the surprise biases smoothed 01365 const FLOAT betaCO = betaImageItr->p[0]; 01366 const FLOAT betaMO = betaImageItr->p[1]; 01367 const FLOAT betaOR = betaImageItr->p[2]; 01368 const FLOAT betaIN = betaImageItr->p[3]; 01369 01370 // compute the surprise bias combinations with the axis bias 01371 const FLOAT COMO = (betaCO + betaMO) * axisBias; 01372 const FLOAT COINORMO = (betaCO + betaIN + betaOR + betaMO) * axisBias; 01373 01374 // Make sure that the values here are not sooo small as to not matter 01375 if((betaCO > SMALL_SALIENCY) || (betaMO > SMALL_SALIENCY) || 01376 (betaOR > SMALL_SALIENCY) || (betaIN > SMALL_SALIENCY)) 01377 { 01378 // figure out where we are in the image and the kernel 01379 frameBufferItr = frameBufferBegin; 01380 typename std::vector<FLOAT>::iterator k = kalmanKernelbegin + 01381 (*itsKStartItr); 01382 int posMod = 0; 01383 if(axis == 'y') 01384 posMod = pos%itsImageSizeX; 01385 else if(axis == 'x') 01386 posMod = pos/itsImageSizeX; 01387 else if(axis == 'z') 01388 *itsStopItr = itsFrameBuffer.size(); 01389 01390 // iterate over the kernel 01391 for(ushort i = *itsStartItr; i < *itsStopItr; i++, ++k) 01392 { 01393 // get the current other pixel x,y,z 01394 PIXTYPE curr; 01395 if(axis == 'z') 01396 { 01397 curr = frameBufferItr->getVal(pos); 01398 frameBufferItr++; 01399 } 01400 else if(axis == 'y') 01401 curr = itsInterImage[0].getVal(posMod,i); 01402 else 01403 curr = itsInterImage[1].getVal(i,posMod); 01404 01405 // if other pixel is to dim, don't use its color 01406 // this avoids H2SV (and HSV) singularities at black for hue 01407 if(curr.p[3] > NEAR_BLACK) 01408 { 01409 const FLOAT COMOk = (*k) * COMO; 01410 outImageItr->p[0] += curr.p[0] * COMOk; 01411 outImageItr->p[1] += curr.p[1] * COMOk; 01412 npixH1 += COMOk; 01413 } 01414 01415 // saturation is biased by color, intensity, 01416 // orientation and motion 01417 const FLOAT COINORMOk = (*k) * COINORMO; 01418 outImageItr->p[2] += curr.p[2] * COINORMOk; 01419 outImageItr->p[3] += curr.p[3] * COINORMOk; 01420 npixS += COINORMOk; 01421 } 01422 } 01423 } 01424 // accumulate the normalization 01425 01426 /* 01427 outImageNormItr->p[0] += npixH1; 01428 outImageNormItr->p[1] += npixH1; 01429 outImageNormItr->p[2] += npixS; 01430 outImageNormItr->p[3] += npixS; 01431 */ 01432 01433 // at x, the final iteration normalize the final image 01434 if(axis == 'x') 01435 { 01436 // add in the original image to average (in a sense) with the 01437 // blurred image 01438 outImageItr->p[0] += inImageTrueItr->p[0]; 01439 outImageItr->p[1] += inImageTrueItr->p[1]; 01440 outImageItr->p[2] += inImageTrueItr->p[2]; 01441 outImageItr->p[3] += inImageTrueItr->p[3]; 01442 01443 npixH1++; npixH2++; npixS++; npixV++; 01444 01445 /* 01446 outImageNormItr->p[0] += 1.0F; 01447 outImageNormItr->p[1] += 1.0F; 01448 outImageNormItr->p[2] += 1.0F; 01449 outImageNormItr->p[3] += 1.0F; 01450 */ 01451 } 01452 01453 01454 /* 01455 outImageItr->p[0] = outImageItr->p[0]/(outImageNormItr->p[0]); 01456 outImageItr->p[1] = outImageItr->p[1]/(outImageNormItr->p[1]); 01457 outImageItr->p[2] = outImageItr->p[2]/(outImageNormItr->p[2]); 01458 outImageItr->p[3] = outImageItr->p[3]/(outImageNormItr->p[3]); 01459 01460 outImageNormItr->p[0] = 0.0F; 01461 outImageNormItr->p[1] = 0.0F; 01462 outImageNormItr->p[2] = 0.0F; 01463 outImageNormItr->p[3] = 0.0F; 01464 */ 01465 01466 outImageItr->p[0] = outImageItr->p[0]/npixH1; 01467 outImageItr->p[1] = outImageItr->p[1]/npixH2; 01468 outImageItr->p[2] = outImageItr->p[2]/npixS; 01469 outImageItr->p[3] = outImageItr->p[3]/npixV; 01470 01471 // We should never increase saturation 01472 if(axis == 'x') 01473 if(outImageItr->p[2] > inImageTrueItr->p[2]) 01474 outImageItr->p[2] = inImageTrueItr->p[2]; 01475 01476 01477 // balance intensity by the change in saturation 01478 /* 01479 if(axis == 'x') 01480 { 01481 // V' = (V - V*S)/(1 - S') 01482 outImageItr->p[3] = fabs((outImageItr->p[3] - 01483 outImageItr->p[3]*inImageTrueItr->p[2])/ 01484 (1 - outImageItr->p[2])); 01485 } 01486 */ 01487 } 01488 01489 //LINFO("B"); 01490 } 01491 01492 /*************************************************************************/ 01493 01494 template <class PIXTYPE, class BETATYPE, class FLOAT> 01495 FLOAT RemoveSurprise<PIXTYPE,BETATYPE,FLOAT>::RScomputeCor(const FLOAT IN, 01496 const FLOAT DR, 01497 const FLOAT FL, 01498 const FLOAT GA, 01499 const FLOAT RG, 01500 const FLOAT BY, 01501 const short idx) const 01502 { 01503 const FLOAT C1 = IN*itsAntiCorrelationMat[idx][0] + 01504 DR*itsAntiCorrelationMat[idx][1] + 01505 FL*itsAntiCorrelationMat[idx][2] + 01506 GA*itsAntiCorrelationMat[idx][3] + 01507 RG*itsAntiCorrelationMat[idx][4] + 01508 BY*itsAntiCorrelationMat[idx][5]; 01509 01510 const FLOAT C2 = IN*itsBaseCorrelationMat[idx][0] + 01511 DR*itsBaseCorrelationMat[idx][1] + 01512 FL*itsBaseCorrelationMat[idx][2] + 01513 GA*itsBaseCorrelationMat[idx][3] + 01514 RG*itsBaseCorrelationMat[idx][4] + 01515 BY*itsBaseCorrelationMat[idx][5]; 01516 /* 01517 LINFO("BASE %f %f %f %f %f %f", 01518 IN*itsBaseCorrelationMat[idx][0], 01519 DR*itsBaseCorrelationMat[idx][1], 01520 FL*itsBaseCorrelationMat[idx][2], 01521 GA*itsBaseCorrelationMat[idx][3], 01522 RG*itsBaseCorrelationMat[idx][4], 01523 BY*itsBaseCorrelationMat[idx][5] 01524 ); 01525 01526 LINFO("ANTI %f %f %f %f %f %f", 01527 IN*itsAntiCorrelationMat[idx][0], 01528 DR*itsAntiCorrelationMat[idx][1], 01529 FL*itsAntiCorrelationMat[idx][2], 01530 GA*itsAntiCorrelationMat[idx][3], 01531 RG*itsAntiCorrelationMat[idx][4], 01532 BY*itsAntiCorrelationMat[idx][5] 01533 ); 01534 01535 LINFO("PARTS %f %f %f %f %f %f", 01536 itsBaseCorrelationMat[idx][0], 01537 itsBaseCorrelationMat[idx][1], 01538 itsBaseCorrelationMat[idx][2], 01539 itsBaseCorrelationMat[idx][3], 01540 itsBaseCorrelationMat[idx][4], 01541 itsBaseCorrelationMat[idx][5]); 01542 01543 LINFO("BETA %f %f %f %f %f %f",IN,DR,FL,GA,RG,BY); 01544 */ 01545 if(C1 > 0) 01546 return C2/C1; 01547 else 01548 return 0; 01549 } 01550 01551 /*************************************************************************/ 01552 01553 template <class PIXTYPE, class BETATYPE, class FLOAT> 01554 Image<PixRGB<FLOAT> > RemoveSurprise<PIXTYPE,BETATYPE,FLOAT>::RSgetFrame() 01555 { 01556 itsInit[0] = false; 01557 itsInit[1] = false; 01558 itsInit[2] = false; 01559 itsInit[3] = false; 01560 itsInit[4] = false; 01561 itsInit[5] = false; 01562 return itsFinalImage; 01563 } 01564 01565 /*************************************************************************/ 01566 01567 template <class PIXTYPE, class BETATYPE, class FLOAT> 01568 Image<PixRGB<FLOAT> > RemoveSurprise<PIXTYPE,BETATYPE,FLOAT>::RSgetOutImage() 01569 const 01570 { 01571 Image<PixRGB<FLOAT> > returnImage; 01572 returnImage.resize(itsOutImage.getWidth(),itsOutImage.getHeight()); 01573 typename Image<PixRGB<FLOAT> >::iterator returnImageItr = 01574 returnImage.beginw(); 01575 typename Image<PIXTYPE>::const_iterator outImageItr = 01576 itsOutImage.begin(); 01577 while(returnImageItr != returnImage.endw()) 01578 { 01579 *returnImageItr = PixRGB<FLOAT>(*outImageItr); 01580 ++returnImageItr; ++outImageItr; 01581 } 01582 01583 return returnImage; 01584 } 01585 01586 /*************************************************************************/ 01587 01588 template <class PIXTYPE, class BETATYPE, class FLOAT> 01589 Image<PIXTYPE> RemoveSurprise<PIXTYPE,BETATYPE,FLOAT>::RSgetRawOutImage() const 01590 { 01591 return itsOutImage; 01592 } 01593 01594 /*************************************************************************/ 01595 01596 template <class PIXTYPE, class BETATYPE, class FLOAT> 01597 Image<PIXTYPE> RemoveSurprise<PIXTYPE,BETATYPE,FLOAT>::RSgetRawInImage() const 01598 { 01599 return itsInImage; 01600 } 01601 01602 /*************************************************************************/ 01603 01604 template <class PIXTYPE, class BETATYPE, class FLOAT> 01605 Image<BETATYPE> RemoveSurprise<PIXTYPE,BETATYPE,FLOAT>::RSgetBetaImage() const 01606 { 01607 return itsBetaImage; 01608 } 01609 01610 /*************************************************************************/ 01611 01612 template class RemoveSurprise<PixH2SV1<float>,PixHyper<float,4>,float>; 01613 template class RemoveSurprise<PixH2SV2<float>,PixHyper<float,4>,float>; 01614 template class RemoveSurprise<PixH2SV1<float>,PixHyper<float,6>,float>; 01615 template class RemoveSurprise<PixH2SV2<float>,PixHyper<float,6>,float>; 01616 01617 #endif