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.
388 lines
10 KiB
388 lines
10 KiB
/* |
|
* The Progressive Graphics File; http://www.libpgf.org |
|
* |
|
* $Date: 2006-06-04 22:05:59 +0200 (So, 04 Jun 2006) $ |
|
* $Revision: 229 $ |
|
* |
|
* 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 Subband.cpp |
|
/// @brief PGF wavelet subband class implementation |
|
/// @author C. Stamm |
|
|
|
#include "Subband.h" |
|
#include "Encoder.h" |
|
#include "Decoder.h" |
|
|
|
///////////////////////////////////////////////////////////////////// |
|
// Default constructor |
|
CSubband::CSubband() |
|
: m_width(0) |
|
, m_height(0) |
|
, m_size(0) |
|
, m_level(0) |
|
, m_orientation(LL) |
|
, m_dataPos(0) |
|
, m_data(0) |
|
#ifdef __PGFROISUPPORT__ |
|
, m_nTiles(0) |
|
#endif |
|
{ |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////// |
|
// Destructor |
|
CSubband::~CSubband() { |
|
FreeMemory(); |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////// |
|
// Initialize subband parameters |
|
void CSubband::Initialize(UINT32 width, UINT32 height, int level, Orientation orient) { |
|
m_width = width; |
|
m_height = height; |
|
m_size = m_width*m_height; |
|
m_level = level; |
|
m_orientation = orient; |
|
m_data = 0; |
|
m_dataPos = 0; |
|
#ifdef __PGFROISUPPORT__ |
|
m_ROI.left = 0; |
|
m_ROI.top = 0; |
|
m_ROI.right = m_width; |
|
m_ROI.bottom = m_height; |
|
m_nTiles = 0; |
|
#endif |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////// |
|
// Allocate a memory buffer to store all wavelet coefficients of this subband. |
|
// @return True if the allocation works without any problems |
|
bool CSubband::AllocMemory() { |
|
UINT32 oldSize = m_size; |
|
|
|
#ifdef __PGFROISUPPORT__ |
|
m_size = BufferWidth()*m_ROI.Height(); |
|
#endif |
|
ASSERT(m_size > 0); |
|
|
|
if (m_data) { |
|
if (oldSize >= m_size) { |
|
return true; |
|
} else { |
|
delete[] m_data; |
|
m_data = new(std::nothrow) DataT[m_size]; |
|
return (m_data != 0); |
|
} |
|
} else { |
|
m_data = new(std::nothrow) DataT[m_size]; |
|
return (m_data != 0); |
|
} |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////// |
|
// Delete the memory buffer of this subband. |
|
void CSubband::FreeMemory() { |
|
if (m_data) { |
|
delete[] m_data; m_data = 0; |
|
} |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////// |
|
// Perform subband quantization with given quantization parameter. |
|
// A scalar quantization (with dead-zone) is used. A large quantization value |
|
// results in strong quantization and therefore in big quality loss. |
|
// @param quantParam A quantization parameter (larger or equal to 0) |
|
void CSubband::Quantize(int quantParam) { |
|
if (m_orientation == LL) { |
|
quantParam -= (m_level + 1); |
|
// uniform rounding quantization |
|
if (quantParam > 0) { |
|
quantParam--; |
|
for (UINT32 i=0; i < m_size; i++) { |
|
if (m_data[i] < 0) { |
|
m_data[i] = -(((-m_data[i] >> quantParam) + 1) >> 1); |
|
} else { |
|
m_data[i] = ((m_data[i] >> quantParam) + 1) >> 1; |
|
} |
|
} |
|
} |
|
} else { |
|
if (m_orientation == HH) { |
|
quantParam -= (m_level - 1); |
|
} else { |
|
quantParam -= m_level; |
|
} |
|
// uniform deadzone quantization |
|
if (quantParam > 0) { |
|
int threshold = ((1 << quantParam) * 7)/5; // good value |
|
quantParam--; |
|
for (UINT32 i=0; i < m_size; i++) { |
|
if (m_data[i] < -threshold) { |
|
m_data[i] = -(((-m_data[i] >> quantParam) + 1) >> 1); |
|
} else if (m_data[i] > threshold) { |
|
m_data[i] = ((m_data[i] >> quantParam) + 1) >> 1; |
|
} else { |
|
m_data[i] = 0; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
////////////////////////////////////////////////////////////////////// |
|
/// Perform subband dequantization with given quantization parameter. |
|
/// A scalar quantization (with dead-zone) is used. A large quantization value |
|
/// results in strong quantization and therefore in big quality loss. |
|
/// @param quantParam A quantization parameter (larger or equal to 0) |
|
void CSubband::Dequantize(int quantParam) { |
|
if (m_orientation == LL) { |
|
quantParam -= m_level + 1; |
|
} else if (m_orientation == HH) { |
|
quantParam -= m_level - 1; |
|
} else { |
|
quantParam -= m_level; |
|
} |
|
if (quantParam > 0) { |
|
for (UINT32 i=0; i < m_size; i++) { |
|
m_data[i] <<= quantParam; |
|
} |
|
} |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////// |
|
/// Extracts a rectangular subregion of this subband. |
|
/// Write wavelet coefficients into buffer. |
|
/// It might throw an IOException. |
|
/// @param encoder An encoder instance |
|
/// @param tile True if just a rectangular region is extracted, false if the entire subband is extracted. |
|
/// @param tileX Tile index in x-direction |
|
/// @param tileY Tile index in y-direction |
|
void CSubband::ExtractTile(CEncoder& encoder, bool tile /*= false*/, UINT32 tileX /*= 0*/, UINT32 tileY /*= 0*/) { |
|
#ifdef __PGFROISUPPORT__ |
|
if (tile) { |
|
// compute tile position and size |
|
UINT32 xPos, yPos, w, h; |
|
TilePosition(tileX, tileY, xPos, yPos, w, h); |
|
|
|
// write values into buffer using partitiong scheme |
|
encoder.Partition(this, w, h, xPos + yPos*m_width, m_width); |
|
} else |
|
#endif |
|
{ |
|
(void)tileX; (void)tileY; (void)tile; // prevents from unreferenced formal parameter warning |
|
// write values into buffer using partitiong scheme |
|
encoder.Partition(this, m_width, m_height, 0, m_width); |
|
} |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////// |
|
/// Decoding and dequantization of this subband. |
|
/// It might throw an IOException. |
|
/// @param decoder A decoder instance |
|
/// @param quantParam Dequantization value |
|
/// @param tile True if just a rectangular region is placed, false if the entire subband is placed. |
|
/// @param tileX Tile index in x-direction |
|
/// @param tileY Tile index in y-direction |
|
void CSubband::PlaceTile(CDecoder& decoder, int quantParam, bool tile /*= false*/, UINT32 tileX /*= 0*/, UINT32 tileY /*= 0*/) { |
|
// allocate memory |
|
if (!AllocMemory()) ReturnWithError(InsufficientMemory); |
|
|
|
// correct quantParam with normalization factor |
|
if (m_orientation == LL) { |
|
quantParam -= m_level + 1; |
|
} else if (m_orientation == HH) { |
|
quantParam -= m_level - 1; |
|
} else { |
|
quantParam -= m_level; |
|
} |
|
if (quantParam < 0) quantParam = 0; |
|
|
|
#ifdef __PGFROISUPPORT__ |
|
if (tile) { |
|
UINT32 xPos, yPos, w, h; |
|
|
|
// compute tile position and size |
|
TilePosition(tileX, tileY, xPos, yPos, w, h); |
|
|
|
ASSERT(xPos >= m_ROI.left && yPos >= m_ROI.top); |
|
decoder.Partition(this, quantParam, w, h, (xPos - m_ROI.left) + (yPos - m_ROI.top)*BufferWidth(), BufferWidth()); |
|
} else |
|
#endif |
|
{ |
|
(void)tileX; (void)tileY; (void)tile; // prevents from unreferenced formal parameter warning |
|
// read values into buffer using partitiong scheme |
|
decoder.Partition(this, quantParam, m_width, m_height, 0, m_width); |
|
} |
|
} |
|
|
|
|
|
|
|
#ifdef __PGFROISUPPORT__ |
|
////////////////////////////////////////////////////////////////////// |
|
/// Set ROI |
|
void CSubband::SetAlignedROI(const PGFRect& roi) { |
|
ASSERT(roi.left <= m_width); |
|
ASSERT(roi.top <= m_height); |
|
|
|
m_ROI = roi; |
|
if (m_ROI.right > m_width) m_ROI.right = m_width; |
|
if (m_ROI.bottom > m_height) m_ROI.bottom = m_height; |
|
} |
|
|
|
////////////////////////////////////////////////////////////////////// |
|
/// Compute tile position and size. |
|
/// @param tileX Tile index in x-direction |
|
/// @param tileY Tile index in y-direction |
|
/// @param xPos [out] Offset to left |
|
/// @param yPos [out] Offset to top |
|
/// @param w [out] Tile width |
|
/// @param h [out] Tile height |
|
void CSubband::TilePosition(UINT32 tileX, UINT32 tileY, UINT32& xPos, UINT32& yPos, UINT32& w, UINT32& h) const { |
|
ASSERT(tileX < m_nTiles); ASSERT(tileY < m_nTiles); |
|
// example |
|
// band = HH, w = 30, ldTiles = 2 -> 4 tiles in a row/column |
|
// --> tile widths |
|
// 8 7 8 7 |
|
// |
|
// tile partitioning scheme |
|
// 0 1 2 3 |
|
// 4 5 6 7 |
|
// 8 9 A B |
|
// C D E F |
|
|
|
UINT32 nTiles = m_nTiles; |
|
UINT32 m; |
|
UINT32 left = 0, right = nTiles; |
|
UINT32 top = 0, bottom = nTiles; |
|
|
|
xPos = 0; |
|
yPos = 0; |
|
w = m_width; |
|
h = m_height; |
|
|
|
while (nTiles > 1) { |
|
// compute xPos and w with binary search |
|
m = left + ((right - left) >> 1); |
|
if (tileX >= m) { |
|
xPos += (w + 1) >> 1; |
|
w >>= 1; |
|
left = m; |
|
} else { |
|
w = (w + 1) >> 1; |
|
right = m; |
|
} |
|
// compute yPos and h with binary search |
|
m = top + ((bottom - top) >> 1); |
|
if (tileY >= m) { |
|
yPos += (h + 1) >> 1; |
|
h >>= 1; |
|
top = m; |
|
} else { |
|
h = (h + 1) >> 1; |
|
bottom = m; |
|
} |
|
nTiles >>= 1; |
|
} |
|
ASSERT(xPos < m_width && (xPos + w <= m_width)); |
|
ASSERT(yPos < m_height && (yPos + h <= m_height)); |
|
} |
|
|
|
////////////////////////////////////////////////////////////////////// |
|
/// Compute tile index and extrem position (x,y) of given position (xPos, yPos). |
|
void CSubband::TileIndex(bool topLeft, UINT32 xPos, UINT32 yPos, UINT32& tileX, UINT32& tileY, UINT32& x, UINT32& y) const { |
|
UINT32 m; |
|
UINT32 left = 0, right = m_width; |
|
UINT32 top = 0, bottom = m_height; |
|
UINT32 nTiles = m_nTiles; |
|
|
|
if (xPos > m_width) xPos = m_width; |
|
if (yPos > m_height) yPos = m_height; |
|
|
|
if (topLeft) { |
|
// compute tileX with binary search |
|
tileX = 0; |
|
while (nTiles > 1) { |
|
nTiles >>= 1; |
|
m = left + ((right - left + 1) >> 1); |
|
if (xPos < m) { |
|
// exclusive m |
|
right = m; |
|
} else { |
|
tileX += nTiles; |
|
left = m; |
|
} |
|
} |
|
x = left; |
|
ASSERT(tileX >= 0 && tileX < m_nTiles); |
|
|
|
// compute tileY with binary search |
|
nTiles = m_nTiles; |
|
tileY = 0; |
|
while (nTiles > 1) { |
|
nTiles >>= 1; |
|
m = top + ((bottom - top + 1) >> 1); |
|
if (yPos < m) { |
|
// exclusive m |
|
bottom = m; |
|
} else { |
|
tileY += nTiles; |
|
top = m; |
|
} |
|
} |
|
y = top; |
|
ASSERT(tileY >= 0 && tileY < m_nTiles); |
|
|
|
} else { |
|
// compute tileX with binary search |
|
tileX = 1; |
|
while (nTiles > 1) { |
|
nTiles >>= 1; |
|
m = left + ((right - left + 1) >> 1); |
|
if (xPos <= m) { |
|
// inclusive m |
|
right = m; |
|
} else { |
|
tileX += nTiles; |
|
left = m; |
|
} |
|
} |
|
x = right; |
|
ASSERT(tileX > 0 && tileX <= m_nTiles); |
|
|
|
// compute tileY with binary search |
|
nTiles = m_nTiles; |
|
tileY = 1; |
|
while (nTiles > 1) { |
|
nTiles >>= 1; |
|
m = top + ((bottom - top + 1) >> 1); |
|
if (yPos <= m) { |
|
// inclusive m |
|
bottom = m; |
|
} else { |
|
tileY += nTiles; |
|
top = m; |
|
} |
|
} |
|
y = bottom; |
|
ASSERT(tileY > 0 && tileY <= m_nTiles); |
|
} |
|
} |
|
|
|
#endif
|
|
|