00001 00002 /*!@file Robots/Beobot2/Navigation/FOE_Navigation/test-FOEopticFlow.C 00003 find the optic flow (Shi Tomasi) and the focus of expansion (Perrone 1992) */ 00004 // //////////////////////////////////////////////////////////////////// // 00005 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the // 00006 // University of Southern California (USC) and the iLab at USC. // 00007 // See http://iLab.usc.edu for information about this project. // 00008 // //////////////////////////////////////////////////////////////////// // 00009 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00010 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00011 // in Visual Environments, and Applications'' by Christof Koch and // 00012 // Laurent Itti, California Institute of Technology, 2001 (patent // 00013 // pending; application number 09/912,225 filed July 23, 2001; see // 00014 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00015 // //////////////////////////////////////////////////////////////////// // 00016 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00017 // // 00018 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00019 // redistribute it and/or modify it under the terms of the GNU General // 00020 // Public License as published by the Free Software Foundation; either // 00021 // version 2 of the License, or (at your option) any later version. // 00022 // // 00023 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00024 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00025 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00026 // PURPOSE. See the GNU General Public License for more details. // 00027 // // 00028 // You should have received a copy of the GNU General Public License // 00029 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00030 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00031 // Boston, MA 02111-1307 USA. // 00032 // //////////////////////////////////////////////////////////////////// // 00033 // 00034 // Primary maintainer for this file: Christian Siagian <siagian@usc.edu> 00035 // $HeadURL: $ 00036 // $Id: $ 00037 00038 // 00039 00040 #define MAX_CORNERS 500 00041 00042 // OpenCV must be first to avoid conflicting defs of int64, uint64 00043 #include "Image/OpenCVUtil.H" 00044 00045 #include <cstdio> 00046 00047 #include "Component/ModelManager.H" 00048 #include "Media/FrameSeries.H" 00049 00050 #include "Image/Image.H" 00051 #include "Image/CutPaste.H" 00052 #include "Image/ColorOps.H" 00053 #include "Image/MathOps.H" 00054 #include "Image/ShapeOps.H" 00055 #include "Image/Pixels.H" 00056 #include "Raster/Raster.H" 00057 00058 #include "SIFT/Keypoint.H" 00059 #include "SIFT/VisualObject.H" 00060 #include "SIFT/VisualObjectMatch.H" 00061 00062 00063 #include "Util/Timer.H" 00064 00065 #include "Robots/Beobot2/Navigation/FOE_Navigation/FoeDetector.H" 00066 #include "Robots/Beobot2/Navigation/FOE_Navigation/MotionOps.H" 00067 00068 // return the optic flow 00069 //Image<float> getOpticFlow(Image<byte> image1, Image<byte> image2); 00070 Image<float> getOpticFlow2(Image<float> image1, Image<float> image2); 00071 00072 // get the ground truth 00073 std::vector<Point2D<int> > getGT(std::string gtFilename); 00074 00075 Image<byte> calculateShift 00076 (Image<byte> prevLum, Image<byte> lum, nub::ref<OutputFrameSeries> ofs); 00077 00078 Image<byte> shiftImage(SIFTaffine aff, Image<byte> ref, Image<byte> tst); 00079 00080 std::vector<std::vector<Point2D<int> > > getGTandData(); 00081 00082 // ###################################################################### 00083 int main(const int argc, const char **argv) 00084 { 00085 MYLOGVERB = LOG_INFO; // suppress debug messages 00086 00087 // instantiate a model manager: 00088 ModelManager manager("Test Optic Flow"); 00089 00090 nub::ref<InputFrameSeries> ifs(new InputFrameSeries(manager)); 00091 manager.addSubComponent(ifs); 00092 00093 nub::ref<OutputFrameSeries> ofs(new OutputFrameSeries(manager)); 00094 manager.addSubComponent(ofs); 00095 00096 nub::ref<FoeDetector> fd(new FoeDetector(manager)); 00097 manager.addSubComponent(fd); 00098 00099 manager.exportOptions(MC_RECURSE); 00100 00101 if (manager.parseCommandLine((const int)argc, (const char**)argv, 00102 "", 0, 0) == false) 00103 return(1); 00104 00105 // get some options 00106 // if(manager.numExtraArgs() > 0) 00107 // { 00108 // outFilename = manager.getExtraArg(0); 00109 // LINFO("save to: %s", outFilename.c_str()); 00110 // } 00111 00112 // get ground truth file 00113 //std::string gtFilename 00114 // ("/lab/tmpib/u/siagian/neuroscience/Data/FOE/driving_nat_3.txt"); 00115 //std::vector<Point2D<int> > gt = getGT(gtFilename); 00116 //int ldpos = gtFilename.find_last_of('.'); 00117 //std::string prefix = gtFilename.substr(0, ldpos); 00118 00119 std::string pprefix 00120 ("/lab/tmpib/u/siagian/neuroscience/Data/FOE/driving_nat_3"); 00121 00122 std::string folder("/lab/tmpib/u/siagian/neuroscience/Data/FOE/"); 00123 std::string ciofmPrefix("DARPA_nv2_2011/Germany_K_CIOFM/SalMap_CIOFM"); 00124 std::string ciofsPrefix("DARPA_nv2_2011/Germany_K_CIOFs/SalMap_CIOFs"); 00125 00126 // let's do it! 00127 manager.start(); 00128 00129 Timer timer(1000000); 00130 timer.reset(); // reset the timer 00131 int frame = 0; 00132 bool keepGoing = true; 00133 00134 const FrameState is = ifs->updateNext(); 00135 Image< PixRGB<byte> > prevImage; 00136 if (is == FRAME_COMPLETE) keepGoing = false; 00137 else prevImage = ifs->readRGB(); 00138 00139 uint width = prevImage.getWidth(); 00140 uint height = prevImage.getHeight(); 00141 00142 // for finding ground truth 00143 rutz::shared_ptr<XWinManaged> win 00144 (new XWinManaged(Dims(width, height), 0, 0, "GT")); 00145 00146 // GROUND TRUTH 1 00147 //float totalErr = 0.0; 00148 // Image<PixRGB<byte> > d1 =prevImage; 00149 // win->drawImage(d1,0,0); 00150 // LINFO("please click for initial FOE location"); 00151 // Raster::waitForKey(); 00152 // Point2D<int> pt1 = win->getLastMouseClick(); 00153 // LINFO("initial point: [%3d]: %d %d", frame, pt1.i, pt1.j); 00154 // drawCross(d1, pt1, PixRGB<byte>(255,0,0), 10, 2); 00155 // win->drawImage(d1,0,0); 00156 // Raster::waitForKey(); 00157 // Point2D<int> lastPt = pt1; 00158 00159 //std::vector<std::vector<Point2D<int> > > foePts = 00160 // getGTandData(); 00161 //Raster::waitForKey(); 00162 // std::vector<PixRGB<byte> > colors(foePts.size()); 00163 // colors[0] = PixRGB<byte>(255, 0, 0); 00164 // colors[1] = PixRGB<byte>( 0, 255, 0); 00165 // colors[2] = PixRGB<byte>( 0, 0, 255); 00166 // colors[3] = PixRGB<byte>(255, 255, 0); 00167 00168 Image<byte> prevLum = Image<byte>(luminance(prevImage)); 00169 win->setDims(Dims(640,720)); 00170 while (keepGoing) 00171 { 00172 if (ofs->becameVoid()) 00173 { 00174 LINFO("quitting because output stream was closed or became void"); 00175 break; 00176 } 00177 00178 const FrameState is = ifs->updateNext(); 00179 if (is == FRAME_COMPLETE) break; // done receiving frames 00180 00181 Image< PixRGB<byte> > currImage = ifs->readRGB(); 00182 Image<byte> lum = Image<byte>(luminance(currImage)); 00183 00184 // saliency map result 00185 00186 Image< PixRGB<byte> > ciofm = Raster::ReadRGB 00187 (folder+sformat("%s_%06d.ppm", ciofmPrefix.c_str(), frame)); 00188 Image< PixRGB<byte> > ciofs = Raster::ReadRGB 00189 (folder+sformat("%s_%06d.ppm", ciofsPrefix.c_str(), frame)); 00190 00191 Image< PixRGB<byte> > salImg(640,720,ZEROS); 00192 inplacePaste(salImg, zoomXY(prevImage,2), Point2D<int>(0,0)); 00193 inplacePaste(salImg, ciofm, Point2D<int>(0 ,480)); 00194 inplacePaste(salImg, ciofs, Point2D<int>(320,480)); 00195 00196 drawLine(salImg, Point2D<int>(0,480), Point2D<int>(640,480), 00197 PixRGB<byte>(255,255,255), 3); 00198 drawLine(salImg, Point2D<int>(320,480), Point2D<int>(320,720), 00199 PixRGB<byte>(255,255,255), 3); 00200 00201 win->drawImage(salImg,0,0); 00202 Raster::waitForKey(); 00203 00204 Raster::WriteRGB 00205 (salImg, sformat("%s_res_%06d.ppm", pprefix.c_str(), frame)); 00206 00207 Raster::waitForKey(); 00208 00209 // ===================================================== 00210 // Ground truthing 00211 // Image< PixRGB<byte> > dispGT = prevImage; 00212 // //drawCross(dispGT, gt[frame], PixRGB<byte>(0,255,0), 10, 2); 00213 // //LINFO("[%3d]: %d %d", frame, gt[frame].i, gt[frame].j); 00214 // //win->drawImage(dispGT,0,0); 00215 // //Raster::waitForKey(); 00216 00217 // Point2D<int> pt = win->getLastMouseClick(); 00218 // while(!pt.isValid()) 00219 // pt = win->getLastMouseClick(); 00220 // if(pt.isValid() && !(pt == lastPt)) lastPt = pt; 00221 00222 // LINFO("[%3d]: pt %d %d", frame, pt.i, pt.j); 00223 // drawCross(dispGT, lastPt, PixRGB<byte>(255,0,0), 10, 2); 00224 // win->drawImage(dispGT,0,0); 00225 00226 // FILE *gtfp; 00227 // LINFO("[%3d] gt file: %s: %d %d", 00228 // frame, gtFilename.c_str(), lastPt.i, lastPt.j); 00229 // if((gtfp = fopen(gtFilename.c_str(),"at")) == NULL) 00230 // LFATAL("not found"); 00231 // fputs(sformat("%d %d \n", lastPt.i, lastPt.j).c_str(), gtfp); 00232 // fclose (gtfp); 00233 00234 00235 // for performance display 00236 // Image<PixRGB<byte> > pimg = prevImage; 00237 // for(uint i = 0; i < foePts.size(); i++) 00238 // { 00239 // if(!(foePts[i][frame].i == -1 && foePts[i][frame].j == -1)) 00240 // drawCross(pimg, foePts[i][frame], colors[i], 10, 2); 00241 // } 00242 // Raster::WriteRGB(pimg, sformat("%s_res_%06d.ppm", pprefix.c_str(), frame)); 00243 // ofs->writeRGB(pimg, "Performance"); 00244 // Raster::waitForKey(); 00245 00246 // ===================================================== 00247 00248 // calculate planar shift using SIFT 00249 //lum = calculateShift(prevLum, lum, ofs); 00250 00251 // compute the optic flow 00252 //rutz::shared_ptr<OpticalFlow> flow = 00253 // getLucasKanadeOpticFlow 00254 //(Image<byte>(luminance(prevImage)), 00255 //Image<byte>(luminance(currImage))); 00256 00257 // rutz::shared_ptr<OpticalFlow> flow = 00258 // getLucasKanadeOpticFlow(prevLum, lum); 00259 // Image<PixRGB<byte> > opticFlow = drawOpticFlow(prevImage, flow); 00260 // Image< PixRGB<byte> > disp(4*width, height, ZEROS); 00261 // inplacePaste(disp, prevImage, Point2D<int>(0 ,0)); 00262 // inplacePaste(disp, currImage, Point2D<int>(width,0)); 00263 00264 // // compute the focus of expansion (FOE) 00265 // Point2D<int> foe = 00266 // fd->getFoe(flow, FOE_METHOD_AVERAGE, false); 00267 // //fd->getFoe(flow, FOE_METHOD_TEMPLATE); 00268 // float err = foe.distance(gt[frame]); 00269 // totalErr += err; 00270 // LINFO("Foe: %d %d: GT: %d %d --> %f --> avg: %f", 00271 // foe.i, foe.j, gt[frame].i, gt[frame].j, 00272 // err, totalErr/(frame+1)); 00273 00274 00275 // drawCross(opticFlow, foe , PixRGB<byte>(0,255,0), 10, 2); 00276 // //drawCross(opticFlow, gt[frame], PixRGB<byte>(255,0,0), 10, 2); 00277 // Image<float> foem = fd->getFoeMap(); 00278 00279 // inplacePaste(disp, opticFlow, Point2D<int>(width*2,0)); 00280 // inplaceNormalize(foem, 0.0F, 255.0F); 00281 // inplacePaste(disp, toRGB(zoomXY(Image<byte>(foem),MAX_NEIGHBORHOOD)), 00282 // Point2D<int>(width*3,0)); 00283 // ofs->writeRGB(disp, "Optic Flow"); 00284 // const FrameState os = ofs->updateNext(); 00285 00286 // // write the file 00287 // //Image<PixRGB<byte> > simg = prevImage; 00288 // //drawCross(simg, foe , PixRGB<byte>(0,255,0), 10, 2); 00289 // //drawCross(simg, gt[frame], PixRGB<byte>(255,0,0), 10, 2); 00290 // //Raster::WriteRGB(simg, sformat("%s_%06d.ppm", prefix.c_str(), frame)); 00291 00292 // //Raster::waitForKey(); 00293 00294 // if (os == FRAME_FINAL) 00295 // break; 00296 00297 prevImage = currImage; 00298 prevLum = lum; 00299 frame++; 00300 00301 //FILE *fp; 00302 //LINFO("FOE %d %d", foe.i, foe.j); 00303 //if((fp = fopen("LK_CB_Germany.txt","at")) == NULL) LFATAL("not found"); 00304 //fputs(sformat("%d %d \n", foe.i, foe.j).c_str(), fp); 00305 //fclose (fp); 00306 00307 } 00308 00309 //LINFO("%d frames in %gs (%.2ffps)\n", 00310 // frame, timer.getSecs(), frame / timer.getSecs()); 00311 00312 // stop all our ModelComponents 00313 manager.stop(); 00314 00315 // all done! 00316 return 0; 00317 00318 } 00319 00320 // ###################################################################### 00321 std::vector<std::vector<Point2D<int> > > getGTandData() 00322 { 00323 uint nSystems = 3; 00324 std::vector<std::vector<Point2D<int> > > data(nSystems+1); 00325 00326 std::string folder("/lab/tmpib/u/siagian/neuroscience/Data/FOE/"); 00327 00328 // Browning 00329 // std::string gt("driving_nat_Browning_2.txt"); 00330 // std::string f1("DARPA_nv2_2011/Browning_K_CIOFs/ST_PS_Browning.txt"); 00331 // std::string f2("DARPA_nv2_2011/Browning_K_CIOFs/BMG_Browning.txt"); 00332 // std::string f3("DARPA_nv2_2011/Browning_K_CIOFs/LK_CB_Browning.txt"); 00333 00334 // Las Vegas 00335 // std::string gt("driving_nat_2b_1.txt"); 00336 // std::string f1("DARPA_nv2_2011/LasVegas_K_CIOFs/ST_PS_LasVegas.txt"); 00337 // std::string f2("DARPA_nv2_2011/LasVegas_K_CIOFs/BMG_LasVegas.txt"); 00338 // std::string f3("DARPA_nv2_2011/LasVegas_K_CIOFs/LK_CB_LasVegas.txt"); 00339 00340 // Germany 00341 std::string gt("driving_nat_3_1.txt"); 00342 std::string f1("DARPA_nv2_2011/Germany_K_CIOFs/ST_PS_Germany.txt"); 00343 std::string f2("DARPA_nv2_2011/Germany_K_CIOFs/BMG_Germany.txt"); 00344 std::string f3("DARPA_nv2_2011/Germany_K_CIOFs/LK_CB_Germany.txt"); 00345 00346 00347 // get data 00348 data[0] = getGT(folder+gt); 00349 data[1] = getGT(folder+f1); 00350 data[2] = getGT(folder+f2); 00351 data[3] = getGT(folder+f3); 00352 00353 // calculate errors as well 00354 for(uint i = 1; i < nSystems+1; i++) 00355 { 00356 float totalErr = 0.0; 00357 uint totalPt = 0; 00358 for(uint j = 0; j < data[i].size(); j++) 00359 { 00360 // if systems is not ready 00361 // just skip the point 00362 if(data[i][j].i == -1 && data[i][j].j == -1) 00363 continue; 00364 00365 // if point is out of bounds just move it to the closest edge 00366 // also change the data 00367 Point2D<int> newPt = data[i][j]; 00368 if(newPt.i < 0) newPt.i = 0; 00369 if(newPt.i >= 320) newPt.i = 319; 00370 if(newPt.j < 0) newPt.j = 0; 00371 if(newPt.j >= 320) newPt.j = 319; 00372 data[i][j] = newPt; 00373 00374 // compare with ground truth 00375 float err = newPt.distance(data[0][j]); 00376 00377 LDEBUG("[%3d %3d] - [%3d %3d]: %f", 00378 newPt.i, newPt.j, data[0][j].i, data[0][j].j, 00379 err); 00380 00381 totalErr += err; 00382 totalPt++; 00383 } 00384 00385 if(totalPt == 0) LINFO("s[%3d] err: 0/0 = 0", i); 00386 else 00387 LINFO("s[%3d] err: %f/%d = %f", 00388 i, totalErr, totalPt, totalErr/totalPt); 00389 } 00390 return data; 00391 } 00392 00393 // ###################################################################### 00394 std::vector<Point2D<int> > getGT(std::string gtFilename) 00395 { 00396 std::vector<Point2D<int> > gt; 00397 00398 FILE *fp; char inLine[200]; //char comment[200]; 00399 00400 LINFO("ground truth file: %s",gtFilename.c_str()); 00401 if((fp = fopen(gtFilename.c_str(),"rb")) == NULL) 00402 { LINFO("not found"); return gt; } 00403 00404 // populate the trial information 00405 uint nFrames = 0; 00406 while(fgets(inLine, 200, fp) != NULL) 00407 { 00408 int x, y; 00409 sscanf(inLine, "%d %d", &x, &y); 00410 LINFO("[%3d] x: %d y: %d", nFrames, x, y); 00411 gt.push_back(Point2D<int>(x,y)); 00412 00413 nFrames++; 00414 } 00415 Raster::waitForKey(); 00416 return gt; 00417 } 00418 00419 // ###################################################################### 00420 Image<float> getOpticFlow2(Image<float> image1, Image<float> image2) 00421 { 00422 00423 // Load two images and allocate other structures 00424 inplaceNormalize(image1, 0.0F, 255.0F); 00425 Image<byte> img1(image1); 00426 IplImage* imgA = img2ipl(img1); 00427 inplaceNormalize(image2, 0.0F, 255.0F); 00428 Image<byte> img2(image2); 00429 IplImage* imgB = img2ipl(img2); 00430 00431 CvSize img_sz = cvGetSize( imgA ); 00432 int win_size = 15; 00433 00434 IplImage* imgC =img2ipl(img1); 00435 00436 // Get the features for tracking 00437 IplImage* eig_image = cvCreateImage( img_sz, IPL_DEPTH_32F, 1 ); 00438 IplImage* tmp_image = cvCreateImage( img_sz, IPL_DEPTH_32F, 1 ); 00439 00440 int corner_count = MAX_CORNERS; 00441 CvPoint2D32f* cornersA = new CvPoint2D32f[ MAX_CORNERS ]; 00442 00443 cvGoodFeaturesToTrack( imgA, eig_image, tmp_image, 00444 cornersA, &corner_count, 00445 0.05, 5.0, 0, 3, 0, 0.04 ); 00446 00447 00448 cvFindCornerSubPix( imgA, cornersA, corner_count, 00449 cvSize( win_size, win_size ), 00450 cvSize( -1, -1 ), 00451 cvTermCriteria( CV_TERMCRIT_ITER | 00452 CV_TERMCRIT_EPS, 20, 0.03 ) ); 00453 00454 // Call Lucas Kanade algorithm 00455 char features_found[ MAX_CORNERS ]; 00456 float feature_errors[ MAX_CORNERS ]; 00457 00458 CvSize pyr_sz = cvSize( imgA->width+8, imgB->height/3 ); 00459 00460 IplImage* pyrA = cvCreateImage( pyr_sz, IPL_DEPTH_32F, 1 ); 00461 IplImage* pyrB = cvCreateImage( pyr_sz, IPL_DEPTH_32F, 1 ); 00462 00463 CvPoint2D32f* cornersB = new CvPoint2D32f[ MAX_CORNERS ]; 00464 00465 cvCalcOpticalFlowPyrLK( imgA, imgB, pyrA, pyrB, 00466 cornersA, cornersB, corner_count, 00467 cvSize( win_size, win_size ), 5, 00468 features_found, feature_errors, 00469 cvTermCriteria( CV_TERMCRIT_ITER | 00470 CV_TERMCRIT_EPS, 20, 0.3 ), 0 ); 00471 00472 // Make an image of the results 00473 00474 for( int i=0; i < MAX_CORNERS; i++ ) 00475 { 00476 LINFO("Error is %f/n", feature_errors[i]); 00477 //continue; 00478 00479 //printf("Got it/n"); 00480 CvPoint p0 = cvPoint( cvRound( cornersA[i].x ), 00481 cvRound( cornersA[i].y ) ); 00482 CvPoint p1 = cvPoint( cvRound( cornersB[i].x ), 00483 cvRound( cornersB[i].y ) ); 00484 cvLine( imgC, p0, p1, CV_RGB(255,0,0), 2 ); 00485 } 00486 00487 return ipl2gray(imgC); 00488 } 00489 00490 // ###################################################################### 00491 Image<byte> calculateShift(Image<byte> prevLum, Image<byte> lum, 00492 nub::ref<OutputFrameSeries> ofs) 00493 { 00494 VisualObjectMatchAlgo voma(VOMA_SIMPLE); 00495 // if (strcmp(argv[1], "KDTree") == 0) voma = VOMA_KDTREE; 00496 // else if (strcmp(argv[1], "KDBBF") == 0) voma = VOMA_KDTREEBBF; 00497 // else if (strcmp(argv[1], "Simple") != 0) 00498 // LFATAL("Unknown matching method %s", argv[0]); 00499 00500 // create visual objects: 00501 rutz::shared_ptr<VisualObject> vo1(new VisualObject("plum", "", prevLum)); 00502 rutz::shared_ptr<VisualObject> vo2(new VisualObject("lum" , "", lum)); 00503 00504 // compute the matching keypoints: 00505 VisualObjectMatch match(vo1, vo2, voma); 00506 LDEBUG("Found %u matches", match.size()); 00507 00508 // let's prune the matches: 00509 uint np = match.prune(); 00510 LDEBUG("Pruned %u outlier matches.", np); 00511 00512 // show our final affine transform: 00513 SIFTaffine s = match.getSIFTaffine(); 00514 LDEBUG("[tstX] [ %- .3f %- .3f ] [refX] [%- .3f]", s.m1, s.m2, s.tx); 00515 LDEBUG("[tstY] = [ %- .3f %- .3f ] [refY] + [%- .3f]", s.m3, s.m4, s.ty); 00516 00517 00518 LDEBUG("getKeypointAvgDist = %f", match.getKeypointAvgDist()); 00519 LDEBUG("getAffineAvgDist = %f", match.getAffineAvgDist()); 00520 LDEBUG("getScore = %f", match.getScore()); 00521 00522 if (match.checkSIFTaffine() == false) 00523 LINFO("### Affine is too weird -- BOGUS MATCH"); 00524 00525 // get an image showing the matches: 00526 Image< PixRGB<byte> > mimg = match.getMatchImage(1.0F); 00527 Image< PixRGB<byte> > fimg = match.getFusedImage(0.25F); 00528 00529 // LINFO("prevLum"); 00530 // ofs->writeRGB 00531 // (toRGB(prevLum), "test-FOE Main", FrameInfo("foe output", SRC_POS)); 00532 // Raster::waitForKey(); 00533 00534 // LINFO("lum"); 00535 // ofs->writeRGB 00536 // (toRGB(lum), "test-FOE Main", FrameInfo("foe output", SRC_POS)); 00537 // Raster::waitForKey(); 00538 00539 LINFO("Shift: %f %f", s.tx, s.ty); 00540 // ofs->writeRGB 00541 // (fimg, "test-FOE Main", FrameInfo("foe output", SRC_POS)); 00542 // Raster::waitForKey(); 00543 00544 Image<byte> res = shiftImage(s, prevLum, lum); 00545 00546 // LINFO("shifted result"); 00547 // ofs->writeRGB 00548 // (toRGB(res), "test-FOE Main", FrameInfo("foe output", SRC_POS)); 00549 // Raster::waitForKey(); 00550 00551 //Point2D<float> shift(s.tx,s.ty); 00552 return res; 00553 } 00554 00555 // ###################################################################### 00556 Image<byte> shiftImage(SIFTaffine aff, Image<byte> refi, Image<byte> tsti) 00557 { 00558 // we loop over all pixel locations in the ref image, transform the 00559 // coordinates using the forward affine transform, get the pixel 00560 // value in the test image, and mix: 00561 00562 uint w = refi.getWidth(), h = refi.getHeight(); 00563 Image<byte> result(w, h, ZEROS); 00564 Image<byte>::const_iterator rptr = refi.begin(); 00565 Image<byte>::iterator dptr = result.beginw(); 00566 00567 for (uint j = 0; j < h; j ++) 00568 for (uint i = 0; i < w; i ++) 00569 { 00570 float u, v; 00571 aff.transform(float(i), float(j), u, v); 00572 byte rval = *rptr++; 00573 00574 if (tsti.coordsOk(u, v)) 00575 { 00576 byte tval = tsti.getValInterp(u, v); 00577 //PixRGB<byte> mval = PixRGB<byte>(rval * mix + tval * (1.0F - mix)); 00578 *dptr++ = tval; 00579 } 00580 else 00581 //*dptr++ = PixRGB<byte>(rval * mix); 00582 *dptr++ = byte(rval); 00583 } 00584 00585 return result; 00586 } 00587 00588 // ###################################################################### 00589 /* So things look consistent in everyone's emacs... */ 00590 /* Local Variables: */ 00591 /* indent-tabs-mode: nil */ 00592 /* End: */