~ubuntu-branches/ubuntu/hardy/avidemux/hardy

« back to all changes in this revision

Viewing changes to avidemux/ADM_videoFilter/ADM_vidSwissArmyKnife.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Matvey Kozhev
  • Date: 2007-12-18 13:53:04 UTC
  • mfrom: (1.1.7 upstream)
  • Revision ID: james.westby@ubuntu.com-20071218135304-cdqec2lg2bglyz15
Tags: 1:2.4~preview3-0.0ubuntu1
* Upload to Ubuntu. (LP: #163287, LP: #126572)
* debian/changelog: re-added Ubuntu releases.
* debian/control:
  - Require debhelper >= 5.0.51 (for dh_icons) and imagemagick.
  - Build-depend on libsdl1.2-dev instead of libsdl-dev.
  - Build against newer libx264-dev. (LP: #138854)
  - Removed libamrnb-dev, not in Ubuntu yet.
* debian/rules:
  - Install all icon sizes, using convert (upstream installs none).
  - Added missing calls to dh_installmenu, dh_installman, dh_icons and
    dh_desktop.
* debian/menu, debian/avidemux-qt.menu:
  - Corrected package and executable names.
* debian/avidemux-common.install: Install icons.
* debian/avidemux.common.manpages: Install man/avidemux.1.
* debian/links, debian/avidemux-cli.links, debian/avidemux-gtk.links:
  - Link manpages to avidemux.1.gz.
* debian/install, debian/avidemux-qt.install, debian/avidemux-gtk.desktop,
  debian/avidemux-qt.desktop: Install desktop files.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
                          ADM_vidSwissArmyKnife.cpp  -  Perform one of many
 
3
                                                        possible operations
 
4
                             -------------------
 
5
                          Chris MacGregor, 2005, 2007
 
6
                         chris-avidemux@bouncingdog.com
 
7
 ***************************************************************************/
 
8
 
 
9
/***************************************************************************
 
10
 *                                                                         *
 
11
 *   This program is free software; you can redistribute it and/or modify  *
 
12
 *   it under the terms of the GNU General Public License as published by  *
 
13
 *   the Free Software Foundation; either version 2 of the License, or     *
 
14
 *   (at your option) any later version.                                   *
 
15
 *                                                                         *
 
16
 ***************************************************************************/
 
17
 
 
18
#include "default.h"
 
19
 
 
20
#include <ctype.h>
 
21
#include <errno.h>
 
22
#include <math.h>
 
23
#include <sys/types.h>
 
24
#include <sys/stat.h>
 
25
 
 
26
#include <iostream>
 
27
#include <fstream>
 
28
#include <iterator>
 
29
 
 
30
#include "ADM_assert.h"
 
31
#include "fourcc.h"
 
32
#include "avio.hxx"
 
33
#include "avi_vars.h"
 
34
 
 
35
#include "ADM_toolkit/toolkit.hxx"
 
36
#include "ADM_editor/ADM_edit.hxx"
 
37
#include "ADM_video/ADM_genvideo.hxx"
 
38
 
 
39
#include "ADM_encoder/ADM_vidEncode.hxx"
 
40
#include "ADM_encoder/adm_encoder.h"
 
41
 
 
42
#include "ADM_filter/video_filters.h"
 
43
 
 
44
#include "ADM_userInterfaces/ADM_commonUI/DIA_factory.h"
 
45
 
 
46
#include "ADM_vidSwissArmyKnife.h"
 
47
#include "ADM_vidParticle.h" // for ImageTool
 
48
#include "ADM_vidComputeAverage.h" // for ADMVideoComputeAverage::FileHeader
 
49
#include "DIA_flyDialog.h" // for MenuMapping
 
50
 
 
51
static const int MAX_PIXEL_LUMA = 255;
 
52
 
 
53
static FILTER_PARAM swissArmyKnifeParam =
 
54
{
 
55
    15,
 
56
    { "tool", "input_type", "input_file", "load_bias",              // 4
 
57
      "load_multiplier", "input_constant", "memory_constant_alpha", // + 3 = 7
 
58
      "init_start_frame", "init_end_frame", "init_by_rolling",      // + 3 = 10
 
59
      "bias", "result_bias", "result_multiplier",                   // + 3 = 13
 
60
      "histogram_frame_interval", "debug"                           // + 2 = 15
 
61
    }
 
62
};
 
63
 
 
64
ADMVideoSwissArmyKnife::ToolMap ADMVideoSwissArmyKnife::tool_map [] =
 
65
{
 
66
    { TOOL_A,         "A",        "%s",        "%s"     },
 
67
    { TOOL_P,         "P",        "P",         "P"      },
 
68
    { TOOL_P_MINUS_A, "P-A",      "P-%s",      "P - %s" },
 
69
    { TOOL_A_MINUS_P, "A-P",      "%s-P",      "%s - P" },
 
70
    { TOOL_P_PLUS_A,  "P+A",      "P+%s",      "P + %s" },
 
71
    { TOOL_P_TIMES_A, "P*A",      "P*%s",      "P * %s" },
 
72
    { TOOL_P_DIVBY_A, "P/A",      "P/%s",      "P / %s" },
 
73
    { TOOL_A_DIVBY_P, "A/P",      "%s/P",      "%s / P" },
 
74
    { TOOL_MIN_P_A,   "min(P,A)", "min(P,%s)", "min (P, %s)" },
 
75
    { TOOL_MAX_P_A,   "max(P,A)", "max(P,%s)", "max (P, %s)" },
 
76
 
 
77
    { TOOL_INVALID, 0, 0, 0 }
 
78
};
 
79
 
 
80
// This is a hack to work around the fact that the ctor & dtor get called
 
81
// too often.  The right solution would be to arrange for the filter
 
82
// objects to be constructed and destructed only when really necessary:
 
83
// when a new instance of a filter is added to the list (by the user), it
 
84
// is constructed, and when it is removed from the list (by the user), it
 
85
// is destructed, and anything else is handled by a separate init() or
 
86
// configure() method.  This would allow the objects to maintain a
 
87
// persistent state in a more straightforward way.
 
88
 
 
89
ADMVideoSwissArmyKnife::PImap ADMVideoSwissArmyKnife::pimap;
 
90
 
 
91
 
 
92
SCRIPT_CREATE(swissarmyknife_script,ADMVideoSwissArmyKnife,swissArmyKnifeParam);
 
93
 
 
94
BUILD_CREATE(swissarmyknife_create,ADMVideoSwissArmyKnife);
 
95
 
 
96
ADMVideoSwissArmyKnife::ADMVideoSwissArmyKnife(AVDMGenericVideoStream *in,CONFcouple *couples)
 
97
                        
 
98
{
 
99
    _in = in;
 
100
    memcpy(&_info, in->getInfo(), sizeof(_info));
 
101
    _info.encoding = 1;
 
102
    _uncompressed = new ADMImage(_in->getInfo()->width, _in->getInfo()->height);
 
103
    ADM_assert(_uncompressed);
 
104
    _param = new SWISSARMYKNIFE_PARAM;
 
105
 
 
106
    if (couples)
 
107
    {
 
108
        GET(tool);
 
109
        GET(input_type);
 
110
 
 
111
                char* tmp;
 
112
        GET2(input_file, tmp);
 
113
        GET(load_bias);
 
114
        GET(load_multiplier);
 
115
 
 
116
        GET(input_constant);
 
117
 
 
118
        GET(memory_constant_alpha);
 
119
        GET(init_start_frame);
 
120
        GET(init_end_frame);
 
121
        GET(init_by_rolling);
 
122
 
 
123
        GET(bias);
 
124
        GET(result_bias);
 
125
        GET(result_multiplier);
 
126
        GET(histogram_frame_interval);
 
127
        GET(debug);
 
128
 
 
129
        _param->enable_preview
 
130
            = (_param->input_type != INPUT_ROLLING_AVERAGE);
 
131
    }
 
132
    else
 
133
    {
 
134
        _param->tool = TOOL_P_MINUS_A;
 
135
        _param->input_type = INPUT_ROLLING_AVERAGE;
 
136
 
 
137
        // _param->input_file = ""; // implicit
 
138
        _param->load_bias = 0.0;
 
139
        _param->load_multiplier = 1.0;
 
140
 
 
141
        _param->input_constant = 0;
 
142
 
 
143
        _param->init_start_frame = 1;
 
144
        _param->init_end_frame = 100;
 
145
        _param->memory_constant_alpha = 1.0 / _param->init_end_frame;
 
146
        _param->init_by_rolling = false;
 
147
 
 
148
        _param->bias = 128;
 
149
        _param->result_bias = 0.0;
 
150
        _param->result_multiplier = 1.0;
 
151
        _param->histogram_frame_interval = 0;
 
152
        _param->debug = 0;
 
153
 
 
154
        _param->enable_preview = false;
 
155
    }
 
156
 
 
157
    // This is a hack to work around the fact that the ctor & dtor get called
 
158
    // too often.  The right solution would be to arrange for the filter
 
159
    // objects to be constructed and destructed only when really necessary:
 
160
    // when a new instance of a filter is added to the list (by the user), it
 
161
    // is constructed, and when it is removed from the list (by the user), it
 
162
    // is destructed, and anything else is handled by a separate init() or
 
163
    // configure() method.  This would allow the objects to maintain a
 
164
    // persistent state in a more straightforward way.
 
165
 
 
166
    // This explicit check wouldn't be necessary if there was an easier way of
 
167
    // ensuring that we got a 0 pointer when a new map entry was auto-consed
 
168
    // up...
 
169
 
 
170
    if (pimap.count (couples) == 0)
 
171
    {
 
172
        myInfo = new PersistentInfo;
 
173
        myInfo->conf = couples;
 
174
        pimap [couples] = myInfo;
 
175
    }
 
176
    else
 
177
    {
 
178
        myInfo = pimap [couples];
 
179
        if (couples)
 
180
        {
 
181
            if (myInfo->oldConf == couples)
 
182
            {
 
183
                pimap.erase (myInfo->conf);
 
184
                myInfo->conf = myInfo->oldConf;
 
185
                myInfo->oldConf = 0;
 
186
            }
 
187
            else
 
188
            {
 
189
                ADM_assert (myInfo->conf == couples);
 
190
 
 
191
                if (myInfo->oldConf)
 
192
                {
 
193
                    pimap.erase (myInfo->oldConf);
 
194
                    myInfo->oldConf = 0;
 
195
                }
 
196
            }
 
197
        }
 
198
    }
 
199
 
 
200
    myInfo->refCount++;
 
201
 
 
202
    printf ("ADMVideoSwissArmyKnife ctor (%p, conf = %p), pi = %p, rc now %d\n",
 
203
            this, couples, myInfo, myInfo->refCount);
 
204
}
 
205
 
 
206
uint8_t ADMVideoSwissArmyKnife::getCoupledConf (CONFcouple **couples)
 
207
{
 
208
 
 
209
    ADM_assert(_param);
 
210
    *couples = new CONFcouple(swissArmyKnifeParam.nb);
 
211
 
 
212
    // This is a hack to work around the fact that the ctor & dtor get called
 
213
    // too often.  The right solution would be to arrange for the filter
 
214
    // objects to be constructed and destructed only when really necessary:
 
215
    // when a new instance of a filter is added to the list (by the user), it
 
216
    // is constructed, and when it is removed from the list (by the user), it
 
217
    // is destructed, and anything else is handled by a separate init() or
 
218
    // configure() method.  This would allow the objects to maintain a
 
219
    // persistent state in a more straightforward way.
 
220
 
 
221
    printf("ADMVideoSwissArmyKnife::getCoupledConf(): this = %p, couples = %p, "
 
222
           "oldConf = %p (was %p), pi = %p\n",
 
223
           this, *couples, myInfo->conf, myInfo->oldConf, myInfo);
 
224
 
 
225
    if (myInfo->oldConf)
 
226
        pimap.erase (myInfo->oldConf);
 
227
    myInfo->oldConf = myInfo->conf;
 
228
    myInfo->conf = *couples;
 
229
    pimap [myInfo->conf] = myInfo;
 
230
    if (myInfo->oldConf == 0)
 
231
        pimap.erase (0);
 
232
 
 
233
    CSET(tool);
 
234
    CSET(input_type);
 
235
 
 
236
    (*couples)->setCouple("input_file", _param->input_file.c_str());
 
237
    CSET(load_bias);
 
238
    CSET(load_multiplier);
 
239
 
 
240
    CSET(input_constant);
 
241
 
 
242
    CSET(memory_constant_alpha);
 
243
    CSET(init_start_frame);
 
244
    CSET(init_end_frame);
 
245
    CSET(init_by_rolling);
 
246
 
 
247
    CSET(bias);
 
248
    CSET(result_bias);
 
249
    CSET(result_multiplier);
 
250
    CSET(histogram_frame_interval);
 
251
    CSET(debug);
 
252
 
 
253
    return 1;
 
254
}
 
255
 
 
256
uint8_t ADMVideoSwissArmyKnife::configure (AVDMGenericVideoStream *in)
 
257
{
 
258
    diaMenuEntry tTool [] = {
 
259
        { TOOL_A,          QT_TR_NOOP("P' = A"), NULL },
 
260
        { TOOL_P,          QT_TR_NOOP("P' = P"), NULL },
 
261
        { TOOL_P_MINUS_A,  QT_TR_NOOP("P' = P - A"), NULL },
 
262
        { TOOL_A_MINUS_P,  QT_TR_NOOP("P' = A - P"), NULL },
 
263
        { TOOL_P_PLUS_A,   QT_TR_NOOP("P' = P + A"), NULL },
 
264
        { TOOL_P_TIMES_A,  QT_TR_NOOP("P' = P * A"), NULL },
 
265
        { TOOL_P_DIVBY_A,  QT_TR_NOOP("P' = P / A"), NULL },
 
266
        { TOOL_A_DIVBY_P,  QT_TR_NOOP("P' = A / P"), NULL },
 
267
        { TOOL_MIN_P_A,    QT_TR_NOOP("P' = min (P, A)"), NULL },
 
268
        { TOOL_MAX_P_A,    QT_TR_NOOP("P' = max (P, A)"), NULL }
 
269
    };
 
270
 
 
271
    diaMenuEntry tInputType [] = {
 
272
        { INPUT_CUSTOM_CONVOLUTION,
 
273
          QT_TR_NOOP("A = convolve(P); Load convolution kernel from file"), NULL },
 
274
        { INPUT_FILE_IMAGE_FLOAT,
 
275
          QT_TR_NOOP("A = pixel from image file as float; Load image from file"), NULL },
 
276
        { INPUT_FILE_IMAGE_INTEGER,
 
277
          QT_TR_NOOP("A = pixel from image file as integer; Load image from file"), NULL },
 
278
        { INPUT_CONSTANT_VALUE,
 
279
          QT_TR_NOOP("A = floating point constant value"), NULL },
 
280
        { INPUT_ROLLING_AVERAGE,
 
281
          QT_TR_NOOP("A = rolling average of pixel: A = A*(1-alpha)+(P*alpha)"), NULL },
 
282
    };
 
283
 
 
284
    diaElemMenu tool
 
285
        (&(_param->tool),
 
286
         QT_TR_NOOP("Select _Operation on each pixel P and input A:"),
 
287
         sizeof (tTool) / sizeof (diaMenuEntry), tTool);
 
288
 
 
289
    diaElemMenu input_type
 
290
        (&(_param->input_type),
 
291
         QT_TR_NOOP("Input _Type:"),
 
292
         sizeof (tInputType) / sizeof (diaMenuEntry), tInputType);
 
293
 
 
294
    MenuMapping menu_mapping [] = {
 
295
        { "operationMenu", my_offsetof (SWISSARMYKNIFE_PARAM, tool),
 
296
          sizeof (tTool) / sizeof (diaMenuEntry), tTool },
 
297
        { "inputTypeMenu", my_offsetof (SWISSARMYKNIFE_PARAM, input_type),
 
298
          sizeof (tInputType) / sizeof (diaMenuEntry), tInputType },
 
299
    };
 
300
 
 
301
    // printf ("ADM_vidSwissArmyKnife: _param = %p\n", _param);
 
302
    uint8_t ret = DIA_SwissArmyKnife (_in, this, _param, menu_mapping,
 
303
                                      sizeof (menu_mapping)
 
304
                                      / sizeof (MenuMapping));
 
305
    if (ret == 1)
 
306
    {
 
307
        return ret;
 
308
    }
 
309
    else if (ret == 0) // 0 = cancel
 
310
    {
 
311
        return ret;
 
312
    }
 
313
    else
 
314
    {
 
315
        ADM_assert (ret == 255); // 255 = whizzy dialog not implemented
 
316
    }
 
317
 
 
318
        char* file = ADM_strdup(_param->input_file.c_str());
 
319
 
 
320
    diaElemFile input_file
 
321
        (0, &file,
 
322
         QT_TR_NOOP("Input _File (image or convolution kernel):"), NULL, QT_TR_NOOP("Select file"));
 
323
    diaElemFloat load_bias
 
324
        (&(_param->load_bias),
 
325
         QT_TR_NOOP("_Load Bias (added to each pixel\n"
 
326
           "in file image when loaded):"),
 
327
         -99999, +99999); // arbitrary!
 
328
    diaElemFloat load_multiplier
 
329
        (&(_param->load_multiplier),
 
330
         QT_TR_NOOP("Load _Multiplier (each pixel in\n"
 
331
           "file image mult. by this when loaded):"),
 
332
         -99999, +99999); // arbitrary!
 
333
 
 
334
    diaElemFloat input_constant
 
335
        (&(_param->input_constant),
 
336
         QT_TR_NOOP("Input _Constant:"), -99999, +99999); // arbitrary!
 
337
 
 
338
    diaElemFloat memory_constant_alpha
 
339
        (&(_param->memory_constant_alpha),
 
340
         QT_TR_NOOP("Memory constant _alpha\n"
 
341
           "(where A = (1-alpha)*A + alpha*curr_frame):"),
 
342
         0, 0x7fffffff);
 
343
    diaElemUInteger init_start_frame
 
344
        (&(_param->init_start_frame),
 
345
         QT_TR_NOOP("Init _Start Frame (first frame # to use for head start):"),
 
346
         0, 0x7fffffff);
 
347
    diaElemUInteger init_end_frame
 
348
        (&(_param->init_end_frame),
 
349
         QT_TR_NOOP("Init _End Frame (last frame # to use for head start):"),
 
350
         0, 0x7fffffff);
 
351
    diaElemToggle init_by_rolling
 
352
        (&(_param->init_by_rolling),
 
353
         QT_TR_NOOP("Init By _Rolling (compute head start using a "
 
354
           "rolling average rather than a straight average)"));
 
355
 
 
356
    diaElemSlider bias
 
357
        (&(_param->bias),
 
358
         QT_TR_NOOP("_Bias (will be added to result):"), -256, +256);
 
359
    diaElemFloat result_bias
 
360
        (&(_param->result_bias),
 
361
         QT_TR_NOOP("_Result Bias (added to each result pixel):"),
 
362
         -99999, +99999); // arbitrary!
 
363
    diaElemFloat result_multiplier
 
364
        (&(_param->result_multiplier),
 
365
         QT_TR_NOOP("Result _Multiplier (each result pixel\n"
 
366
           "multiplied by this):"),
 
367
         -99999, +99999); // arbitrary!
 
368
    diaElemUInteger histogram_frame_interval
 
369
        (&(_param->histogram_frame_interval),
 
370
         QT_TR_NOOP("_Histogram every N frames (0 to disable):"), 0, 0x7fffffff);
 
371
    diaElemUInteger debug
 
372
        (&(_param->debug), QT_TR_NOOP("_Debugging settings (bits):"), 0, 0x7fffffff);
 
373
 
 
374
    diaElem * elems[] = { &tool, &input_type, &input_file, &load_bias,
 
375
                          &load_multiplier, &input_constant,
 
376
                          &memory_constant_alpha, &init_start_frame,
 
377
                          &init_end_frame, &init_by_rolling,
 
378
                          &bias, &result_bias, &result_multiplier,
 
379
                          &histogram_frame_interval, &debug };
 
380
 
 
381
    ret = diaFactoryRun (QT_TR_NOOP("Swiss Army Knife Configuration"),
 
382
                         sizeof (elems) / sizeof (diaElem *), elems);
 
383
    if (ret) // 0 = cancel
 
384
    {
 
385
        myInfo->image_data_invalid = true;
 
386
        myInfo->histogram_data_invalid = true;
 
387
    }
 
388
 
 
389
        _param->input_file = file;
 
390
        delete[] file;
 
391
 
 
392
    return ret;
 
393
}
 
394
 
 
395
ADMVideoSwissArmyKnife::~ADMVideoSwissArmyKnife()
 
396
{
 
397
    // This is a hack to work around the fact that the ctor & dtor get called
 
398
    // too often.  The right solution would be to arrange for the filter
 
399
    // objects to be constructed and destructed only when really necessary:
 
400
    // when a new instance of a filter is added to the list (by the user), it
 
401
    // is constructed, and when it is removed from the list (by the user), it
 
402
    // is destructed, and anything else is handled by a separate init() or
 
403
    // configure() method.  This would allow the objects to maintain a
 
404
    // persistent state in a more straightforward way.
 
405
 
 
406
    myInfo->refCount--;
 
407
    printf ("ADMVideoSwissArmyKnife dtor (%p), conf = %p, pi = %p, rc now %d\n",
 
408
            this, myInfo->conf, myInfo, myInfo->refCount);
 
409
 
 
410
    if (myInfo->oldConf)
 
411
    {
 
412
        pimap.erase (myInfo->oldConf);
 
413
        myInfo->oldConf = 0;
 
414
    }
 
415
 
 
416
    if (myInfo->refCount < 1)
 
417
    {
 
418
        pimap.erase (myInfo->conf);
 
419
        delete myInfo;
 
420
    }
 
421
 
 
422
    DELETE(_param);
 
423
    delete _uncompressed;
 
424
    _uncompressed = NULL;
 
425
}
 
426
 
 
427
char * ADMVideoSwissArmyKnife::printConf ()
 
428
{
 
429
    return getConf (_param, false);
 
430
}
 
431
 
 
432
char * ADMVideoSwissArmyKnife::getConf (SWISSARMYKNIFE_PARAM * param,
 
433
                                        bool forDialog)
 
434
{
 
435
    const int CONF_LEN = 1024;
 
436
    static char conf[CONF_LEN];
 
437
 
 
438
    ToolMap * tm;
 
439
    for (tm = tool_map; tm->outputName; tm++)
 
440
        if (tm->toolid == param->tool)
 
441
            break;
 
442
 
 
443
    char inputstr [CONF_LEN];
 
444
    char where [256];
 
445
    where[0] = '\0';
 
446
    char moreinfo [256];
 
447
    moreinfo[0] = '\0';
 
448
    const char * input_file = param->input_file.c_str();
 
449
    if (!input_file || !*input_file)
 
450
        input_file = "**** no file selected ****";
 
451
 
 
452
    const char * space = forDialog ? " " : "";
 
453
 
 
454
    switch (param->input_type)
 
455
    {
 
456
    case INPUT_CUSTOM_CONVOLUTION:
 
457
        snprintf (inputstr, CONF_LEN, "convolve%s(P,%s%s)",
 
458
                  space, space, input_file);
 
459
        break;
 
460
    case INPUT_FILE_IMAGE_FLOAT:
 
461
        snprintf (inputstr, CONF_LEN,
 
462
                  (param->load_bias == 0.0 && param->load_multiplier == 1.0)
 
463
                  ? "pixel_from%s(%s)"
 
464
                  : (forDialog ? "((pixel_from%s(%s) + %.6f) * %.6f)"
 
465
                     : "((pixel_from%s(%s)%+.6f)*%.6f)"),
 
466
                  space, input_file,
 
467
                  param->load_bias, param->load_multiplier);
 
468
        break;
 
469
    case INPUT_FILE_IMAGE_INTEGER:
 
470
        snprintf (inputstr, CONF_LEN,
 
471
                  (param->load_bias == 0.0 && param->load_multiplier == 1.0)
 
472
                  ? "integer(pixel_from%s(%s))"
 
473
                  : (forDialog ? "integer((pixel_from%s(%s) + %.6f) * %.6f)"
 
474
                     : "integer((pixel_from%s(%s)%+.6f)*%.6f)"),
 
475
                  space, input_file,
 
476
                  param->load_bias, param->load_multiplier);
 
477
        break;
 
478
    case INPUT_CONSTANT_VALUE:
 
479
        if (int (param->input_constant) == param->input_constant)
 
480
            sprintf (inputstr, "%d", int (param->input_constant));
 
481
        else
 
482
            sprintf (inputstr, "%.6f", param->input_constant);
 
483
        break;
 
484
    case INPUT_ROLLING_AVERAGE:
 
485
        sprintf (inputstr, "A");
 
486
        sprintf (where, " (where each frame, A=(A*(1-alpha))+(P*alpha), "
 
487
                 "alpha%s=%s%.6f)",
 
488
                 space, space, param->memory_constant_alpha);
 
489
        if (param->init_start_frame)
 
490
            sprintf (moreinfo, ", initial A = %s avg of frames %u - %u",
 
491
                     param->init_by_rolling ? "rolling" : "straight",
 
492
                     param->init_start_frame, param->init_end_frame);
 
493
        break;
 
494
    default:
 
495
        sprintf (inputstr, "OOOPS!! (unexpected type %d)",
 
496
                 param->input_type);
 
497
        break;
 
498
    }
 
499
 
 
500
    char * cptr = conf;
 
501
 
 
502
    bool result_is_scaled
 
503
        = (param->result_bias != 0.0 || param->result_multiplier != 1.0);
 
504
 
 
505
    if (!forDialog)
 
506
        cptr += snprintf (conf, CONF_LEN, "Swiss Army Knife: ");
 
507
    cptr += snprintf (cptr, CONF_LEN - (cptr - conf), "P' = %s",
 
508
                      result_is_scaled ? "((" : "");
 
509
    cptr += snprintf (cptr, CONF_LEN - (cptr - conf),
 
510
                      forDialog ? tm->spacy_format : tm->format, inputstr);
 
511
    if (param->bias)
 
512
        cptr += snprintf (cptr, CONF_LEN - (cptr - conf),
 
513
                          forDialog ? " + %d" : "%+d", param->bias);
 
514
    cptr += snprintf (cptr, CONF_LEN - (cptr - conf), "%s", where);
 
515
    if (result_is_scaled)
 
516
        cptr += snprintf (cptr, CONF_LEN - (cptr - conf),
 
517
                          forDialog ? ") + %.6f) * %.6f" : ")%+.6f)*%.6f",
 
518
                          param->result_bias, param->result_multiplier);
 
519
    cptr += snprintf (cptr, CONF_LEN - (cptr - conf), "%s", moreinfo);
 
520
    if (param->histogram_frame_interval)
 
521
        cptr += snprintf (cptr, CONF_LEN - (cptr - conf),
 
522
                          ", histogram every %u frames",
 
523
                          param->histogram_frame_interval);
 
524
    if (param->debug)
 
525
        cptr += snprintf (cptr, CONF_LEN - (cptr - conf),
 
526
                          ", debug%s=%s0x%x", space, space, param->debug);
 
527
    if (!forDialog)
 
528
        fprintf (stderr, "SAK conf is (%d) \"%s\"\n", cptr - conf, conf);
 
529
    return conf;
 
530
}
 
531
 
 
532
//============================================================================
 
533
 
 
534
// Note: The structure of the following code (with the template functions, and
 
535
// the functor objects, etc.) is all about minimizing the code executed
 
536
// per-pixel.  We need to select an input (convolution, etc.), and an
 
537
// operation to apply that input to each pixel (P' = P - A, etc.), and
 
538
// optionally scale the result, and optionally collect a histogram...but we
 
539
// don't want any more if's or pointer (or reference dereferences) in the
 
540
// per-pixel core of the loop than we absolutely must have, and we certainly
 
541
// don't want any switches or function calls.  At the same time, we don't want
 
542
// to duplicate the code that humans have to deal with - that's the whole
 
543
// point of templates.  So, buckle your seat belts, because this is where C++
 
544
// gets really fun!
 
545
 
 
546
//============================================================================
 
547
 
 
548
class HistogramNull // do-nothing version
 
549
{
 
550
public:
 
551
    static
 
552
    void reset()
 
553
    {
 
554
    }
 
555
    static
 
556
    void record_input (uint8_t P)
 
557
    {
 
558
    }
 
559
    static
 
560
    void record_output (int32_t P)
 
561
    {
 
562
    }
 
563
    static
 
564
    void dump (uint32_t frame_count, uint32_t pixels_per_frame)
 
565
    {
 
566
    }
 
567
    static
 
568
    bool frame_check ()
 
569
    {
 
570
        return false;
 
571
    }
 
572
};
 
573
 
 
574
//----------------------------------------------------------------------------
 
575
 
 
576
class Histogram
 
577
{
 
578
public:
 
579
    // Optionally, we could make this a template class with range_size a
 
580
    // template parameter.  However, it would have to be used in more than one
 
581
    // place, with different range sizes, for that to be worth doing.
 
582
 
 
583
    static const int32_t input_range_size = 256; // 8 bit pixels
 
584
    static const int32_t range_size = 1024; // This must be a power of 2!
 
585
    static const int32_t midpoint = 128;
 
586
    static const int32_t range_min = midpoint - (range_size / 2);
 
587
    static const int32_t range_max = midpoint + (range_size / 2) - 1;
 
588
    static const int32_t out_of_range_mask = ~(range_size - 1);
 
589
 
 
590
    uint32_t * input_data;
 
591
    uint32_t * output_data;
 
592
    uint32_t pixels_per_frame;
 
593
    uint32_t & frame_count;
 
594
    uint32_t frame_interval;
 
595
 
 
596
    // The default copy ctor and assignment operators are just fine in this
 
597
    // case!  Also, note that the ctor allocates the memory and sets the
 
598
    // pointers to which it is passed references, but does not keep the
 
599
    // references (since it won't need to change those pointers again) - it
 
600
    // keeps local copies instead, to avoid later indirections.  It does store
 
601
    // a reference to the frame_count for use in frame_check().
 
602
 
 
603
    Histogram (uint32_t * & input_data_ref, uint32_t * & output_data_ref,
 
604
               uint32_t frame_interval, uint32_t & frame_count,
 
605
               uint32_t pixels_per_frame)
 
606
        : input_data (input_data_ref),
 
607
          output_data (output_data_ref),
 
608
          pixels_per_frame (pixels_per_frame),
 
609
          frame_count (frame_count),
 
610
          frame_interval (frame_interval)
 
611
    {
 
612
        if (!input_data)
 
613
        {
 
614
            input_data = input_data_ref = new uint32_t [input_range_size];
 
615
            output_data = output_data_ref = new uint32_t [range_size];
 
616
            // printf ("histogram: allocated data at %p, %p\n",
 
617
            //         input_data, output_data);
 
618
            reset();
 
619
        }
 
620
        else
 
621
            ;// printf ("histogram: using data at %p, %p\n",
 
622
             //         input_data, output_data);
 
623
    }
 
624
 
 
625
    // no dtor needed - deallocation is handled elsewhere
 
626
 
 
627
    void reset () const
 
628
    {
 
629
        memset (input_data, 0, input_range_size * sizeof (input_data[0]));
 
630
        memset (output_data, 0, range_size * sizeof (output_data[0]));
 
631
        frame_count = 0;
 
632
    }
 
633
 
 
634
    void record_input (uint8_t P) const
 
635
    {
 
636
        input_data[P]++;
 
637
    }
 
638
 
 
639
    void record_output (int32_t P) const
 
640
    {
 
641
        P -= range_min; // scale into histogram data array index
 
642
        if ((P & out_of_range_mask) == 0)
 
643
        {
 
644
            output_data[P]++;
 
645
            return;
 
646
        }
 
647
 
 
648
        if (P < 0)
 
649
            P = 0;
 
650
        else if (P >= range_size)
 
651
            P = range_size - 1;
 
652
 
 
653
        output_data[P]++;
 
654
    }
 
655
 
 
656
    void dump () const
 
657
    {
 
658
        int32_t index_min = 0;
 
659
        int32_t index_max = range_size - 1;
 
660
        while (index_min < index_max)
 
661
        {
 
662
            if (output_data[index_min])
 
663
                break;
 
664
            ++index_min;
 
665
        }
 
666
        while (index_min < index_max)
 
667
        {
 
668
            if (output_data[index_max])
 
669
                break;
 
670
            --index_max;
 
671
        }
 
672
        
 
673
        printf ("Swiss Army Knife Histogram for past %u frames:\n"
 
674
                " =================== Input (0 - 255), "
 
675
                "avg/frame over %d frames: ====================\n",
 
676
                frame_count, frame_count);
 
677
        do_dump (input_data, 0, 255, 0);
 
678
        printf ("=========== Result before saturation (%d - %d), "
 
679
                "avg/frame over %d frames: ==========\n",
 
680
                index_min + range_min, index_max + range_min, frame_count);
 
681
        do_dump (output_data, index_min, index_max, range_min);
 
682
    }
 
683
 
 
684
    // returns true if it outputs data and resets the counter, else false.
 
685
 
 
686
    bool frame_check () const
 
687
    {
 
688
        if (++frame_count < frame_interval)
 
689
        {
 
690
            // printf ("histogram: frame %d of %d\n",
 
691
            //         frame_count, frame_interval);
 
692
            return false;
 
693
        }
 
694
 
 
695
        dump();
 
696
        reset();
 
697
        return true;
 
698
    }
 
699
 
 
700
private:
 
701
    void do_dump (uint32_t * data, int32_t index_min, int32_t index_max,
 
702
                  int32_t bias) const
 
703
    {
 
704
        // We scan the data to find the maximum value, so we can scale the
 
705
        // bars to provide useful visual data.
 
706
 
 
707
        uint32_t max_pixels = 0;
 
708
        for (int32_t index = index_min; index <= index_max; index++)
 
709
        {
 
710
            if (data[index] > max_pixels)
 
711
                max_pixels = data[index];
 
712
        }
 
713
 
 
714
        // Effectively, for each pixel-value count, we divide by the frame
 
715
        // count to get the average number of times that pixel value occurred
 
716
        // per frame, and then we scale the bar so that only the max number of
 
717
        // pixels gets 100% of the bar.
 
718
 
 
719
        const int32_t bar_max = 11; // hardcoded as %11s in printf below
 
720
#if 0
 
721
        max_pixels /= frame_count;
 
722
        int32_t divisor = frame_count * max_pixels / bar_max;
 
723
#else
 
724
        int32_t divisor = max_pixels / bar_max;
 
725
#endif
 
726
 
 
727
        const int32_t columns = 4;
 
728
        // The "+ columns" below is to round up to the total number of rows we
 
729
        // need including partial rows; it's really "+ 1 + (columns - 1)",
 
730
        // where the + 1 is to account for index_max being the top end of the
 
731
        // range, not the top end + 1.
 
732
        int32_t column_len = (index_max - index_min + columns) / columns;
 
733
 
 
734
        int32_t column_end = index_min + column_len;
 
735
 
 
736
        const char * bar = "*********************************************";
 
737
        const char * bar_end = bar + strlen (bar);
 
738
 
 
739
        for (int32_t index = index_min; index < column_end; index++)
 
740
        {
 
741
            int32_t index2 = index;
 
742
            int32_t val = index + bias;
 
743
            
 
744
            for (int32_t column = 0;
 
745
                 column < columns;
 
746
                 ++column, index2 += column_len, val += column_len)
 
747
            {
 
748
                if (index2 > index_max)
 
749
                    break;
 
750
 
 
751
                int32_t dat = data[index2];
 
752
                int32_t bar_size = dat / divisor;
 
753
                if (bar_size == 0 && dat != 0)
 
754
                    bar_size = 1;
 
755
#define HISTOGRAM_SHOW_VALUES 1
 
756
#ifdef HISTOGRAM_SHOW_VALUES
 
757
                printf (" %5d: %6d %-11s", val, dat / frame_count, bar_end - bar_size);
 
758
#else
 
759
                printf (" %5d: %-11s", val, bar_end - bar_size);
 
760
#endif
 
761
            }
 
762
            printf ("\n");
 
763
        }
 
764
    }
 
765
};
 
766
 
 
767
//============================================================================
 
768
 
 
769
template <typename Oper, typename Histo>
 
770
void ImageTool::convolve (const std::vector <float> & kernel,
 
771
                          uint32_t kw, uint32_t kh, int32_t bias,
 
772
                          const Oper & op_in, const Histo & histogram_in)
 
773
{
 
774
    // We make local copies of the functors so that the calls below to
 
775
    // record_input() and record_output() (for the histogram) and operator()
 
776
    // (for the op) are accessing stack data rather than incurring yet another
 
777
    // indirection.  When it's per-pixel, every little bit helps!
 
778
 
 
779
    Histo histogram = histogram_in;
 
780
    Oper op = op_in;
 
781
 
 
782
    uint32_t sathigh = 0;
 
783
    uint32_t satlow = 0;
 
784
 
 
785
    // The following code is copied with little significant change (mostly
 
786
    // just porting & performance tweaks, and adding some debugging output)
 
787
    // from ImageJ's Convolver::convolveFloat() function.  Blame them for
 
788
    // variable names like "uc". ;-)
 
789
 
 
790
    // We have (for the moment) skipped the normalizing step - we assume that
 
791
    // the scale is 1.0.
 
792
 
 
793
    // We also assume that kw and kh are both odd.
 
794
 
 
795
    int32_t uc = kw / 2;
 
796
    int32_t vc = kh / 2;
 
797
 
 
798
    uint32_t xedge = my_w - uc;
 
799
    uint32_t yedge = my_h - vc;
 
800
 
 
801
    for (uint32_t y = 0; y < my_h; y++)
 
802
    {
 
803
        bool y_is_edgy = (y < vc || y >= yedge);
 
804
 
 
805
        for (uint32_t x = 0; x < my_w; x++)
 
806
        {
 
807
            float sum = 0;
 
808
            uint32_t i = 0;
 
809
 
 
810
            // If some of this pixel's neighbors are "off the edge" of the
 
811
            // input image, we'll use the "safe" getPixel().
 
812
 
 
813
            if (y_is_edgy || x < uc || x >= xedge)
 
814
            {
 
815
                for (int32_t v = -vc; v <= vc; v++)
 
816
                    for (int32_t u = -uc; u <= uc; u++)
 
817
                        sum += getPixelSafely (x + u, y + v) * kernel [i++];
 
818
            }
 
819
            else
 
820
            {
 
821
                // HERE: we could optimize this a good bit by putting
 
822
                // &(getPixel(x - uc, y - vc)) into a pointer, then just
 
823
                // incrementing the pointer (and adding a precomputed (my_w -
 
824
                // uc * 2) to shift lines).  It violates the nice
 
825
                // encapsulation provided by ImageTool, but if/when we add a
 
826
                // SIMD version of this loop, that sure isn't going to use
 
827
                // GetPixel()... ;-)
 
828
 
 
829
                for (int32_t v = -vc; v <= vc; v++)
 
830
                {
 
831
                    int32_t offset = x + ((y + v) * my_w);
 
832
 
 
833
                    for (int32_t u = -uc; u <= uc; u++)
 
834
                        sum += getPixel (offset + u) * kernel [i++];
 
835
                }
 
836
            }
 
837
 
 
838
            // as noted above, we're currently assuming the matrix was already
 
839
            // normalized...
 
840
            // sum *= scale;
 
841
 
 
842
            int32_t P = getPixel (x, y);
 
843
 
 
844
            histogram.record_input (P);
 
845
 
 
846
            float A = sum;
 
847
 
 
848
            int32_t result = op (P, A) + bias;
 
849
 
 
850
            histogram.record_output (result);
 
851
 
 
852
            if (result & 0xffffff00)
 
853
            {
 
854
                if (result < 0)
 
855
                {
 
856
                    result = 0;
 
857
                    satlow++;
 
858
                }
 
859
                else // if (result > 255)
 
860
                {
 
861
                    result = 255;
 
862
                    sathigh++;
 
863
                }
 
864
            }
 
865
 
 
866
            outPixel (x, y) = result;
 
867
        }
 
868
    }
 
869
 
 
870
    if (debug & 2)
 
871
    {
 
872
        if (satlow || sathigh)
 
873
            printf ("    Saturated %d low, %d high\n", satlow, sathigh);
 
874
    }
 
875
}
 
876
 
 
877
//============================================================================
 
878
 
 
879
template <typename Oper, typename Histo>
 
880
void ADMVideoSwissArmyKnife::computeRollingAverage (ADMImage * image,
 
881
                                                    ADMImage * data,
 
882
                                                    uint32_t planesize,
 
883
                                                    SWISSARMYKNIFE_PARAM * param,
 
884
                                                    int32_t bias,
 
885
                                                    const Oper & op_in,
 
886
                                                    const Histo & histogram_in)
 
887
{
 
888
    // We make local copies of the functors so that the calls below to
 
889
    // record_input() and record_output() (for the histogram) and operator()
 
890
    // (for the op) are accessing stack data rather than incurring yet another
 
891
    // indirection.  When it's per-pixel, every little bit helps!
 
892
 
 
893
    Histo histogram = histogram_in;
 
894
    Oper op = op_in;
 
895
 
 
896
    float alpha = param->memory_constant_alpha;
 
897
    float oneminusalpha = 1 - alpha;
 
898
 
 
899
    // HERE: for speed, we do luma (Y plane) only.  However, some
 
900
    // users might want chroma, too... we should make that
 
901
    // an option or something.
 
902
 
 
903
    uint8_t * currp = YPLANE (image) + planesize;
 
904
    uint8_t * destp = YPLANE (data) + planesize;
 
905
    float * bgp = myInfo->bg + planesize;
 
906
    uint32_t pixremaining = planesize + 1;
 
907
 
 
908
    uint32_t sathigh = 0;
 
909
    uint32_t satlow = 0;
 
910
 
 
911
    while (--pixremaining)
 
912
    {
 
913
        int32_t P = *--currp;
 
914
        histogram.record_input (P);
 
915
 
 
916
        float A = *--bgp;
 
917
        *bgp = (A * oneminusalpha) + (P * alpha);
 
918
 
 
919
        int32_t result = op (P, A) + bias;
 
920
 
 
921
        histogram.record_output (result);
 
922
 
 
923
        if (result & 0xffffff00)
 
924
        {
 
925
            if (result < 0)
 
926
            {
 
927
                result = 0;
 
928
                satlow++;
 
929
            }
 
930
            else // if (result > 255)
 
931
            {
 
932
                result = 255;
 
933
                sathigh++;
 
934
            }
 
935
        }
 
936
 
 
937
        *--destp = result;
 
938
    }
 
939
 
 
940
    if (param->debug & 2)
 
941
    {
 
942
        if (satlow || sathigh)
 
943
            printf ("    Saturated %d low, %d high\n", satlow, sathigh);
 
944
    }
 
945
}
 
946
 
 
947
//============================================================================
 
948
 
 
949
template <typename InputImageType, typename Oper, typename Histo>
 
950
void ADMVideoSwissArmyKnife::applyImage (ADMImage * image, ADMImage * data,
 
951
                                         uint32_t planesize,
 
952
                                         SWISSARMYKNIFE_PARAM * param,
 
953
                                         int32_t bias,
 
954
                                         InputImageType * input_image,
 
955
                                         const Oper & op_in,
 
956
                                         const Histo & histogram_in)
 
957
{
 
958
    // We make local copies of the functors so that the calls below to
 
959
    // record_input() and record_output() (for the histogram) and operator()
 
960
    // (for the op) are accessing stack data rather than incurring yet another
 
961
    // indirection.  When it's per-pixel, every little bit helps!
 
962
 
 
963
    Histo histogram = histogram_in;
 
964
    Oper op = op_in;
 
965
 
 
966
    // HERE: for speed, we do luma (Y plane) only.  However, some
 
967
    // users might want chroma, too... we should make that
 
968
    // an option or something.
 
969
 
 
970
    uint8_t * currp = YPLANE (image) + planesize;
 
971
    uint8_t * destp = YPLANE (data) + planesize;
 
972
    InputImageType * bgp = input_image + planesize;
 
973
    uint32_t pixremaining = planesize + 1;
 
974
 
 
975
    uint32_t sathigh = 0;
 
976
    uint32_t satlow = 0;
 
977
 
 
978
    while (--pixremaining)
 
979
    {
 
980
        int32_t P = *--currp;
 
981
        histogram.record_input (P);
 
982
 
 
983
        InputImageType A = *--bgp;
 
984
        int32_t result = op (P, A) + bias;
 
985
 
 
986
        histogram.record_output (result);
 
987
 
 
988
        if (result & 0xffffff00)
 
989
        {
 
990
            if (result < 0)
 
991
            {
 
992
                result = 0;
 
993
                satlow++;
 
994
            }
 
995
            else // if (result > 255)
 
996
            {
 
997
                result = 255;
 
998
                sathigh++;
 
999
            }
 
1000
        }
 
1001
 
 
1002
        *--destp = result;
 
1003
    }
 
1004
 
 
1005
    if (param->debug & 2)
 
1006
    {
 
1007
        if (satlow || sathigh)
 
1008
            printf ("    Saturated %d low, %d high\n", satlow, sathigh);
 
1009
    }
 
1010
}
 
1011
 
 
1012
//============================================================================
 
1013
 
 
1014
template <typename Oper, typename Histo>
 
1015
void ADMVideoSwissArmyKnife::applyConstant (ADMImage * image, ADMImage * data,
 
1016
                                            uint32_t planesize,
 
1017
                                            SWISSARMYKNIFE_PARAM * param,
 
1018
                                            int32_t bias,
 
1019
                                            const Oper & op_in,
 
1020
                                            const Histo & histogram_in)
 
1021
{
 
1022
    // We make local copies of the functors so that the calls below to
 
1023
    // record_input() and record_output() (for the histogram) and operator()
 
1024
    // (for the op) are accessing stack data rather than incurring yet another
 
1025
    // indirection.  When it's per-pixel, every little bit helps!
 
1026
 
 
1027
    Histo histogram = histogram_in;
 
1028
    Oper op = op_in;
 
1029
 
 
1030
    // HERE: for speed, we do luma (Y plane) only.  However, some
 
1031
    // users might want chroma, too... we should make that
 
1032
    // an option or something.
 
1033
 
 
1034
    uint8_t * currp = YPLANE (image) + planesize;
 
1035
    uint8_t * destp = YPLANE (data) + planesize;
 
1036
    float A = param->input_constant;
 
1037
    uint32_t pixremaining = planesize + 1;
 
1038
 
 
1039
    uint32_t sathigh = 0;
 
1040
    uint32_t satlow = 0;
 
1041
 
 
1042
    while (--pixremaining)
 
1043
    {
 
1044
        int32_t P = *--currp;
 
1045
        histogram.record_input (P);
 
1046
 
 
1047
        int32_t result = op (P, A) + bias;
 
1048
 
 
1049
        histogram.record_output (result);
 
1050
 
 
1051
        if (result & 0xffffff00)
 
1052
        {
 
1053
            if (result < 0)
 
1054
            {
 
1055
                result = 0;
 
1056
                satlow++;
 
1057
            }
 
1058
            else // if (result > 255)
 
1059
            {
 
1060
                result = 255;
 
1061
                sathigh++;
 
1062
            }
 
1063
        }
 
1064
 
 
1065
        *--destp = result;
 
1066
    }
 
1067
 
 
1068
    if (param->debug & 2)
 
1069
    {
 
1070
        if (satlow || sathigh)
 
1071
            printf ("    Saturated %d low, %d high\n", satlow, sathigh);
 
1072
    }
 
1073
}
 
1074
 
 
1075
//============================================================================
 
1076
 
 
1077
class OpPequalsA
 
1078
{
 
1079
public:
 
1080
    int32_t operator () (int32_t P, float A) const
 
1081
    {
 
1082
        return static_cast <int32_t> (A + .5);
 
1083
    }
 
1084
 
 
1085
    int32_t operator () (int32_t P, uint8_t A) const
 
1086
    {
 
1087
        return A;
 
1088
    }
 
1089
};
 
1090
 
 
1091
class OpPequalsP
 
1092
{
 
1093
public:
 
1094
    int32_t operator () (int32_t P, float A) const
 
1095
    {
 
1096
        return P;
 
1097
    }
 
1098
 
 
1099
    int32_t operator () (int32_t P, uint8_t A) const
 
1100
    {
 
1101
        return P;
 
1102
    }
 
1103
};
 
1104
 
 
1105
class OpPequalsPminusA
 
1106
{
 
1107
public:
 
1108
    int32_t operator () (int32_t P, float A) const
 
1109
    {
 
1110
        return (P - static_cast <int32_t> (A + .5));
 
1111
    }
 
1112
 
 
1113
    int32_t operator () (int32_t P, uint8_t A) const
 
1114
    {
 
1115
        return (P - A);
 
1116
    }
 
1117
};
 
1118
 
 
1119
class OpPequalsAminusP
 
1120
{
 
1121
public:
 
1122
    int32_t operator () (int32_t P, float A) const
 
1123
    {
 
1124
        return (static_cast <int32_t> (A + .5) - P);
 
1125
    }
 
1126
 
 
1127
    int32_t operator () (int32_t P, uint8_t A) const
 
1128
    {
 
1129
        return (A - P);
 
1130
    }
 
1131
};
 
1132
 
 
1133
class OpPequalsPplusA
 
1134
{
 
1135
public:
 
1136
    int32_t operator () (int32_t P, float A) const
 
1137
    {
 
1138
        return (P + static_cast <int32_t> (A + .5));
 
1139
    }
 
1140
 
 
1141
    int32_t operator () (int32_t P, uint8_t A) const
 
1142
    {
 
1143
        return (P + A);
 
1144
    }
 
1145
};
 
1146
 
 
1147
class OpPequalsPtimesA
 
1148
{
 
1149
public:
 
1150
    int32_t operator () (int32_t P, float A) const
 
1151
    {
 
1152
        return static_cast <int32_t> ((P * A) + .5);
 
1153
    }
 
1154
 
 
1155
    int32_t operator () (int32_t P, uint8_t A) const
 
1156
    {
 
1157
        return (P * A);
 
1158
    }
 
1159
};
 
1160
 
 
1161
class OpPequalsPdivByA
 
1162
{
 
1163
public:
 
1164
    int32_t operator () (int32_t P, float A) const
 
1165
    {
 
1166
        return static_cast <int32_t> ((P / A) + .5);
 
1167
    }
 
1168
 
 
1169
    int32_t operator () (int32_t P, uint8_t A) const
 
1170
    {
 
1171
        return (P / A);
 
1172
    }
 
1173
};
 
1174
 
 
1175
class OpPequalsAdivByP
 
1176
{
 
1177
public:
 
1178
    int32_t operator () (int32_t P, float A) const
 
1179
    {
 
1180
        return static_cast <int32_t> ((A / P) + .5);
 
1181
    }
 
1182
 
 
1183
    int32_t operator () (int32_t P, uint8_t A) const
 
1184
    {
 
1185
        return (A / P);
 
1186
    }
 
1187
};
 
1188
 
 
1189
class OpPequalsMinPA
 
1190
{
 
1191
public:
 
1192
    int32_t operator () (int32_t P, float A) const
 
1193
    {
 
1194
        int32_t intA = static_cast <int32_t> (A + .5);
 
1195
        return ((intA > P) ? P : intA);
 
1196
    }
 
1197
 
 
1198
    int32_t operator () (int32_t P, uint8_t A) const
 
1199
    {
 
1200
        return ((A > P) ? P : A);
 
1201
    }
 
1202
};
 
1203
 
 
1204
class OpPequalsMaxPA
 
1205
{
 
1206
public:
 
1207
    int32_t operator () (int32_t P, float A) const
 
1208
    {
 
1209
        int32_t intA = static_cast <int32_t> (A + .5);
 
1210
        return ((intA > P) ? intA : P);
 
1211
    }
 
1212
 
 
1213
    int32_t operator () (int32_t P, uint8_t A) const
 
1214
    {
 
1215
        return ((A > P) ? A : P);
 
1216
    }
 
1217
};
 
1218
 
 
1219
//----------------------------------------------------------------------------
 
1220
 
 
1221
class OpPequalsA_Scaled
 
1222
{
 
1223
    float bias;
 
1224
    float multiplier;
 
1225
public:
 
1226
    OpPequalsA_Scaled (float bias, float multiplier)
 
1227
        : bias (bias),
 
1228
          multiplier (multiplier)  { }
 
1229
 
 
1230
    int32_t operator () (int32_t P, float A) const
 
1231
    {
 
1232
        return static_cast <int32_t> (((A + bias) * multiplier) + .5);
 
1233
    }
 
1234
};
 
1235
 
 
1236
class OpPequalsP_Scaled
 
1237
{
 
1238
    float bias;
 
1239
    float multiplier;
 
1240
public:
 
1241
    OpPequalsP_Scaled (float bias, float multiplier)
 
1242
        : bias (bias),
 
1243
          multiplier (multiplier)  { }
 
1244
 
 
1245
    int32_t operator () (int32_t P, float A) const
 
1246
    {
 
1247
        return static_cast <int32_t> (((P + bias) * multiplier) + .5);
 
1248
    }
 
1249
};
 
1250
 
 
1251
class OpPequalsPminusA_Scaled
 
1252
{
 
1253
    float bias;
 
1254
    float multiplier;
 
1255
public:
 
1256
    OpPequalsPminusA_Scaled (float bias, float multiplier)
 
1257
        : bias (bias),
 
1258
          multiplier (multiplier)  { }
 
1259
 
 
1260
    int32_t operator () (int32_t P, float A) const
 
1261
    {
 
1262
        return (static_cast <int32_t>
 
1263
                ((((P - A) + bias) * multiplier) + .5));
 
1264
    }
 
1265
};
 
1266
 
 
1267
class OpPequalsAminusP_Scaled
 
1268
{
 
1269
    float bias;
 
1270
    float multiplier;
 
1271
public:
 
1272
    OpPequalsAminusP_Scaled (float bias, float multiplier)
 
1273
        : bias (bias),
 
1274
          multiplier (multiplier)  { }
 
1275
 
 
1276
    int32_t operator () (int32_t P, float A) const
 
1277
    {
 
1278
        return (static_cast <int32_t>
 
1279
                ((((A - P) + bias) * multiplier) + .5));
 
1280
    }
 
1281
};
 
1282
 
 
1283
class OpPequalsPplusA_Scaled
 
1284
{
 
1285
    float bias;
 
1286
    float multiplier;
 
1287
public:
 
1288
    OpPequalsPplusA_Scaled (float bias, float multiplier)
 
1289
        : bias (bias),
 
1290
          multiplier (multiplier)  { }
 
1291
 
 
1292
    int32_t operator () (int32_t P, float A) const
 
1293
    {
 
1294
        return (static_cast <int32_t>
 
1295
                ((((P + A) + bias) * multiplier) + .5));
 
1296
    }
 
1297
};
 
1298
 
 
1299
class OpPequalsPtimesA_Scaled
 
1300
{
 
1301
    float bias;
 
1302
    float multiplier;
 
1303
public:
 
1304
    OpPequalsPtimesA_Scaled (float bias, float multiplier)
 
1305
        : bias (bias),
 
1306
          multiplier (multiplier)  { }
 
1307
 
 
1308
    int32_t operator () (int32_t P, float A) const
 
1309
    {
 
1310
        return (static_cast <int32_t>
 
1311
                ((((P * A) + bias) * multiplier) + .5));
 
1312
    }
 
1313
};
 
1314
 
 
1315
class OpPequalsPdivByA_Scaled
 
1316
{
 
1317
    float bias;
 
1318
    float multiplier;
 
1319
public:
 
1320
    OpPequalsPdivByA_Scaled (float bias, float multiplier)
 
1321
        : bias (bias),
 
1322
          multiplier (multiplier)  { }
 
1323
 
 
1324
    int32_t operator () (int32_t P, float A) const
 
1325
    {
 
1326
        return (static_cast <int32_t>
 
1327
                ((((P / A) + bias) * multiplier) + .5));
 
1328
    }
 
1329
};
 
1330
 
 
1331
class OpPequalsAdivByP_Scaled
 
1332
{
 
1333
    float bias;
 
1334
    float multiplier;
 
1335
public:
 
1336
    OpPequalsAdivByP_Scaled (float bias, float multiplier)
 
1337
        : bias (bias),
 
1338
          multiplier (multiplier)  { }
 
1339
 
 
1340
    int32_t operator () (int32_t P, float A) const
 
1341
    {
 
1342
        return (static_cast <int32_t>
 
1343
                ((((A / P) + bias) * multiplier) + .5));
 
1344
    }
 
1345
};
 
1346
 
 
1347
class OpPequalsMinPA_Scaled
 
1348
{
 
1349
    float bias;
 
1350
    float multiplier;
 
1351
public:
 
1352
    OpPequalsMinPA_Scaled (float bias, float multiplier)
 
1353
        : bias (bias),
 
1354
          multiplier (multiplier)  { }
 
1355
 
 
1356
    int32_t operator () (int32_t P, float A) const
 
1357
    {
 
1358
        return (static_cast <int32_t>
 
1359
                ((((A > P ? P : A) + bias) * multiplier) + .5));
 
1360
    }
 
1361
};
 
1362
 
 
1363
class OpPequalsMaxPA_Scaled
 
1364
{
 
1365
    float bias;
 
1366
    float multiplier;
 
1367
public:
 
1368
    OpPequalsMaxPA_Scaled (float bias, float multiplier)
 
1369
        : bias (bias),
 
1370
          multiplier (multiplier)  { }
 
1371
 
 
1372
    int32_t operator () (int32_t P, float A) const
 
1373
    {
 
1374
        return (static_cast <int32_t>
 
1375
                ((((A > P ? A : P) + bias) * multiplier) + .5));
 
1376
    }
 
1377
};
 
1378
 
 
1379
//============================================================================
 
1380
 
 
1381
uint8_t ADMVideoSwissArmyKnife::getFrameNumberNoAlloc(uint32_t frame,
 
1382
                                                      uint32_t *len,
 
1383
                                                      ADMImage *data,
 
1384
                                                      uint32_t *flags)
 
1385
{
 
1386
    if (frame >= _info.nb_frames)
 
1387
        return 0;
 
1388
 
 
1389
    if (_param->debug & 1)
 
1390
        printf ("in ADMVideoSwissArmyKnife::getFrameNumberNoAlloc(%d, ...)\n",
 
1391
                frame);
 
1392
 
 
1393
    if (!_in->getFrameNumberNoAlloc (frame, len, _uncompressed, flags))
 
1394
        return 0;
 
1395
 
 
1396
    uint32_t planesize = _info.width * _info.height;
 
1397
    uint32_t size = (planesize * 3) >> 1;
 
1398
    *len = size;
 
1399
 
 
1400
    uint8_t ret = doSwissArmyKnife (_uncompressed, data, _in, this, _param,
 
1401
                                    _info.width, _info.height);
 
1402
    return ret;
 
1403
}
 
1404
 
 
1405
uint8_t
 
1406
ADMVideoSwissArmyKnife::doSwissArmyKnife (ADMImage * image,
 
1407
                                          ADMImage * data,
 
1408
                                          AVDMGenericVideoStream * in,
 
1409
                                          ADMVideoSwissArmyKnife * sak,
 
1410
                                          SWISSARMYKNIFE_PARAM * param,
 
1411
                                          uint32_t width, uint32_t height)
 
1412
{
 
1413
    PersistentInfo * myInfo = sak->myInfo;
 
1414
    uint32_t debug = param->debug;
 
1415
 
 
1416
    bool doingConvolution = (param->input_type == INPUT_CUSTOM_CONVOLUTION);
 
1417
    bool doingRollingAvg = (param->input_type == INPUT_ROLLING_AVERAGE);
 
1418
    bool doingFileImage = (param->input_type == INPUT_FILE_IMAGE_FLOAT
 
1419
                           || param->input_type == INPUT_FILE_IMAGE_INTEGER);
 
1420
    bool doingFileImageFloat = (param->input_type == INPUT_FILE_IMAGE_FLOAT);
 
1421
    bool doingApplyConstant = (param->input_type == INPUT_CONSTANT_VALUE);
 
1422
 
 
1423
    bool needRead = false;
 
1424
    bool needFile = doingConvolution || doingFileImage;
 
1425
 
 
1426
    if (needFile)
 
1427
    {
 
1428
        if (myInfo->input_file_name != param->input_file)
 
1429
        {
 
1430
            myInfo->input_file_name = param->input_file;
 
1431
            myInfo->input_file_mtime = 0;
 
1432
            printf ("SwissArmyKnife: new input file has been selected: %s\n",
 
1433
                    myInfo->input_file_name.c_str());
 
1434
            needRead = true;
 
1435
        }
 
1436
 
 
1437
        // HERE: we should rearrange a bit to move the stat() call out to the
 
1438
        // ctor - we don't need to check it every frame!
 
1439
 
 
1440
        struct stat st;
 
1441
        if (stat (myInfo->input_file_name.c_str(), &st) == -1)
 
1442
        {
 
1443
            perror (myInfo->input_file_name.c_str());
 
1444
            return 0;
 
1445
        }
 
1446
 
 
1447
        if (st.st_mtime != myInfo->input_file_mtime)
 
1448
        {
 
1449
            if (!needRead && myInfo->input_file_mtime)
 
1450
                printf ("SwissArmyKnife: input file %s has been changed - "
 
1451
                        "re-reading it\n", myInfo->input_file_name.c_str());
 
1452
            needRead = true;
 
1453
            myInfo->input_file_mtime = st.st_mtime;
 
1454
        }
 
1455
        else if (!needRead && doingFileImage)
 
1456
        {
 
1457
            if (myInfo->image_data_invalid
 
1458
                || myInfo->image_bias != param->load_bias
 
1459
                || myInfo->image_multiplier != param->load_multiplier)
 
1460
            {
 
1461
                needRead = true;
 
1462
            }
 
1463
        }
 
1464
    }
 
1465
 
 
1466
    FloatVector & kernel = myInfo->kernel;
 
1467
    uint32_t & kernel_w = myInfo->kernel_w;
 
1468
    uint32_t & kernel_h = myInfo->kernel_h;
 
1469
 
 
1470
    uint32_t planesize = width * height;
 
1471
                        
 
1472
    if (needRead)
 
1473
    {
 
1474
        myInfo->histogram_data_invalid = true;
 
1475
 
 
1476
        if (doingConvolution)
 
1477
        {
 
1478
            kernel.clear();
 
1479
            kernel_w = 0;
 
1480
            kernel_h = 0;
 
1481
 
 
1482
            using namespace std;
 
1483
 
 
1484
            const char * filename = myInfo->input_file_name.c_str();
 
1485
            ifstream inputStream (filename);
 
1486
            if (!inputStream)
 
1487
            {
 
1488
                fprintf (stderr, "SwissArmyKnife: can't open input file %s, "
 
1489
                         "but it apparently does exist...(%d)\n",
 
1490
                         filename, errno);
 
1491
                return 0;
 
1492
            }
 
1493
 
 
1494
#ifndef ASSUME_SQUARE_MATRIX
 
1495
            // We read the dimensions as floats just in case they happen to be
 
1496
            // written that way (no reason to punt) - however, we do expect
 
1497
            // that anything to the right of the decimal is 0!
 
1498
 
 
1499
            float dimtmp;
 
1500
            inputStream >> dimtmp;
 
1501
            kernel_w = uint32_t (dimtmp);
 
1502
            if (float (kernel_w) != dimtmp)
 
1503
                printf ("SwissArmyKnife: %s: What exactly do you expect a "
 
1504
                        "width of %f to mean?  Truncating to %d...\n",
 
1505
                        filename, dimtmp, uint32_t (dimtmp));
 
1506
            inputStream >> dimtmp;
 
1507
            kernel_h = uint32_t (dimtmp);
 
1508
            if (float (kernel_h) != dimtmp)
 
1509
                printf ("SwissArmyKnife: %s: What exactly do you expect a "
 
1510
                        "height of %f to mean?  Truncating to %d...\n",
 
1511
                        filename, dimtmp, uint32_t (dimtmp));
 
1512
            if (kernel_w < 1 || (kernel_w & 1) == 0
 
1513
                || kernel_h < 1 || (kernel_h & 1) == 0)
 
1514
            {
 
1515
                printf ("SwissArmyKnife: %s: Can't handle a convolution "
 
1516
                        "kernel with dimensions %dx%d - both dimensions "
 
1517
                        "must be odd (and positive)\n",
 
1518
                        filename, int (kernel_w), int (kernel_h));
 
1519
                myInfo->input_file_mtime = 0;  // force re-read, avoid crash
 
1520
                return 0;
 
1521
            }
 
1522
#endif
 
1523
 
 
1524
            copy (istream_iterator <float> (inputStream),
 
1525
                  istream_iterator <float> (),
 
1526
                  back_inserter (kernel));
 
1527
 
 
1528
#ifdef ASSUME_SQUARE_MATRIX
 
1529
            kernel_dim = uint32_t (sqrtf (kernel.size()));
 
1530
            if (kernel_dim * kernel_dim != kernel.size())
 
1531
            {
 
1532
                if ((kernel_dim + 1) * (kernel_dim + 1) == kernel.size())
 
1533
                    ++kernel_dim;
 
1534
                else
 
1535
                {
 
1536
                    printf ("SwissArmyKnife: Can't determine matrix "
 
1537
                            "dimensions to explain %d input values! "
 
1538
                            "(sqrt(%d) = %f)\n",
 
1539
                            kernel.size(), kernel.size(),
 
1540
                            sqrt (kernel.size()));
 
1541
                    kernel_dim = 0;
 
1542
                    return 0;
 
1543
                }
 
1544
            }
 
1545
#endif
 
1546
 
 
1547
            printf ("SwissArmyKnife: read %d convolution kernel values "
 
1548
                    "from %s (%dx%d):\n",
 
1549
                    kernel.size(), filename, kernel_w, kernel_h);
 
1550
            if (debug & 8)
 
1551
            {
 
1552
                FloatVector::const_iterator kit = kernel.begin();
 
1553
                int count = 0;
 
1554
                while (kit != kernel.end())
 
1555
                {
 
1556
                    printf ("%.6f%c", *kit++,
 
1557
                            (++count % kernel_w) ? ' ' : '\n');
 
1558
                }
 
1559
                if (count % kernel_w)
 
1560
                    printf ("[incomplete?!]\n");
 
1561
            }
 
1562
        }
 
1563
        else // file image (not convolution)
 
1564
        {
 
1565
            ADM_assert (param->input_type == INPUT_FILE_IMAGE_FLOAT
 
1566
                        || param->input_type == INPUT_FILE_IMAGE_INTEGER);
 
1567
 
 
1568
            const char * filename = myInfo->input_file_name.c_str();
 
1569
            FILE * fin = fopen (filename, "rb");
 
1570
            if (!fin)
 
1571
            {
 
1572
                fprintf (stderr, "SwissArmyKnife: can't open input file %s, "
 
1573
                         "but it apparently does exist...(%d)\n",
 
1574
                         filename, errno);
 
1575
                return 0;
 
1576
            }
 
1577
 
 
1578
            ADMVideoComputeAverage::FileHeader header;
 
1579
            int nread = fread (&header, sizeof (header), 1, fin);
 
1580
            if (nread != 1 || strncmp (header.magic, "DGCMimgF", 8) != 0)
 
1581
            {
 
1582
                fprintf (stderr, "SwissArmyKnife: %s does not appear to be a "
 
1583
                         "valid DG/CM floating-point raw image file (produced "
 
1584
                         "by the ComputeAverage filter)\n", filename);
 
1585
                fclose (fin);
 
1586
                return 0;
 
1587
            }
 
1588
 
 
1589
            uint32_t width = header.width;
 
1590
            uint32_t height = header.height;
 
1591
            uint32_t pixelcount = width * height;
 
1592
 
 
1593
            if (width > 2000 || height > 2000)
 
1594
            {
 
1595
                fprintf (stderr, "SwissArmyKnife: invalid image dimensions "
 
1596
                         "(%dx%d) in %s\n",
 
1597
                         int (width), int (height), filename);
 
1598
                fclose (fin);
 
1599
                return 0;
 
1600
            }
 
1601
 
 
1602
            myInfo->image_data_invalid = true;
 
1603
            delete [] myInfo->image_float;
 
1604
            delete [] myInfo->image_int;
 
1605
 
 
1606
            myInfo->image_float = new float [pixelcount];
 
1607
 
 
1608
            nread = fread (myInfo->image_float, sizeof (float), pixelcount, fin);
 
1609
            fclose (fin);
 
1610
            if (nread != pixelcount)
 
1611
            {
 
1612
                fprintf (stderr, "SwissArmyKnife: failed to read image data "
 
1613
                         "(%ux%u = %u) from %s (got %u)\n",
 
1614
                         width, height, pixelcount, filename, nread);
 
1615
                delete [] myInfo->image_float;
 
1616
                myInfo->image_float = 0;
 
1617
                return 0;
 
1618
            }
 
1619
 
 
1620
            printf ("SwissArmyKnife: successfully loaded image data "
 
1621
                    "(%ux%u = %u) from %s\n",
 
1622
                    width, height, pixelcount, filename);
 
1623
 
 
1624
            myInfo->image_int = new uint8_t [pixelcount];
 
1625
            float * floatpixp = myInfo->image_float + pixelcount;
 
1626
            uint8_t * intpixp = myInfo->image_int + pixelcount;
 
1627
 
 
1628
            if (param->load_bias == 0.0 && param->load_multiplier == 1.0)
 
1629
            {
 
1630
                printf ("Converting %u pixels to integer values (and keeping "
 
1631
                        "the floats, too)\n", pixelcount);
 
1632
 
 
1633
                ++pixelcount;
 
1634
                while (--pixelcount)
 
1635
                {
 
1636
                    *--intpixp = static_cast <uint8_t> (*--floatpixp + 0.5);
 
1637
                }
 
1638
            }
 
1639
            else
 
1640
            {
 
1641
                float load_bias = param->load_bias;
 
1642
                float load_multiplier = param->load_multiplier;
 
1643
 
 
1644
                printf ("applying P = (P + %.6f) * %.6f to %u pixels\n",
 
1645
                        load_bias, load_multiplier, pixelcount);
 
1646
 
 
1647
                ++pixelcount;
 
1648
                while (--pixelcount)
 
1649
                {
 
1650
                    float floatpix
 
1651
                        = (*--floatpixp + load_bias) * load_multiplier;
 
1652
                    *floatpixp = floatpix;
 
1653
 
 
1654
                    uint8_t intpix;
 
1655
                    if (floatpix < 0)
 
1656
                        intpix = 0;
 
1657
                    else if (floatpix > 255)
 
1658
                        intpix = 255;
 
1659
                    else
 
1660
                        intpix = static_cast <uint8_t> (floatpix + 0.5);
 
1661
 
 
1662
                    *--intpixp = intpix;
 
1663
                }
 
1664
            }
 
1665
 
 
1666
            myInfo->image_w = width;
 
1667
            myInfo->image_h = height;
 
1668
            myInfo->image_bias = param->load_bias;
 
1669
            myInfo->image_multiplier = param->load_multiplier;
 
1670
            myInfo->image_data_invalid = false;
 
1671
        }
 
1672
    }
 
1673
    else if (doingRollingAvg)
 
1674
    {
 
1675
        if (!myInfo->bg
 
1676
            || myInfo->bg_x != width || myInfo->bg_y != height
 
1677
            || myInfo->bg_mca != param->memory_constant_alpha
 
1678
            || myInfo->bg_isf != param->init_start_frame
 
1679
            || myInfo->bg_ief != param->init_end_frame
 
1680
            || myInfo->bg_ibr != param->init_by_rolling)
 
1681
        {
 
1682
            if (!myInfo->bg || myInfo->bg_x != width || myInfo->bg_y != height)
 
1683
            {
 
1684
                myInfo->bg_x = width;
 
1685
                myInfo->bg_y = height;
 
1686
                delete [] myInfo->bg;
 
1687
                myInfo->bg = new float [planesize];
 
1688
            }
 
1689
 
 
1690
            myInfo->histogram_data_invalid = true;
 
1691
 
 
1692
            myInfo->bg_mca = param->memory_constant_alpha;
 
1693
            myInfo->bg_isf = param->init_start_frame;
 
1694
            myInfo->bg_ief = param->init_end_frame;
 
1695
            myInfo->bg_ibr = param->init_by_rolling;
 
1696
 
 
1697
            if (myInfo->bg_isf && myInfo->bg_isf <= myInfo->bg_ief)
 
1698
            {
 
1699
                uint32_t do_frames = myInfo->bg_ief - myInfo->bg_isf + 1;
 
1700
 
 
1701
                uint32_t firstframe = myInfo->bg_isf - 1;
 
1702
                uint32_t lastframe = myInfo->bg_ief - 1;
 
1703
                const ADV_Info & info = sak->getInfo();
 
1704
                if (lastframe >= info.nb_frames)
 
1705
                {
 
1706
                    lastframe = info.nb_frames - 1;
 
1707
                    if (firstframe > info.nb_frames)
 
1708
                    {
 
1709
                        firstframe = lastframe - do_frames + 1;
 
1710
                        if (firstframe > info.nb_frames)
 
1711
                            firstframe = 0;
 
1712
                    }
 
1713
                    do_frames = lastframe - firstframe + 1;
 
1714
                }
 
1715
 
 
1716
                // if (debug & 2)
 
1717
                printf ("Getting a \"head start\" on rolling average by "
 
1718
                        "computing a %s %d frames of size %dx%d from %d to "
 
1719
                        "%d with alpha = %.6f\n",
 
1720
                        myInfo->bg_ibr ? "rolling average over"
 
1721
                        : "straight average of",
 
1722
                        do_frames, myInfo->bg_x, myInfo->bg_y,
 
1723
                        firstframe + 1, lastframe + 1, myInfo->bg_mca);
 
1724
 
 
1725
                ADMImage aimage (myInfo->bg_x, myInfo->bg_y);
 
1726
 
 
1727
                // HERE: for speed, we do luma (Y plane) only.  However, some
 
1728
                // users might want chroma, too... we should make that an option
 
1729
                // or something.  (...in which case bg should be big enough for
 
1730
                // all three planes.)
 
1731
 
 
1732
                if (myInfo->bg_ibr)
 
1733
                {
 
1734
                    // We want to "prime" the rolling average with the values from
 
1735
                    // the first frame (rather than zeroes, which doesn't seem to
 
1736
                    // work out well).  So we do the following block just once,
 
1737
                    // but in its own scope to not collide with the locals of the
 
1738
                    // loop that follows:
 
1739
                    {
 
1740
                        uint32_t flen;
 
1741
                        uint32_t fflags = 0;
 
1742
                        if (!in->getFrameNumberNoAlloc (firstframe, &flen,
 
1743
                                                        &aimage, &fflags))
 
1744
                            return 0;
 
1745
 
 
1746
                        uint8_t * currp = YPLANE (&aimage) + planesize;
 
1747
                        float * bgp = myInfo->bg + planesize;
 
1748
                        uint32_t pixremaining = planesize + 1;
 
1749
                        while (--pixremaining)
 
1750
                        {
 
1751
                            *--bgp = *--currp;
 
1752
                        }
 
1753
 
 
1754
                        ++firstframe; // don't include this one again
 
1755
                    }
 
1756
 
 
1757
                    float alpha = param->memory_constant_alpha;
 
1758
                    float oneminusalpha = 1 - alpha;
 
1759
 
 
1760
                    for (int fnum = firstframe; fnum <= lastframe; fnum++)
 
1761
                    {
 
1762
                        uint32_t flen;
 
1763
                        uint32_t fflags = 0;
 
1764
                        if (!in->getFrameNumberNoAlloc (fnum, &flen,
 
1765
                                                        &aimage, &fflags))
 
1766
                            return 0;
 
1767
 
 
1768
                        uint8_t * currp = YPLANE (&aimage) + planesize;
 
1769
                        float * bgp = myInfo->bg + planesize;
 
1770
                        uint32_t pixremaining = planesize + 1;
 
1771
                        while (--pixremaining)
 
1772
                        {
 
1773
                            --bgp;
 
1774
                            *bgp = (*bgp * oneminusalpha) + (*--currp * alpha);
 
1775
                        }
 
1776
                    }
 
1777
                }
 
1778
                else // head start uses straight average (not rolling average)
 
1779
                {
 
1780
                    uint32_t sums [planesize];
 
1781
                    memset (sums, 0, planesize * sizeof sums[0]);
 
1782
 
 
1783
                    for (int fnum = firstframe; fnum <= lastframe; fnum++)
 
1784
                    {
 
1785
                        uint32_t flen;
 
1786
                        uint32_t fflags = 0;
 
1787
                        if (!in->getFrameNumberNoAlloc (fnum, &flen,
 
1788
                                                        &aimage, &fflags))
 
1789
                            return 0;
 
1790
 
 
1791
                        uint8_t * currp = YPLANE (&aimage) + planesize;
 
1792
                        uint32_t * sump = sums + planesize;
 
1793
                        uint32_t pixremaining = planesize + 1;
 
1794
                        while (--pixremaining)
 
1795
                        {
 
1796
                            *--sump += *--currp;
 
1797
                        }
 
1798
                    }
 
1799
 
 
1800
                    float * bgp = myInfo->bg + planesize;
 
1801
                    uint32_t * sump = sums + planesize;
 
1802
                    uint32_t pixremaining = planesize + 1;
 
1803
                    // we use a floating point multiply of a reciprocal rather
 
1804
                    // than a floating point divide, because floating point
 
1805
                    // folklore says the multiply will be faster.
 
1806
                    float one_over_framecount = 1.0 / do_frames;
 
1807
                    while (--pixremaining)
 
1808
                    {
 
1809
                        *--bgp = *--sump * one_over_framecount;
 
1810
                    }
 
1811
                }
 
1812
 
 
1813
                // if (debug & 2)
 
1814
                printf ("Done computing head start.\n");
 
1815
            }
 
1816
            else // if (debug & 2)
 
1817
            {
 
1818
                printf ("Starting with new 0 baseline background\n");
 
1819
                memset (myInfo->bg, 0, planesize * sizeof (myInfo->bg[0]));
 
1820
            }
 
1821
        }
 
1822
        else
 
1823
        {
 
1824
            if (debug & 4)
 
1825
                printf ("Using existing baseline background of size %dx%d with "
 
1826
                        "alpha = %.6f (1/%d)\n", myInfo->bg_x, myInfo->bg_y,
 
1827
                        myInfo->bg_mca);
 
1828
        }
 
1829
    }                   
 
1830
 
 
1831
    uint8_t * imagePixels = YPLANE (image);
 
1832
 
 
1833
    ImageTool imtool (imagePixels, width, height, data);
 
1834
    imtool.setDebug (debug);
 
1835
 
 
1836
    Histogram * histogram = 0;
 
1837
    int32_t bias = param->bias;
 
1838
    uint32_t tool = param->tool;
 
1839
 
 
1840
    // HERE: give some thought to the general issue of keeping myInfo & param
 
1841
    // in sync, and resetting the histogram (or whatever) when things change.
 
1842
 
 
1843
    if (param->histogram_frame_interval != 0)
 
1844
    {
 
1845
        histogram = new Histogram (myInfo->histogram_input_data,
 
1846
                                   myInfo->histogram_output_data,
 
1847
                                   param->histogram_frame_interval,
 
1848
                                   myInfo->histogram_frame_count,
 
1849
                                   width * height);
 
1850
        tool += TOOL_ADD_HISTOGRAM;
 
1851
        if (myInfo->histogram_frame_interval !=
 
1852
            param->histogram_frame_interval)
 
1853
        {
 
1854
            if (myInfo->histogram_frame_interval)
 
1855
                myInfo->histogram_data_invalid = true;
 
1856
            myInfo->histogram_frame_interval
 
1857
                = param->histogram_frame_interval;
 
1858
        }
 
1859
 
 
1860
        if (myInfo->histogram_data_invalid)
 
1861
        {
 
1862
            myInfo->histogram_data_invalid = false;
 
1863
            histogram->reset();
 
1864
        }
 
1865
    }
 
1866
 
 
1867
    float rbias = param->result_bias;
 
1868
    float rmultiplier = param->result_multiplier;
 
1869
    if (fabsf (rbias) >= 0.0001 || fabsf (rmultiplier - 1.0) >= 0.0001)
 
1870
    {
 
1871
        tool += TOOL_ADD_SCALING;
 
1872
    }
 
1873
 
 
1874
    if (doingConvolution)
 
1875
    {
 
1876
        if (kernel.empty())
 
1877
        {
 
1878
            fprintf (stderr, "No convolution kernel loaded - can't do "
 
1879
                     "convolution!\n");
 
1880
            return 0;
 
1881
        }
 
1882
 
 
1883
        switch (tool)
 
1884
        {
 
1885
        case TOOL_A:
 
1886
            imtool.convolve (kernel, kernel_w, kernel_h, bias, OpPequalsA(), HistogramNull());
 
1887
            break;
 
1888
        case TOOL_P: // HERE: we could optimize this if we wanted to
 
1889
            imtool.convolve (kernel, kernel_w, kernel_h, bias, OpPequalsP(), HistogramNull());
 
1890
            break;
 
1891
        case TOOL_P_MINUS_A:
 
1892
            imtool.convolve (kernel, kernel_w, kernel_h, bias, OpPequalsPminusA(), HistogramNull());
 
1893
            break;
 
1894
        case TOOL_A_MINUS_P:
 
1895
            imtool.convolve (kernel, kernel_w, kernel_h, bias, OpPequalsAminusP(), HistogramNull());
 
1896
            break;
 
1897
        case TOOL_P_PLUS_A:
 
1898
            imtool.convolve (kernel, kernel_w, kernel_h, bias, OpPequalsPplusA(), HistogramNull());
 
1899
            break;
 
1900
        case TOOL_P_TIMES_A:
 
1901
            imtool.convolve (kernel, kernel_w, kernel_h, bias, OpPequalsPtimesA(), HistogramNull());
 
1902
            break;
 
1903
        case TOOL_P_DIVBY_A:
 
1904
            imtool.convolve (kernel, kernel_w, kernel_h, bias, OpPequalsPdivByA(), HistogramNull());
 
1905
            break;
 
1906
        case TOOL_A_DIVBY_P:
 
1907
            imtool.convolve (kernel, kernel_w, kernel_h, bias, OpPequalsAdivByP(), HistogramNull());
 
1908
            break;
 
1909
        case TOOL_MIN_P_A:
 
1910
            imtool.convolve (kernel, kernel_w, kernel_h, bias, OpPequalsMinPA(), HistogramNull());
 
1911
            break;
 
1912
        case TOOL_MAX_P_A:
 
1913
            imtool.convolve (kernel, kernel_w, kernel_h, bias, OpPequalsMaxPA(), HistogramNull());
 
1914
            break;
 
1915
 
 
1916
        case TOOL_A_WITH_HISTOGRAM:
 
1917
            imtool.convolve (kernel, kernel_w, kernel_h, bias, OpPequalsA(), *histogram);
 
1918
            break;
 
1919
        case TOOL_P_WITH_HISTOGRAM: // HERE: we could optimize this if we wanted to
 
1920
            imtool.convolve (kernel, kernel_w, kernel_h, bias, OpPequalsP(), *histogram);
 
1921
            break;
 
1922
        case TOOL_P_MINUS_A_WITH_HISTOGRAM:
 
1923
            imtool.convolve (kernel, kernel_w, kernel_h, bias, OpPequalsPminusA(), *histogram);
 
1924
            break;
 
1925
        case TOOL_A_MINUS_P_WITH_HISTOGRAM:
 
1926
            imtool.convolve (kernel, kernel_w, kernel_h, bias, OpPequalsAminusP(), *histogram);
 
1927
            break;
 
1928
        case TOOL_P_PLUS_A_WITH_HISTOGRAM:
 
1929
            imtool.convolve (kernel, kernel_w, kernel_h, bias, OpPequalsPplusA(), *histogram);
 
1930
            break;
 
1931
        case TOOL_P_TIMES_A_WITH_HISTOGRAM:
 
1932
            imtool.convolve (kernel, kernel_w, kernel_h, bias, OpPequalsPtimesA(), *histogram);
 
1933
            break;
 
1934
        case TOOL_P_DIVBY_A_WITH_HISTOGRAM:
 
1935
            imtool.convolve (kernel, kernel_w, kernel_h, bias, OpPequalsPdivByA(), *histogram);
 
1936
            break;
 
1937
        case TOOL_A_DIVBY_P_WITH_HISTOGRAM:
 
1938
            imtool.convolve (kernel, kernel_w, kernel_h, bias, OpPequalsAdivByP(), *histogram);
 
1939
            break;
 
1940
        case TOOL_MIN_P_A_WITH_HISTOGRAM:
 
1941
            imtool.convolve (kernel, kernel_w, kernel_h, bias, OpPequalsMinPA(), *histogram);
 
1942
            break;
 
1943
        case TOOL_MAX_P_A_WITH_HISTOGRAM:
 
1944
            imtool.convolve (kernel, kernel_w, kernel_h, bias, OpPequalsMaxPA(), *histogram);
 
1945
            break;
 
1946
 
 
1947
        case TOOL_A_SCALED:
 
1948
            imtool.convolve (kernel, kernel_w, kernel_h, bias,
 
1949
                             OpPequalsA_Scaled (rbias, rmultiplier), HistogramNull());
 
1950
            break;
 
1951
        case TOOL_P_SCALED: // HERE_SCALED: we could optimize this if we wanted to
 
1952
            imtool.convolve (kernel, kernel_w, kernel_h, bias,
 
1953
                             OpPequalsP_Scaled (rbias, rmultiplier), HistogramNull());
 
1954
            break;
 
1955
        case TOOL_P_MINUS_A_SCALED:
 
1956
            imtool.convolve (kernel, kernel_w, kernel_h, bias,
 
1957
                             OpPequalsPminusA_Scaled (rbias, rmultiplier), HistogramNull());
 
1958
            break;
 
1959
        case TOOL_A_MINUS_P_SCALED:
 
1960
            imtool.convolve (kernel, kernel_w, kernel_h, bias,
 
1961
                             OpPequalsAminusP_Scaled (rbias, rmultiplier), HistogramNull());
 
1962
            break;
 
1963
        case TOOL_P_PLUS_A_SCALED:
 
1964
            imtool.convolve (kernel, kernel_w, kernel_h, bias,
 
1965
                             OpPequalsPplusA_Scaled (rbias, rmultiplier), HistogramNull());
 
1966
            break;
 
1967
        case TOOL_P_TIMES_A_SCALED:
 
1968
            imtool.convolve (kernel, kernel_w, kernel_h, bias,
 
1969
                             OpPequalsPtimesA_Scaled (rbias, rmultiplier), HistogramNull());
 
1970
            break;
 
1971
        case TOOL_P_DIVBY_A_SCALED:
 
1972
            imtool.convolve (kernel, kernel_w, kernel_h, bias,
 
1973
                             OpPequalsPdivByA_Scaled (rbias, rmultiplier), HistogramNull());
 
1974
            break;
 
1975
        case TOOL_A_DIVBY_P_SCALED:
 
1976
            imtool.convolve (kernel, kernel_w, kernel_h, bias,
 
1977
                             OpPequalsAdivByP_Scaled (rbias, rmultiplier), HistogramNull());
 
1978
            break;
 
1979
        case TOOL_MIN_P_A_SCALED:
 
1980
            imtool.convolve (kernel, kernel_w, kernel_h, bias,
 
1981
                             OpPequalsMinPA_Scaled (rbias, rmultiplier), HistogramNull());
 
1982
            break;
 
1983
        case TOOL_MAX_P_A_SCALED:
 
1984
            imtool.convolve (kernel, kernel_w, kernel_h, bias,
 
1985
                             OpPequalsMaxPA_Scaled (rbias, rmultiplier), HistogramNull());
 
1986
            break;
 
1987
 
 
1988
        case TOOL_A_SCALED_WITH_HISTOGRAM:
 
1989
            imtool.convolve (kernel, kernel_w, kernel_h, bias,
 
1990
                             OpPequalsA_Scaled (rbias, rmultiplier), *histogram);
 
1991
            break;
 
1992
        case TOOL_P_SCALED_WITH_HISTOGRAM: // HERE: we could optimize this if we wanted to
 
1993
            imtool.convolve (kernel, kernel_w, kernel_h, bias,
 
1994
                             OpPequalsP_Scaled (rbias, rmultiplier), *histogram);
 
1995
            break;
 
1996
        case TOOL_P_MINUS_A_SCALED_WITH_HISTOGRAM:
 
1997
            imtool.convolve (kernel, kernel_w, kernel_h, bias,
 
1998
                             OpPequalsPminusA_Scaled (rbias, rmultiplier), *histogram);
 
1999
            break;
 
2000
        case TOOL_A_MINUS_P_SCALED_WITH_HISTOGRAM:
 
2001
            imtool.convolve (kernel, kernel_w, kernel_h, bias,
 
2002
                             OpPequalsAminusP_Scaled (rbias, rmultiplier), *histogram);
 
2003
            break;
 
2004
        case TOOL_P_PLUS_A_SCALED_WITH_HISTOGRAM:
 
2005
            imtool.convolve (kernel, kernel_w, kernel_h, bias,
 
2006
                             OpPequalsPplusA_Scaled (rbias, rmultiplier), *histogram);
 
2007
            break;
 
2008
        case TOOL_P_TIMES_A_SCALED_WITH_HISTOGRAM:
 
2009
            imtool.convolve (kernel, kernel_w, kernel_h, bias,
 
2010
                             OpPequalsPtimesA_Scaled (rbias, rmultiplier), *histogram);
 
2011
            break;
 
2012
        case TOOL_P_DIVBY_A_SCALED_WITH_HISTOGRAM:
 
2013
            imtool.convolve (kernel, kernel_w, kernel_h, bias,
 
2014
                             OpPequalsPdivByA_Scaled (rbias, rmultiplier), *histogram);
 
2015
            break;
 
2016
        case TOOL_A_DIVBY_P_SCALED_WITH_HISTOGRAM:
 
2017
            imtool.convolve (kernel, kernel_w, kernel_h, bias,
 
2018
                             OpPequalsAdivByP_Scaled (rbias, rmultiplier), *histogram);
 
2019
            break;
 
2020
        case TOOL_MIN_P_A_SCALED_WITH_HISTOGRAM:
 
2021
            imtool.convolve (kernel, kernel_w, kernel_h, bias,
 
2022
                             OpPequalsMinPA_Scaled (rbias, rmultiplier), *histogram);
 
2023
            break;
 
2024
        case TOOL_MAX_P_A_SCALED_WITH_HISTOGRAM:
 
2025
            imtool.convolve (kernel, kernel_w, kernel_h, bias,
 
2026
                             OpPequalsMaxPA_Scaled (rbias, rmultiplier), *histogram);
 
2027
            break;
 
2028
 
 
2029
        default:
 
2030
            fprintf (stderr, "SwissArmyKnife: unknown operation (tool) %d!\n",
 
2031
                     param->tool);
 
2032
            return 0;
 
2033
        }
 
2034
    }
 
2035
    else if (doingRollingAvg)
 
2036
    {
 
2037
        switch (tool)
 
2038
        {
 
2039
        case TOOL_A:
 
2040
            sak->computeRollingAverage (image, data, planesize, param, bias,
 
2041
                                        OpPequalsA(), HistogramNull());
 
2042
            break;
 
2043
        case TOOL_P: // HERE: we could optimize this if we wanted to
 
2044
            sak->computeRollingAverage (image, data, planesize, param, bias,
 
2045
                                        OpPequalsP(), HistogramNull());
 
2046
            break;
 
2047
        case TOOL_P_MINUS_A:
 
2048
            sak->computeRollingAverage (image, data, planesize, param, bias,
 
2049
                                        OpPequalsPminusA(), HistogramNull());
 
2050
            break;
 
2051
        case TOOL_A_MINUS_P:
 
2052
            sak->computeRollingAverage (image, data, planesize, param, bias,
 
2053
                                        OpPequalsAminusP(), HistogramNull());
 
2054
            break;
 
2055
        case TOOL_P_PLUS_A:
 
2056
            sak->computeRollingAverage (image, data, planesize, param, bias,
 
2057
                                        OpPequalsPplusA(), HistogramNull());
 
2058
            break;
 
2059
        case TOOL_P_TIMES_A:
 
2060
            sak->computeRollingAverage (image, data, planesize, param, bias,
 
2061
                                        OpPequalsPtimesA(), HistogramNull());
 
2062
            break;
 
2063
        case TOOL_P_DIVBY_A:
 
2064
            sak->computeRollingAverage (image, data, planesize, param, bias,
 
2065
                                        OpPequalsPdivByA(), HistogramNull());
 
2066
            break;
 
2067
        case TOOL_A_DIVBY_P:
 
2068
            sak->computeRollingAverage (image, data, planesize, param, bias,
 
2069
                                        OpPequalsAdivByP(), HistogramNull());
 
2070
            break;
 
2071
        case TOOL_MIN_P_A:
 
2072
            sak->computeRollingAverage (image, data, planesize, param, bias,
 
2073
                                        OpPequalsMinPA(), HistogramNull());
 
2074
            break;
 
2075
        case TOOL_MAX_P_A:
 
2076
            sak->computeRollingAverage (image, data, planesize, param, bias,
 
2077
                                        OpPequalsMaxPA(), HistogramNull());
 
2078
            break;
 
2079
 
 
2080
        case TOOL_A_WITH_HISTOGRAM:
 
2081
            sak->computeRollingAverage (image, data, planesize, param, bias,
 
2082
                                        OpPequalsA(), *histogram);
 
2083
            break;
 
2084
        case TOOL_P_WITH_HISTOGRAM: // HERE: we could optimize this if we wanted to
 
2085
            sak->computeRollingAverage (image, data, planesize, param, bias,
 
2086
                                        OpPequalsP(), *histogram);
 
2087
            break;
 
2088
        case TOOL_P_MINUS_A_WITH_HISTOGRAM:
 
2089
            sak->computeRollingAverage (image, data, planesize, param, bias,
 
2090
                                        OpPequalsPminusA(), *histogram);
 
2091
            break;
 
2092
        case TOOL_A_MINUS_P_WITH_HISTOGRAM:
 
2093
            sak->computeRollingAverage (image, data, planesize, param, bias,
 
2094
                                        OpPequalsAminusP(), *histogram);
 
2095
            break;
 
2096
        case TOOL_P_PLUS_A_WITH_HISTOGRAM:
 
2097
            sak->computeRollingAverage (image, data, planesize, param, bias,
 
2098
                                        OpPequalsPplusA(), *histogram);
 
2099
            break;
 
2100
        case TOOL_P_TIMES_A_WITH_HISTOGRAM:
 
2101
            sak->computeRollingAverage (image, data, planesize, param, bias,
 
2102
                                        OpPequalsPtimesA(), *histogram);
 
2103
            break;
 
2104
        case TOOL_P_DIVBY_A_WITH_HISTOGRAM:
 
2105
            sak->computeRollingAverage (image, data, planesize, param, bias,
 
2106
                                        OpPequalsPdivByA(), *histogram);
 
2107
            break;
 
2108
        case TOOL_A_DIVBY_P_WITH_HISTOGRAM:
 
2109
            sak->computeRollingAverage (image, data, planesize, param, bias,
 
2110
                                        OpPequalsAdivByP(), *histogram);
 
2111
            break;
 
2112
        case TOOL_MIN_P_A_WITH_HISTOGRAM:
 
2113
            sak->computeRollingAverage (image, data, planesize, param, bias,
 
2114
                                        OpPequalsMinPA(), *histogram);
 
2115
            break;
 
2116
        case TOOL_MAX_P_A_WITH_HISTOGRAM:
 
2117
            sak->computeRollingAverage (image, data, planesize, param, bias,
 
2118
                                        OpPequalsMaxPA(), *histogram);
 
2119
            break;
 
2120
 
 
2121
        case TOOL_A_SCALED:
 
2122
            sak->computeRollingAverage (image, data, planesize, param, bias,
 
2123
                                        OpPequalsA_Scaled (rbias, rmultiplier),
 
2124
                                        HistogramNull());
 
2125
            break;
 
2126
        case TOOL_P_SCALED: // HERE_SCALED: we could optimize this if we wanted to
 
2127
            sak->computeRollingAverage (image, data, planesize, param, bias,
 
2128
                                        OpPequalsP_Scaled (rbias, rmultiplier),
 
2129
                                        HistogramNull());
 
2130
            break;
 
2131
        case TOOL_P_MINUS_A_SCALED:
 
2132
            sak->computeRollingAverage (image, data, planesize, param, bias,
 
2133
                                        OpPequalsPminusA_Scaled (rbias, rmultiplier),
 
2134
                                        HistogramNull());
 
2135
            break;
 
2136
        case TOOL_A_MINUS_P_SCALED:
 
2137
            sak->computeRollingAverage (image, data, planesize, param, bias,
 
2138
                                        OpPequalsAminusP_Scaled (rbias, rmultiplier),
 
2139
                                        HistogramNull());
 
2140
            break;
 
2141
        case TOOL_P_PLUS_A_SCALED:
 
2142
            sak->computeRollingAverage (image, data, planesize, param, bias,
 
2143
                                        OpPequalsPplusA_Scaled (rbias, rmultiplier),
 
2144
                                        HistogramNull());
 
2145
            break;
 
2146
        case TOOL_P_TIMES_A_SCALED:
 
2147
            sak->computeRollingAverage (image, data, planesize, param, bias,
 
2148
                                        OpPequalsPtimesA_Scaled (rbias, rmultiplier),
 
2149
                                        HistogramNull());
 
2150
            break;
 
2151
        case TOOL_P_DIVBY_A_SCALED:
 
2152
            sak->computeRollingAverage (image, data, planesize, param, bias,
 
2153
                                        OpPequalsPdivByA_Scaled (rbias, rmultiplier),
 
2154
                                        HistogramNull());
 
2155
            break;
 
2156
        case TOOL_A_DIVBY_P_SCALED:
 
2157
            sak->computeRollingAverage (image, data, planesize, param, bias,
 
2158
                                        OpPequalsAdivByP_Scaled (rbias, rmultiplier),
 
2159
                                        HistogramNull());
 
2160
            break;
 
2161
        case TOOL_MIN_P_A_SCALED:
 
2162
            sak->computeRollingAverage (image, data, planesize, param, bias,
 
2163
                                        OpPequalsMinPA_Scaled (rbias, rmultiplier),
 
2164
                                        HistogramNull());
 
2165
            break;
 
2166
        case TOOL_MAX_P_A_SCALED:
 
2167
            sak->computeRollingAverage (image, data, planesize, param, bias,
 
2168
                                        OpPequalsMaxPA_Scaled (rbias, rmultiplier),
 
2169
                                        HistogramNull());
 
2170
            break;
 
2171
 
 
2172
        case TOOL_A_SCALED_WITH_HISTOGRAM:
 
2173
            sak->computeRollingAverage (image, data, planesize, param, bias,
 
2174
                                        OpPequalsA_Scaled (rbias, rmultiplier),
 
2175
                                        *histogram);
 
2176
            break;
 
2177
        case TOOL_P_SCALED_WITH_HISTOGRAM: // HERE: we could optimize this if we wanted to
 
2178
            sak->computeRollingAverage (image, data, planesize, param, bias,
 
2179
                                        OpPequalsP_Scaled (rbias, rmultiplier),
 
2180
                                        *histogram);
 
2181
            break;
 
2182
        case TOOL_P_MINUS_A_SCALED_WITH_HISTOGRAM:
 
2183
            sak->computeRollingAverage (image, data, planesize, param, bias,
 
2184
                                        OpPequalsPminusA_Scaled (rbias, rmultiplier),
 
2185
                                        *histogram);
 
2186
            break;
 
2187
        case TOOL_A_MINUS_P_SCALED_WITH_HISTOGRAM:
 
2188
            sak->computeRollingAverage (image, data, planesize, param, bias,
 
2189
                                        OpPequalsAminusP_Scaled (rbias, rmultiplier),
 
2190
                                        *histogram);
 
2191
            break;
 
2192
        case TOOL_P_PLUS_A_SCALED_WITH_HISTOGRAM:
 
2193
            sak->computeRollingAverage (image, data, planesize, param, bias,
 
2194
                                        OpPequalsPplusA_Scaled (rbias, rmultiplier),
 
2195
                                        *histogram);
 
2196
            break;
 
2197
        case TOOL_P_TIMES_A_SCALED_WITH_HISTOGRAM:
 
2198
            sak->computeRollingAverage (image, data, planesize, param, bias,
 
2199
                                        OpPequalsPtimesA_Scaled (rbias, rmultiplier),
 
2200
                                        *histogram);
 
2201
            break;
 
2202
        case TOOL_P_DIVBY_A_SCALED_WITH_HISTOGRAM:
 
2203
            sak->computeRollingAverage (image, data, planesize, param, bias,
 
2204
                                        OpPequalsPdivByA_Scaled (rbias, rmultiplier),
 
2205
                                        *histogram);
 
2206
            break;
 
2207
        case TOOL_A_DIVBY_P_SCALED_WITH_HISTOGRAM:
 
2208
            sak->computeRollingAverage (image, data, planesize, param, bias,
 
2209
                                        OpPequalsAdivByP_Scaled (rbias, rmultiplier),
 
2210
                                        *histogram);
 
2211
            break;
 
2212
        case TOOL_MIN_P_A_SCALED_WITH_HISTOGRAM:
 
2213
            sak->computeRollingAverage (image, data, planesize, param, bias,
 
2214
                                        OpPequalsMinPA_Scaled (rbias, rmultiplier),
 
2215
                                        *histogram);
 
2216
            break;
 
2217
        case TOOL_MAX_P_A_SCALED_WITH_HISTOGRAM:
 
2218
            sak->computeRollingAverage (image, data, planesize, param, bias,
 
2219
                                        OpPequalsMaxPA_Scaled (rbias, rmultiplier),
 
2220
                                        *histogram);
 
2221
            break;
 
2222
 
 
2223
        default:
 
2224
            fprintf (stderr, "SwissArmyKnife: unknown operation (tool) %d!\n",
 
2225
                     param->tool);
 
2226
            return 0;
 
2227
        }
 
2228
    }
 
2229
    else if (doingFileImageFloat)
 
2230
    {
 
2231
        if (width != myInfo->image_w || height != myInfo->image_h)
 
2232
        {
 
2233
            const char * bar = "*************************";
 
2234
            fprintf (stderr, "\n%s%s%s\nAttempting to apply a %ux%u input "
 
2235
                     "image to %ux%u video - even if I could do that, it "
 
2236
                     "probably wouldn't be what you wanted...\n%s%s%s\n",
 
2237
                     bar, bar, bar, myInfo->image_w, myInfo->image_h,
 
2238
                     width, height, bar, bar, bar);
 
2239
            return 0;
 
2240
        }
 
2241
 
 
2242
        float * flt_img = myInfo->image_float;
 
2243
 
 
2244
        switch (tool)
 
2245
        {
 
2246
        case TOOL_A:
 
2247
            sak->applyImage (image, data, planesize, param, bias, flt_img,
 
2248
                             OpPequalsA(), HistogramNull());
 
2249
            break;
 
2250
        case TOOL_P: // HERE: we could optimize this if we wanted to
 
2251
            sak->applyImage (image, data, planesize, param, bias, flt_img,
 
2252
                             OpPequalsP(), HistogramNull());
 
2253
            break;
 
2254
        case TOOL_P_MINUS_A:
 
2255
            sak->applyImage (image, data, planesize, param, bias, flt_img,
 
2256
                             OpPequalsPminusA(), HistogramNull());
 
2257
            break;
 
2258
        case TOOL_A_MINUS_P:
 
2259
            sak->applyImage (image, data, planesize, param, bias, flt_img,
 
2260
                             OpPequalsAminusP(), HistogramNull());
 
2261
            break;
 
2262
        case TOOL_P_PLUS_A:
 
2263
            sak->applyImage (image, data, planesize, param, bias, flt_img,
 
2264
                             OpPequalsPplusA(), HistogramNull());
 
2265
            break;
 
2266
        case TOOL_P_TIMES_A:
 
2267
            sak->applyImage (image, data, planesize, param, bias, flt_img,
 
2268
                             OpPequalsPtimesA(), HistogramNull());
 
2269
            break;
 
2270
        case TOOL_P_DIVBY_A:
 
2271
            sak->applyImage (image, data, planesize, param, bias, flt_img,
 
2272
                             OpPequalsPdivByA(), HistogramNull());
 
2273
            break;
 
2274
        case TOOL_A_DIVBY_P:
 
2275
            sak->applyImage (image, data, planesize, param, bias, flt_img,
 
2276
                             OpPequalsAdivByP(), HistogramNull());
 
2277
            break;
 
2278
        case TOOL_MIN_P_A:
 
2279
            sak->applyImage (image, data, planesize, param, bias, flt_img,
 
2280
                             OpPequalsMinPA(), HistogramNull());
 
2281
            break;
 
2282
        case TOOL_MAX_P_A:
 
2283
            sak->applyImage (image, data, planesize, param, bias, flt_img,
 
2284
                             OpPequalsMaxPA(), HistogramNull());
 
2285
            break;
 
2286
 
 
2287
        case TOOL_A_WITH_HISTOGRAM:
 
2288
            sak->applyImage (image, data, planesize, param, bias, flt_img,
 
2289
                             OpPequalsA(), *histogram);
 
2290
            break;
 
2291
        case TOOL_P_WITH_HISTOGRAM: // HERE: we could optimize this if we wanted to
 
2292
            sak->applyImage (image, data, planesize, param, bias, flt_img,
 
2293
                             OpPequalsP(), *histogram);
 
2294
            break;
 
2295
        case TOOL_P_MINUS_A_WITH_HISTOGRAM:
 
2296
            sak->applyImage (image, data, planesize, param, bias, flt_img,
 
2297
                             OpPequalsPminusA(), *histogram);
 
2298
            break;
 
2299
        case TOOL_A_MINUS_P_WITH_HISTOGRAM:
 
2300
            sak->applyImage (image, data, planesize, param, bias, flt_img,
 
2301
                             OpPequalsAminusP(), *histogram);
 
2302
            break;
 
2303
        case TOOL_P_PLUS_A_WITH_HISTOGRAM:
 
2304
            sak->applyImage (image, data, planesize, param, bias, flt_img,
 
2305
                             OpPequalsPplusA(), *histogram);
 
2306
            break;
 
2307
        case TOOL_P_TIMES_A_WITH_HISTOGRAM:
 
2308
            sak->applyImage (image, data, planesize, param, bias, flt_img,
 
2309
                             OpPequalsPtimesA(), *histogram);
 
2310
            break;
 
2311
        case TOOL_P_DIVBY_A_WITH_HISTOGRAM:
 
2312
            sak->applyImage (image, data, planesize, param, bias, flt_img,
 
2313
                             OpPequalsPdivByA(), *histogram);
 
2314
            break;
 
2315
        case TOOL_A_DIVBY_P_WITH_HISTOGRAM:
 
2316
            sak->applyImage (image, data, planesize, param, bias, flt_img,
 
2317
                             OpPequalsAdivByP(), *histogram);
 
2318
            break;
 
2319
        case TOOL_MIN_P_A_WITH_HISTOGRAM:
 
2320
            sak->applyImage (image, data, planesize, param, bias, flt_img,
 
2321
                             OpPequalsMinPA(), *histogram);
 
2322
            break;
 
2323
        case TOOL_MAX_P_A_WITH_HISTOGRAM:
 
2324
            sak->applyImage (image, data, planesize, param, bias, flt_img,
 
2325
                             OpPequalsMaxPA(), *histogram);
 
2326
            break;
 
2327
 
 
2328
        case TOOL_A_SCALED:
 
2329
            sak->applyImage (image, data, planesize, param, bias, flt_img,
 
2330
                             OpPequalsA_Scaled (rbias, rmultiplier),
 
2331
                             HistogramNull());
 
2332
            break;
 
2333
        case TOOL_P_SCALED: // HERE_SCALED: we could optimize this if we wanted to
 
2334
            sak->applyImage (image, data, planesize, param, bias, flt_img,
 
2335
                             OpPequalsP_Scaled (rbias, rmultiplier),
 
2336
                             HistogramNull());
 
2337
            break;
 
2338
        case TOOL_P_MINUS_A_SCALED:
 
2339
            sak->applyImage (image, data, planesize, param, bias, flt_img,
 
2340
                             OpPequalsPminusA_Scaled (rbias, rmultiplier),
 
2341
                             HistogramNull());
 
2342
            break;
 
2343
        case TOOL_A_MINUS_P_SCALED:
 
2344
            sak->applyImage (image, data, planesize, param, bias, flt_img,
 
2345
                             OpPequalsAminusP_Scaled (rbias, rmultiplier),
 
2346
                             HistogramNull());
 
2347
            break;
 
2348
        case TOOL_P_PLUS_A_SCALED:
 
2349
            sak->applyImage (image, data, planesize, param, bias, flt_img,
 
2350
                             OpPequalsPplusA_Scaled (rbias, rmultiplier),
 
2351
                             HistogramNull());
 
2352
            break;
 
2353
        case TOOL_P_TIMES_A_SCALED:
 
2354
            sak->applyImage (image, data, planesize, param, bias, flt_img,
 
2355
                             OpPequalsPtimesA_Scaled (rbias, rmultiplier),
 
2356
                             HistogramNull());
 
2357
            break;
 
2358
        case TOOL_P_DIVBY_A_SCALED:
 
2359
            sak->applyImage (image, data, planesize, param, bias, flt_img,
 
2360
                             OpPequalsPdivByA_Scaled (rbias, rmultiplier),
 
2361
                             HistogramNull());
 
2362
            break;
 
2363
        case TOOL_A_DIVBY_P_SCALED:
 
2364
            sak->applyImage (image, data, planesize, param, bias, flt_img,
 
2365
                             OpPequalsAdivByP_Scaled (rbias, rmultiplier),
 
2366
                             HistogramNull());
 
2367
            break;
 
2368
        case TOOL_MIN_P_A_SCALED:
 
2369
            sak->applyImage (image, data, planesize, param, bias, flt_img,
 
2370
                             OpPequalsMinPA_Scaled (rbias, rmultiplier),
 
2371
                             HistogramNull());
 
2372
            break;
 
2373
        case TOOL_MAX_P_A_SCALED:
 
2374
            sak->applyImage (image, data, planesize, param, bias, flt_img,
 
2375
                             OpPequalsMaxPA_Scaled (rbias, rmultiplier),
 
2376
                             HistogramNull());
 
2377
            break;
 
2378
 
 
2379
        case TOOL_A_SCALED_WITH_HISTOGRAM:
 
2380
            sak->applyImage (image, data, planesize, param, bias, flt_img,
 
2381
                             OpPequalsA_Scaled (rbias, rmultiplier),
 
2382
                             *histogram);
 
2383
            break;
 
2384
        case TOOL_P_SCALED_WITH_HISTOGRAM: // HERE: we could optimize this if we wanted to
 
2385
            sak->applyImage (image, data, planesize, param, bias, flt_img,
 
2386
                             OpPequalsP_Scaled (rbias, rmultiplier),
 
2387
                             *histogram);
 
2388
            break;
 
2389
        case TOOL_P_MINUS_A_SCALED_WITH_HISTOGRAM:
 
2390
            sak->applyImage (image, data, planesize, param, bias, flt_img,
 
2391
                             OpPequalsPminusA_Scaled (rbias, rmultiplier),
 
2392
                             *histogram);
 
2393
            break;
 
2394
        case TOOL_A_MINUS_P_SCALED_WITH_HISTOGRAM:
 
2395
            sak->applyImage (image, data, planesize, param, bias, flt_img,
 
2396
                             OpPequalsAminusP_Scaled (rbias, rmultiplier),
 
2397
                             *histogram);
 
2398
            break;
 
2399
        case TOOL_P_PLUS_A_SCALED_WITH_HISTOGRAM:
 
2400
            sak->applyImage (image, data, planesize, param, bias, flt_img,
 
2401
                             OpPequalsPplusA_Scaled (rbias, rmultiplier),
 
2402
                             *histogram);
 
2403
            break;
 
2404
        case TOOL_P_TIMES_A_SCALED_WITH_HISTOGRAM:
 
2405
            sak->applyImage (image, data, planesize, param, bias, flt_img,
 
2406
                             OpPequalsPtimesA_Scaled (rbias, rmultiplier),
 
2407
                             *histogram);
 
2408
            break;
 
2409
        case TOOL_P_DIVBY_A_SCALED_WITH_HISTOGRAM:
 
2410
            sak->applyImage (image, data, planesize, param, bias, flt_img,
 
2411
                             OpPequalsPdivByA_Scaled (rbias, rmultiplier),
 
2412
                             *histogram);
 
2413
            break;
 
2414
        case TOOL_A_DIVBY_P_SCALED_WITH_HISTOGRAM:
 
2415
            sak->applyImage (image, data, planesize, param, bias, flt_img,
 
2416
                             OpPequalsAdivByP_Scaled (rbias, rmultiplier),
 
2417
                             *histogram);
 
2418
            break;
 
2419
        case TOOL_MIN_P_A_SCALED_WITH_HISTOGRAM:
 
2420
            sak->applyImage (image, data, planesize, param, bias, flt_img,
 
2421
                             OpPequalsMinPA_Scaled (rbias, rmultiplier),
 
2422
                             *histogram);
 
2423
            break;
 
2424
        case TOOL_MAX_P_A_SCALED_WITH_HISTOGRAM:
 
2425
            sak->applyImage (image, data, planesize, param, bias, flt_img,
 
2426
                             OpPequalsMaxPA_Scaled (rbias, rmultiplier),
 
2427
                             *histogram);
 
2428
            break;
 
2429
 
 
2430
        default:
 
2431
            fprintf (stderr, "SwissArmyKnife: unknown operation (tool) %d!\n",
 
2432
                     param->tool);
 
2433
            return 0;
 
2434
        }
 
2435
    }
 
2436
    else if (doingFileImage)
 
2437
    {
 
2438
        if (width != myInfo->image_w || height != myInfo->image_h)
 
2439
        {
 
2440
            const char * bar = "*************************";
 
2441
            fprintf (stderr, "\n%s%s%s\nAttempting to apply a %ux%u input "
 
2442
                     "image to %ux%u video - even if I could do that, it "
 
2443
                     "probably wouldn't be what you wanted...\n%s%s%s\n",
 
2444
                     bar, bar, bar, myInfo->image_w, myInfo->image_h,
 
2445
                     width, height, bar, bar, bar);
 
2446
            return 0;
 
2447
        }
 
2448
 
 
2449
        uint8_t * int_img = myInfo->image_int;
 
2450
 
 
2451
        switch (tool)
 
2452
        {
 
2453
        case TOOL_A:
 
2454
            sak->applyImage (image, data, planesize, param, bias, int_img,
 
2455
                             OpPequalsA(), HistogramNull());
 
2456
            break;
 
2457
        case TOOL_P: // HERE: we could optimize this if we wanted to
 
2458
            sak->applyImage (image, data, planesize, param, bias, int_img,
 
2459
                             OpPequalsP(), HistogramNull());
 
2460
            break;
 
2461
        case TOOL_P_MINUS_A:
 
2462
            sak->applyImage (image, data, planesize, param, bias, int_img,
 
2463
                             OpPequalsPminusA(), HistogramNull());
 
2464
            break;
 
2465
        case TOOL_A_MINUS_P:
 
2466
            sak->applyImage (image, data, planesize, param, bias, int_img,
 
2467
                             OpPequalsAminusP(), HistogramNull());
 
2468
            break;
 
2469
        case TOOL_P_PLUS_A:
 
2470
            sak->applyImage (image, data, planesize, param, bias, int_img,
 
2471
                             OpPequalsPplusA(), HistogramNull());
 
2472
            break;
 
2473
        case TOOL_P_TIMES_A:
 
2474
            sak->applyImage (image, data, planesize, param, bias, int_img,
 
2475
                             OpPequalsPtimesA(), HistogramNull());
 
2476
            break;
 
2477
        case TOOL_P_DIVBY_A:
 
2478
            sak->applyImage (image, data, planesize, param, bias, int_img,
 
2479
                             OpPequalsPdivByA(), HistogramNull());
 
2480
            break;
 
2481
        case TOOL_A_DIVBY_P:
 
2482
            sak->applyImage (image, data, planesize, param, bias, int_img,
 
2483
                             OpPequalsAdivByP(), HistogramNull());
 
2484
            break;
 
2485
        case TOOL_MIN_P_A:
 
2486
            sak->applyImage (image, data, planesize, param, bias, int_img,
 
2487
                             OpPequalsMinPA(), HistogramNull());
 
2488
            break;
 
2489
        case TOOL_MAX_P_A:
 
2490
            sak->applyImage (image, data, planesize, param, bias, int_img,
 
2491
                             OpPequalsMaxPA(), HistogramNull());
 
2492
            break;
 
2493
 
 
2494
        case TOOL_A_WITH_HISTOGRAM:
 
2495
            sak->applyImage (image, data, planesize, param, bias, int_img,
 
2496
                             OpPequalsA(), *histogram);
 
2497
            break;
 
2498
        case TOOL_P_WITH_HISTOGRAM: // HERE: we could optimize this if we wanted to
 
2499
            sak->applyImage (image, data, planesize, param, bias, int_img,
 
2500
                             OpPequalsP(), *histogram);
 
2501
            break;
 
2502
        case TOOL_P_MINUS_A_WITH_HISTOGRAM:
 
2503
            sak->applyImage (image, data, planesize, param, bias, int_img,
 
2504
                             OpPequalsPminusA(), *histogram);
 
2505
            break;
 
2506
        case TOOL_A_MINUS_P_WITH_HISTOGRAM:
 
2507
            sak->applyImage (image, data, planesize, param, bias, int_img,
 
2508
                             OpPequalsAminusP(), *histogram);
 
2509
            break;
 
2510
        case TOOL_P_PLUS_A_WITH_HISTOGRAM:
 
2511
            sak->applyImage (image, data, planesize, param, bias, int_img,
 
2512
                             OpPequalsPplusA(), *histogram);
 
2513
            break;
 
2514
        case TOOL_P_TIMES_A_WITH_HISTOGRAM:
 
2515
            sak->applyImage (image, data, planesize, param, bias, int_img,
 
2516
                             OpPequalsPtimesA(), *histogram);
 
2517
            break;
 
2518
        case TOOL_P_DIVBY_A_WITH_HISTOGRAM:
 
2519
            sak->applyImage (image, data, planesize, param, bias, int_img,
 
2520
                             OpPequalsPdivByA(), *histogram);
 
2521
            break;
 
2522
        case TOOL_A_DIVBY_P_WITH_HISTOGRAM:
 
2523
            sak->applyImage (image, data, planesize, param, bias, int_img,
 
2524
                             OpPequalsAdivByP(), *histogram);
 
2525
            break;
 
2526
        case TOOL_MIN_P_A_WITH_HISTOGRAM:
 
2527
            sak->applyImage (image, data, planesize, param, bias, int_img,
 
2528
                             OpPequalsMinPA(), *histogram);
 
2529
            break;
 
2530
        case TOOL_MAX_P_A_WITH_HISTOGRAM:
 
2531
            sak->applyImage (image, data, planesize, param, bias, int_img,
 
2532
                             OpPequalsMaxPA(), *histogram);
 
2533
            break;
 
2534
 
 
2535
        case TOOL_A_SCALED:
 
2536
            sak->applyImage (image, data, planesize, param, bias, int_img,
 
2537
                             OpPequalsA_Scaled (rbias, rmultiplier),
 
2538
                             HistogramNull());
 
2539
            break;
 
2540
        case TOOL_P_SCALED: // HERE_SCALED: we could optimize this if we wanted to
 
2541
            sak->applyImage (image, data, planesize, param, bias, int_img,
 
2542
                             OpPequalsP_Scaled (rbias, rmultiplier),
 
2543
                             HistogramNull());
 
2544
            break;
 
2545
        case TOOL_P_MINUS_A_SCALED:
 
2546
            sak->applyImage (image, data, planesize, param, bias, int_img,
 
2547
                             OpPequalsPminusA_Scaled (rbias, rmultiplier),
 
2548
                             HistogramNull());
 
2549
            break;
 
2550
        case TOOL_A_MINUS_P_SCALED:
 
2551
            sak->applyImage (image, data, planesize, param, bias, int_img,
 
2552
                             OpPequalsAminusP_Scaled (rbias, rmultiplier),
 
2553
                             HistogramNull());
 
2554
            break;
 
2555
        case TOOL_P_PLUS_A_SCALED:
 
2556
            sak->applyImage (image, data, planesize, param, bias, int_img,
 
2557
                             OpPequalsPplusA_Scaled (rbias, rmultiplier),
 
2558
                             HistogramNull());
 
2559
            break;
 
2560
        case TOOL_P_TIMES_A_SCALED:
 
2561
            sak->applyImage (image, data, planesize, param, bias, int_img,
 
2562
                             OpPequalsPtimesA_Scaled (rbias, rmultiplier),
 
2563
                             HistogramNull());
 
2564
            break;
 
2565
        case TOOL_P_DIVBY_A_SCALED:
 
2566
            sak->applyImage (image, data, planesize, param, bias, int_img,
 
2567
                             OpPequalsPdivByA_Scaled (rbias, rmultiplier),
 
2568
                             HistogramNull());
 
2569
            break;
 
2570
        case TOOL_A_DIVBY_P_SCALED:
 
2571
            sak->applyImage (image, data, planesize, param, bias, int_img,
 
2572
                             OpPequalsAdivByP_Scaled (rbias, rmultiplier),
 
2573
                             HistogramNull());
 
2574
            break;
 
2575
        case TOOL_MIN_P_A_SCALED:
 
2576
            sak->applyImage (image, data, planesize, param, bias, int_img,
 
2577
                             OpPequalsMinPA_Scaled (rbias, rmultiplier),
 
2578
                             HistogramNull());
 
2579
            break;
 
2580
        case TOOL_MAX_P_A_SCALED:
 
2581
            sak->applyImage (image, data, planesize, param, bias, int_img,
 
2582
                             OpPequalsMaxPA_Scaled (rbias, rmultiplier),
 
2583
                             HistogramNull());
 
2584
            break;
 
2585
 
 
2586
        case TOOL_A_SCALED_WITH_HISTOGRAM:
 
2587
            sak->applyImage (image, data, planesize, param, bias, int_img,
 
2588
                             OpPequalsA_Scaled (rbias, rmultiplier),
 
2589
                             *histogram);
 
2590
            break;
 
2591
        case TOOL_P_SCALED_WITH_HISTOGRAM: // HERE: we could optimize this if we wanted to
 
2592
            sak->applyImage (image, data, planesize, param, bias, int_img,
 
2593
                             OpPequalsP_Scaled (rbias, rmultiplier),
 
2594
                             *histogram);
 
2595
            break;
 
2596
        case TOOL_P_MINUS_A_SCALED_WITH_HISTOGRAM:
 
2597
            sak->applyImage (image, data, planesize, param, bias, int_img,
 
2598
                             OpPequalsPminusA_Scaled (rbias, rmultiplier),
 
2599
                             *histogram);
 
2600
            break;
 
2601
        case TOOL_A_MINUS_P_SCALED_WITH_HISTOGRAM:
 
2602
            sak->applyImage (image, data, planesize, param, bias, int_img,
 
2603
                             OpPequalsAminusP_Scaled (rbias, rmultiplier),
 
2604
                             *histogram);
 
2605
            break;
 
2606
        case TOOL_P_PLUS_A_SCALED_WITH_HISTOGRAM:
 
2607
            sak->applyImage (image, data, planesize, param, bias, int_img,
 
2608
                             OpPequalsPplusA_Scaled (rbias, rmultiplier),
 
2609
                             *histogram);
 
2610
            break;
 
2611
        case TOOL_P_TIMES_A_SCALED_WITH_HISTOGRAM:
 
2612
            sak->applyImage (image, data, planesize, param, bias, int_img,
 
2613
                             OpPequalsPtimesA_Scaled (rbias, rmultiplier),
 
2614
                             *histogram);
 
2615
            break;
 
2616
        case TOOL_P_DIVBY_A_SCALED_WITH_HISTOGRAM:
 
2617
            sak->applyImage (image, data, planesize, param, bias, int_img,
 
2618
                             OpPequalsPdivByA_Scaled (rbias, rmultiplier),
 
2619
                             *histogram);
 
2620
            break;
 
2621
        case TOOL_A_DIVBY_P_SCALED_WITH_HISTOGRAM:
 
2622
            sak->applyImage (image, data, planesize, param, bias, int_img,
 
2623
                             OpPequalsAdivByP_Scaled (rbias, rmultiplier),
 
2624
                             *histogram);
 
2625
            break;
 
2626
        case TOOL_MIN_P_A_SCALED_WITH_HISTOGRAM:
 
2627
            sak->applyImage (image, data, planesize, param, bias, int_img,
 
2628
                             OpPequalsMinPA_Scaled (rbias, rmultiplier),
 
2629
                             *histogram);
 
2630
            break;
 
2631
        case TOOL_MAX_P_A_SCALED_WITH_HISTOGRAM:
 
2632
            sak->applyImage (image, data, planesize, param, bias, int_img,
 
2633
                             OpPequalsMaxPA_Scaled (rbias, rmultiplier),
 
2634
                             *histogram);
 
2635
            break;
 
2636
 
 
2637
        default:
 
2638
            fprintf (stderr, "SwissArmyKnife: unknown operation (tool) %d!\n",
 
2639
                     param->tool);
 
2640
            return 0;
 
2641
        }
 
2642
    }
 
2643
    else if (doingApplyConstant)
 
2644
    {
 
2645
        switch (tool)
 
2646
        {
 
2647
        case TOOL_A:
 
2648
            sak->applyConstant (image, data, planesize, param, bias,
 
2649
                                OpPequalsA(), HistogramNull());
 
2650
            break;
 
2651
        case TOOL_P: // HERE: we could optimize this if we wanted to
 
2652
            sak->applyConstant (image, data, planesize, param, bias,
 
2653
                                OpPequalsP(), HistogramNull());
 
2654
            break;
 
2655
        case TOOL_P_MINUS_A:
 
2656
            sak->applyConstant (image, data, planesize, param, bias,
 
2657
                                OpPequalsPminusA(), HistogramNull());
 
2658
            break;
 
2659
        case TOOL_A_MINUS_P:
 
2660
            sak->applyConstant (image, data, planesize, param, bias,
 
2661
                                OpPequalsAminusP(), HistogramNull());
 
2662
            break;
 
2663
        case TOOL_P_PLUS_A:
 
2664
            sak->applyConstant (image, data, planesize, param, bias,
 
2665
                                OpPequalsPplusA(), HistogramNull());
 
2666
            break;
 
2667
        case TOOL_P_TIMES_A:
 
2668
            sak->applyConstant (image, data, planesize, param, bias,
 
2669
                                OpPequalsPtimesA(), HistogramNull());
 
2670
            break;
 
2671
        case TOOL_P_DIVBY_A:
 
2672
            sak->applyConstant (image, data, planesize, param, bias,
 
2673
                                OpPequalsPdivByA(), HistogramNull());
 
2674
            break;
 
2675
        case TOOL_A_DIVBY_P:
 
2676
            sak->applyConstant (image, data, planesize, param, bias,
 
2677
                                OpPequalsAdivByP(), HistogramNull());
 
2678
            break;
 
2679
        case TOOL_MIN_P_A:
 
2680
            sak->applyConstant (image, data, planesize, param, bias,
 
2681
                                OpPequalsMinPA(), HistogramNull());
 
2682
            break;
 
2683
        case TOOL_MAX_P_A:
 
2684
            sak->applyConstant (image, data, planesize, param, bias,
 
2685
                                OpPequalsMaxPA(), HistogramNull());
 
2686
            break;
 
2687
 
 
2688
        case TOOL_A_WITH_HISTOGRAM:
 
2689
            sak->applyConstant (image, data, planesize, param, bias,
 
2690
                                OpPequalsA(), *histogram);
 
2691
            break;
 
2692
        case TOOL_P_WITH_HISTOGRAM: // HERE: we could optimize this if we wanted to
 
2693
            sak->applyConstant (image, data, planesize, param, bias,
 
2694
                                OpPequalsP(), *histogram);
 
2695
            break;
 
2696
        case TOOL_P_MINUS_A_WITH_HISTOGRAM:
 
2697
            sak->applyConstant (image, data, planesize, param, bias,
 
2698
                                OpPequalsPminusA(), *histogram);
 
2699
            break;
 
2700
        case TOOL_A_MINUS_P_WITH_HISTOGRAM:
 
2701
            sak->applyConstant (image, data, planesize, param, bias,
 
2702
                                OpPequalsAminusP(), *histogram);
 
2703
            break;
 
2704
        case TOOL_P_PLUS_A_WITH_HISTOGRAM:
 
2705
            sak->applyConstant (image, data, planesize, param, bias,
 
2706
                                OpPequalsPplusA(), *histogram);
 
2707
            break;
 
2708
        case TOOL_P_TIMES_A_WITH_HISTOGRAM:
 
2709
            sak->applyConstant (image, data, planesize, param, bias,
 
2710
                                OpPequalsPtimesA(), *histogram);
 
2711
            break;
 
2712
        case TOOL_P_DIVBY_A_WITH_HISTOGRAM:
 
2713
            sak->applyConstant (image, data, planesize, param, bias,
 
2714
                                OpPequalsPdivByA(), *histogram);
 
2715
            break;
 
2716
        case TOOL_A_DIVBY_P_WITH_HISTOGRAM:
 
2717
            sak->applyConstant (image, data, planesize, param, bias,
 
2718
                                OpPequalsAdivByP(), *histogram);
 
2719
            break;
 
2720
        case TOOL_MIN_P_A_WITH_HISTOGRAM:
 
2721
            sak->applyConstant (image, data, planesize, param, bias,
 
2722
                                OpPequalsMinPA(), *histogram);
 
2723
            break;
 
2724
        case TOOL_MAX_P_A_WITH_HISTOGRAM:
 
2725
            sak->applyConstant (image, data, planesize, param, bias,
 
2726
                                OpPequalsMaxPA(), *histogram);
 
2727
            break;
 
2728
 
 
2729
        case TOOL_A_SCALED:
 
2730
            sak->applyConstant (image, data, planesize, param, bias,
 
2731
                                OpPequalsA_Scaled (rbias, rmultiplier),
 
2732
                                HistogramNull());
 
2733
            break;
 
2734
        case TOOL_P_SCALED: // HERE_SCALED: we could optimize this if we wanted to
 
2735
            sak->applyConstant (image, data, planesize, param, bias,
 
2736
                                OpPequalsP_Scaled (rbias, rmultiplier),
 
2737
                                HistogramNull());
 
2738
            break;
 
2739
        case TOOL_P_MINUS_A_SCALED:
 
2740
            sak->applyConstant (image, data, planesize, param, bias,
 
2741
                                OpPequalsPminusA_Scaled (rbias, rmultiplier),
 
2742
                                HistogramNull());
 
2743
            break;
 
2744
        case TOOL_A_MINUS_P_SCALED:
 
2745
            sak->applyConstant (image, data, planesize, param, bias,
 
2746
                                OpPequalsAminusP_Scaled (rbias, rmultiplier),
 
2747
                                HistogramNull());
 
2748
            break;
 
2749
        case TOOL_P_PLUS_A_SCALED:
 
2750
            sak->applyConstant (image, data, planesize, param, bias,
 
2751
                                OpPequalsPplusA_Scaled (rbias, rmultiplier),
 
2752
                                HistogramNull());
 
2753
            break;
 
2754
        case TOOL_P_TIMES_A_SCALED:
 
2755
            sak->applyConstant (image, data, planesize, param, bias,
 
2756
                                OpPequalsPtimesA_Scaled (rbias, rmultiplier),
 
2757
                                HistogramNull());
 
2758
            break;
 
2759
        case TOOL_P_DIVBY_A_SCALED:
 
2760
            sak->applyConstant (image, data, planesize, param, bias,
 
2761
                                OpPequalsPdivByA_Scaled (rbias, rmultiplier),
 
2762
                                HistogramNull());
 
2763
            break;
 
2764
        case TOOL_A_DIVBY_P_SCALED:
 
2765
            sak->applyConstant (image, data, planesize, param, bias,
 
2766
                                OpPequalsAdivByP_Scaled (rbias, rmultiplier),
 
2767
                                HistogramNull());
 
2768
            break;
 
2769
        case TOOL_MIN_P_A_SCALED:
 
2770
            sak->applyConstant (image, data, planesize, param, bias,
 
2771
                                OpPequalsMinPA_Scaled (rbias, rmultiplier),
 
2772
                                HistogramNull());
 
2773
            break;
 
2774
        case TOOL_MAX_P_A_SCALED:
 
2775
            sak->applyConstant (image, data, planesize, param, bias,
 
2776
                                OpPequalsMaxPA_Scaled (rbias, rmultiplier),
 
2777
                                HistogramNull());
 
2778
            break;
 
2779
 
 
2780
        case TOOL_A_SCALED_WITH_HISTOGRAM:
 
2781
            sak->applyConstant (image, data, planesize, param, bias,
 
2782
                                OpPequalsA_Scaled (rbias, rmultiplier),
 
2783
                                *histogram);
 
2784
            break;
 
2785
        case TOOL_P_SCALED_WITH_HISTOGRAM: // HERE: we could optimize this if we wanted to
 
2786
            sak->applyConstant (image, data, planesize, param, bias,
 
2787
                                OpPequalsP_Scaled (rbias, rmultiplier),
 
2788
                                *histogram);
 
2789
            break;
 
2790
        case TOOL_P_MINUS_A_SCALED_WITH_HISTOGRAM:
 
2791
            sak->applyConstant (image, data, planesize, param, bias,
 
2792
                                OpPequalsPminusA_Scaled (rbias, rmultiplier),
 
2793
                                *histogram);
 
2794
            break;
 
2795
        case TOOL_A_MINUS_P_SCALED_WITH_HISTOGRAM:
 
2796
            sak->applyConstant (image, data, planesize, param, bias,
 
2797
                                OpPequalsAminusP_Scaled (rbias, rmultiplier),
 
2798
                                *histogram);
 
2799
            break;
 
2800
        case TOOL_P_PLUS_A_SCALED_WITH_HISTOGRAM:
 
2801
            sak->applyConstant (image, data, planesize, param, bias,
 
2802
                                OpPequalsPplusA_Scaled (rbias, rmultiplier),
 
2803
                                *histogram);
 
2804
            break;
 
2805
        case TOOL_P_TIMES_A_SCALED_WITH_HISTOGRAM:
 
2806
            sak->applyConstant (image, data, planesize, param, bias,
 
2807
                                OpPequalsPtimesA_Scaled (rbias, rmultiplier),
 
2808
                                *histogram);
 
2809
            break;
 
2810
        case TOOL_P_DIVBY_A_SCALED_WITH_HISTOGRAM:
 
2811
            sak->applyConstant (image, data, planesize, param, bias,
 
2812
                                OpPequalsPdivByA_Scaled (rbias, rmultiplier),
 
2813
                                *histogram);
 
2814
            break;
 
2815
        case TOOL_A_DIVBY_P_SCALED_WITH_HISTOGRAM:
 
2816
            sak->applyConstant (image, data, planesize, param, bias,
 
2817
                                OpPequalsAdivByP_Scaled (rbias, rmultiplier),
 
2818
                                *histogram);
 
2819
            break;
 
2820
        case TOOL_MIN_P_A_SCALED_WITH_HISTOGRAM:
 
2821
            sak->applyConstant (image, data, planesize, param, bias,
 
2822
                                OpPequalsMinPA_Scaled (rbias, rmultiplier),
 
2823
                                *histogram);
 
2824
            break;
 
2825
        case TOOL_MAX_P_A_SCALED_WITH_HISTOGRAM:
 
2826
            sak->applyConstant (image, data, planesize, param, bias,
 
2827
                                OpPequalsMaxPA_Scaled (rbias, rmultiplier),
 
2828
                                *histogram);
 
2829
            break;
 
2830
 
 
2831
        default:
 
2832
            fprintf (stderr, "SwissArmyKnife: unknown operation (tool) %d!\n",
 
2833
                     param->tool);
 
2834
            return 0;
 
2835
        }
 
2836
    }
 
2837
    else
 
2838
    {
 
2839
        fprintf (stderr, "ooops!  input selection botch in SwissArmyKnife!\n");
 
2840
        return 0;
 
2841
    }
 
2842
 
 
2843
    if (histogram)
 
2844
    {
 
2845
        histogram->frame_check();
 
2846
        delete histogram;
 
2847
    }
 
2848
 
 
2849
    // HERE: the following two lines do a luma-only-ize
 
2850
 
 
2851
    memset (UPLANE (data), 128, planesize >> 2);
 
2852
    memset (VPLANE (data), 128, planesize >> 2);
 
2853
 
 
2854
    data->copyInfo(image);
 
2855
 
 
2856
    return 1;
 
2857
}