00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 #include "Neuro/GistEstimatorStd.H"
00042 #include "Component/ModelManager.H"
00043 #include "Channels/ChannelMaps.H"
00044
00045
00046
00047
00048
00049
00050 #include "GUI/XWinManaged.H"
00051 #include "Image/CutPaste.H"
00052 #include "Image/DrawOps.H"
00053 #include "Image/FilterOps.H"
00054 #include "Image/MathOps.H"
00055 #include "Image/ShapeOps.H"
00056 #include "Neuro/gistParams.H"
00057 #include "Raster/Raster.H"
00058
00059 #include "Simulation/SimEventQueue.H"
00060 #include "Neuro/NeuroSimEvents.H"
00061 #include "Simulation/SimEvents.H"
00062 #include "Channels/ChannelOpts.H"
00063 #include "Channels/SingleChannel.H"
00064
00065 #include "Util/Timer.H"
00066 #include "Util/StringUtil.H"
00067
00068
00069
00070 Image<double> getSubSum(Image<float> img)
00071 {
00072 Image<float> res(1, 21, ZEROS);
00073
00074 int w = img.getWidth(); int h = img.getHeight();
00075 std::vector<float> tempRes(21);
00076
00077 for (int i = 0; i < 21; i++) tempRes[i] = 0.0;
00078 std::vector<int> counts(16);
00079 for (int i = 0 ; i < 16; i++) counts[i] = 0;
00080
00081 Image<float>::const_iterator itr = img.begin();
00082 for (int y = 0; y < h; ++y)
00083 {
00084 int suby = (4*y)/h;
00085 for (int x = 0; x < w; ++x)
00086 {
00087 int subx = (4*x)/w;
00088 int subpos = 4*suby + subx;
00089 tempRes[subpos+5] += *itr;
00090
00091 ++(counts[subpos]);
00092 ++itr;
00093 }
00094 }
00095
00096 int order[] = { 5,6,9,10, 7,8,11,12, 13,14,17,18, 15,16,19,20 };
00097 for (int i = 0 ; i < 16; ++i)
00098 if (counts[i] > 0)
00099 res[i+5] = tempRes[order[i]] / (counts[order[i] - 5]+ 0.0);
00100
00101 float tre1 = tempRes[5] + tempRes[6] + tempRes[9] + tempRes[10];
00102 int ct1 = counts[0] + counts[1] + counts[4] + counts[5];
00103
00104 float tre2 = tempRes[7] + tempRes[8] + tempRes[11] + tempRes[12];
00105 int ct2 = counts[2] + counts[3] + counts[6] + counts[7];
00106
00107 float tre3 = tempRes[13] + tempRes[14] + tempRes[17] + tempRes[18];
00108 int ct3 = counts[8] + counts[9] + counts[12] + counts[13];
00109
00110 float tre4 = tempRes[15] + tempRes[16] + tempRes[19] + tempRes[20];
00111 int ct4 = counts[10] + counts[11] + counts[14] + counts[15];
00112
00113 res[1] = tre1/ct1;
00114 res[2] = tre2/ct2;
00115 res[3] = tre3/ct3;
00116 res[4] = tre4/ct4;
00117
00118 res[0] = (tre1 + tre2 + tre3 + tre4)/(ct1 + ct2 + ct3 + ct4);
00119
00120 LDEBUG("lev1 : %14.4f", res[0]);
00121 LDEBUG("lev2 : %14.4f, %14.4f", res[1], res[2]);
00122 LDEBUG(" : %14.4f, %14.4f", res[3], res[4]);
00123 LDEBUG("lev3 : %14.4f, %14.4f, %14.4f, %14.4f",
00124 res[ 5], res[ 6], res[ 9], res[10]);
00125 LDEBUG(" : %14.4f, %14.4f, %14.4f, %14.4f",
00126 res[ 7], res[ 8], res[11], res[12]);
00127 LDEBUG(" : %14.4f, %14.4f, %14.4f, %14.4f",
00128 res[13], res[14], res[17], res[18]);
00129 LDEBUG(" : %14.4f, %14.4f, %14.4f, %14.4f",
00130 res[15], res[16], res[19], res[20]);
00131
00132 return res;
00133 }
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267 double getMeanPoly(Image<float> img, std::vector<Point2D<int> > polygon)
00268 {
00269 double res;
00270 double sum = 0;
00271 int countP = 0;
00272
00273 Point2D<int> P;
00274 for (int i = 0; i < img.getWidth(); i++)
00275 {
00276 for (int j = 0; j < img.getHeight(); j++)
00277 {
00278 P = Point2D<int> (i,j);
00279 if (pnpoly(polygon,P))
00280 {
00281 sum = sum + img.getVal(P);
00282 countP ++;
00283 }
00284 }
00285 }
00286
00287 res = sum/countP;
00288 return res;
00289 }
00290
00291
00292
00293
00294 RawGistEstimatorStd::RawGistEstimatorStd(OptionManager& mgr,
00295 const std::string& descrName,
00296 const std::string& tagName) :
00297 ModelComponent(mgr, descrName, tagName)
00298 {
00299 itsGistVector.resize(1,NUM_GIST_FEAT * NUM_GIST_CHAN, NO_INIT);
00300 }
00301
00302
00303 RawGistEstimatorStd::~RawGistEstimatorStd()
00304 { }
00305
00306
00307 Image<float> RawGistEstimatorStd::compute(rutz::shared_ptr<ChannelMaps> chmp)
00308 {
00309 computeFeatureVector(chmp);
00310 return itsGistVector;
00311 }
00312
00313
00314 std::vector<float> RawGistEstimatorStd::computeOnPolygon(rutz::shared_ptr<ChannelMaps> chanMaps, std::vector<Point2D<float> > polygonFS)
00315 {
00316
00317 std::vector<float> gistPolyVector;
00318
00319
00320 std::vector<Point2D<int> > polygon(polygonFS.size());
00321 Point2D<int> Ppoly;
00322 for(uint k=0; k<polygonFS.size(); k++)
00323 {
00324 Ppoly.i = (int) floor(polygonFS[k].i/16);
00325 Ppoly.j = (int) floor(polygonFS[k].j/16);
00326 polygon[k] = Ppoly;
00327 }
00328
00329 double areaPoly = area(polygon);
00330 if (areaPoly<=0)
00331 {
00332 LINFO("The given polygon is too small for the gist computation!");
00333
00334 int minx, miny, maxx, maxy;
00335 minx = miny =100000000;
00336 maxx = maxy =-100000000;
00337 for (uint k=0; k<polygonFS.size(); k++)
00338 {
00339 if(minx > (int) polygonFS[k].i) minx = (int) polygonFS[k].i;
00340 if(miny > (int) polygonFS[k].j) miny = (int) polygonFS[k].j;
00341 if(maxx < (int) polygonFS[k].i) maxx = (int) polygonFS[k].i;
00342 if(maxy < (int) polygonFS[k].j) maxy = (int) polygonFS[k].j;
00343 }
00344 int minxR, minyR, maxxR, maxyR;
00345 minxR = floor(minx/16.0);
00346 minyR = floor(miny/16.0);
00347 maxxR = ceil(maxx/16.0);
00348 maxyR = ceil(maxy/16.0);
00349
00350 polygon.clear();
00351 polygon.resize(4);
00352 polygon[0] = Point2D<int> (minxR, minyR);
00353 polygon[1] = Point2D<int> (maxxR, minyR);
00354 polygon[2] = Point2D<int> (maxxR, maxyR);
00355 polygon[3] = Point2D<int> (minxR, maxyR);
00356 }
00357
00358 rutz::shared_ptr<ChannelMaps> orientationMaps;
00359 rutz::shared_ptr<ChannelMaps> colorMaps;
00360 rutz::shared_ptr<ChannelMaps> intensityMaps;
00361
00362 for(uint i=0; i < chanMaps->numSubchans(); i++)
00363 {
00364
00365 rutz::shared_ptr<ChannelMaps> currChan = chanMaps->subChanMaps(i);
00366
00367
00368 std::vector<std::string> chanNameVec;
00369 split(currChan->getMap().name(), ":", std::back_inserter(chanNameVec));
00370 std::string chanName = chanNameVec[1];
00371
00372
00373 if(chanName == "orientation")
00374 orientationMaps = currChan;
00375 else if(chanName == "color")
00376 colorMaps = currChan;
00377 else if(chanName == "intensity")
00378 intensityMaps = currChan;
00379 }
00380
00381 LDEBUG("Orientation Subchans: %d", orientationMaps->numSubchans());
00382 LDEBUG("Color Subchans: %d", colorMaps->numSubchans());
00383 LDEBUG("Intensity Subchans: %d", intensityMaps->numSubchans());
00384
00385
00386
00387 ASSERT(orientationMaps->numSubchans() == 4);
00388 ASSERT(colorMaps->numSubchans() == 2);
00389 ASSERT(intensityMaps->numSubchans() == 0);
00390
00391
00392 rutz::shared_ptr<ChannelMaps> orientation_0 = orientationMaps->subChanMaps(0);
00393 rutz::shared_ptr<ChannelMaps> orientation_45 = orientationMaps->subChanMaps(1);
00394 rutz::shared_ptr<ChannelMaps> orientation_90 = orientationMaps->subChanMaps(2);
00395 rutz::shared_ptr<ChannelMaps> orientation_135 = orientationMaps->subChanMaps(3);
00396
00397
00398 rutz::shared_ptr<ChannelMaps> rg;
00399 rutz::shared_ptr<ChannelMaps> by;
00400 for(uint i=0; i<colorMaps->numSubchans(); i++)
00401 {
00402 std::vector<std::string> chanNameVec;
00403 split(colorMaps->subChanMaps(i)->getMap().name(), ":", std::back_inserter(chanNameVec));
00404 std::string chanName = chanNameVec[2];
00405
00406 if(chanName == "rg")
00407 rg = colorMaps->subChanMaps(i);
00408 else if(chanName == "by")
00409 by = colorMaps->subChanMaps(i);
00410 }
00411
00412 ASSERT(rg.is_valid());
00413 ASSERT(by.is_valid());
00414
00415
00416
00417
00418 int count = 0;
00419 for(int i = 0; i < NUM_GIST_LEV; i++)
00420 {
00421 float meanPoly = getMeanPoly(orientation_0->getSubmap(i), polygon);
00422 gistPolyVector.push_back(meanPoly);
00423 count += 1;
00424 }
00425
00426 for(int i = 0; i < NUM_GIST_LEV; i++)
00427 {
00428 float meanPoly = getMeanPoly(orientation_45->getSubmap(i), polygon);
00429 gistPolyVector.push_back(meanPoly);
00430 count += 1;;
00431 }
00432
00433 for(int i = 0; i < NUM_GIST_LEV; i++)
00434 {
00435 float meanPoly = getMeanPoly(orientation_90->getSubmap(i), polygon);
00436 gistPolyVector.push_back(meanPoly);
00437 count += 1;
00438 }
00439
00440 for(int i = 0; i < NUM_GIST_LEV; i++)
00441 {
00442 float meanPoly = getMeanPoly(orientation_135->getSubmap(i), polygon);
00443 gistPolyVector.push_back(meanPoly);
00444 count += 1;
00445 }
00446
00447
00448
00449
00450
00451
00452
00453 for(uint i=0; i<rg->numSubmaps(); i++)
00454 {
00455 float meanPoly = getMeanPoly(rg->getSubmap(i), polygon);
00456 gistPolyVector.push_back(meanPoly);
00457 count += 1;
00458 }
00459
00460 for(uint i=0; i<by->numSubmaps(); i++)
00461 {
00462 float meanPoly = getMeanPoly(by->getSubmap(i), polygon);
00463 gistPolyVector.push_back(meanPoly);
00464 count += 1;
00465 }
00466
00467 for(uint i=0; i<intensityMaps->numSubmaps(); i++)
00468 {
00469 float meanPoly = getMeanPoly(intensityMaps->getSubmap(i), polygon);
00470 gistPolyVector.push_back(meanPoly);
00471 count += 1;
00472 }
00473
00474 return gistPolyVector;
00475 }
00476
00477
00478 void RawGistEstimatorStd::computeFeatureVector(rutz::shared_ptr<ChannelMaps> chanMaps)
00479 {
00480 rutz::shared_ptr<ChannelMaps> orientationMaps;
00481 rutz::shared_ptr<ChannelMaps> colorMaps;
00482 rutz::shared_ptr<ChannelMaps> intensityMaps;
00483
00484 for(uint i=0; i < chanMaps->numSubchans(); i++)
00485 {
00486
00487 rutz::shared_ptr<ChannelMaps> currChan = chanMaps->subChanMaps(i);
00488
00489
00490 std::vector<std::string> chanNameVec;
00491 split(currChan->getMap().name(), ":", std::back_inserter(chanNameVec));
00492 std::string chanName = chanNameVec[1];
00493
00494
00495 if(chanName == "orientation")
00496 orientationMaps = currChan;
00497 else if(chanName == "color")
00498 colorMaps = currChan;
00499 else if(chanName == "intensity")
00500 intensityMaps = currChan;
00501 }
00502
00503 LDEBUG("Orientation Subchans: %d", orientationMaps->numSubchans());
00504 LDEBUG("Color Subchans: %d", colorMaps->numSubchans());
00505 LDEBUG("Intensity Subchans: %d", intensityMaps->numSubchans());
00506
00507 LINFO("Orientation Subchans: %d", orientationMaps->numSubchans());
00508 LINFO("Color Subchans: %d", colorMaps->numSubchans());
00509 LINFO("Intensity Subchans: %d", intensityMaps->numSubchans());
00510
00511
00512
00513 ASSERT(orientationMaps->numSubchans() == 4);
00514 ASSERT(colorMaps->numSubchans() == 2);
00515 ASSERT(intensityMaps->numSubchans() == 0);
00516
00517
00518 rutz::shared_ptr<ChannelMaps> orientation_0 = orientationMaps->subChanMaps(0);
00519 rutz::shared_ptr<ChannelMaps> orientation_45 = orientationMaps->subChanMaps(1);
00520 rutz::shared_ptr<ChannelMaps> orientation_90 = orientationMaps->subChanMaps(2);
00521 rutz::shared_ptr<ChannelMaps> orientation_135 = orientationMaps->subChanMaps(3);
00522
00523
00524 rutz::shared_ptr<ChannelMaps> rg;
00525 rutz::shared_ptr<ChannelMaps> by;
00526 for(uint i=0; i<colorMaps->numSubchans(); i++)
00527 {
00528 std::vector<std::string> chanNameVec;
00529 split(colorMaps->subChanMaps(i)->getMap().name(), ":", std::back_inserter(chanNameVec));
00530 std::string chanName = chanNameVec[2];
00531
00532 if(chanName == "rg")
00533 rg = colorMaps->subChanMaps(i);
00534 else if(chanName == "by")
00535 by = colorMaps->subChanMaps(i);
00536 }
00537
00538 ASSERT(rg.is_valid());
00539 ASSERT(by.is_valid());
00540
00541
00542
00543 int count = 0;
00544 for(int i = 0; i < NUM_GIST_LEV; i++)
00545 {
00546 Image<float> subSum = getSubSum(orientation_0->getSubmap(i));
00547 inplacePaste(itsGistVector, subSum,
00548 Point2D<int>(0, count));
00549 count += subSum.getHeight();
00550 }
00551
00552
00553 for(int i = 0; i < NUM_GIST_LEV; i++)
00554 {
00555 Image<float> subSum = getSubSum(orientation_45->getSubmap(i));
00556 inplacePaste(itsGistVector, subSum,
00557 Point2D<int>(0, count));
00558 count += subSum.getHeight();
00559 }
00560
00561
00562 for(int i = 0; i < NUM_GIST_LEV; i++)
00563 {
00564 Image<float> subSum = getSubSum(orientation_90->getSubmap(i));
00565 inplacePaste(itsGistVector, subSum,
00566 Point2D<int>(0, count));
00567 count += subSum.getHeight();
00568 }
00569
00570
00571 for(int i = 0; i < NUM_GIST_LEV; i++)
00572 {
00573 Image<float> subSum = getSubSum(orientation_135->getSubmap(i));
00574 inplacePaste(itsGistVector, subSum,
00575 Point2D<int>(0, count));
00576 count += subSum.getHeight();
00577 }
00578
00579
00580
00581
00582
00583
00584
00585 for(uint i=0; i<rg->numSubmaps(); i++)
00586 {
00587 Image<float> subSum = getSubSum(rg->getSubmap(i));
00588 inplacePaste(itsGistVector, subSum,
00589 Point2D<int>(0, count));
00590 count += subSum.getHeight();
00591 }
00592
00593
00594 for(uint i=0; i<by->numSubmaps(); i++)
00595 {
00596 Image<float> subSum = getSubSum(by->getSubmap(i));
00597 inplacePaste(itsGistVector, subSum,
00598 Point2D<int>(0, count));
00599 count += subSum.getHeight();
00600 }
00601
00602
00603
00604 for(uint i=0; i<intensityMaps->numSubmaps(); i++)
00605 {
00606 Image<float> subSum = getSubSum(intensityMaps->getSubmap(i));
00607 inplacePaste(itsGistVector, subSum,
00608 Point2D<int>(0, count));
00609 count += subSum.getHeight();
00610 }
00611 }
00612
00613
00614
00615 Image<float> RawGistEstimatorStd::getGistImage(int sqSize,
00616 float minO, float maxO,
00617 float minC, float maxC,
00618 float minI, float maxI)
00619 {
00620
00621 int s = sqSize;
00622 Image<float> img(NUM_GIST_COL * s, NUM_GIST_FEAT * s, ZEROS);
00623 float range;
00624
00625
00626 if(maxO == minO)
00627 {
00628 minO = itsGistVector.getVal(0);
00629 maxO = itsGistVector.getVal(0);
00630 for(int i = 0; i < 16; i++)
00631 for(int j = 0; j < NUM_GIST_FEAT; j++)
00632 {
00633 float val = itsGistVector.getVal(i*NUM_GIST_FEAT+j);
00634 if(val < minO)
00635 minO = val;
00636 else if(val > maxO)
00637 maxO = val;
00638 }
00639 LDEBUG("Orientation Channel Min: %f, max: %f", minO, maxO);
00640 }
00641 range = maxO - minO;
00642
00643
00644 for(int a = 0; a < 4; a++)
00645 for(int b = 0; b < 4; b++)
00646 for(int j = 0; j < NUM_GIST_FEAT; j++)
00647 {
00648 int i = b*4 + a;
00649 int ii = a*4 + b;
00650 float val = itsGistVector.getVal(ii*NUM_GIST_FEAT+j);
00651 drawPatch(img, Point2D<int>(i*s+s/2,j*s+s/2),s/2,(val-minO)/range);
00652 }
00653
00654
00655 if(maxC == minC)
00656 {
00657 minC = itsGistVector.getVal(16*NUM_GIST_FEAT);
00658 maxC = itsGistVector.getVal(16*NUM_GIST_FEAT);
00659 for(int i = 16; i < 28; i++)
00660 for(int j = 0; j < NUM_GIST_FEAT; j++)
00661 {
00662 float val = itsGistVector.getVal(i*NUM_GIST_FEAT+j);
00663 if(val < minC)
00664 minC = val;
00665 else if(val > maxC)
00666 maxC = val;
00667 }
00668 LDEBUG("Color Channel Min: %f, max: %f", minC, maxC);
00669 }
00670 range = maxC - minC;
00671
00672
00673 for(int i = 16; i < 28; i++)
00674 for(int j = 0; j < NUM_GIST_FEAT; j++)
00675 {
00676 float val = itsGistVector.getVal(i*NUM_GIST_FEAT+j);
00677 drawPatch(img, Point2D<int>(i*s+s/2,j*s+s/2),s/2,(val-minC)/range);
00678 }
00679
00680
00681 if(maxI == minI)
00682 {
00683 minI = itsGistVector.getVal(28*NUM_GIST_FEAT);
00684 maxI = itsGistVector.getVal(28*NUM_GIST_FEAT);
00685 for(int i = 28; i < 34; i++)
00686 for(int j = 0; j < NUM_GIST_FEAT; j++)
00687 {
00688 float val = itsGistVector.getVal(i*NUM_GIST_FEAT+j);
00689 if(val < minI)
00690 minI = val;
00691 else if(val > maxI)
00692 maxI = val;
00693 }
00694 LDEBUG("Intensity Channel Min: %f, max: %f", minI, maxI);
00695 }
00696 range = maxI - minI;
00697
00698
00699 for(int i = 28; i < NUM_GIST_COL; i++)
00700 for(int j = 0; j < NUM_GIST_FEAT; j++)
00701 {
00702 float val = itsGistVector.getVal(i*NUM_GIST_FEAT+j);
00703 drawPatch(img, Point2D<int>(i*s+s/2,j*s+s/2),s/2,(val-minI)/range);
00704 }
00705
00706
00707
00708 float max = 1.0f;
00709 drawLine(img, Point2D<int>(0, 1*s), Point2D<int>(NUM_GIST_COL*s, 1*s), max, 1);
00710 drawLine(img, Point2D<int>(0, 5*s), Point2D<int>(NUM_GIST_COL*s, 5*s), max, 1);
00711 drawLine(img, Point2D<int>(0, 9*s), Point2D<int>(NUM_GIST_COL*s, 9*s), max/2, 1);
00712 drawLine(img, Point2D<int>(0, 13*s), Point2D<int>(NUM_GIST_COL*s, 13*s), max/2, 1);
00713 drawLine(img, Point2D<int>(0, 17*s), Point2D<int>(NUM_GIST_COL*s, 17*s), max/2, 1);
00714
00715
00716 drawLine(img, Point2D<int>( 4*s, 0), Point2D<int>( 4*s, NUM_GIST_FEAT*s), max, 1);
00717 drawLine(img, Point2D<int>( 8*s, 0), Point2D<int>( 8*s, NUM_GIST_FEAT*s), max, 1);
00718 drawLine(img, Point2D<int>(12*s, 0), Point2D<int>(12*s, NUM_GIST_FEAT*s), max, 1);
00719 drawLine(img, Point2D<int>(16*s, 0), Point2D<int>(16*s, NUM_GIST_FEAT*s), max, 1);
00720 drawLine(img, Point2D<int>(22*s, 0), Point2D<int>(22*s, NUM_GIST_FEAT*s), max, 1);
00721 drawLine(img, Point2D<int>(28*s, 0), Point2D<int>(28*s, NUM_GIST_FEAT*s), max, 1);
00722
00723 return img;
00724 }
00725
00726
00727
00728 Image<double> RawGistEstimatorStd::diffGist(Image<double> in)
00729 {
00730 LFATAL("fix");
00731 double total = 0.0;
00732 double a,b,c,d;
00733
00734 for(int i = 0; i < NUM_GIST_COL; i++)
00735 {
00736 for(int j = 0; j < NUM_GIST_FEAT; j++)
00737 {
00738 a = itsGistVector.getVal(i*NUM_GIST_FEAT +j) /
00739 itsGistVector.getVal(i*NUM_GIST_FEAT);
00740 b = in.getVal(i*NUM_GIST_FEAT +j) / in.getVal(i*NUM_GIST_FEAT);
00741 c = itsGistVector.getVal(i*NUM_GIST_FEAT) +
00742 in.getVal(i*NUM_GIST_FEAT);
00743 d = (a - b) * c/2;
00744 LINFO("%6.3f - %6.3f = %f",a,b,fabs(d));
00745
00746 if((j-5)%4 == 3) LINFO("-:-:-");
00747 total += sqrt((d*d));
00748 }
00749 LINFO(" ");
00750 }
00751 LINFO("Diff = %f -> %f\n",total,total/NUM_GIST_COL/NUM_GIST_FEAT);
00752 Raster::waitForKey();
00753
00754 return Image<double>();
00755 }
00756
00757
00758
00759
00760
00761