1
/***************************************************************************
2
ADM_vidSwissArmyKnife.cpp - Perform one of many
5
Chris MacGregor, 2005, 2007
6
chris-avidemux@bouncingdog.com
7
***************************************************************************/
9
/***************************************************************************
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. *
16
***************************************************************************/
23
#include <sys/types.h>
30
#include "ADM_assert.h"
35
#include "ADM_toolkit/toolkit.hxx"
36
#include "ADM_editor/ADM_edit.hxx"
37
#include "ADM_video/ADM_genvideo.hxx"
39
#include "ADM_encoder/ADM_vidEncode.hxx"
40
#include "ADM_encoder/adm_encoder.h"
42
#include "ADM_filter/video_filters.h"
44
#include "ADM_userInterfaces/ADM_commonUI/DIA_factory.h"
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
51
static const int MAX_PIXEL_LUMA = 255;
53
static FILTER_PARAM swissArmyKnifeParam =
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
64
ADMVideoSwissArmyKnife::ToolMap ADMVideoSwissArmyKnife::tool_map [] =
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)" },
77
{ TOOL_INVALID, 0, 0, 0 }
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.
89
ADMVideoSwissArmyKnife::PImap ADMVideoSwissArmyKnife::pimap;
92
SCRIPT_CREATE(swissarmyknife_script,ADMVideoSwissArmyKnife,swissArmyKnifeParam);
94
BUILD_CREATE(swissarmyknife_create,ADMVideoSwissArmyKnife);
96
ADMVideoSwissArmyKnife::ADMVideoSwissArmyKnife(AVDMGenericVideoStream *in,CONFcouple *couples)
100
memcpy(&_info, in->getInfo(), sizeof(_info));
102
_uncompressed = new ADMImage(_in->getInfo()->width, _in->getInfo()->height);
103
ADM_assert(_uncompressed);
104
_param = new SWISSARMYKNIFE_PARAM;
112
GET2(input_file, tmp);
114
GET(load_multiplier);
118
GET(memory_constant_alpha);
119
GET(init_start_frame);
121
GET(init_by_rolling);
125
GET(result_multiplier);
126
GET(histogram_frame_interval);
129
_param->enable_preview
130
= (_param->input_type != INPUT_ROLLING_AVERAGE);
134
_param->tool = TOOL_P_MINUS_A;
135
_param->input_type = INPUT_ROLLING_AVERAGE;
137
// _param->input_file = ""; // implicit
138
_param->load_bias = 0.0;
139
_param->load_multiplier = 1.0;
141
_param->input_constant = 0;
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;
149
_param->result_bias = 0.0;
150
_param->result_multiplier = 1.0;
151
_param->histogram_frame_interval = 0;
154
_param->enable_preview = false;
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.
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
170
if (pimap.count (couples) == 0)
172
myInfo = new PersistentInfo;
173
myInfo->conf = couples;
174
pimap [couples] = myInfo;
178
myInfo = pimap [couples];
181
if (myInfo->oldConf == couples)
183
pimap.erase (myInfo->conf);
184
myInfo->conf = myInfo->oldConf;
189
ADM_assert (myInfo->conf == couples);
193
pimap.erase (myInfo->oldConf);
202
printf ("ADMVideoSwissArmyKnife ctor (%p, conf = %p), pi = %p, rc now %d\n",
203
this, couples, myInfo, myInfo->refCount);
206
uint8_t ADMVideoSwissArmyKnife::getCoupledConf (CONFcouple **couples)
210
*couples = new CONFcouple(swissArmyKnifeParam.nb);
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.
221
printf("ADMVideoSwissArmyKnife::getCoupledConf(): this = %p, couples = %p, "
222
"oldConf = %p (was %p), pi = %p\n",
223
this, *couples, myInfo->conf, myInfo->oldConf, myInfo);
226
pimap.erase (myInfo->oldConf);
227
myInfo->oldConf = myInfo->conf;
228
myInfo->conf = *couples;
229
pimap [myInfo->conf] = myInfo;
230
if (myInfo->oldConf == 0)
236
(*couples)->setCouple("input_file", _param->input_file.c_str());
238
CSET(load_multiplier);
240
CSET(input_constant);
242
CSET(memory_constant_alpha);
243
CSET(init_start_frame);
244
CSET(init_end_frame);
245
CSET(init_by_rolling);
249
CSET(result_multiplier);
250
CSET(histogram_frame_interval);
256
uint8_t ADMVideoSwissArmyKnife::configure (AVDMGenericVideoStream *in)
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 }
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 },
286
QT_TR_NOOP("Select _Operation on each pixel P and input A:"),
287
sizeof (tTool) / sizeof (diaMenuEntry), tTool);
289
diaElemMenu input_type
290
(&(_param->input_type),
291
QT_TR_NOOP("Input _Type:"),
292
sizeof (tInputType) / sizeof (diaMenuEntry), tInputType);
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 },
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));
309
else if (ret == 0) // 0 = cancel
315
ADM_assert (ret == 255); // 255 = whizzy dialog not implemented
318
char* file = ADM_strdup(_param->input_file.c_str());
320
diaElemFile input_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!
334
diaElemFloat input_constant
335
(&(_param->input_constant),
336
QT_TR_NOOP("Input _Constant:"), -99999, +99999); // arbitrary!
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):"),
343
diaElemUInteger init_start_frame
344
(&(_param->init_start_frame),
345
QT_TR_NOOP("Init _Start Frame (first frame # to use for head start):"),
347
diaElemUInteger init_end_frame
348
(&(_param->init_end_frame),
349
QT_TR_NOOP("Init _End Frame (last frame # to use for head start):"),
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)"));
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);
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 };
381
ret = diaFactoryRun (QT_TR_NOOP("Swiss Army Knife Configuration"),
382
sizeof (elems) / sizeof (diaElem *), elems);
383
if (ret) // 0 = cancel
385
myInfo->image_data_invalid = true;
386
myInfo->histogram_data_invalid = true;
389
_param->input_file = file;
395
ADMVideoSwissArmyKnife::~ADMVideoSwissArmyKnife()
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.
407
printf ("ADMVideoSwissArmyKnife dtor (%p), conf = %p, pi = %p, rc now %d\n",
408
this, myInfo->conf, myInfo, myInfo->refCount);
412
pimap.erase (myInfo->oldConf);
416
if (myInfo->refCount < 1)
418
pimap.erase (myInfo->conf);
423
delete _uncompressed;
424
_uncompressed = NULL;
427
char * ADMVideoSwissArmyKnife::printConf ()
429
return getConf (_param, false);
432
char * ADMVideoSwissArmyKnife::getConf (SWISSARMYKNIFE_PARAM * param,
435
const int CONF_LEN = 1024;
436
static char conf[CONF_LEN];
439
for (tm = tool_map; tm->outputName; tm++)
440
if (tm->toolid == param->tool)
443
char inputstr [CONF_LEN];
448
const char * input_file = param->input_file.c_str();
449
if (!input_file || !*input_file)
450
input_file = "**** no file selected ****";
452
const char * space = forDialog ? " " : "";
454
switch (param->input_type)
456
case INPUT_CUSTOM_CONVOLUTION:
457
snprintf (inputstr, CONF_LEN, "convolve%s(P,%s%s)",
458
space, space, input_file);
460
case INPUT_FILE_IMAGE_FLOAT:
461
snprintf (inputstr, CONF_LEN,
462
(param->load_bias == 0.0 && param->load_multiplier == 1.0)
464
: (forDialog ? "((pixel_from%s(%s) + %.6f) * %.6f)"
465
: "((pixel_from%s(%s)%+.6f)*%.6f)"),
467
param->load_bias, param->load_multiplier);
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)"),
476
param->load_bias, param->load_multiplier);
478
case INPUT_CONSTANT_VALUE:
479
if (int (param->input_constant) == param->input_constant)
480
sprintf (inputstr, "%d", int (param->input_constant));
482
sprintf (inputstr, "%.6f", param->input_constant);
484
case INPUT_ROLLING_AVERAGE:
485
sprintf (inputstr, "A");
486
sprintf (where, " (where each frame, A=(A*(1-alpha))+(P*alpha), "
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);
495
sprintf (inputstr, "OOOPS!! (unexpected type %d)",
502
bool result_is_scaled
503
= (param->result_bias != 0.0 || param->result_multiplier != 1.0);
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);
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);
525
cptr += snprintf (cptr, CONF_LEN - (cptr - conf),
526
", debug%s=%s0x%x", space, space, param->debug);
528
fprintf (stderr, "SAK conf is (%d) \"%s\"\n", cptr - conf, conf);
532
//============================================================================
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++
546
//============================================================================
548
class HistogramNull // do-nothing version
556
void record_input (uint8_t P)
560
void record_output (int32_t P)
564
void dump (uint32_t frame_count, uint32_t pixels_per_frame)
574
//----------------------------------------------------------------------------
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.
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);
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;
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().
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)
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);
621
;// printf ("histogram: using data at %p, %p\n",
622
// input_data, output_data);
625
// no dtor needed - deallocation is handled elsewhere
629
memset (input_data, 0, input_range_size * sizeof (input_data[0]));
630
memset (output_data, 0, range_size * sizeof (output_data[0]));
634
void record_input (uint8_t P) const
639
void record_output (int32_t P) const
641
P -= range_min; // scale into histogram data array index
642
if ((P & out_of_range_mask) == 0)
650
else if (P >= range_size)
658
int32_t index_min = 0;
659
int32_t index_max = range_size - 1;
660
while (index_min < index_max)
662
if (output_data[index_min])
666
while (index_min < index_max)
668
if (output_data[index_max])
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);
684
// returns true if it outputs data and resets the counter, else false.
686
bool frame_check () const
688
if (++frame_count < frame_interval)
690
// printf ("histogram: frame %d of %d\n",
691
// frame_count, frame_interval);
701
void do_dump (uint32_t * data, int32_t index_min, int32_t index_max,
704
// We scan the data to find the maximum value, so we can scale the
705
// bars to provide useful visual data.
707
uint32_t max_pixels = 0;
708
for (int32_t index = index_min; index <= index_max; index++)
710
if (data[index] > max_pixels)
711
max_pixels = data[index];
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.
719
const int32_t bar_max = 11; // hardcoded as %11s in printf below
721
max_pixels /= frame_count;
722
int32_t divisor = frame_count * max_pixels / bar_max;
724
int32_t divisor = max_pixels / bar_max;
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;
734
int32_t column_end = index_min + column_len;
736
const char * bar = "*********************************************";
737
const char * bar_end = bar + strlen (bar);
739
for (int32_t index = index_min; index < column_end; index++)
741
int32_t index2 = index;
742
int32_t val = index + bias;
744
for (int32_t column = 0;
746
++column, index2 += column_len, val += column_len)
748
if (index2 > index_max)
751
int32_t dat = data[index2];
752
int32_t bar_size = dat / divisor;
753
if (bar_size == 0 && dat != 0)
755
#define HISTOGRAM_SHOW_VALUES 1
756
#ifdef HISTOGRAM_SHOW_VALUES
757
printf (" %5d: %6d %-11s", val, dat / frame_count, bar_end - bar_size);
759
printf (" %5d: %-11s", val, bar_end - bar_size);
767
//============================================================================
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)
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!
779
Histo histogram = histogram_in;
782
uint32_t sathigh = 0;
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". ;-)
790
// We have (for the moment) skipped the normalizing step - we assume that
793
// We also assume that kw and kh are both odd.
798
uint32_t xedge = my_w - uc;
799
uint32_t yedge = my_h - vc;
801
for (uint32_t y = 0; y < my_h; y++)
803
bool y_is_edgy = (y < vc || y >= yedge);
805
for (uint32_t x = 0; x < my_w; x++)
810
// If some of this pixel's neighbors are "off the edge" of the
811
// input image, we'll use the "safe" getPixel().
813
if (y_is_edgy || x < uc || x >= xedge)
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++];
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
829
for (int32_t v = -vc; v <= vc; v++)
831
int32_t offset = x + ((y + v) * my_w);
833
for (int32_t u = -uc; u <= uc; u++)
834
sum += getPixel (offset + u) * kernel [i++];
838
// as noted above, we're currently assuming the matrix was already
842
int32_t P = getPixel (x, y);
844
histogram.record_input (P);
848
int32_t result = op (P, A) + bias;
850
histogram.record_output (result);
852
if (result & 0xffffff00)
859
else // if (result > 255)
866
outPixel (x, y) = result;
872
if (satlow || sathigh)
873
printf (" Saturated %d low, %d high\n", satlow, sathigh);
877
//============================================================================
879
template <typename Oper, typename Histo>
880
void ADMVideoSwissArmyKnife::computeRollingAverage (ADMImage * image,
883
SWISSARMYKNIFE_PARAM * param,
886
const Histo & histogram_in)
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!
893
Histo histogram = histogram_in;
896
float alpha = param->memory_constant_alpha;
897
float oneminusalpha = 1 - alpha;
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.
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;
908
uint32_t sathigh = 0;
911
while (--pixremaining)
913
int32_t P = *--currp;
914
histogram.record_input (P);
917
*bgp = (A * oneminusalpha) + (P * alpha);
919
int32_t result = op (P, A) + bias;
921
histogram.record_output (result);
923
if (result & 0xffffff00)
930
else // if (result > 255)
940
if (param->debug & 2)
942
if (satlow || sathigh)
943
printf (" Saturated %d low, %d high\n", satlow, sathigh);
947
//============================================================================
949
template <typename InputImageType, typename Oper, typename Histo>
950
void ADMVideoSwissArmyKnife::applyImage (ADMImage * image, ADMImage * data,
952
SWISSARMYKNIFE_PARAM * param,
954
InputImageType * input_image,
956
const Histo & histogram_in)
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!
963
Histo histogram = histogram_in;
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.
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;
975
uint32_t sathigh = 0;
978
while (--pixremaining)
980
int32_t P = *--currp;
981
histogram.record_input (P);
983
InputImageType A = *--bgp;
984
int32_t result = op (P, A) + bias;
986
histogram.record_output (result);
988
if (result & 0xffffff00)
995
else // if (result > 255)
1005
if (param->debug & 2)
1007
if (satlow || sathigh)
1008
printf (" Saturated %d low, %d high\n", satlow, sathigh);
1012
//============================================================================
1014
template <typename Oper, typename Histo>
1015
void ADMVideoSwissArmyKnife::applyConstant (ADMImage * image, ADMImage * data,
1017
SWISSARMYKNIFE_PARAM * param,
1020
const Histo & histogram_in)
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!
1027
Histo histogram = histogram_in;
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.
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;
1039
uint32_t sathigh = 0;
1040
uint32_t satlow = 0;
1042
while (--pixremaining)
1044
int32_t P = *--currp;
1045
histogram.record_input (P);
1047
int32_t result = op (P, A) + bias;
1049
histogram.record_output (result);
1051
if (result & 0xffffff00)
1058
else // if (result > 255)
1068
if (param->debug & 2)
1070
if (satlow || sathigh)
1071
printf (" Saturated %d low, %d high\n", satlow, sathigh);
1075
//============================================================================
1080
int32_t operator () (int32_t P, float A) const
1082
return static_cast <int32_t> (A + .5);
1085
int32_t operator () (int32_t P, uint8_t A) const
1094
int32_t operator () (int32_t P, float A) const
1099
int32_t operator () (int32_t P, uint8_t A) const
1105
class OpPequalsPminusA
1108
int32_t operator () (int32_t P, float A) const
1110
return (P - static_cast <int32_t> (A + .5));
1113
int32_t operator () (int32_t P, uint8_t A) const
1119
class OpPequalsAminusP
1122
int32_t operator () (int32_t P, float A) const
1124
return (static_cast <int32_t> (A + .5) - P);
1127
int32_t operator () (int32_t P, uint8_t A) const
1133
class OpPequalsPplusA
1136
int32_t operator () (int32_t P, float A) const
1138
return (P + static_cast <int32_t> (A + .5));
1141
int32_t operator () (int32_t P, uint8_t A) const
1147
class OpPequalsPtimesA
1150
int32_t operator () (int32_t P, float A) const
1152
return static_cast <int32_t> ((P * A) + .5);
1155
int32_t operator () (int32_t P, uint8_t A) const
1161
class OpPequalsPdivByA
1164
int32_t operator () (int32_t P, float A) const
1166
return static_cast <int32_t> ((P / A) + .5);
1169
int32_t operator () (int32_t P, uint8_t A) const
1175
class OpPequalsAdivByP
1178
int32_t operator () (int32_t P, float A) const
1180
return static_cast <int32_t> ((A / P) + .5);
1183
int32_t operator () (int32_t P, uint8_t A) const
1189
class OpPequalsMinPA
1192
int32_t operator () (int32_t P, float A) const
1194
int32_t intA = static_cast <int32_t> (A + .5);
1195
return ((intA > P) ? P : intA);
1198
int32_t operator () (int32_t P, uint8_t A) const
1200
return ((A > P) ? P : A);
1204
class OpPequalsMaxPA
1207
int32_t operator () (int32_t P, float A) const
1209
int32_t intA = static_cast <int32_t> (A + .5);
1210
return ((intA > P) ? intA : P);
1213
int32_t operator () (int32_t P, uint8_t A) const
1215
return ((A > P) ? A : P);
1219
//----------------------------------------------------------------------------
1221
class OpPequalsA_Scaled
1226
OpPequalsA_Scaled (float bias, float multiplier)
1228
multiplier (multiplier) { }
1230
int32_t operator () (int32_t P, float A) const
1232
return static_cast <int32_t> (((A + bias) * multiplier) + .5);
1236
class OpPequalsP_Scaled
1241
OpPequalsP_Scaled (float bias, float multiplier)
1243
multiplier (multiplier) { }
1245
int32_t operator () (int32_t P, float A) const
1247
return static_cast <int32_t> (((P + bias) * multiplier) + .5);
1251
class OpPequalsPminusA_Scaled
1256
OpPequalsPminusA_Scaled (float bias, float multiplier)
1258
multiplier (multiplier) { }
1260
int32_t operator () (int32_t P, float A) const
1262
return (static_cast <int32_t>
1263
((((P - A) + bias) * multiplier) + .5));
1267
class OpPequalsAminusP_Scaled
1272
OpPequalsAminusP_Scaled (float bias, float multiplier)
1274
multiplier (multiplier) { }
1276
int32_t operator () (int32_t P, float A) const
1278
return (static_cast <int32_t>
1279
((((A - P) + bias) * multiplier) + .5));
1283
class OpPequalsPplusA_Scaled
1288
OpPequalsPplusA_Scaled (float bias, float multiplier)
1290
multiplier (multiplier) { }
1292
int32_t operator () (int32_t P, float A) const
1294
return (static_cast <int32_t>
1295
((((P + A) + bias) * multiplier) + .5));
1299
class OpPequalsPtimesA_Scaled
1304
OpPequalsPtimesA_Scaled (float bias, float multiplier)
1306
multiplier (multiplier) { }
1308
int32_t operator () (int32_t P, float A) const
1310
return (static_cast <int32_t>
1311
((((P * A) + bias) * multiplier) + .5));
1315
class OpPequalsPdivByA_Scaled
1320
OpPequalsPdivByA_Scaled (float bias, float multiplier)
1322
multiplier (multiplier) { }
1324
int32_t operator () (int32_t P, float A) const
1326
return (static_cast <int32_t>
1327
((((P / A) + bias) * multiplier) + .5));
1331
class OpPequalsAdivByP_Scaled
1336
OpPequalsAdivByP_Scaled (float bias, float multiplier)
1338
multiplier (multiplier) { }
1340
int32_t operator () (int32_t P, float A) const
1342
return (static_cast <int32_t>
1343
((((A / P) + bias) * multiplier) + .5));
1347
class OpPequalsMinPA_Scaled
1352
OpPequalsMinPA_Scaled (float bias, float multiplier)
1354
multiplier (multiplier) { }
1356
int32_t operator () (int32_t P, float A) const
1358
return (static_cast <int32_t>
1359
((((A > P ? P : A) + bias) * multiplier) + .5));
1363
class OpPequalsMaxPA_Scaled
1368
OpPequalsMaxPA_Scaled (float bias, float multiplier)
1370
multiplier (multiplier) { }
1372
int32_t operator () (int32_t P, float A) const
1374
return (static_cast <int32_t>
1375
((((A > P ? A : P) + bias) * multiplier) + .5));
1379
//============================================================================
1381
uint8_t ADMVideoSwissArmyKnife::getFrameNumberNoAlloc(uint32_t frame,
1386
if (frame >= _info.nb_frames)
1389
if (_param->debug & 1)
1390
printf ("in ADMVideoSwissArmyKnife::getFrameNumberNoAlloc(%d, ...)\n",
1393
if (!_in->getFrameNumberNoAlloc (frame, len, _uncompressed, flags))
1396
uint32_t planesize = _info.width * _info.height;
1397
uint32_t size = (planesize * 3) >> 1;
1400
uint8_t ret = doSwissArmyKnife (_uncompressed, data, _in, this, _param,
1401
_info.width, _info.height);
1406
ADMVideoSwissArmyKnife::doSwissArmyKnife (ADMImage * image,
1408
AVDMGenericVideoStream * in,
1409
ADMVideoSwissArmyKnife * sak,
1410
SWISSARMYKNIFE_PARAM * param,
1411
uint32_t width, uint32_t height)
1413
PersistentInfo * myInfo = sak->myInfo;
1414
uint32_t debug = param->debug;
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);
1423
bool needRead = false;
1424
bool needFile = doingConvolution || doingFileImage;
1428
if (myInfo->input_file_name != param->input_file)
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());
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!
1441
if (stat (myInfo->input_file_name.c_str(), &st) == -1)
1443
perror (myInfo->input_file_name.c_str());
1447
if (st.st_mtime != myInfo->input_file_mtime)
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());
1453
myInfo->input_file_mtime = st.st_mtime;
1455
else if (!needRead && doingFileImage)
1457
if (myInfo->image_data_invalid
1458
|| myInfo->image_bias != param->load_bias
1459
|| myInfo->image_multiplier != param->load_multiplier)
1466
FloatVector & kernel = myInfo->kernel;
1467
uint32_t & kernel_w = myInfo->kernel_w;
1468
uint32_t & kernel_h = myInfo->kernel_h;
1470
uint32_t planesize = width * height;
1474
myInfo->histogram_data_invalid = true;
1476
if (doingConvolution)
1482
using namespace std;
1484
const char * filename = myInfo->input_file_name.c_str();
1485
ifstream inputStream (filename);
1488
fprintf (stderr, "SwissArmyKnife: can't open input file %s, "
1489
"but it apparently does exist...(%d)\n",
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!
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)
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
1524
copy (istream_iterator <float> (inputStream),
1525
istream_iterator <float> (),
1526
back_inserter (kernel));
1528
#ifdef ASSUME_SQUARE_MATRIX
1529
kernel_dim = uint32_t (sqrtf (kernel.size()));
1530
if (kernel_dim * kernel_dim != kernel.size())
1532
if ((kernel_dim + 1) * (kernel_dim + 1) == kernel.size())
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()));
1547
printf ("SwissArmyKnife: read %d convolution kernel values "
1548
"from %s (%dx%d):\n",
1549
kernel.size(), filename, kernel_w, kernel_h);
1552
FloatVector::const_iterator kit = kernel.begin();
1554
while (kit != kernel.end())
1556
printf ("%.6f%c", *kit++,
1557
(++count % kernel_w) ? ' ' : '\n');
1559
if (count % kernel_w)
1560
printf ("[incomplete?!]\n");
1563
else // file image (not convolution)
1565
ADM_assert (param->input_type == INPUT_FILE_IMAGE_FLOAT
1566
|| param->input_type == INPUT_FILE_IMAGE_INTEGER);
1568
const char * filename = myInfo->input_file_name.c_str();
1569
FILE * fin = fopen (filename, "rb");
1572
fprintf (stderr, "SwissArmyKnife: can't open input file %s, "
1573
"but it apparently does exist...(%d)\n",
1578
ADMVideoComputeAverage::FileHeader header;
1579
int nread = fread (&header, sizeof (header), 1, fin);
1580
if (nread != 1 || strncmp (header.magic, "DGCMimgF", 8) != 0)
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);
1589
uint32_t width = header.width;
1590
uint32_t height = header.height;
1591
uint32_t pixelcount = width * height;
1593
if (width > 2000 || height > 2000)
1595
fprintf (stderr, "SwissArmyKnife: invalid image dimensions "
1597
int (width), int (height), filename);
1602
myInfo->image_data_invalid = true;
1603
delete [] myInfo->image_float;
1604
delete [] myInfo->image_int;
1606
myInfo->image_float = new float [pixelcount];
1608
nread = fread (myInfo->image_float, sizeof (float), pixelcount, fin);
1610
if (nread != pixelcount)
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;
1620
printf ("SwissArmyKnife: successfully loaded image data "
1621
"(%ux%u = %u) from %s\n",
1622
width, height, pixelcount, filename);
1624
myInfo->image_int = new uint8_t [pixelcount];
1625
float * floatpixp = myInfo->image_float + pixelcount;
1626
uint8_t * intpixp = myInfo->image_int + pixelcount;
1628
if (param->load_bias == 0.0 && param->load_multiplier == 1.0)
1630
printf ("Converting %u pixels to integer values (and keeping "
1631
"the floats, too)\n", pixelcount);
1634
while (--pixelcount)
1636
*--intpixp = static_cast <uint8_t> (*--floatpixp + 0.5);
1641
float load_bias = param->load_bias;
1642
float load_multiplier = param->load_multiplier;
1644
printf ("applying P = (P + %.6f) * %.6f to %u pixels\n",
1645
load_bias, load_multiplier, pixelcount);
1648
while (--pixelcount)
1651
= (*--floatpixp + load_bias) * load_multiplier;
1652
*floatpixp = floatpix;
1657
else if (floatpix > 255)
1660
intpix = static_cast <uint8_t> (floatpix + 0.5);
1662
*--intpixp = intpix;
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;
1673
else if (doingRollingAvg)
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)
1682
if (!myInfo->bg || myInfo->bg_x != width || myInfo->bg_y != height)
1684
myInfo->bg_x = width;
1685
myInfo->bg_y = height;
1686
delete [] myInfo->bg;
1687
myInfo->bg = new float [planesize];
1690
myInfo->histogram_data_invalid = true;
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;
1697
if (myInfo->bg_isf && myInfo->bg_isf <= myInfo->bg_ief)
1699
uint32_t do_frames = myInfo->bg_ief - myInfo->bg_isf + 1;
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)
1706
lastframe = info.nb_frames - 1;
1707
if (firstframe > info.nb_frames)
1709
firstframe = lastframe - do_frames + 1;
1710
if (firstframe > info.nb_frames)
1713
do_frames = lastframe - firstframe + 1;
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);
1725
ADMImage aimage (myInfo->bg_x, myInfo->bg_y);
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.)
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:
1741
uint32_t fflags = 0;
1742
if (!in->getFrameNumberNoAlloc (firstframe, &flen,
1746
uint8_t * currp = YPLANE (&aimage) + planesize;
1747
float * bgp = myInfo->bg + planesize;
1748
uint32_t pixremaining = planesize + 1;
1749
while (--pixremaining)
1754
++firstframe; // don't include this one again
1757
float alpha = param->memory_constant_alpha;
1758
float oneminusalpha = 1 - alpha;
1760
for (int fnum = firstframe; fnum <= lastframe; fnum++)
1763
uint32_t fflags = 0;
1764
if (!in->getFrameNumberNoAlloc (fnum, &flen,
1768
uint8_t * currp = YPLANE (&aimage) + planesize;
1769
float * bgp = myInfo->bg + planesize;
1770
uint32_t pixremaining = planesize + 1;
1771
while (--pixremaining)
1774
*bgp = (*bgp * oneminusalpha) + (*--currp * alpha);
1778
else // head start uses straight average (not rolling average)
1780
uint32_t sums [planesize];
1781
memset (sums, 0, planesize * sizeof sums[0]);
1783
for (int fnum = firstframe; fnum <= lastframe; fnum++)
1786
uint32_t fflags = 0;
1787
if (!in->getFrameNumberNoAlloc (fnum, &flen,
1791
uint8_t * currp = YPLANE (&aimage) + planesize;
1792
uint32_t * sump = sums + planesize;
1793
uint32_t pixremaining = planesize + 1;
1794
while (--pixremaining)
1796
*--sump += *--currp;
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)
1809
*--bgp = *--sump * one_over_framecount;
1814
printf ("Done computing head start.\n");
1816
else // if (debug & 2)
1818
printf ("Starting with new 0 baseline background\n");
1819
memset (myInfo->bg, 0, planesize * sizeof (myInfo->bg[0]));
1825
printf ("Using existing baseline background of size %dx%d with "
1826
"alpha = %.6f (1/%d)\n", myInfo->bg_x, myInfo->bg_y,
1831
uint8_t * imagePixels = YPLANE (image);
1833
ImageTool imtool (imagePixels, width, height, data);
1834
imtool.setDebug (debug);
1836
Histogram * histogram = 0;
1837
int32_t bias = param->bias;
1838
uint32_t tool = param->tool;
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.
1843
if (param->histogram_frame_interval != 0)
1845
histogram = new Histogram (myInfo->histogram_input_data,
1846
myInfo->histogram_output_data,
1847
param->histogram_frame_interval,
1848
myInfo->histogram_frame_count,
1850
tool += TOOL_ADD_HISTOGRAM;
1851
if (myInfo->histogram_frame_interval !=
1852
param->histogram_frame_interval)
1854
if (myInfo->histogram_frame_interval)
1855
myInfo->histogram_data_invalid = true;
1856
myInfo->histogram_frame_interval
1857
= param->histogram_frame_interval;
1860
if (myInfo->histogram_data_invalid)
1862
myInfo->histogram_data_invalid = false;
1867
float rbias = param->result_bias;
1868
float rmultiplier = param->result_multiplier;
1869
if (fabsf (rbias) >= 0.0001 || fabsf (rmultiplier - 1.0) >= 0.0001)
1871
tool += TOOL_ADD_SCALING;
1874
if (doingConvolution)
1878
fprintf (stderr, "No convolution kernel loaded - can't do "
1886
imtool.convolve (kernel, kernel_w, kernel_h, bias, OpPequalsA(), HistogramNull());
1888
case TOOL_P: // HERE: we could optimize this if we wanted to
1889
imtool.convolve (kernel, kernel_w, kernel_h, bias, OpPequalsP(), HistogramNull());
1891
case TOOL_P_MINUS_A:
1892
imtool.convolve (kernel, kernel_w, kernel_h, bias, OpPequalsPminusA(), HistogramNull());
1894
case TOOL_A_MINUS_P:
1895
imtool.convolve (kernel, kernel_w, kernel_h, bias, OpPequalsAminusP(), HistogramNull());
1898
imtool.convolve (kernel, kernel_w, kernel_h, bias, OpPequalsPplusA(), HistogramNull());
1900
case TOOL_P_TIMES_A:
1901
imtool.convolve (kernel, kernel_w, kernel_h, bias, OpPequalsPtimesA(), HistogramNull());
1903
case TOOL_P_DIVBY_A:
1904
imtool.convolve (kernel, kernel_w, kernel_h, bias, OpPequalsPdivByA(), HistogramNull());
1906
case TOOL_A_DIVBY_P:
1907
imtool.convolve (kernel, kernel_w, kernel_h, bias, OpPequalsAdivByP(), HistogramNull());
1910
imtool.convolve (kernel, kernel_w, kernel_h, bias, OpPequalsMinPA(), HistogramNull());
1913
imtool.convolve (kernel, kernel_w, kernel_h, bias, OpPequalsMaxPA(), HistogramNull());
1916
case TOOL_A_WITH_HISTOGRAM:
1917
imtool.convolve (kernel, kernel_w, kernel_h, bias, OpPequalsA(), *histogram);
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);
1922
case TOOL_P_MINUS_A_WITH_HISTOGRAM:
1923
imtool.convolve (kernel, kernel_w, kernel_h, bias, OpPequalsPminusA(), *histogram);
1925
case TOOL_A_MINUS_P_WITH_HISTOGRAM:
1926
imtool.convolve (kernel, kernel_w, kernel_h, bias, OpPequalsAminusP(), *histogram);
1928
case TOOL_P_PLUS_A_WITH_HISTOGRAM:
1929
imtool.convolve (kernel, kernel_w, kernel_h, bias, OpPequalsPplusA(), *histogram);
1931
case TOOL_P_TIMES_A_WITH_HISTOGRAM:
1932
imtool.convolve (kernel, kernel_w, kernel_h, bias, OpPequalsPtimesA(), *histogram);
1934
case TOOL_P_DIVBY_A_WITH_HISTOGRAM:
1935
imtool.convolve (kernel, kernel_w, kernel_h, bias, OpPequalsPdivByA(), *histogram);
1937
case TOOL_A_DIVBY_P_WITH_HISTOGRAM:
1938
imtool.convolve (kernel, kernel_w, kernel_h, bias, OpPequalsAdivByP(), *histogram);
1940
case TOOL_MIN_P_A_WITH_HISTOGRAM:
1941
imtool.convolve (kernel, kernel_w, kernel_h, bias, OpPequalsMinPA(), *histogram);
1943
case TOOL_MAX_P_A_WITH_HISTOGRAM:
1944
imtool.convolve (kernel, kernel_w, kernel_h, bias, OpPequalsMaxPA(), *histogram);
1948
imtool.convolve (kernel, kernel_w, kernel_h, bias,
1949
OpPequalsA_Scaled (rbias, rmultiplier), HistogramNull());
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());
1955
case TOOL_P_MINUS_A_SCALED:
1956
imtool.convolve (kernel, kernel_w, kernel_h, bias,
1957
OpPequalsPminusA_Scaled (rbias, rmultiplier), HistogramNull());
1959
case TOOL_A_MINUS_P_SCALED:
1960
imtool.convolve (kernel, kernel_w, kernel_h, bias,
1961
OpPequalsAminusP_Scaled (rbias, rmultiplier), HistogramNull());
1963
case TOOL_P_PLUS_A_SCALED:
1964
imtool.convolve (kernel, kernel_w, kernel_h, bias,
1965
OpPequalsPplusA_Scaled (rbias, rmultiplier), HistogramNull());
1967
case TOOL_P_TIMES_A_SCALED:
1968
imtool.convolve (kernel, kernel_w, kernel_h, bias,
1969
OpPequalsPtimesA_Scaled (rbias, rmultiplier), HistogramNull());
1971
case TOOL_P_DIVBY_A_SCALED:
1972
imtool.convolve (kernel, kernel_w, kernel_h, bias,
1973
OpPequalsPdivByA_Scaled (rbias, rmultiplier), HistogramNull());
1975
case TOOL_A_DIVBY_P_SCALED:
1976
imtool.convolve (kernel, kernel_w, kernel_h, bias,
1977
OpPequalsAdivByP_Scaled (rbias, rmultiplier), HistogramNull());
1979
case TOOL_MIN_P_A_SCALED:
1980
imtool.convolve (kernel, kernel_w, kernel_h, bias,
1981
OpPequalsMinPA_Scaled (rbias, rmultiplier), HistogramNull());
1983
case TOOL_MAX_P_A_SCALED:
1984
imtool.convolve (kernel, kernel_w, kernel_h, bias,
1985
OpPequalsMaxPA_Scaled (rbias, rmultiplier), HistogramNull());
1988
case TOOL_A_SCALED_WITH_HISTOGRAM:
1989
imtool.convolve (kernel, kernel_w, kernel_h, bias,
1990
OpPequalsA_Scaled (rbias, rmultiplier), *histogram);
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);
1996
case TOOL_P_MINUS_A_SCALED_WITH_HISTOGRAM:
1997
imtool.convolve (kernel, kernel_w, kernel_h, bias,
1998
OpPequalsPminusA_Scaled (rbias, rmultiplier), *histogram);
2000
case TOOL_A_MINUS_P_SCALED_WITH_HISTOGRAM:
2001
imtool.convolve (kernel, kernel_w, kernel_h, bias,
2002
OpPequalsAminusP_Scaled (rbias, rmultiplier), *histogram);
2004
case TOOL_P_PLUS_A_SCALED_WITH_HISTOGRAM:
2005
imtool.convolve (kernel, kernel_w, kernel_h, bias,
2006
OpPequalsPplusA_Scaled (rbias, rmultiplier), *histogram);
2008
case TOOL_P_TIMES_A_SCALED_WITH_HISTOGRAM:
2009
imtool.convolve (kernel, kernel_w, kernel_h, bias,
2010
OpPequalsPtimesA_Scaled (rbias, rmultiplier), *histogram);
2012
case TOOL_P_DIVBY_A_SCALED_WITH_HISTOGRAM:
2013
imtool.convolve (kernel, kernel_w, kernel_h, bias,
2014
OpPequalsPdivByA_Scaled (rbias, rmultiplier), *histogram);
2016
case TOOL_A_DIVBY_P_SCALED_WITH_HISTOGRAM:
2017
imtool.convolve (kernel, kernel_w, kernel_h, bias,
2018
OpPequalsAdivByP_Scaled (rbias, rmultiplier), *histogram);
2020
case TOOL_MIN_P_A_SCALED_WITH_HISTOGRAM:
2021
imtool.convolve (kernel, kernel_w, kernel_h, bias,
2022
OpPequalsMinPA_Scaled (rbias, rmultiplier), *histogram);
2024
case TOOL_MAX_P_A_SCALED_WITH_HISTOGRAM:
2025
imtool.convolve (kernel, kernel_w, kernel_h, bias,
2026
OpPequalsMaxPA_Scaled (rbias, rmultiplier), *histogram);
2030
fprintf (stderr, "SwissArmyKnife: unknown operation (tool) %d!\n",
2035
else if (doingRollingAvg)
2040
sak->computeRollingAverage (image, data, planesize, param, bias,
2041
OpPequalsA(), HistogramNull());
2043
case TOOL_P: // HERE: we could optimize this if we wanted to
2044
sak->computeRollingAverage (image, data, planesize, param, bias,
2045
OpPequalsP(), HistogramNull());
2047
case TOOL_P_MINUS_A:
2048
sak->computeRollingAverage (image, data, planesize, param, bias,
2049
OpPequalsPminusA(), HistogramNull());
2051
case TOOL_A_MINUS_P:
2052
sak->computeRollingAverage (image, data, planesize, param, bias,
2053
OpPequalsAminusP(), HistogramNull());
2056
sak->computeRollingAverage (image, data, planesize, param, bias,
2057
OpPequalsPplusA(), HistogramNull());
2059
case TOOL_P_TIMES_A:
2060
sak->computeRollingAverage (image, data, planesize, param, bias,
2061
OpPequalsPtimesA(), HistogramNull());
2063
case TOOL_P_DIVBY_A:
2064
sak->computeRollingAverage (image, data, planesize, param, bias,
2065
OpPequalsPdivByA(), HistogramNull());
2067
case TOOL_A_DIVBY_P:
2068
sak->computeRollingAverage (image, data, planesize, param, bias,
2069
OpPequalsAdivByP(), HistogramNull());
2072
sak->computeRollingAverage (image, data, planesize, param, bias,
2073
OpPequalsMinPA(), HistogramNull());
2076
sak->computeRollingAverage (image, data, planesize, param, bias,
2077
OpPequalsMaxPA(), HistogramNull());
2080
case TOOL_A_WITH_HISTOGRAM:
2081
sak->computeRollingAverage (image, data, planesize, param, bias,
2082
OpPequalsA(), *histogram);
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);
2088
case TOOL_P_MINUS_A_WITH_HISTOGRAM:
2089
sak->computeRollingAverage (image, data, planesize, param, bias,
2090
OpPequalsPminusA(), *histogram);
2092
case TOOL_A_MINUS_P_WITH_HISTOGRAM:
2093
sak->computeRollingAverage (image, data, planesize, param, bias,
2094
OpPequalsAminusP(), *histogram);
2096
case TOOL_P_PLUS_A_WITH_HISTOGRAM:
2097
sak->computeRollingAverage (image, data, planesize, param, bias,
2098
OpPequalsPplusA(), *histogram);
2100
case TOOL_P_TIMES_A_WITH_HISTOGRAM:
2101
sak->computeRollingAverage (image, data, planesize, param, bias,
2102
OpPequalsPtimesA(), *histogram);
2104
case TOOL_P_DIVBY_A_WITH_HISTOGRAM:
2105
sak->computeRollingAverage (image, data, planesize, param, bias,
2106
OpPequalsPdivByA(), *histogram);
2108
case TOOL_A_DIVBY_P_WITH_HISTOGRAM:
2109
sak->computeRollingAverage (image, data, planesize, param, bias,
2110
OpPequalsAdivByP(), *histogram);
2112
case TOOL_MIN_P_A_WITH_HISTOGRAM:
2113
sak->computeRollingAverage (image, data, planesize, param, bias,
2114
OpPequalsMinPA(), *histogram);
2116
case TOOL_MAX_P_A_WITH_HISTOGRAM:
2117
sak->computeRollingAverage (image, data, planesize, param, bias,
2118
OpPequalsMaxPA(), *histogram);
2122
sak->computeRollingAverage (image, data, planesize, param, bias,
2123
OpPequalsA_Scaled (rbias, rmultiplier),
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),
2131
case TOOL_P_MINUS_A_SCALED:
2132
sak->computeRollingAverage (image, data, planesize, param, bias,
2133
OpPequalsPminusA_Scaled (rbias, rmultiplier),
2136
case TOOL_A_MINUS_P_SCALED:
2137
sak->computeRollingAverage (image, data, planesize, param, bias,
2138
OpPequalsAminusP_Scaled (rbias, rmultiplier),
2141
case TOOL_P_PLUS_A_SCALED:
2142
sak->computeRollingAverage (image, data, planesize, param, bias,
2143
OpPequalsPplusA_Scaled (rbias, rmultiplier),
2146
case TOOL_P_TIMES_A_SCALED:
2147
sak->computeRollingAverage (image, data, planesize, param, bias,
2148
OpPequalsPtimesA_Scaled (rbias, rmultiplier),
2151
case TOOL_P_DIVBY_A_SCALED:
2152
sak->computeRollingAverage (image, data, planesize, param, bias,
2153
OpPequalsPdivByA_Scaled (rbias, rmultiplier),
2156
case TOOL_A_DIVBY_P_SCALED:
2157
sak->computeRollingAverage (image, data, planesize, param, bias,
2158
OpPequalsAdivByP_Scaled (rbias, rmultiplier),
2161
case TOOL_MIN_P_A_SCALED:
2162
sak->computeRollingAverage (image, data, planesize, param, bias,
2163
OpPequalsMinPA_Scaled (rbias, rmultiplier),
2166
case TOOL_MAX_P_A_SCALED:
2167
sak->computeRollingAverage (image, data, planesize, param, bias,
2168
OpPequalsMaxPA_Scaled (rbias, rmultiplier),
2172
case TOOL_A_SCALED_WITH_HISTOGRAM:
2173
sak->computeRollingAverage (image, data, planesize, param, bias,
2174
OpPequalsA_Scaled (rbias, rmultiplier),
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),
2182
case TOOL_P_MINUS_A_SCALED_WITH_HISTOGRAM:
2183
sak->computeRollingAverage (image, data, planesize, param, bias,
2184
OpPequalsPminusA_Scaled (rbias, rmultiplier),
2187
case TOOL_A_MINUS_P_SCALED_WITH_HISTOGRAM:
2188
sak->computeRollingAverage (image, data, planesize, param, bias,
2189
OpPequalsAminusP_Scaled (rbias, rmultiplier),
2192
case TOOL_P_PLUS_A_SCALED_WITH_HISTOGRAM:
2193
sak->computeRollingAverage (image, data, planesize, param, bias,
2194
OpPequalsPplusA_Scaled (rbias, rmultiplier),
2197
case TOOL_P_TIMES_A_SCALED_WITH_HISTOGRAM:
2198
sak->computeRollingAverage (image, data, planesize, param, bias,
2199
OpPequalsPtimesA_Scaled (rbias, rmultiplier),
2202
case TOOL_P_DIVBY_A_SCALED_WITH_HISTOGRAM:
2203
sak->computeRollingAverage (image, data, planesize, param, bias,
2204
OpPequalsPdivByA_Scaled (rbias, rmultiplier),
2207
case TOOL_A_DIVBY_P_SCALED_WITH_HISTOGRAM:
2208
sak->computeRollingAverage (image, data, planesize, param, bias,
2209
OpPequalsAdivByP_Scaled (rbias, rmultiplier),
2212
case TOOL_MIN_P_A_SCALED_WITH_HISTOGRAM:
2213
sak->computeRollingAverage (image, data, planesize, param, bias,
2214
OpPequalsMinPA_Scaled (rbias, rmultiplier),
2217
case TOOL_MAX_P_A_SCALED_WITH_HISTOGRAM:
2218
sak->computeRollingAverage (image, data, planesize, param, bias,
2219
OpPequalsMaxPA_Scaled (rbias, rmultiplier),
2224
fprintf (stderr, "SwissArmyKnife: unknown operation (tool) %d!\n",
2229
else if (doingFileImageFloat)
2231
if (width != myInfo->image_w || height != myInfo->image_h)
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);
2242
float * flt_img = myInfo->image_float;
2247
sak->applyImage (image, data, planesize, param, bias, flt_img,
2248
OpPequalsA(), HistogramNull());
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());
2254
case TOOL_P_MINUS_A:
2255
sak->applyImage (image, data, planesize, param, bias, flt_img,
2256
OpPequalsPminusA(), HistogramNull());
2258
case TOOL_A_MINUS_P:
2259
sak->applyImage (image, data, planesize, param, bias, flt_img,
2260
OpPequalsAminusP(), HistogramNull());
2263
sak->applyImage (image, data, planesize, param, bias, flt_img,
2264
OpPequalsPplusA(), HistogramNull());
2266
case TOOL_P_TIMES_A:
2267
sak->applyImage (image, data, planesize, param, bias, flt_img,
2268
OpPequalsPtimesA(), HistogramNull());
2270
case TOOL_P_DIVBY_A:
2271
sak->applyImage (image, data, planesize, param, bias, flt_img,
2272
OpPequalsPdivByA(), HistogramNull());
2274
case TOOL_A_DIVBY_P:
2275
sak->applyImage (image, data, planesize, param, bias, flt_img,
2276
OpPequalsAdivByP(), HistogramNull());
2279
sak->applyImage (image, data, planesize, param, bias, flt_img,
2280
OpPequalsMinPA(), HistogramNull());
2283
sak->applyImage (image, data, planesize, param, bias, flt_img,
2284
OpPequalsMaxPA(), HistogramNull());
2287
case TOOL_A_WITH_HISTOGRAM:
2288
sak->applyImage (image, data, planesize, param, bias, flt_img,
2289
OpPequalsA(), *histogram);
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);
2295
case TOOL_P_MINUS_A_WITH_HISTOGRAM:
2296
sak->applyImage (image, data, planesize, param, bias, flt_img,
2297
OpPequalsPminusA(), *histogram);
2299
case TOOL_A_MINUS_P_WITH_HISTOGRAM:
2300
sak->applyImage (image, data, planesize, param, bias, flt_img,
2301
OpPequalsAminusP(), *histogram);
2303
case TOOL_P_PLUS_A_WITH_HISTOGRAM:
2304
sak->applyImage (image, data, planesize, param, bias, flt_img,
2305
OpPequalsPplusA(), *histogram);
2307
case TOOL_P_TIMES_A_WITH_HISTOGRAM:
2308
sak->applyImage (image, data, planesize, param, bias, flt_img,
2309
OpPequalsPtimesA(), *histogram);
2311
case TOOL_P_DIVBY_A_WITH_HISTOGRAM:
2312
sak->applyImage (image, data, planesize, param, bias, flt_img,
2313
OpPequalsPdivByA(), *histogram);
2315
case TOOL_A_DIVBY_P_WITH_HISTOGRAM:
2316
sak->applyImage (image, data, planesize, param, bias, flt_img,
2317
OpPequalsAdivByP(), *histogram);
2319
case TOOL_MIN_P_A_WITH_HISTOGRAM:
2320
sak->applyImage (image, data, planesize, param, bias, flt_img,
2321
OpPequalsMinPA(), *histogram);
2323
case TOOL_MAX_P_A_WITH_HISTOGRAM:
2324
sak->applyImage (image, data, planesize, param, bias, flt_img,
2325
OpPequalsMaxPA(), *histogram);
2329
sak->applyImage (image, data, planesize, param, bias, flt_img,
2330
OpPequalsA_Scaled (rbias, rmultiplier),
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),
2338
case TOOL_P_MINUS_A_SCALED:
2339
sak->applyImage (image, data, planesize, param, bias, flt_img,
2340
OpPequalsPminusA_Scaled (rbias, rmultiplier),
2343
case TOOL_A_MINUS_P_SCALED:
2344
sak->applyImage (image, data, planesize, param, bias, flt_img,
2345
OpPequalsAminusP_Scaled (rbias, rmultiplier),
2348
case TOOL_P_PLUS_A_SCALED:
2349
sak->applyImage (image, data, planesize, param, bias, flt_img,
2350
OpPequalsPplusA_Scaled (rbias, rmultiplier),
2353
case TOOL_P_TIMES_A_SCALED:
2354
sak->applyImage (image, data, planesize, param, bias, flt_img,
2355
OpPequalsPtimesA_Scaled (rbias, rmultiplier),
2358
case TOOL_P_DIVBY_A_SCALED:
2359
sak->applyImage (image, data, planesize, param, bias, flt_img,
2360
OpPequalsPdivByA_Scaled (rbias, rmultiplier),
2363
case TOOL_A_DIVBY_P_SCALED:
2364
sak->applyImage (image, data, planesize, param, bias, flt_img,
2365
OpPequalsAdivByP_Scaled (rbias, rmultiplier),
2368
case TOOL_MIN_P_A_SCALED:
2369
sak->applyImage (image, data, planesize, param, bias, flt_img,
2370
OpPequalsMinPA_Scaled (rbias, rmultiplier),
2373
case TOOL_MAX_P_A_SCALED:
2374
sak->applyImage (image, data, planesize, param, bias, flt_img,
2375
OpPequalsMaxPA_Scaled (rbias, rmultiplier),
2379
case TOOL_A_SCALED_WITH_HISTOGRAM:
2380
sak->applyImage (image, data, planesize, param, bias, flt_img,
2381
OpPequalsA_Scaled (rbias, rmultiplier),
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),
2389
case TOOL_P_MINUS_A_SCALED_WITH_HISTOGRAM:
2390
sak->applyImage (image, data, planesize, param, bias, flt_img,
2391
OpPequalsPminusA_Scaled (rbias, rmultiplier),
2394
case TOOL_A_MINUS_P_SCALED_WITH_HISTOGRAM:
2395
sak->applyImage (image, data, planesize, param, bias, flt_img,
2396
OpPequalsAminusP_Scaled (rbias, rmultiplier),
2399
case TOOL_P_PLUS_A_SCALED_WITH_HISTOGRAM:
2400
sak->applyImage (image, data, planesize, param, bias, flt_img,
2401
OpPequalsPplusA_Scaled (rbias, rmultiplier),
2404
case TOOL_P_TIMES_A_SCALED_WITH_HISTOGRAM:
2405
sak->applyImage (image, data, planesize, param, bias, flt_img,
2406
OpPequalsPtimesA_Scaled (rbias, rmultiplier),
2409
case TOOL_P_DIVBY_A_SCALED_WITH_HISTOGRAM:
2410
sak->applyImage (image, data, planesize, param, bias, flt_img,
2411
OpPequalsPdivByA_Scaled (rbias, rmultiplier),
2414
case TOOL_A_DIVBY_P_SCALED_WITH_HISTOGRAM:
2415
sak->applyImage (image, data, planesize, param, bias, flt_img,
2416
OpPequalsAdivByP_Scaled (rbias, rmultiplier),
2419
case TOOL_MIN_P_A_SCALED_WITH_HISTOGRAM:
2420
sak->applyImage (image, data, planesize, param, bias, flt_img,
2421
OpPequalsMinPA_Scaled (rbias, rmultiplier),
2424
case TOOL_MAX_P_A_SCALED_WITH_HISTOGRAM:
2425
sak->applyImage (image, data, planesize, param, bias, flt_img,
2426
OpPequalsMaxPA_Scaled (rbias, rmultiplier),
2431
fprintf (stderr, "SwissArmyKnife: unknown operation (tool) %d!\n",
2436
else if (doingFileImage)
2438
if (width != myInfo->image_w || height != myInfo->image_h)
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);
2449
uint8_t * int_img = myInfo->image_int;
2454
sak->applyImage (image, data, planesize, param, bias, int_img,
2455
OpPequalsA(), HistogramNull());
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());
2461
case TOOL_P_MINUS_A:
2462
sak->applyImage (image, data, planesize, param, bias, int_img,
2463
OpPequalsPminusA(), HistogramNull());
2465
case TOOL_A_MINUS_P:
2466
sak->applyImage (image, data, planesize, param, bias, int_img,
2467
OpPequalsAminusP(), HistogramNull());
2470
sak->applyImage (image, data, planesize, param, bias, int_img,
2471
OpPequalsPplusA(), HistogramNull());
2473
case TOOL_P_TIMES_A:
2474
sak->applyImage (image, data, planesize, param, bias, int_img,
2475
OpPequalsPtimesA(), HistogramNull());
2477
case TOOL_P_DIVBY_A:
2478
sak->applyImage (image, data, planesize, param, bias, int_img,
2479
OpPequalsPdivByA(), HistogramNull());
2481
case TOOL_A_DIVBY_P:
2482
sak->applyImage (image, data, planesize, param, bias, int_img,
2483
OpPequalsAdivByP(), HistogramNull());
2486
sak->applyImage (image, data, planesize, param, bias, int_img,
2487
OpPequalsMinPA(), HistogramNull());
2490
sak->applyImage (image, data, planesize, param, bias, int_img,
2491
OpPequalsMaxPA(), HistogramNull());
2494
case TOOL_A_WITH_HISTOGRAM:
2495
sak->applyImage (image, data, planesize, param, bias, int_img,
2496
OpPequalsA(), *histogram);
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);
2502
case TOOL_P_MINUS_A_WITH_HISTOGRAM:
2503
sak->applyImage (image, data, planesize, param, bias, int_img,
2504
OpPequalsPminusA(), *histogram);
2506
case TOOL_A_MINUS_P_WITH_HISTOGRAM:
2507
sak->applyImage (image, data, planesize, param, bias, int_img,
2508
OpPequalsAminusP(), *histogram);
2510
case TOOL_P_PLUS_A_WITH_HISTOGRAM:
2511
sak->applyImage (image, data, planesize, param, bias, int_img,
2512
OpPequalsPplusA(), *histogram);
2514
case TOOL_P_TIMES_A_WITH_HISTOGRAM:
2515
sak->applyImage (image, data, planesize, param, bias, int_img,
2516
OpPequalsPtimesA(), *histogram);
2518
case TOOL_P_DIVBY_A_WITH_HISTOGRAM:
2519
sak->applyImage (image, data, planesize, param, bias, int_img,
2520
OpPequalsPdivByA(), *histogram);
2522
case TOOL_A_DIVBY_P_WITH_HISTOGRAM:
2523
sak->applyImage (image, data, planesize, param, bias, int_img,
2524
OpPequalsAdivByP(), *histogram);
2526
case TOOL_MIN_P_A_WITH_HISTOGRAM:
2527
sak->applyImage (image, data, planesize, param, bias, int_img,
2528
OpPequalsMinPA(), *histogram);
2530
case TOOL_MAX_P_A_WITH_HISTOGRAM:
2531
sak->applyImage (image, data, planesize, param, bias, int_img,
2532
OpPequalsMaxPA(), *histogram);
2536
sak->applyImage (image, data, planesize, param, bias, int_img,
2537
OpPequalsA_Scaled (rbias, rmultiplier),
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),
2545
case TOOL_P_MINUS_A_SCALED:
2546
sak->applyImage (image, data, planesize, param, bias, int_img,
2547
OpPequalsPminusA_Scaled (rbias, rmultiplier),
2550
case TOOL_A_MINUS_P_SCALED:
2551
sak->applyImage (image, data, planesize, param, bias, int_img,
2552
OpPequalsAminusP_Scaled (rbias, rmultiplier),
2555
case TOOL_P_PLUS_A_SCALED:
2556
sak->applyImage (image, data, planesize, param, bias, int_img,
2557
OpPequalsPplusA_Scaled (rbias, rmultiplier),
2560
case TOOL_P_TIMES_A_SCALED:
2561
sak->applyImage (image, data, planesize, param, bias, int_img,
2562
OpPequalsPtimesA_Scaled (rbias, rmultiplier),
2565
case TOOL_P_DIVBY_A_SCALED:
2566
sak->applyImage (image, data, planesize, param, bias, int_img,
2567
OpPequalsPdivByA_Scaled (rbias, rmultiplier),
2570
case TOOL_A_DIVBY_P_SCALED:
2571
sak->applyImage (image, data, planesize, param, bias, int_img,
2572
OpPequalsAdivByP_Scaled (rbias, rmultiplier),
2575
case TOOL_MIN_P_A_SCALED:
2576
sak->applyImage (image, data, planesize, param, bias, int_img,
2577
OpPequalsMinPA_Scaled (rbias, rmultiplier),
2580
case TOOL_MAX_P_A_SCALED:
2581
sak->applyImage (image, data, planesize, param, bias, int_img,
2582
OpPequalsMaxPA_Scaled (rbias, rmultiplier),
2586
case TOOL_A_SCALED_WITH_HISTOGRAM:
2587
sak->applyImage (image, data, planesize, param, bias, int_img,
2588
OpPequalsA_Scaled (rbias, rmultiplier),
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),
2596
case TOOL_P_MINUS_A_SCALED_WITH_HISTOGRAM:
2597
sak->applyImage (image, data, planesize, param, bias, int_img,
2598
OpPequalsPminusA_Scaled (rbias, rmultiplier),
2601
case TOOL_A_MINUS_P_SCALED_WITH_HISTOGRAM:
2602
sak->applyImage (image, data, planesize, param, bias, int_img,
2603
OpPequalsAminusP_Scaled (rbias, rmultiplier),
2606
case TOOL_P_PLUS_A_SCALED_WITH_HISTOGRAM:
2607
sak->applyImage (image, data, planesize, param, bias, int_img,
2608
OpPequalsPplusA_Scaled (rbias, rmultiplier),
2611
case TOOL_P_TIMES_A_SCALED_WITH_HISTOGRAM:
2612
sak->applyImage (image, data, planesize, param, bias, int_img,
2613
OpPequalsPtimesA_Scaled (rbias, rmultiplier),
2616
case TOOL_P_DIVBY_A_SCALED_WITH_HISTOGRAM:
2617
sak->applyImage (image, data, planesize, param, bias, int_img,
2618
OpPequalsPdivByA_Scaled (rbias, rmultiplier),
2621
case TOOL_A_DIVBY_P_SCALED_WITH_HISTOGRAM:
2622
sak->applyImage (image, data, planesize, param, bias, int_img,
2623
OpPequalsAdivByP_Scaled (rbias, rmultiplier),
2626
case TOOL_MIN_P_A_SCALED_WITH_HISTOGRAM:
2627
sak->applyImage (image, data, planesize, param, bias, int_img,
2628
OpPequalsMinPA_Scaled (rbias, rmultiplier),
2631
case TOOL_MAX_P_A_SCALED_WITH_HISTOGRAM:
2632
sak->applyImage (image, data, planesize, param, bias, int_img,
2633
OpPequalsMaxPA_Scaled (rbias, rmultiplier),
2638
fprintf (stderr, "SwissArmyKnife: unknown operation (tool) %d!\n",
2643
else if (doingApplyConstant)
2648
sak->applyConstant (image, data, planesize, param, bias,
2649
OpPequalsA(), HistogramNull());
2651
case TOOL_P: // HERE: we could optimize this if we wanted to
2652
sak->applyConstant (image, data, planesize, param, bias,
2653
OpPequalsP(), HistogramNull());
2655
case TOOL_P_MINUS_A:
2656
sak->applyConstant (image, data, planesize, param, bias,
2657
OpPequalsPminusA(), HistogramNull());
2659
case TOOL_A_MINUS_P:
2660
sak->applyConstant (image, data, planesize, param, bias,
2661
OpPequalsAminusP(), HistogramNull());
2664
sak->applyConstant (image, data, planesize, param, bias,
2665
OpPequalsPplusA(), HistogramNull());
2667
case TOOL_P_TIMES_A:
2668
sak->applyConstant (image, data, planesize, param, bias,
2669
OpPequalsPtimesA(), HistogramNull());
2671
case TOOL_P_DIVBY_A:
2672
sak->applyConstant (image, data, planesize, param, bias,
2673
OpPequalsPdivByA(), HistogramNull());
2675
case TOOL_A_DIVBY_P:
2676
sak->applyConstant (image, data, planesize, param, bias,
2677
OpPequalsAdivByP(), HistogramNull());
2680
sak->applyConstant (image, data, planesize, param, bias,
2681
OpPequalsMinPA(), HistogramNull());
2684
sak->applyConstant (image, data, planesize, param, bias,
2685
OpPequalsMaxPA(), HistogramNull());
2688
case TOOL_A_WITH_HISTOGRAM:
2689
sak->applyConstant (image, data, planesize, param, bias,
2690
OpPequalsA(), *histogram);
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);
2696
case TOOL_P_MINUS_A_WITH_HISTOGRAM:
2697
sak->applyConstant (image, data, planesize, param, bias,
2698
OpPequalsPminusA(), *histogram);
2700
case TOOL_A_MINUS_P_WITH_HISTOGRAM:
2701
sak->applyConstant (image, data, planesize, param, bias,
2702
OpPequalsAminusP(), *histogram);
2704
case TOOL_P_PLUS_A_WITH_HISTOGRAM:
2705
sak->applyConstant (image, data, planesize, param, bias,
2706
OpPequalsPplusA(), *histogram);
2708
case TOOL_P_TIMES_A_WITH_HISTOGRAM:
2709
sak->applyConstant (image, data, planesize, param, bias,
2710
OpPequalsPtimesA(), *histogram);
2712
case TOOL_P_DIVBY_A_WITH_HISTOGRAM:
2713
sak->applyConstant (image, data, planesize, param, bias,
2714
OpPequalsPdivByA(), *histogram);
2716
case TOOL_A_DIVBY_P_WITH_HISTOGRAM:
2717
sak->applyConstant (image, data, planesize, param, bias,
2718
OpPequalsAdivByP(), *histogram);
2720
case TOOL_MIN_P_A_WITH_HISTOGRAM:
2721
sak->applyConstant (image, data, planesize, param, bias,
2722
OpPequalsMinPA(), *histogram);
2724
case TOOL_MAX_P_A_WITH_HISTOGRAM:
2725
sak->applyConstant (image, data, planesize, param, bias,
2726
OpPequalsMaxPA(), *histogram);
2730
sak->applyConstant (image, data, planesize, param, bias,
2731
OpPequalsA_Scaled (rbias, rmultiplier),
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),
2739
case TOOL_P_MINUS_A_SCALED:
2740
sak->applyConstant (image, data, planesize, param, bias,
2741
OpPequalsPminusA_Scaled (rbias, rmultiplier),
2744
case TOOL_A_MINUS_P_SCALED:
2745
sak->applyConstant (image, data, planesize, param, bias,
2746
OpPequalsAminusP_Scaled (rbias, rmultiplier),
2749
case TOOL_P_PLUS_A_SCALED:
2750
sak->applyConstant (image, data, planesize, param, bias,
2751
OpPequalsPplusA_Scaled (rbias, rmultiplier),
2754
case TOOL_P_TIMES_A_SCALED:
2755
sak->applyConstant (image, data, planesize, param, bias,
2756
OpPequalsPtimesA_Scaled (rbias, rmultiplier),
2759
case TOOL_P_DIVBY_A_SCALED:
2760
sak->applyConstant (image, data, planesize, param, bias,
2761
OpPequalsPdivByA_Scaled (rbias, rmultiplier),
2764
case TOOL_A_DIVBY_P_SCALED:
2765
sak->applyConstant (image, data, planesize, param, bias,
2766
OpPequalsAdivByP_Scaled (rbias, rmultiplier),
2769
case TOOL_MIN_P_A_SCALED:
2770
sak->applyConstant (image, data, planesize, param, bias,
2771
OpPequalsMinPA_Scaled (rbias, rmultiplier),
2774
case TOOL_MAX_P_A_SCALED:
2775
sak->applyConstant (image, data, planesize, param, bias,
2776
OpPequalsMaxPA_Scaled (rbias, rmultiplier),
2780
case TOOL_A_SCALED_WITH_HISTOGRAM:
2781
sak->applyConstant (image, data, planesize, param, bias,
2782
OpPequalsA_Scaled (rbias, rmultiplier),
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),
2790
case TOOL_P_MINUS_A_SCALED_WITH_HISTOGRAM:
2791
sak->applyConstant (image, data, planesize, param, bias,
2792
OpPequalsPminusA_Scaled (rbias, rmultiplier),
2795
case TOOL_A_MINUS_P_SCALED_WITH_HISTOGRAM:
2796
sak->applyConstant (image, data, planesize, param, bias,
2797
OpPequalsAminusP_Scaled (rbias, rmultiplier),
2800
case TOOL_P_PLUS_A_SCALED_WITH_HISTOGRAM:
2801
sak->applyConstant (image, data, planesize, param, bias,
2802
OpPequalsPplusA_Scaled (rbias, rmultiplier),
2805
case TOOL_P_TIMES_A_SCALED_WITH_HISTOGRAM:
2806
sak->applyConstant (image, data, planesize, param, bias,
2807
OpPequalsPtimesA_Scaled (rbias, rmultiplier),
2810
case TOOL_P_DIVBY_A_SCALED_WITH_HISTOGRAM:
2811
sak->applyConstant (image, data, planesize, param, bias,
2812
OpPequalsPdivByA_Scaled (rbias, rmultiplier),
2815
case TOOL_A_DIVBY_P_SCALED_WITH_HISTOGRAM:
2816
sak->applyConstant (image, data, planesize, param, bias,
2817
OpPequalsAdivByP_Scaled (rbias, rmultiplier),
2820
case TOOL_MIN_P_A_SCALED_WITH_HISTOGRAM:
2821
sak->applyConstant (image, data, planesize, param, bias,
2822
OpPequalsMinPA_Scaled (rbias, rmultiplier),
2825
case TOOL_MAX_P_A_SCALED_WITH_HISTOGRAM:
2826
sak->applyConstant (image, data, planesize, param, bias,
2827
OpPequalsMaxPA_Scaled (rbias, rmultiplier),
2832
fprintf (stderr, "SwissArmyKnife: unknown operation (tool) %d!\n",
2839
fprintf (stderr, "ooops! input selection botch in SwissArmyKnife!\n");
2845
histogram->frame_check();
2849
// HERE: the following two lines do a luma-only-ize
2851
memset (UPLANE (data), 128, planesize >> 2);
2852
memset (VPLANE (data), 128, planesize >> 2);
2854
data->copyInfo(image);