📄 hplx_vert_synthesis_by_lifting.c
字号:
/*****************************************************************************/
/* Copyright 1998, Hewlett-Packard Company */
/* All rights reserved */
/* File: "hplx_vert_synthesis_by_lifting.c" */
/* Description: Implementation of the `hplx_analysis_stage' object for */
/* vertical synthesis via lifting. */
/* Author: David Taubman */
/* Affiliation: Hewlett-Packard and */
/* The University of New South Wales, Australia */
/* Acknowledgements: Partly developed in collaboration with */
/* Christos Chrysafis of HP Labs */
/* Version: VM9.0 */
/* Last Revised: 20 April, 2001 */
/*****************************************************************************/
/*****************************************************************************/
/* Modifications tagged with comment lines or delimiters involving the */
/* string, "David T mod" or "mod by David T", have been made by David */
/* Taubman; they are copyrighted by Hewlett-Packard Company with all rights */
/* reserved for the modified parts. */
/*****************************************************************************/
/*****************************************************************************/
/* Modifications tagged with comment lines or delimiters involving the */
/* string "BBDWT mod" have been made to implement the single-sample */
/* overlap Wavelet transform within the frames paradigm -- this is the */
/* BBDWT transform proposed by Canon Research France and accepted at the */
/* meeting in Seoul, Korea. */
/*****************************************************************************/
/*****************************************************************************/
/* Modifications marked "Christos Chrysafis (HPL)" made to ensure that */
/* the boundary extension policy for lifting is identical to that used for */
/* convolution so that convolution vs. lifting is purely an implementation */
/* decision. Mods might cause problems for non-symmetric kernels, but that */
/* should not be relevant to the standard. The modifications are */
/* copyrighted by Hewlett-Packard Company with all rights reserved for the */
/* modified parts. */
/*****************************************************************************/
/*****************************************************************************/
/* Modified by David Taubman to support arbitrary reference points for the */
/* transform and the various regular partitions, so as to facilitate */
/* cropping and geometric transformations in the compressed domain and to */
/* enable full support for CRF's single-sample overlap Wavelet transform, */
/* as originally documented in Seoul. Changes are too numerous to flag */
/* individually within the code. Changes copyrighted by HP with all rights */
/* reserved for the modified parts. */
/*****************************************************************************/
/*****************************************************************************/
/* Modified by David Taubman to support interface modifications, arbitrary */
/* changes in coding parameters from component to component and from tile */
/* to tile, to support the full generality of PART-1 of the JPEG2000 */
/* standard, and to support most anticipated generality of PART-2. Changes */
/* are too numerous to flag individually within the code, which in some */
/* places has been completely rewritten. All changes copyrighted by HP with */
/* all rights reserved for the modified parts. */
/*****************************************************************************/
/*****************************************************************************/
/* Modified by David Taubman to allow SSO-DWT style extension at tile */
/* boundaries. Changes copyrighted by HP with all rights reserved for the */
/* modified parts. */
/*****************************************************************************/
/*****************************************************************************/
/* Modified for general wavelet decompositions. */
/* Copyright 2000 Science Applications International Corporation (SAIC). */
/* Copyright 1995 University of Arizona, Arizona Board of Regents. */
/* All Rights Reserved for modified parts. */
/*****************************************************************************/
#include <local_services.h>
#include <string.h>
#include <math.h>
#include <assert.h>
#include <ifc.h>
#include "hplx_vert_lifting.h"
#include "hplx_synthesis_local.h"
/* ========================================================================= */
/* ------------------------ Extended Object Definition --------------------- */
/* ========================================================================= */
typedef struct hplx_vert_synthesis_by_lifting_obj
*hplx_vert_synthesis_by_lifting_ref;
/*****************************************************************************/
/* hplx_synth_buffering_stage */
/*****************************************************************************/
typedef
struct hplx_synth_buffering_stage {
hplx_buffering_stage base;
hplx_vert_synthesis_by_lifting_ref owner_ref;
} hplx_synth_buffering_stage, *hplx_synth_buffering_stage_ptr;
/* Extends the basic `hplx_buffering_stage' structure to include the
additional elements required to obtain new buffer rows when the
`generator' field is NULL (see comments appearing with the
definition of `hplx_buffering_stage' in "hplx_vert_synthesis.h").
When this happens, the required buffer rows cannot be generated from
other lifting steps within the same `hplx_synthesis_stage' object;
they must be obtained either via the `pull_line' interface functions
of another `hplx_synthesis_stage' object, or by invoking the relevant
`pull_line' interface function of a dequantizer object. In either
case, the methods may be obtained and correctly invoked with the
aid of a reference to the `hplx_vert_synthesis_by_lifting' object
to which this stage belongs. */
/*****************************************************************************/
/* hplx_vert_synthesis_by_lifting_obj */
/*****************************************************************************/
typedef
struct hplx_vert_synthesis_by_lifting_obj {
hplx_synthesis_stage_obj base;
int kernel_type;
int num_steps;
hplx_lifting_step_ptr steps;
int num_buffering_stages;
hplx_synth_buffering_stage_ptr buffering_stages;
int branch_needs_scaling[2]; /* Only for float-lifting. */
float branch_scale[2]; /* Only for float-lifting. */
hplx_row_buffer_heap heap;
int num_frames, frame_rows, frame_ref, frame_idx, first_frame_rows;
int current_frame_rows, first_row_idx_in_frame;
int rows_left_in_tile, rows_left_in_frame;
int ovlp_top, ovlp_bottom;
} hplx_vert_synthesis_by_lifting_obj;
/* This structure defines the extended `hplx_synthesis_stage' object.
`kernel_type' is one of INFO__FLOAT_LIFTING or INFO__INT_LIFTING.
`num_steps' identifies the number of lifting steps.
`steps' points to an array with `num_steps' entries, which describes
each of the lifting steps.
`num_buffering_stages' identifies the number of entries in the
`buffering_stages' array. There are always exactly two more buffering
stages than lifting steps. The first two buffering stages correspond
to the odd and even line sub-sequences, respectively, which we can
recover by undoing all relevant lifting steps. Subsequent
buffering stages hold the intermediate results which were produced
during analysis by each of the consecutive lifting steps. The last
two buffering stages hold the vertically low- and high-pass subbands.
Even indexed entries of the `buffering_stages' array always correspond
to odd numbered lines and vice-versa.
The `banch_needs_scaling' and `branch_scale' arrays are used only
for float-lifting kernels. If `branch_needs_scaling[b]' is non-zero
then the subband samples for branch b (0=low-pass, 1=high-pass) must
be scaled by `branch_scale[b]' immediately after they are retrieved
from the relevant descendant synthesis stage object.
`heap' manages a heap for recycled line buffers, so that they can
be distributed amongst the buffering stages in the most efficient
manner.
The `num_frames' field holds the number of frames. The SSO-DWT
is applied if and only if `num_frames' is not equal to 1. Even
though the SSO-DWT is an overlapping transform, the number of frames
is computed based upon a disjoint partition. The overlap samples
are then determined subsequently. This is important, since it can
happen that the overlap sample is an entire frame.
The `frame_rows' field holds the nominal vertical frame
dimension; it is meaningful only if `num_frames' > 1.
The `frame_ref' field holds the vertical anchor coordinate
for the frame partition.
The `frame_idx' field runs from 0 to `num_frames'-1 and is used
to determine whether we are processing and internal frame or one
which abuts a boundary.
The `current_frame_rows' and `first_row_idx_in_frame' hold the
absolute size and location of the current frame which is being
processed, with respect to the canvas coordinate system.
The `ovlp_top' and `ovlp_bottom' fields indicate whether the
frame which is currently being processed contains an extra overlap
row (i.e. outside the nominal frame partition) at the top or bottom
of the frame (exactly one of these must be true for internal frames
being processed using the SSO-DWT). These fields are used to mimic
the type of processing which would be used to build an efficient
hardware implementation of the SSO-DWT. */
/* ========================================================================= */
/* ---------------------------- Internal Functions ------------------------- */
/* ========================================================================= */
/*****************************************************************************/
/* STATIC start_vertical_frame */
/*****************************************************************************/
static void
start_vertical_frame(hplx_vert_synthesis_by_lifting_ref self,
hplx_row_buffer_state_ptr ovlp)
/* Performs the initialization code required to restart the vertical
buffering at the start of each vertical frame. The function administers
the `self->first_row_idx_in_frame', `self->current_frame_rows',
`self->ovlp_top' and `self->ovlp_bottom' fields, as well as
setting up the fields in each buffering stage in preparation for the
new frame. The `ovlp' argument identifies a copy of the last row from
the previous frame, if any, which is to be used to
initialize the first row of the current frame in the 1-sample overlap
mode. */
{
hplx_buffering_stage_ptr stage;
int b, n, k, num_buffers, even_taps;
int special_first, special_last, skip_last;
int top_boundary_odd, bottom_boundary_odd, ovlp_top, ovlp_bottom;
int subseq_rows[2];
if (self->frame_idx == 0)
{ /* Set the location and size of the current frame partition. */
self->current_frame_rows = self->first_frame_rows;
assert(self->current_frame_rows <= self->rows_left_in_tile);
if (self->current_frame_rows == 0)
return;
}
else
{
/* Adjust counters to reflect the true frame partition, rather than
the current transform block. */
self->current_frame_rows -= self->ovlp_top + self->ovlp_bottom;
self->first_row_idx_in_frame += self->ovlp_top;
/* Update the location and size of the current frame partition. */
self->first_row_idx_in_frame += self->current_frame_rows;
self->rows_left_in_tile -= self->current_frame_rows;
self->current_frame_rows = self->frame_rows;
if (self->current_frame_rows > self->rows_left_in_tile)
self->current_frame_rows = self->rows_left_in_tile;
}
assert(self->current_frame_rows > 0);
top_boundary_odd = self->first_row_idx_in_frame & 1;
bottom_boundary_odd =
(self->first_row_idx_in_frame+self->current_frame_rows-1) & 1;
subseq_rows[0] = (self->current_frame_rows+1-top_boundary_odd) >> 1;
subseq_rows[1] = (self->current_frame_rows+top_boundary_odd) >> 1;
special_first = special_last = skip_last = ovlp_top = ovlp_bottom = 0;
if (self->frame_idx > 0)
{ /* Internal top boundary. */
special_first = 1;
if (top_boundary_odd)
{ ovlp_top = 1; subseq_rows[0]++; top_boundary_odd = 0; }
}
else if (self->base.sso_ext && !top_boundary_odd)
special_first = 1; /* Use SSO-DWT style extension at tile boundaries. */
if (self->frame_idx < (self->num_frames-1))
{ /* Internal bottom boundary. */
special_last = skip_last = 1;
if (bottom_boundary_odd)
{ ovlp_bottom = 1; subseq_rows[0]++; bottom_boundary_odd = 0; }
}
else if (self->base.sso_ext && !bottom_boundary_odd)
special_last = 1; /* Use SSO-DWT style extension at tile boundaries. */
/* Make `first_row_idx_in_frame', `current_frame_rows' and
`rows_left_in_frame' refer to the transform block, instead of the
frame partition. We will restore their interpretations when we
re-enter this function at the beginning of the next frame (see above). */
self->ovlp_bottom = ovlp_bottom;
self->ovlp_top = ovlp_top;
self->first_row_idx_in_frame -= ovlp_top;
self->current_frame_rows += ovlp_top + ovlp_bottom;
self->rows_left_in_frame = self->current_frame_rows;
/* Now set up working buffers. */
for (b=0; b < ((hplx_synthesis_stage_ref) self)->vert_limit; b++)
{ /* b = 0 corresponds to the sub-sequence of even rows in the frame */
even_taps = (self->steps->neg_support + self->steps->pos_support+1) & 1;
for (n=0; n < self->num_buffering_stages; n++)
{
stage = &(self->buffering_stages[n].base);
if (stage->odd_lines == b)
{
if (even_taps)
{
if (top_boundary_odd)
local_error("Cannot start image, tile or frame with an "
"odd indexed sample when using even length "
"filters! Use odd length filters!");
stage->first_extension =
symmetric_extension_type(1,self->current_frame_rows&1,b,0);
stage->first_extension =
symmetric_extension_type(1,self->current_frame_rows&1,b,1);
}
else
{ /* Simple case for odd length filters. */
stage->first_extension = (top_boundary_odd^(1-b))?0:1;
stage->last_extension = (bottom_boundary_odd^(1-b))?0:1;
}
if (b == 0)
{
stage->special_first = special_first;
stage->special_last = special_last;
stage->skip_last = skip_last;
stage->missing_first_row = top_boundary_odd;
}
else
{
stage->special_first = 0;
stage->special_last = 0;
stage->skip_last = 0;
stage->missing_first_row = 0;
}
stage->rows = subseq_rows[b];
num_buffers = stage->next_row_idx - stage->min_row_idx;
for (k=0; k < num_buffers; k++)
hplx_lift_heap__return_buffer(stage->heap,
stage->row_buffers[k]);
stage->min_row_idx = 0;
stage->next_row_idx = 0;
}
else
assert(stage->odd_lines == (1-b));
}
}
if (special_first && (ovlp != NULL))
{ /* Need to copy `ovlp' buffer into the first row of low-pass subbands. */
hplx_row_buffer_state_ptr buf;
stage = &(self->buffering_stages[self->num_buffering_stages-1].base);
if (stage->odd_lines)
stage = &(self->buffering_stages[self->num_buffering_stages-2].base);
assert(stage->generator == NULL);
buf = hplx_lift_stage__add_row(stage);
if (buf->float_buf != NULL)
{
float *sp, *dp, scale;
assert(ovlp->float_buf != NULL);
scale = self->branch_scale[0];
for (sp=ovlp->float_buf, dp=buf->float_buf, n=stage->cols; n--; )
*(dp++) = *(sp++) * scale;
}
else
{
ifc_int *sp, *dp;
assert(ovlp->int_buf != NULL);
for (sp=ovlp->int_buf, dp=buf->int_buf, n=stage->cols; n--; )
*(dp++) = *(sp++);
}
}
}
/*****************************************************************************/
/* STATIC go_outside_synth_stage_for_row */
/*****************************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -