You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
570 lines
19 KiB
570 lines
19 KiB
/* |
|
* The Progressive Graphics File; http://www.libpgf.org |
|
* |
|
* $Date: 2006-05-18 16:03:32 +0200 (Do, 18 Mai 2006) $ |
|
* $Revision: 194 $ |
|
* |
|
* This file Copyright (C) 2006 xeraina GmbH, Switzerland |
|
* |
|
* This program is free software; you can redistribute it and/or |
|
* modify it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE |
|
* as published by the Free Software Foundation; either version 2.1 |
|
* of the License, or (at your option) any later version. |
|
* |
|
* This program is distributed in the hope that it will be useful, |
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
* GNU General Public License for more details. |
|
* |
|
* You should have received a copy of the GNU General Public License |
|
* along with this program; if not, write to the Free Software |
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
|
*/ |
|
|
|
////////////////////////////////////////////////////////////////////// |
|
/// @file WaveletTransform.cpp |
|
/// @brief PGF wavelet transform class implementation |
|
/// @author C. Stamm |
|
|
|
#include "WaveletTransform.h" |
|
|
|
#define c1 1 // best value 1 |
|
#define c2 2 // best value 2 |
|
|
|
////////////////////////////////////////////////////////////////////////// |
|
// Constructor: Constructs a wavelet transform pyramid of given size and levels. |
|
// @param width The width of the original image (at level 0) in pixels |
|
// @param height The height of the original image (at level 0) in pixels |
|
// @param levels The number of levels (>= 0) |
|
// @param data Input data of subband LL at level 0 |
|
CWaveletTransform::CWaveletTransform(UINT32 width, UINT32 height, int levels, DataT* data) |
|
: |
|
#ifdef __PGFROISUPPORT__ |
|
m_indices(nullptr), |
|
#endif |
|
m_nLevels(levels + 1) // m_nLevels in CPGFImage determines the number of FWT steps; this.m_nLevels determines the number subband-planes |
|
, m_subband(nullptr) |
|
{ |
|
ASSERT(m_nLevels > 0 && m_nLevels <= MaxLevel + 1); |
|
InitSubbands(width, height, data); |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////// |
|
// Initialize size subbands on all levels |
|
void CWaveletTransform::InitSubbands(UINT32 width, UINT32 height, DataT* data) { |
|
if (m_subband) Destroy(); |
|
|
|
// create subbands |
|
m_subband = new CSubband[m_nLevels][NSubbands]; |
|
|
|
// init subbands |
|
UINT32 loWidth = width; |
|
UINT32 hiWidth = width; |
|
UINT32 loHeight = height; |
|
UINT32 hiHeight = height; |
|
|
|
for (int level = 0; level < m_nLevels; level++) { |
|
m_subband[level][LL].Initialize(loWidth, loHeight, level, LL); // LL |
|
m_subband[level][HL].Initialize(hiWidth, loHeight, level, HL); // HL |
|
m_subband[level][LH].Initialize(loWidth, hiHeight, level, LH); // LH |
|
m_subband[level][HH].Initialize(hiWidth, hiHeight, level, HH); // HH |
|
hiWidth = loWidth >> 1; hiHeight = loHeight >> 1; |
|
loWidth = (loWidth + 1) >> 1; loHeight = (loHeight + 1) >> 1; |
|
} |
|
if (data) { |
|
m_subband[0][LL].SetBuffer(data); |
|
} |
|
} |
|
|
|
////////////////////////////////////////////////////////////////////////// |
|
// Compute fast forward wavelet transform of LL subband at given level and |
|
// stores result in all 4 subbands of level + 1. |
|
// Wavelet transform used in writing a PGF file |
|
// Forward Transform of srcBand and split and store it into subbands on destLevel |
|
// low pass filter at even positions: 1/8[-1, 2, (6), 2, -1] |
|
// high pass filter at odd positions: 1/4[-2, (4), -2] |
|
// @param level A wavelet transform pyramid level (>= 0 && < Levels()) |
|
// @param quant A quantization value (linear scalar quantization) |
|
// @return error in case of a memory allocation problem |
|
OSError CWaveletTransform::ForwardTransform(int level, int quant) { |
|
ASSERT(level >= 0 && level < m_nLevels - 1); |
|
const int destLevel = level + 1; |
|
ASSERT(m_subband[destLevel]); |
|
CSubband* srcBand = &m_subband[level][LL]; ASSERT(srcBand); |
|
const UINT32 width = srcBand->GetWidth(); |
|
const UINT32 height = srcBand->GetHeight(); |
|
DataT* src = srcBand->GetBuffer(); ASSERT(src); |
|
DataT *row0, *row1, *row2, *row3; |
|
|
|
// Allocate memory for next transform level |
|
for (int i=0; i < NSubbands; i++) { |
|
if (!m_subband[destLevel][i].AllocMemory()) return InsufficientMemory; |
|
} |
|
|
|
if (height >= FilterSize) { // changed from FilterSizeH to FilterSize |
|
// top border handling |
|
row0 = src; row1 = row0 + width; row2 = row1 + width; |
|
ForwardRow(row0, width); |
|
ForwardRow(row1, width); |
|
ForwardRow(row2, width); |
|
for (UINT32 k=0; k < width; k++) { |
|
row1[k] -= ((row0[k] + row2[k] + c1) >> 1); // high pass |
|
row0[k] += ((row1[k] + c1) >> 1); // low pass |
|
} |
|
InterleavedToSubbands(destLevel, row0, row1, width); |
|
row0 = row1; row1 = row2; row2 += width; row3 = row2 + width; |
|
|
|
// middle part |
|
for (UINT32 i=3; i < height-1; i += 2) { |
|
ForwardRow(row2, width); |
|
ForwardRow(row3, width); |
|
for (UINT32 k=0; k < width; k++) { |
|
row2[k] -= ((row1[k] + row3[k] + c1) >> 1); // high pass filter |
|
row1[k] += ((row0[k] + row2[k] + c2) >> 2); // low pass filter |
|
} |
|
InterleavedToSubbands(destLevel, row1, row2, width); |
|
row0 = row2; row1 = row3; row2 = row3 + width; row3 = row2 + width; |
|
} |
|
|
|
// bottom border handling |
|
if (height & 1) { |
|
for (UINT32 k=0; k < width; k++) { |
|
row1[k] += ((row0[k] + c1) >> 1); // low pass |
|
} |
|
InterleavedToSubbands(destLevel, row1, nullptr, width); |
|
row0 = row1; row1 += width; |
|
} else { |
|
ForwardRow(row2, width); |
|
for (UINT32 k=0; k < width; k++) { |
|
row2[k] -= row1[k]; // high pass |
|
row1[k] += ((row0[k] + row2[k] + c2) >> 2); // low pass |
|
} |
|
InterleavedToSubbands(destLevel, row1, row2, width); |
|
row0 = row1; row1 = row2; row2 += width; |
|
} |
|
} else { |
|
// if height is too small |
|
row0 = src; row1 = row0 + width; |
|
// first part |
|
for (UINT32 k=0; k < height; k += 2) { |
|
ForwardRow(row0, width); |
|
ForwardRow(row1, width); |
|
InterleavedToSubbands(destLevel, row0, row1, width); |
|
row0 += width << 1; row1 += width << 1; |
|
} |
|
// bottom |
|
if (height & 1) { |
|
InterleavedToSubbands(destLevel, row0, nullptr, width); |
|
} |
|
} |
|
|
|
if (quant > 0) { |
|
// subband quantization (without LL) |
|
for (int i=1; i < NSubbands; i++) { |
|
m_subband[destLevel][i].Quantize(quant); |
|
} |
|
// LL subband quantization |
|
if (destLevel == m_nLevels - 1) { |
|
m_subband[destLevel][LL].Quantize(quant); |
|
} |
|
} |
|
|
|
// free source band |
|
srcBand->FreeMemory(); |
|
return NoError; |
|
} |
|
|
|
////////////////////////////////////////////////////////////// |
|
// Forward transform one row |
|
// low pass filter at even positions: 1/8[-1, 2, (6), 2, -1] |
|
// high pass filter at odd positions: 1/4[-2, (4), -2] |
|
void CWaveletTransform::ForwardRow(DataT* src, UINT32 width) { |
|
if (width >= FilterSize) { |
|
UINT32 i = 3; |
|
|
|
// left border handling |
|
src[1] -= ((src[0] + src[2] + c1) >> 1); // high pass |
|
src[0] += ((src[1] + c1) >> 1); // low pass |
|
|
|
// middle part |
|
for (; i < width-1; i += 2) { |
|
src[i] -= ((src[i-1] + src[i+1] + c1) >> 1); // high pass |
|
src[i-1] += ((src[i-2] + src[i] + c2) >> 2); // low pass |
|
} |
|
|
|
// right border handling |
|
if (width & 1) { |
|
src[i-1] += ((src[i-2] + c1) >> 1); // low pass |
|
} else { |
|
src[i] -= src[i-1]; // high pass |
|
src[i-1] += ((src[i-2] + src[i] + c2) >> 2); // low pass |
|
} |
|
} |
|
} |
|
|
|
///////////////////////////////////////////////////////////////// |
|
// Copy transformed and interleaved (L,H,L,H,...) rows loRow and hiRow to subbands LL,HL,LH,HH |
|
void CWaveletTransform::InterleavedToSubbands(int destLevel, DataT* loRow, DataT* hiRow, UINT32 width) { |
|
const UINT32 wquot = width >> 1; |
|
const bool wrem = (width & 1); |
|
CSubband &ll = m_subband[destLevel][LL], &hl = m_subband[destLevel][HL]; |
|
CSubband &lh = m_subband[destLevel][LH], &hh = m_subband[destLevel][HH]; |
|
|
|
if (hiRow) { |
|
for (UINT32 i=0; i < wquot; i++) { |
|
ll.WriteBuffer(*loRow++); // first access, than increment |
|
hl.WriteBuffer(*loRow++); |
|
lh.WriteBuffer(*hiRow++); // first access, than increment |
|
hh.WriteBuffer(*hiRow++); |
|
} |
|
if (wrem) { |
|
ll.WriteBuffer(*loRow); |
|
lh.WriteBuffer(*hiRow); |
|
} |
|
} else { |
|
for (UINT32 i=0; i < wquot; i++) { |
|
ll.WriteBuffer(*loRow++); // first access, than increment |
|
hl.WriteBuffer(*loRow++); |
|
} |
|
if (wrem) ll.WriteBuffer(*loRow); |
|
} |
|
} |
|
|
|
////////////////////////////////////////////////////////////////////////// |
|
// Compute fast inverse wavelet transform of all 4 subbands of given level and |
|
// stores result in LL subband of level - 1. |
|
// Inverse wavelet transform used in reading a PGF file |
|
// Inverse Transform srcLevel and combine to destBand |
|
// low-pass coefficients at even positions, high-pass coefficients at odd positions |
|
// inverse filter for even positions: 1/4[-1, (4), -1] |
|
// inverse filter for odd positions: 1/8[-1, 4, (6), 4, -1] |
|
// @param srcLevel A wavelet transform pyramid level (> 0 && <= Levels()) |
|
// @param w [out] A pointer to the returned width of subband LL (in pixels) |
|
// @param h [out] A pointer to the returned height of subband LL (in pixels) |
|
// @param data [out] A pointer to the returned array of image data |
|
// @return error in case of a memory allocation problem |
|
OSError CWaveletTransform::InverseTransform(int srcLevel, UINT32* w, UINT32* h, DataT** data) { |
|
ASSERT(srcLevel > 0 && srcLevel < m_nLevels); |
|
const int destLevel = srcLevel - 1; |
|
ASSERT(m_subband[destLevel]); |
|
CSubband* destBand = &m_subband[destLevel][LL]; |
|
UINT32 width, height; |
|
|
|
// allocate memory for the results of the inverse transform |
|
if (!destBand->AllocMemory()) return InsufficientMemory; |
|
DataT *origin = destBand->GetBuffer(), *row0, *row1, *row2, *row3; |
|
|
|
#ifdef __PGFROISUPPORT__ |
|
PGFRect destROI = destBand->GetAlignedROI(); |
|
const UINT32 destWidth = destROI.Width(); // destination buffer width |
|
const UINT32 destHeight = destROI.Height(); // destination buffer height |
|
width = destWidth; // destination working width |
|
height = destHeight; // destination working height |
|
|
|
// update destination ROI |
|
if (destROI.top & 1) { |
|
destROI.top++; |
|
origin += destWidth; |
|
height--; |
|
} |
|
if (destROI.left & 1) { |
|
destROI.left++; |
|
origin++; |
|
width--; |
|
} |
|
|
|
// init source buffer position |
|
const UINT32 leftD = destROI.left >> 1; |
|
const UINT32 left0 = m_subband[srcLevel][LL].GetAlignedROI().left; |
|
const UINT32 left1 = m_subband[srcLevel][HL].GetAlignedROI().left; |
|
const UINT32 topD = destROI.top >> 1; |
|
const UINT32 top0 = m_subband[srcLevel][LL].GetAlignedROI().top; |
|
const UINT32 top1 = m_subband[srcLevel][LH].GetAlignedROI().top; |
|
ASSERT(m_subband[srcLevel][LH].GetAlignedROI().left == left0); |
|
ASSERT(m_subband[srcLevel][HH].GetAlignedROI().left == left1); |
|
ASSERT(m_subband[srcLevel][HL].GetAlignedROI().top == top0); |
|
ASSERT(m_subband[srcLevel][HH].GetAlignedROI().top == top1); |
|
|
|
UINT32 srcOffsetX[2] = { 0, 0 }; |
|
UINT32 srcOffsetY[2] = { 0, 0 }; |
|
|
|
if (leftD >= __max(left0, left1)) { |
|
srcOffsetX[0] = leftD - left0; |
|
srcOffsetX[1] = leftD - left1; |
|
} else { |
|
if (left0 <= left1) { |
|
const UINT32 dx = (left1 - leftD) << 1; |
|
destROI.left += dx; |
|
origin += dx; |
|
width -= dx; |
|
srcOffsetX[0] = left1 - left0; |
|
} else { |
|
const UINT32 dx = (left0 - leftD) << 1; |
|
destROI.left += dx; |
|
origin += dx; |
|
width -= dx; |
|
srcOffsetX[1] = left0 - left1; |
|
} |
|
} |
|
if (topD >= __max(top0, top1)) { |
|
srcOffsetY[0] = topD - top0; |
|
srcOffsetY[1] = topD - top1; |
|
} else { |
|
if (top0 <= top1) { |
|
const UINT32 dy = (top1 - topD) << 1; |
|
destROI.top += dy; |
|
origin += dy*destWidth; |
|
height -= dy; |
|
srcOffsetY[0] = top1 - top0; |
|
} else { |
|
const UINT32 dy = (top0 - topD) << 1; |
|
destROI.top += dy; |
|
origin += dy*destWidth; |
|
height -= dy; |
|
srcOffsetY[1] = top0 - top1; |
|
} |
|
} |
|
|
|
m_subband[srcLevel][LL].InitBuffPos(srcOffsetX[0], srcOffsetY[0]); |
|
m_subband[srcLevel][HL].InitBuffPos(srcOffsetX[1], srcOffsetY[0]); |
|
m_subband[srcLevel][LH].InitBuffPos(srcOffsetX[0], srcOffsetY[1]); |
|
m_subband[srcLevel][HH].InitBuffPos(srcOffsetX[1], srcOffsetY[1]); |
|
|
|
#else |
|
width = destBand->GetWidth(); |
|
height = destBand->GetHeight(); |
|
PGFRect destROI(0, 0, width, height); |
|
const UINT32 destWidth = width; // destination buffer width |
|
const UINT32 destHeight = height; // destination buffer height |
|
|
|
// init source buffer position |
|
for (int i = 0; i < NSubbands; i++) { |
|
m_subband[srcLevel][i].InitBuffPos(); |
|
} |
|
#endif |
|
|
|
if (destHeight >= FilterSize) { // changed from FilterSizeH to FilterSize |
|
// top border handling |
|
row0 = origin; row1 = row0 + destWidth; |
|
SubbandsToInterleaved(srcLevel, row0, row1, width); |
|
for (UINT32 k = 0; k < width; k++) { |
|
row0[k] -= ((row1[k] + c1) >> 1); // even |
|
} |
|
|
|
// middle part |
|
row2 = row1 + destWidth; row3 = row2 + destWidth; |
|
for (UINT32 i = destROI.top + 2; i < destROI.bottom - 1; i += 2) { |
|
SubbandsToInterleaved(srcLevel, row2, row3, width); |
|
for (UINT32 k = 0; k < width; k++) { |
|
row2[k] -= ((row1[k] + row3[k] + c2) >> 2); // even |
|
row1[k] += ((row0[k] + row2[k] + c1) >> 1); // odd |
|
} |
|
InverseRow(row0, width); |
|
InverseRow(row1, width); |
|
row0 = row2; row1 = row3; row2 = row1 + destWidth; row3 = row2 + destWidth; |
|
} |
|
|
|
// bottom border handling |
|
if (height & 1) { |
|
SubbandsToInterleaved(srcLevel, row2, nullptr, width); |
|
for (UINT32 k = 0; k < width; k++) { |
|
row2[k] -= ((row1[k] + c1) >> 1); // even |
|
row1[k] += ((row0[k] + row2[k] + c1) >> 1); // odd |
|
} |
|
InverseRow(row0, width); |
|
InverseRow(row1, width); |
|
InverseRow(row2, width); |
|
row0 = row1; row1 = row2; row2 += destWidth; |
|
} else { |
|
for (UINT32 k = 0; k < width; k++) { |
|
row1[k] += row0[k]; |
|
} |
|
InverseRow(row0, width); |
|
InverseRow(row1, width); |
|
row0 = row1; row1 += destWidth; |
|
} |
|
} else { |
|
// height is too small |
|
row0 = origin; row1 = row0 + destWidth; |
|
// first part |
|
for (UINT32 k = 0; k < height; k += 2) { |
|
SubbandsToInterleaved(srcLevel, row0, row1, width); |
|
InverseRow(row0, width); |
|
InverseRow(row1, width); |
|
row0 += destWidth << 1; row1 += destWidth << 1; |
|
} |
|
// bottom |
|
if (height & 1) { |
|
SubbandsToInterleaved(srcLevel, row0, nullptr, width); |
|
InverseRow(row0, width); |
|
} |
|
} |
|
|
|
// free memory of the current srcLevel |
|
for (int i = 0; i < NSubbands; i++) { |
|
m_subband[srcLevel][i].FreeMemory(); |
|
} |
|
|
|
// return info |
|
*w = destWidth; |
|
*h = destHeight; |
|
*data = destBand->GetBuffer(); |
|
return NoError; |
|
} |
|
|
|
////////////////////////////////////////////////////////////////////// |
|
// Inverse Wavelet Transform of one row |
|
// low-pass coefficients at even positions, high-pass coefficients at odd positions |
|
// inverse filter for even positions: 1/4[-1, (4), -1] |
|
// inverse filter for odd positions: 1/8[-1, 4, (6), 4, -1] |
|
void CWaveletTransform::InverseRow(DataT* dest, UINT32 width) { |
|
if (width >= FilterSize) { |
|
UINT32 i = 2; |
|
|
|
// left border handling |
|
dest[0] -= ((dest[1] + c1) >> 1); // even |
|
|
|
// middle part |
|
for (; i < width - 1; i += 2) { |
|
dest[i] -= ((dest[i-1] + dest[i+1] + c2) >> 2); // even |
|
dest[i-1] += ((dest[i-2] + dest[i] + c1) >> 1); // odd |
|
} |
|
|
|
// right border handling |
|
if (width & 1) { |
|
dest[i] -= ((dest[i-1] + c1) >> 1); // even |
|
dest[i-1] += ((dest[i-2] + dest[i] + c1) >> 1); // odd |
|
} else { |
|
dest[i-1] += dest[i-2]; // odd |
|
} |
|
} |
|
} |
|
|
|
/////////////////////////////////////////////////////////////////// |
|
// Copy transformed coefficients from subbands LL,HL,LH,HH to interleaved format (L,H,L,H,...) |
|
void CWaveletTransform::SubbandsToInterleaved(int srcLevel, DataT* loRow, DataT* hiRow, UINT32 width) { |
|
const UINT32 wquot = width >> 1; |
|
const bool wrem = (width & 1); |
|
CSubband &ll = m_subband[srcLevel][LL], &hl = m_subband[srcLevel][HL]; |
|
CSubband &lh = m_subband[srcLevel][LH], &hh = m_subband[srcLevel][HH]; |
|
|
|
if (hiRow) { |
|
#ifdef __PGFROISUPPORT__ |
|
const bool storePos = wquot < ll.BufferWidth(); |
|
UINT32 llPos = 0, hlPos = 0, lhPos = 0, hhPos = 0; |
|
|
|
if (storePos) { |
|
// save current src buffer positions |
|
llPos = ll.GetBuffPos(); |
|
hlPos = hl.GetBuffPos(); |
|
lhPos = lh.GetBuffPos(); |
|
hhPos = hh.GetBuffPos(); |
|
} |
|
#endif |
|
|
|
for (UINT32 i=0; i < wquot; i++) { |
|
*loRow++ = ll.ReadBuffer();// first access, than increment |
|
*loRow++ = hl.ReadBuffer();// first access, than increment |
|
*hiRow++ = lh.ReadBuffer();// first access, than increment |
|
*hiRow++ = hh.ReadBuffer();// first access, than increment |
|
} |
|
|
|
if (wrem) { |
|
*loRow++ = ll.ReadBuffer();// first access, than increment |
|
*hiRow++ = lh.ReadBuffer();// first access, than increment |
|
} |
|
|
|
#ifdef __PGFROISUPPORT__ |
|
if (storePos) { |
|
// increment src buffer positions |
|
ll.IncBuffRow(llPos); |
|
hl.IncBuffRow(hlPos); |
|
lh.IncBuffRow(lhPos); |
|
hh.IncBuffRow(hhPos); |
|
} |
|
#endif |
|
|
|
} else { |
|
#ifdef __PGFROISUPPORT__ |
|
const bool storePos = wquot < ll.BufferWidth(); |
|
UINT32 llPos = 0, hlPos = 0; |
|
|
|
if (storePos) { |
|
// save current src buffer positions |
|
llPos = ll.GetBuffPos(); |
|
hlPos = hl.GetBuffPos(); |
|
} |
|
#endif |
|
|
|
for (UINT32 i=0; i < wquot; i++) { |
|
*loRow++ = ll.ReadBuffer();// first access, than increment |
|
*loRow++ = hl.ReadBuffer();// first access, than increment |
|
} |
|
if (wrem) *loRow++ = ll.ReadBuffer(); |
|
|
|
#ifdef __PGFROISUPPORT__ |
|
if (storePos) { |
|
// increment src buffer positions |
|
ll.IncBuffRow(llPos); |
|
hl.IncBuffRow(hlPos); |
|
} |
|
#endif |
|
} |
|
} |
|
|
|
#ifdef __PGFROISUPPORT__ |
|
////////////////////////////////////////////////////////////////////// |
|
/// Compute and store ROIs for nLevels |
|
/// @param roi rectangular region of interest at level 0 |
|
void CWaveletTransform::SetROI(PGFRect roi) { |
|
const UINT32 delta = (FilterSize >> 1) << m_nLevels; |
|
|
|
// create tile indices |
|
delete[] m_indices; |
|
m_indices = new PGFRect[m_nLevels]; |
|
|
|
// enlarge rect: add margin |
|
roi.left = (roi.left > delta) ? roi.left - delta : 0; |
|
roi.top = (roi.top > delta) ? roi.top - delta : 0; |
|
roi.right += delta; |
|
roi.bottom += delta; |
|
|
|
for (int l = 0; l < m_nLevels; l++) { |
|
PGFRect alignedROI; |
|
PGFRect& indices = m_indices[l]; |
|
UINT32 nTiles = GetNofTiles(l); |
|
CSubband& subband = m_subband[l][LL]; |
|
|
|
// use roi to determine the necessary tile indices (for all subbands the same) and aligned ROI for LL subband |
|
subband.SetNTiles(nTiles); // must be called before TileIndex() |
|
subband.TileIndex(true, roi.left, roi.top, indices.left, indices.top, alignedROI.left, alignedROI.top); |
|
subband.TileIndex(false, roi.right, roi.bottom, indices.right, indices.bottom, alignedROI.right, alignedROI.bottom); |
|
subband.SetAlignedROI(alignedROI); |
|
ASSERT(l == 0 || |
|
(m_indices[l-1].left >= 2*m_indices[l].left && |
|
m_indices[l-1].top >= 2*m_indices[l].top && |
|
m_indices[l-1].right <= 2*m_indices[l].right && |
|
m_indices[l-1].bottom <= 2*m_indices[l].bottom)); |
|
|
|
// determine aligned ROI of other three subbands |
|
PGFRect aroi; |
|
UINT32 w, h; |
|
for (int b = 1; b < NSubbands; b++) { |
|
CSubband& sb = m_subband[l][b]; |
|
sb.SetNTiles(nTiles); // must be called before TilePosition() |
|
sb.TilePosition(indices.left, indices.top, aroi.left, aroi.top, w, h); |
|
sb.TilePosition(indices.right - 1, indices.bottom - 1, aroi.right, aroi.bottom, w, h); |
|
aroi.right += w; |
|
aroi.bottom += h; |
|
sb.SetAlignedROI(aroi); |
|
} |
|
|
|
// use aligned ROI of LL subband for next level |
|
roi.left = alignedROI.left >> 1; |
|
roi.top = alignedROI.top >> 1; |
|
roi.right = (alignedROI.right + 1) >> 1; |
|
roi.bottom = (alignedROI.bottom + 1) >> 1; |
|
} |
|
} |
|
|
|
#endif // __PGFROISUPPORT__
|
|
|