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 #include "Channels/ChannelBase.H"
00040 #include "Channels/ChannelOpts.H"
00041 #include "Channels/ContourChannel.H"
00042 #include "Component/ModelManager.H"
00043 #include "Image/CutPaste.H"
00044 #include "Image/Image.H"
00045 #include "Image/MathOps.H"
00046 #include "Media/FrameSeries.H"
00047 #include "Raster/Raster.H"
00048 #include "Util/Assert.H"
00049 #include "Util/CpuTimer.H"
00050 #include "Util/SimTime.H"
00051 #include "Util/log.H"
00052 #include "rutz/compat_snprintf.h"
00053 #include "rutz/shared_ptr.h"
00054
00055 #include <exception>
00056 #include <iostream>
00057
00058 #ifdef HAVE_FENV_H
00059 #include <fenv.h>
00060 #endif
00061
00062 namespace
00063 {
00064
00065 double OVERLAP_FRACTION = 0.2;
00066
00067
00068
00069 int SPLIT_SIZE = 1400000;
00070
00071 int NEST_DEPTH = 0;
00072
00073
00074 Image<float> processWholeImage(const Image<byte>& img,
00075 ModelManager& manager,
00076 const std::string& saveprefix,
00077 int& pixused,
00078 nub::ref<FrameOstream> ofs);
00079
00080 Image<float> processSplitImage(const Image<byte>& img,
00081 ModelManager& manager,
00082 const std::string& saveprefix,
00083 int& pixused,
00084 nub::ref<FrameOstream> ofs);
00085
00086
00087 Image<float> processImage(const Image<byte>& img,
00088 ModelManager& manager,
00089 const std::string& saveprefix,
00090 int& pixused,
00091 nub::ref<FrameOstream> ofs)
00092 {
00093 Image<float> output;
00094
00095 if (img.getSize() > abs(SPLIT_SIZE))
00096 {
00097 LINFO("%*sin PARTS (%s, w x h = %d x %d = %d)",
00098 NEST_DEPTH*4, "",
00099 saveprefix.c_str(), img.getWidth(), img.getHeight(),
00100 img.getSize());
00101
00102 ++NEST_DEPTH;
00103
00104 output = processSplitImage(img, manager, saveprefix,
00105 pixused, ofs);
00106
00107 LINFO("%*seffective tiling ratio: %d/%d = %.4f",
00108 NEST_DEPTH*4, "",
00109 pixused, img.getSize(),
00110 double(pixused) / double(img.getSize()));
00111
00112 --NEST_DEPTH;
00113 }
00114 else
00115 {
00116 LINFO("%*sin whole (%s, w x h = %d x %d = %d)",
00117 NEST_DEPTH*4, "",
00118 saveprefix.c_str(), img.getWidth(), img.getHeight(),
00119 img.getSize());
00120 output = processWholeImage(img, manager, saveprefix,
00121 pixused, ofs);
00122 }
00123
00124 ASSERT(output.initialized());
00125
00126 return output;
00127 }
00128
00129
00130 Image<float> processWholeImage(const Image<byte>& img,
00131 ModelManager& manager,
00132 const std::string& saveprefix,
00133 int& pixused,
00134 nub::ref<FrameOstream> ofs)
00135 {
00136 pixused = img.getSize();
00137
00138 if (SPLIT_SIZE > 0)
00139 {
00140 nub::ref<ChannelBase> contourChan =
00141 makeContourChannel(manager, saveprefix);
00142
00143 manager.addSubComponent(contourChan);
00144 contourChan->exportOptions(MC_RECURSE);
00145
00146 contourChan->start();
00147
00148 const Image<float> gray(img);
00149 contourChan->input(InputFrame::fromGrayFloat(&gray, SimTime::ZERO()));
00150
00151 const Image<float> result = contourChan->getOutput();
00152
00153 contourChan->saveResults(ofs);
00154
00155 contourChan->stop();
00156 manager.removeSubComponent(*contourChan);
00157
00158 return result;
00159 }
00160 else
00161 {
00162 return Image<float>(img);
00163 }
00164 }
00165
00166 Image<float> processSplitImage(const Image<byte>& input,
00167 ModelManager& manager,
00168 const std::string& saveprefix,
00169 int& pixused,
00170 nub::ref<FrameOstream> ofs)
00171 {
00172
00173 const int w = input.getWidth();
00174 const int h = input.getHeight();
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 const int wm = w/2;
00217 const int hm = h/2;
00218
00219 ASSERT(OVERLAP_FRACTION >= 0.0);
00220 ASSERT(OVERLAP_FRACTION <= 1.0);
00221
00222 const int wtile = int(w*(0.5+0.5*OVERLAP_FRACTION));
00223 const int htile = int(h*(0.5+0.5*OVERLAP_FRACTION));
00224
00225 LINFO("%*stile area is %dx%d",
00226 NEST_DEPTH*4, "", wtile, htile);
00227
00228 const int w1 = w - wtile;
00229 const int w2 = 0 + wtile - 1;
00230
00231 const int h1 = h - htile;
00232 const int h2 = 0 + htile - 1;
00233
00234 const Rectangle input_rect[4] = {
00235 Rectangle::tlbrI (0, 0, h2, w2),
00236 Rectangle::tlbrI (0, w1, h2, w-1 ),
00237 Rectangle::tlbrI (h1, 0, h-1, w2),
00238 Rectangle::tlbrI (h1, w1, h-1, w-1 )
00239 };
00240
00241 for (size_t i = 0; i < 4; ++i)
00242 {
00243 LDEBUG("input_rect[%"ZU"].dims() = %dx%d",
00244 i, input_rect[i].dims().w(), input_rect[i].dims().h());
00245 ASSERT(input.rectangleOk(input_rect[i]));
00246 ASSERT(input_rect[i].dims() == Dims(wtile, htile));
00247 }
00248
00249 const Rectangle subcrop_rect[4] = {
00250 Rectangle (Point2D<int>(0, 0), Dims(wm, hm) ),
00251 Rectangle (Point2D<int>(wm-w1, 0), Dims(w-wm, hm) ),
00252 Rectangle (Point2D<int>(0, hm-h1), Dims(wm, h-hm) ),
00253 Rectangle (Point2D<int>(wm-w1, hm-h1), Dims(w-wm, h-hm) ),
00254 };
00255
00256 const Point2D<int> subcrop_paste_pt[4] = {
00257 Point2D<int>(0, 0 ),
00258 Point2D<int>(wm, 0 ),
00259 Point2D<int>(0, hm),
00260 Point2D<int>(wm, hm)
00261 };
00262
00263 Image<float> output(input.getDims(), NO_INIT);
00264
00265
00266
00267
00268
00269 Image<byte> reconstruct_input(input.getDims(), ZEROS);
00270
00271 pixused = 0;
00272
00273
00274 for (int i = 0; i < 4; ++i)
00275 {
00276 const Image<byte> subinput =
00277 crop(input,
00278 input_rect[i].topLeft(),
00279 input_rect[i].dims());
00280
00281 const std::string subprefix =
00282 sformat("%s-sub%d", saveprefix.c_str(), i);
00283
00284 int subpix = 0;
00285
00286 const Image<float> suboutput =
00287 processImage(subinput, manager, subprefix, subpix, ofs);
00288
00289 if (suboutput.getDims() != subinput.getDims())
00290 LFATAL("Oops! In order to handle a subdivided image, the "
00291 "contour channel must give output the same size as "
00292 "its input (%dx%d), but the actual output was %dx%d. "
00293 "Make sure that the --levelspec option includes a "
00294 "map level of 0 (e.g., --levelspec=2,4,3,4,0); its "
00295 "current value is --levelspec=%s.",
00296 subinput.getWidth(), subinput.getHeight(),
00297 suboutput.getWidth(), suboutput.getHeight(),
00298 manager.getOptionValString(&OPT_LevelSpec).c_str());
00299
00300 pixused += subpix;
00301
00302 const Image<float> subsuboutput =
00303 crop(suboutput,
00304 subcrop_rect[i].topLeft(),
00305 subcrop_rect[i].dims());
00306
00307 const Image<float> subsubinput =
00308 crop(subinput,
00309 subcrop_rect[i].topLeft(),
00310 subcrop_rect[i].dims());
00311
00312 inplacePaste(output, subsuboutput, subcrop_paste_pt[i]);
00313 inplacePaste(reconstruct_input, Image<byte>(subsubinput),
00314 subcrop_paste_pt[i]);
00315 }
00316
00317 if (!(reconstruct_input == input))
00318 {
00319 LFATAL("crop/paste error: reconstructed input differs from original input");
00320 }
00321
00322 return output;
00323 }
00324 }
00325
00326 int main(int argc, char* argv[])
00327 {
00328 try
00329 {
00330 ModelManager manager("Contour");
00331
00332 nub::ref<OutputFrameSeries> ofs(new OutputFrameSeries(manager));
00333 manager.addSubComponent(ofs);
00334
00335
00336
00337 nub::ref<ChannelBase> dummyContourChannel =
00338 makeContourChannel(manager);
00339 manager.addSubComponent(dummyContourChannel);
00340
00341
00342
00343 manager.setOptionValString(&OPT_LevelSpec, "2,4,3,4,0");
00344 manager.setOptionValString(&OPT_MaxNormType, "Ignore");
00345
00346 MYLOGVERB = LOG_DEBUG;
00347
00348 if (manager.parseCommandLine(argc, argv,
00349 "input.pnm [save_prefix] "
00350 "[split_size] [overlap_fraction]",
00351 1, 4) == false)
00352 return 1;
00353
00354 #ifdef HAVE_FEENABLEEXCEPT
00355 fedisableexcept(FE_ALL_EXCEPT);
00356 feenableexcept(FE_DIVBYZERO|FE_INVALID);
00357 #endif
00358
00359 const Image<byte> input = Raster::ReadGray(manager.getExtraArg(0));
00360
00361 const std::string saveprefix =
00362 (manager.numExtraArgs() >= 2 && manager.getExtraArg(1).length() > 0)
00363 ? manager.getExtraArg(1) : "contourout";
00364
00365 if (manager.numExtraArgs() >= 3 && manager.getExtraArg(2).length() > 0)
00366 SPLIT_SIZE = manager.getExtraArgAs<int>(2);
00367
00368 if (manager.numExtraArgs() >= 4 && manager.getExtraArg(3).length() > 0)
00369 OVERLAP_FRACTION = manager.getExtraArgAs<double>(3);
00370
00371 manager.start();
00372
00373 CpuTimer t;
00374
00375 int pixused = 0;
00376 const Image<float> output =
00377 processImage(input, manager, saveprefix, pixused, ofs);
00378
00379 t.mark();
00380 t.report("full contour operation");
00381
00382 if (SPLIT_SIZE < 0)
00383 {
00384 ofs->writeGray(Image<byte>(output),
00385 sformat("%s.output", saveprefix.c_str()));
00386 }
00387 else
00388 {
00389 ofs->writeFloat(output,
00390 FLOAT_NORM_0_255,
00391 sformat("%s.output", saveprefix.c_str()));
00392
00393 ofs->writeFloat(output,
00394 FLOAT_NORM_0_255|FLOAT_NORM_WITH_SCALE,
00395 sformat("%s.output-s", saveprefix.c_str()));
00396 }
00397
00398 manager.stop();
00399
00400 return 0;
00401 }
00402 catch (...)
00403 {
00404 REPORT_CURRENT_EXCEPTION;
00405 }
00406
00407 return 1;
00408 }
00409
00410
00411
00412
00413
00414