📄 hplx_vert_synthesis_by_lifting.c
字号:
static void
go_outside_synth_stage_for_row(hplx_synth_buffering_stage_ptr ext_stage)
/* This function is called from within the `hplx_lift_stage__get_rows'
function whenever a new row is required for a buffering stage which
has no generator (result can be produced by a lifting step) within
the current `hplx_synthesis_stage' object. In this case, the row
must be recovered via a `pull_line_xxx' interface function of either
another `hplx_synthesis_stage' object or a dequantizer. The
appropriate object references and invocation arguments are all
found within the current `hplx_vert_synthesis_by_lifting' object
which is referenced by `ext_stage->owner_ref'. */
{
hplx_buffering_stage_ptr stage = &(ext_stage->base);
hplx_vert_synthesis_by_lifting_ref owner;
hplx_synthesis_stage_ref synth;
hplx_row_buffer_state_ptr buf;
int branch_idx;
assert(stage->generator == NULL);
owner = ext_stage->owner_ref;
buf = hplx_lift_stage__add_row(stage);
branch_idx = stage->odd_lines;
synth = owner->base.branches[branch_idx];
if (buf->float_buf != NULL)
{
synth->pull_line_float(synth,buf->float_buf,stage->cols);
if (owner->branch_needs_scaling[branch_idx])
{
float scale, *sp;
int n;
scale = owner->branch_scale[branch_idx];
for (sp=buf->float_buf, n=stage->cols; n > 0; n--)
*(sp++) *= scale;
}
}
else
synth->pull_line_fixed(synth,buf->int_buf,stage->cols);
}
/*****************************************************************************/
/* STATIC hplx_lift_stage__get_rows */
/*****************************************************************************/
static void
hplx_lift_stage__get_rows(hplx_buffering_stage_ptr stage,
int min_row_idx, int num_rows,
hplx_row_buffer_state_ptr bufs[])
/* This function does all the computational work associated with lifting,
including management of extensions at the vertical boundaries of the
image or tile. The function tries to satisfy a request for a range
of rows from the supplied buffering stage. If the range extends beyond
the upper or lower image boundaries, it is modified to include only
those rows which lie within the image and the missing rows are
extrapolated using the same zero-order hold policy which is adopted for
horizontal lifting. Once the range of valid row indices is determined
in this way, the function generate any rows which it does
not already have, either by undoing the lifting steps identified by
buffering stage's `generator' field or, if there is no generator,
by pulling rows from the dequantizer or another `hplx_synthesis_stage'
object. */
{
hplx_synth_buffering_stage_ptr ext_stage =
(hplx_synth_buffering_stage_ptr) stage;
int ext_before, ext_after, next_row_idx, offset, n, p;
hplx_lifting_step_ptr step;
hplx_row_buffer_state_ptr *fp, *lp;
if ((min_row_idx >= stage->rows) || ((min_row_idx+num_rows) <= 0))
{ /* Request lies entirely outside image. No extension will be applied
here; caller should detect NULL buffers and skip the relevant
lifting step. */
while (num_rows--)
*(bufs++) = NULL;
return;
}
ext_before = 0;
if (min_row_idx < 0)
{
ext_before = -min_row_idx;
num_rows -= ext_before;
min_row_idx = 0;
}
ext_after = (num_rows+min_row_idx) - stage->rows;
if (ext_after > 0)
num_rows -= ext_after;
else
ext_after = 0;
assert((num_rows > 0) && (min_row_idx >= stage->min_row_idx));
step = stage->generator;
while ((next_row_idx=stage->next_row_idx) < (min_row_idx+num_rows))
{ /* Need to generate this row. */
hplx_row_buffer_state_ptr source_bufs[8], target_buf, output_buf;
int source_rows, min_source_idx;
int n, k;
if (step == NULL)
{
go_outside_synth_stage_for_row(ext_stage);
continue;
}
/* Undo lifting steps. */
min_source_idx = next_row_idx - step->neg_support;
min_source_idx += step->target->missing_first_row -
step->source->missing_first_row;
source_rows = step->pos_support + step->neg_support + 1;
assert(source_rows <= 8);
hplx_lift_stage__get_rows(step->source,min_source_idx,source_rows,
source_bufs);
hplx_lift_stage__get_rows(step->target,next_row_idx,1,&target_buf);
hplx_lift_stage__release_row(step->source,min_source_idx);
hplx_lift_stage__release_row(step->target,next_row_idx);
output_buf = hplx_lift_stage__add_row(stage);
if (step->float_taps != NULL)
{ /* Undo floating-point lifting step. */
float *taps, *sp[8], *tp, *op, sum;
tp = target_buf->float_buf;
op = output_buf->float_buf;
if (source_bufs[0] == NULL)
{ /* Source range entirely outside image support; skip the step. */
for (n=stage->cols; n > 0; n--)
*(op++) = *(tp++);
}
else if (((next_row_idx == 0) && stage->special_first) ||
(next_row_idx == (stage->rows-stage->special_last)))
{ /* Simply scale the row instead of performing the actual
lifting step. */
float dc_gain = 1.0F / step->dc_gain;
for (n=stage->cols; n > 0; n--)
*(op++) = *(tp++) * dc_gain;
}
else
{
for (k=0; k < source_rows; k++)
sp[k] = source_bufs[k]->float_buf;
taps = step->float_taps - step->neg_support;
for (n=stage->cols; n > 0; n--)
{
for (sum=0.0F, k=0; k < source_rows; k++)
sum += taps[k] * *((sp[k])++);
*(op++) = *(tp++) - sum;
}
}
}
else
{ /* Undo integer lifting step. */
int *taps;
ifc_int *sp[8], *tp, *op;
std_int sum, offset, downshift;
tp = target_buf->int_buf;
op = output_buf->int_buf;
if (source_bufs[0] == NULL)
{ /* Source range entirely outside image support; skip the step. */
for (n=stage->cols; n > 0; n--)
*(op++) = *(tp++);
}
else if (((next_row_idx == 0) && stage->special_first) ||
(next_row_idx == (stage->rows-stage->special_last)))
{ /* Skip lifting step on frame boundaries. */
for (n=stage->cols; n > 0; n--)
*(op++) = *(tp++);
}
else
{
for (k=0; k < source_rows; k++)
sp[k] = source_bufs[k]->int_buf;
taps = step->int_taps - step->neg_support;
downshift = step->int_downshift;
offset = (1<<downshift)>>1;
for (n=stage->cols; n > 0; n--)
{
for (sum=0, k=0; k < source_rows; k++)
sum += taps[k] * *((sp[k])++);
*(op++) = *(tp++) - ((sum+offset)>>downshift);
}
}
}
}
/* Fill in the contents of the `bufs' array, applying the relevant
symmetric extension policies as necessary. */
offset = min_row_idx - stage->min_row_idx;
fp = bufs + ext_before; /* Points to first interior row. */
lp = fp + num_rows - 1; /* Points to last interior row. */
for (n=0; n < num_rows; n++)
fp[n] = stage->row_buffers[offset+n];
/* Perform extensions, alternating between left and right extension
until we are done. Note that this code will probably not mimic
symmetric extension for even length filters. */
for (n=p=1; (n <= ext_before) || (p <= ext_after); )
{
int did_something;
did_something = 0;
if (n <= ext_before)
{ /* Still need extension to upper part of image. */
if (stage->first_extension)
{ /* Half-point extension. */
if (n <= (num_rows+p-1))
{ fp[-n] = fp[n-1]; n++; did_something = 1; }
}
else
{ /* Whole-point extension. */
if (n < (num_rows+p-1))
{ fp[-n] = fp[n]; n++; did_something = 1; }
}
}
if (p <= ext_after)
{ /* Still need extension to lower part of image. */
if (stage->last_extension)
{ /* Half-point extension. */
if (p <= (num_rows+n-1))
{ lp[p] = lp[-p+1]; p++; did_something = 1; }
}
else
{ /* Whole-point extension. */
if (p < (num_rows+n-1))
{ lp[p] = lp[-p]; p++; did_something = 1; }
}
}
assert(did_something);
}
}
/* ========================================================================= */
/* ------------------ Implementation of Interface Functions ---------------- */
/* ========================================================================= */
/*****************************************************************************/
/* STATIC __initialize */
/*****************************************************************************/
static void
__initialize(hplx_synthesis_stage_ref base, reverse_info_ref info,
canvas_dims_ptr dims, canvas_dims_ptr frame_dims)
{
hplx_vert_synthesis_by_lifting_ref self =
(hplx_vert_synthesis_by_lifting_ref) base;
frame_info frame;
hplx_synth_buffering_stage_ptr ext_stage;
hplx_buffering_stage_ptr stage;
hplx_lifting_step_ptr step;
int neg_supports[INFO__MAX_LIFTING_STEPS];
int pos_supports[INFO__MAX_LIFTING_STEPS];
int int_downshifts[INFO__MAX_LIFTING_STEPS];
int *int_taps[INFO__MAX_LIFTING_STEPS];
float *float_taps[INFO__MAX_LIFTING_STEPS];
int b, n;
/* Begin by determining the Wavelet kernels and derivative properties. */
self->kernel_type =
info->get_kernel_type(info,base->direction,INFO__SYNTHESIS,
base->component_idx,base->level_idx,NULL,NULL,
NULL,NULL);
if (self->kernel_type == INFO__INT_LIFTING)
{
self->num_steps =
info->get_int_steps(info,base->direction,base->component_idx,
base->level_idx,neg_supports,pos_supports,
int_taps,int_downshifts);
for (b=0; b < base->vert_limit; b++)
self->branch_needs_scaling[b] = 0;
}
else if (self->kernel_type == INFO__FLOAT_LIFTING)
{
self->num_steps =
info->get_float_steps(info,base->direction,base->component_idx,
base->level_idx,neg_supports,pos_supports,
float_taps,self->branch_scale,
self->branch_scale+1);
for (b=0; b < base->vert_limit; b++)
{
float val = self->branch_scale[b];
self->branch_needs_scaling[b] = (val > 1.00001F) || (val < 0.99999F);
self->branch_scale[b] = 1.0F / val;
}
self->heap.use_floats = 1;
}
else
assert(0);
self->steps = (hplx_lifting_step_ptr)
local_malloc(XFORM_MEM_KEY,sizeof(hplx_lifting_step)*self->num_steps);
memset(self->steps,0,sizeof(hplx_lifting_step)*(size_t)(self->num_steps));
self->num_buffering_stages = self->num_steps + 2;
self->buffering_stages = (hplx_synth_buffering_stage_ptr)
local_malloc(XFORM_MEM_KEY,sizeof(hplx_synth_buffering_stage)*
self->num_buffering_stages);
for (n=0; n < self->num_buffering_stages; n++)
{
ext_stage = self->buffering_stages + n;
ext_stage->owner_ref = self;
stage = &(ext_stage->base);
stage->odd_lines = ((n & 1) == 0);
stage->max_buffered_rows = 1;
stage->num_users = 0;
stage->row_buffers = (hplx_row_buffer_state_ptr *)
local_malloc(XFORM_MEM_KEY,sizeof(hplx_row_buffer_state_ptr)*
stage->max_buffered_rows);
if (n < self->num_steps)
stage->generator = self->steps + n;
stage->heap = &(self->heap);
}
for (n=0; n < self->num_steps; n++)
{
step = self->steps + n;
step->source = &(self->buffering_stages[n+1].base);
step->target = &(self->buffering_stages[n+2].base);
step->source->num_users++;
step->target->num_users++;
step->neg_support = neg_supports[n];
step->pos_support = pos_supports[n];
if (self->kernel_type == INFO__INT_LIFTING)
{
step->int_taps = int_taps[n];
step->int_downshift = int_downshifts[n];
}
else
step->float_taps = float_taps[n];
}
if (self->kernel_type == INFO__FLOAT_LIFTING)
{ /* Compute DC gains associated with the output of each update lifting
step, i.e. the 1'st, 3'rd, ... lifting steps. */
float current_gain, source_gain, step_gain;
int k;
for (n=0; n < self->num_steps; n++)
{
step = self->steps + n;
current_gain = (n>=2)?(step[-2].dc_gain):1.0F;
source_gain = (n>=1)?(step[-1].dc_gain):1.0F;
step_gain = 0.0F;
for (k=-step->neg_support; k <= step->pos_support; k++)
step_gain += step->float_taps[k];
step->dc_gain = current_gain + step_gain*source_gain;
}
for (current_gain=1.0F, n=1; n < self->num_steps; n+=2)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -