AKTIVE

Artifact [a7a714d6c6]
Login

Artifact [a7a714d6c6]

Artifact a7a714d6c63eb2d18e69fd7c164374c58d9bd9c605f32001f8843d73f574a4e6:


## -*- mode: tcl ; fill-column: 90 -*-
# # ## ### ##### ######## ############# #####################
## Transformers -- Statistics by bands.

# # ## ### ##### ######## ############# #####################
## Compress bands down to a statistic

operator {dexpr attr} {
    op::band::arg::max   {first index}        maximal
    op::band::arg::min   {first index}        minimal
    op::band::max         maximum              {}
    op::band::mean        {arithmetic mean}    {}
    op::band::min         minimum              {}
    op::band::stddev      {standard deviation} {}
    op::band::sum         sum                  {}
    op::band::sumsquared  sum                  squared
    op::band::variance    variance             {}
} {
    op -> _ kind fun extra
    if {$fun eq "arg"} { def fun $fun$extra }

    section transform statistics

    ## simplifications (also apply for input depth == 1)
    #
    ## - arg::max   :: const 0 (single value is max, at index 0)
    ## - arg::min   :: const 0 (single value is min, at index 0)
    ## - max        :: elide (idempotent / identity)
    ## - mean       :: elide (idempotent / identity)
    ## - min        :: elide (idempotent / identity)
    ## - stddev     :: const 0
    ## - sum        :: elide (idempotent / identity)
    ## - sumsquared :: op math1 pow 2 (power chaining)
    ## - variance   :: const 0

    import? ../simpler/stat_$fun.rules	;# queries kind !!

    note Returns an image with the input bands compressed to a single value, \
	the ${dexpr} of the {*}$attr band values. The result is a single-band \
	image with the same width and height as the input.

    input

    state -setup {
	aktive_geometry_copy (domain, aktive_image_get_geometry (srcs->v[0]));
	domain->depth = 1;
    }

    # iterate over rows in the region and call the band-reducer
    blit reducer {
	{DH {y 0 1 up} {y 0 1 up}}
    } {raw reduce-band {
	REDUCE (dstvalue, srcvalue, SW, SD); // dstvalue, srcvalue :: row start
    }}

    pixels {
	TRACE_RECTANGLE_M("@@fun@@", request);
	aktive_block* src = aktive_region_fetch_area (0, request);
	#define REDUCE aktive_reduce_row_bands_@@fun@@
	@@reducer@@
	#undef REDUCE
    }
}

# # ## ### ##### ######## ############# #####################
## More `arg.*` operators. These take a threshold as controlling argument.

operator {attr} {
    op::band::arg::ge {greater than or equal}
    op::band::arg::gt {greater than}
    op::band::arg::le {lesser than or equal}
    op::band::arg::lt {lesser than}
} {
    op -> _ _ _ fun

    section transform statistics

    note Returns the source image with its bands compressed to a single value, \
	the first index where the band value is $attr than the threshold. \
	The result is a single-band image with the same width and height as the \
	inputs.

    # TODO simplification: for a single-band image the operation is a ternary
    # specifically:   (src REL threshold) ? 0 : DEPTH
    # or:             (src anti-REL threshold) ? DEPTH : 0
    # <=>             (src anti-REL threshold) * DEPTH
    #                 aktive op math1 scale (aktive op math <anti-REL> SRC T) factor DEPTH
    #
    # relation anti-relation
    # -------- -------------
    # ge       lt
    # gt       le
    # le       gt
    # lt       ge
    # -------- -------------

    note The result is suitable for use by "<!xref: aktive op take z>."

    note At the pixels where no band matches the condition the result is the \
	depth of the data image.

    note Both images have to have the same width and height.

    note The threshold image has to be single-band.

    input thresholds	Single-band image of thresholds.
    input src		Source to scan and compress.

    state -setup {
	aktive_image     thresholds = srcs->v[0];
	aktive_image     data       = srcs->v[1];
	aktive_geometry* tg         = aktive_image_get_geometry (thresholds);
	aktive_geometry* dg         = aktive_image_get_geometry (data);

	if (tg->width  != dg->width)  aktive_failf ("width mismatch, %d != %d",  tg->width,  dg->width);
	if (tg->height != dg->height) aktive_failf ("height mismatch, %d != %d", tg->height, dg->height);
	if (tg->depth != 1) aktive_failf ("bad threshold input has depth %d != 1", tg->depth);

	aktive_geometry_copy (domain, tg);
    }

    blit reducer {
	{DH {y 0 1 up} {y 0 1 up} {y 0 1 up}}
	{DW {x 0 1 up} {x 0 1 up} {x 0 1 up}}
    } {raw reduce-band {
	// dstvalue    = row/col start -
	// src0value = row/col start - single-band           | threshold
	// src1value = row/col start - 1-strided band vector | data
	*dstvalue = REDUCE (src1value, S1D, 1, src0value);
    }}

    pixels {
	TRACE_RECTANGLE_M("arg@@fun@@ data", request);
	aktive_block* srcb = aktive_region_fetch_area (1, request);
	TRACE_GEOMETRY_M("srcb geometry (d)", &srcb->domain);

	TRACE_RECTANGLE_M("arg@@fun@@ thresholds", request);
	aktive_block* srca = aktive_region_fetch_area (0, request);
	TRACE_GEOMETRY_M("srca geometry (t)", &srca->domain);

	/**/
	TRACE_GEOMETRY_M("p srcb geometry (d)", &srcb->domain);
	TRACE_GEOMETRY_M("p srca geometry (t)", &srca->domain);
	#define REDUCE aktive_reduce_arg@@fun@@
	@@reducer@@
	#undef REDUCE
    }
}

##
# # ## ### ##### ######## ############# #####################
::return