mirror of
https://github.com/SatDump/SatDump
synced 2026-08-13 17:47:30 -04:00
495 lines
15 KiB
C++
495 lines
15 KiB
C++
/*
|
||
* Copyright 2011-2019, European Organisation for the Exploitation of Meteorological Satellites (EUMETSAT)
|
||
*
|
||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
* you may not use this file except in compliance with the License.
|
||
* You may obtain a copy of the License at
|
||
*
|
||
* http://www.apache.org/licenses/LICENSE-2.0
|
||
*
|
||
* Unless required by applicable law or agreed to in writing, software
|
||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
* See the License for the specific language governing permissions and
|
||
* limitations under the License.
|
||
*/
|
||
|
||
#ifndef CImage_included
|
||
#define CImage_included
|
||
|
||
/*******************************************************************************
|
||
|
||
TYPE:
|
||
Concrete class
|
||
|
||
PURPOSE:
|
||
Provide support for image-based data manipulation.
|
||
|
||
FUNCTION:
|
||
An image is a data buffer of a non trivial (i.e. architecture dependent) datatype
|
||
(in this case short) together with size information. The functions supported are
|
||
requantization, point-transform and packing, together with more basic access functions.
|
||
|
||
|
||
INTERFACES:
|
||
See 'INTERFACES' in the module declaration below
|
||
|
||
RESOURCES:
|
||
Heap Memory (>2K).
|
||
|
||
REFERENCE:
|
||
None.
|
||
|
||
PROCESSING:
|
||
The constructor takes either a CDataFieldUncompressed buffer or a size information
|
||
as input. The necessary memory (image buffer) is then allocated. In the case a
|
||
CDataFieldUncompressed buffer was passed, the imagebuffer is filled with the data
|
||
present in the CDataField, eventually unpacked.
|
||
The functions put_block() and get_block() respectively insert/extract a 8x8 pixel
|
||
block from the image at the specified location. Ihe private function pad_block()
|
||
is used in order to support put/get operations across the edge of the image (in case
|
||
the dimension of the image wouldn't be a multiple of 8).
|
||
The member functions Forward_point_transform() and Inverse_point_transform() perform
|
||
the "point-transform" (shifting of the image data value).
|
||
The member function Pack() returns the current image, packed according to the specified
|
||
parameter in a CDataFieldUncompressedImage;
|
||
The member function Requantize() performs data requantization as specified in the MSI. The
|
||
m_NB data member is modified accordingly.
|
||
Various miscelaneous functions (operator()(), GetNext(), SetNext()) allow access
|
||
to individual pixel values. ResetState() performs a reset of the internal
|
||
position counters used by {Get|Set}Next().
|
||
|
||
DATA:
|
||
None
|
||
|
||
LOGIC:
|
||
|
||
*******************************************************************************/
|
||
|
||
#include <vector>
|
||
|
||
#include "CDataField.h" // DISE
|
||
#include "CBlock.h" // COMP
|
||
#include "RMAErrorHandling.h" // COMP
|
||
#include "Compress.h" // COMP
|
||
|
||
namespace COMP
|
||
{
|
||
|
||
class CImage
|
||
{
|
||
|
||
private:
|
||
//DATA:
|
||
|
||
// Object variables
|
||
std::vector<unsigned short> m_data; // Pointer to the raw image data buffer.
|
||
std::vector<unsigned short *> m_dataptr; // array of pointers to each line of the block
|
||
// m_dataptr[0] = m_data
|
||
// m_dataptr[1] = m_data + m_NC
|
||
// m_dataptr[2] = m_data + 2 * m_NC
|
||
// ...
|
||
// m_dataptr[n] = m_data + n * m_NC
|
||
// ...
|
||
// m_dataptr[m_NL-1] = m_data + (m_NL - 1) * m_NC
|
||
unsigned short m_NL; // Number of lines in the image
|
||
unsigned short m_NC; // Number of columns in the image
|
||
unsigned short m_NB; // Max number of valid bits of the current data
|
||
unsigned long m_size; // Number of pixels in the image.
|
||
// State variables: used to store object state information
|
||
unsigned long m_index; // Linear position in the buffer
|
||
unsigned short m_cur_L; // Current line position
|
||
unsigned short m_cur_C; // Current column position in the buffer
|
||
unsigned short m_cur_RI; // Current Restart Interval index
|
||
unsigned short m_RI; // Current Restart interval length (in pixels)
|
||
|
||
//INTERFACE:
|
||
|
||
// Description: Performs the block padding for an incomplete block.
|
||
// Returns: Nothing.
|
||
void pad_block(
|
||
CBlock<unsigned short> &t_blk, // block to be padded
|
||
const unsigned short &i_goodCol, // # of valid columns
|
||
const unsigned short &i_goodLine // # of valid lines
|
||
)
|
||
const
|
||
{
|
||
COMP_TRYTHIS
|
||
// Pads missing pixels by copying last column, last line
|
||
// 1<> Copying columns
|
||
unsigned int tmp = i_goodCol - 1;
|
||
for (unsigned int j = i_goodCol; j < 8; j++)
|
||
for (unsigned int i = 0; i < i_goodLine; i++)
|
||
t_blk.Cset(i, j, t_blk.Cget(i, tmp));
|
||
|
||
// 2<> Copying lines
|
||
tmp = i_goodLine - 1;
|
||
for (unsigned int i = i_goodLine; i < 8; i++)
|
||
for (unsigned int j = 0; j < 8; j++)
|
||
t_blk.Cset(i, j, t_blk.Cget(tmp, j));
|
||
COMP_CATCHTHIS
|
||
}
|
||
|
||
public:
|
||
// Description: Creates a CImage from size information.
|
||
// This is also the default constructor.
|
||
// Returns: Nothing.
|
||
CImage(
|
||
unsigned short i_NC = 0, // Number of columns of the image to create
|
||
unsigned short i_NL = 0, // Number of lines of the image to create
|
||
unsigned short i_NB = 16 // "Depth" of the image to create (is used in the pack() member)
|
||
);
|
||
|
||
// Description: Creates a CImage from the CDataFieldUncompressedImage by unpacking it.
|
||
// Returns: Nothing.
|
||
CImage(
|
||
const Util::CDataFieldUncompressedImage &i_cdfui // buffer containing the image data.
|
||
// May be packed.
|
||
);
|
||
|
||
// Description: Destructor
|
||
// Returns: Nothing.
|
||
~CImage()
|
||
{
|
||
}
|
||
|
||
// Description: Recreates a CImage from size information.
|
||
// Existing information is discarted.
|
||
// Returns: Nothing.
|
||
void Resize(
|
||
unsigned short i_NC, // Number of columns of the image to create
|
||
unsigned short i_NL, // Number of lines of the image to create
|
||
unsigned short i_NB = 16 // "Depth" of the image to create (is used in the pack() member)
|
||
);
|
||
|
||
// Description: Place the given pixel 8x8 block at the specified position.
|
||
// Returns: Nothing.
|
||
void put_block(
|
||
CBlock<unsigned short> &i_blk, // pixel block to insert
|
||
unsigned short i_colLeft, // position of the upper left pixel of the block
|
||
unsigned short i_lineUp // "
|
||
)
|
||
{
|
||
COMP_TRYTHIS
|
||
// Puts a 8*8 pixels block into the buffer at the specified position
|
||
unsigned int bStep, iStep;
|
||
unsigned int stop_line = i_lineUp + 8;
|
||
unsigned int stop_column = i_colLeft + 8;
|
||
|
||
#ifdef DEBUG
|
||
Assert(i_lineUp < m_NL, Util::CParamException());
|
||
Assert(i_colLeft < m_NC, Util::CParamException());
|
||
#endif
|
||
|
||
// check for image limits
|
||
if (stop_line > m_NL)
|
||
stop_line = m_NL;
|
||
if (stop_column > m_NC)
|
||
{
|
||
stop_column = m_NC;
|
||
bStep = 8 - stop_column + i_colLeft;
|
||
iStep = m_NC - 8 + bStep;
|
||
}
|
||
else
|
||
{
|
||
bStep = 0;
|
||
iStep = m_NC - 8;
|
||
}
|
||
|
||
unsigned int maxval = (1 << m_NB) - 1;
|
||
unsigned short val = 0;
|
||
|
||
// copy the block into the buffer
|
||
unsigned int bIndex = 0;
|
||
unsigned long iIndex = (unsigned long)i_lineUp * m_NC + i_colLeft;
|
||
for (unsigned int i = i_lineUp; i < stop_line; i++, bIndex += bStep, iIndex += iStep)
|
||
for (unsigned int j = i_colLeft; j < stop_column; j++)
|
||
//m_data[iIndex++] = i_blk.Cget (bIndex++);
|
||
m_data[iIndex++] = ((val = i_blk.Cget(bIndex++)) > maxval) ? maxval : val;
|
||
COMP_CATCHTHIS
|
||
}
|
||
|
||
// Description: Extract a pixel block at the specified position
|
||
// Returns: Nothing.
|
||
void get_block(
|
||
CBlock<unsigned short> &o_blk, //
|
||
unsigned short i_colLeft, // position of the upper left pixel of the block
|
||
unsigned short i_lineUp // "
|
||
)
|
||
const
|
||
{
|
||
COMP_TRYTHIS
|
||
// Takes a 8*8 pixels block into the buffer at the specified position,
|
||
// and pads it if needed.
|
||
|
||
unsigned int bStep, iStep;
|
||
unsigned int stop_line = i_lineUp + 8;
|
||
unsigned int stop_column = i_colLeft + 8;
|
||
unsigned int real_lines = 8; // number of correct lines
|
||
unsigned int real_columns = 8; // number of correct columns
|
||
bool padding = false;
|
||
|
||
#ifdef DEBUG
|
||
Assert(i_lineUp < m_NL, Util::CParamException());
|
||
Assert(i_colLeft < m_NC, Util::CParamException());
|
||
#endif
|
||
|
||
// Test for image boundaries
|
||
if (stop_line > m_NL)
|
||
{
|
||
padding = true;
|
||
stop_line = m_NL;
|
||
real_lines = stop_line - i_lineUp;
|
||
}
|
||
if (stop_column > m_NC)
|
||
{
|
||
padding = true;
|
||
stop_column = m_NC;
|
||
real_columns = stop_column - i_colLeft;
|
||
bStep = 8 - real_columns;
|
||
iStep = m_NC - 8 + bStep;
|
||
}
|
||
else
|
||
{
|
||
bStep = 0;
|
||
iStep = m_NC - 8;
|
||
}
|
||
|
||
// 1<> Take real pixels
|
||
|
||
unsigned int bIndex = 0;
|
||
unsigned long iIndex = (unsigned long)i_lineUp * m_NC + i_colLeft;
|
||
for (unsigned int i = i_lineUp; i < stop_line; i++, bIndex += bStep, iIndex += iStep)
|
||
for (unsigned int j = i_colLeft; j < stop_column; j++)
|
||
o_blk.Cset(bIndex++, m_data[iIndex++]);
|
||
|
||
// 2<> Padding, if needed
|
||
if (padding)
|
||
pad_block(o_blk, real_columns, real_lines);
|
||
COMP_CATCHTHIS
|
||
}
|
||
|
||
// Description: Performs the forward point transform on the data
|
||
// as specified in the JPEG norm.
|
||
// Returns: Nothing.
|
||
void Forward_point_transform(
|
||
unsigned short i_pt // point transform
|
||
);
|
||
|
||
// Description: Performs the inverse point transform on the data
|
||
// as specified in the JPEG norm
|
||
// Returns: Nothing.
|
||
void Inverse_point_transform(
|
||
unsigned short i_pt // point transform
|
||
);
|
||
|
||
// Description: Packs an uncompressed image, from 16 bits/pixel
|
||
// to the specified representation.
|
||
// Returns: The packed uncompressed image.
|
||
Util::CDataFieldUncompressedImage pack(
|
||
unsigned short i_NR // number of representation bits.
|
||
);
|
||
|
||
// Description: Perform data requantization (12|10 bit-> 8bit) as specified in the MSI.
|
||
// Note that this function is supposed to also modify the m_NB to reflect
|
||
// the change.
|
||
// Returns: Nothing.
|
||
void Requantize(
|
||
COMP::ERequantizationMode i_mode // specifies the chosen requantization mode.
|
||
);
|
||
|
||
// Description: Returns a reference to the specified pixel value.
|
||
// Returns: The pixel value at the specified location.
|
||
unsigned short &operator()(
|
||
const unsigned short &i_i, // line number of the pixel value to return
|
||
const unsigned short &i_j // column number of the pixel value to return
|
||
)
|
||
{
|
||
COMP_TRYTHIS_SPEED
|
||
#ifdef _DEBUG
|
||
Assert(((unsigned long)i_i * m_NC + i_j) < m_size, Util::CParamException());
|
||
#endif
|
||
return m_dataptr[i_i][i_j];
|
||
COMP_CATCHTHIS_SPEED
|
||
}
|
||
|
||
// Description: Returns the value of the specified pixel.
|
||
// Returns: The pixel value at the specified location.
|
||
unsigned short Cget(
|
||
const unsigned short &i_i, // line number of the pixel value to return
|
||
const unsigned short &i_j // column number of the pixel value to return
|
||
)
|
||
const
|
||
{
|
||
COMP_TRYTHIS_SPEED
|
||
#ifdef _DEBUG
|
||
Assert(((unsigned long)i_i * m_NC + i_j) < m_size, Util::CParamException());
|
||
#endif
|
||
return m_dataptr[i_i][i_j];
|
||
COMP_CATCHTHIS_SPEED
|
||
}
|
||
|
||
// Description: Set the value of the specified pixel.
|
||
// Returns: Nothing.
|
||
void Cset(
|
||
const unsigned short &i_i, // line number of the pixel value to return
|
||
const unsigned short &i_j, // column number of the pixel value to return
|
||
const unsigned short &i_val // the pixel value
|
||
)
|
||
{
|
||
COMP_TRYTHIS_SPEED
|
||
#ifdef _DEBUG
|
||
Assert(((unsigned long)i_i * m_NC + i_j) < m_size, Util::CParamException());
|
||
#endif
|
||
m_dataptr[i_i][i_j] = i_val;
|
||
COMP_CATCHTHIS_SPEED
|
||
}
|
||
|
||
// Description: Returns a reference to the specified pixel value.
|
||
// Returns: The pixel value at the specified location.
|
||
unsigned short &operator[](
|
||
const unsigned long &i_i // linear pixel index to return
|
||
)
|
||
{
|
||
COMP_TRYTHIS_SPEED
|
||
#ifdef _DEBUG
|
||
Assert(i_i < m_size, Util::CParamException());
|
||
#endif
|
||
return m_data[i_i];
|
||
COMP_CATCHTHIS_SPEED
|
||
}
|
||
|
||
// Description: Returns the value of the specified pixel.
|
||
// Returns: The pixel value at the specified location.
|
||
unsigned short Cget(
|
||
const unsigned long &i_i // the linear pixel index
|
||
)
|
||
const
|
||
{
|
||
COMP_TRYTHIS_SPEED
|
||
#ifdef _DEBUG
|
||
Assert(i_i < m_size, Util::CParamException());
|
||
#endif
|
||
return m_data[i_i];
|
||
COMP_CATCHTHIS_SPEED
|
||
}
|
||
|
||
// Description: Set the value of the specified pixel
|
||
// Returns: Nothing.
|
||
void Cset(
|
||
const unsigned long &i_i, // the linear pixel index
|
||
const unsigned short &i_val // the pixel value
|
||
)
|
||
{
|
||
COMP_TRYTHIS_SPEED
|
||
#ifdef _DEBUG
|
||
Assert(i_i < m_size, Util::CParamException());
|
||
#endif
|
||
m_data[i_i] = i_val;
|
||
COMP_CATCHTHIS_SPEED
|
||
}
|
||
|
||
// Description: Put the given value at the current index position and increment
|
||
// the current index position. Index position are counted in a linear
|
||
// manner in the image buffer
|
||
// Returns: Nothing.
|
||
void SetNext(
|
||
const unsigned short &i_v // new value of the pixel.
|
||
)
|
||
{
|
||
COMP_TRYTHIS
|
||
#ifdef _DEBUG
|
||
Assert(m_index < m_size, COMP::COutOfBufferException());
|
||
#endif
|
||
m_data[m_index++] = i_v;
|
||
COMP_CATCHTHIS
|
||
}
|
||
|
||
// Description: Returns the pixel value at the current index position and increment
|
||
// the current index position.
|
||
// Returns: The specified pixel value
|
||
unsigned short GetNext()
|
||
{
|
||
COMP_TRYTHIS
|
||
#ifdef _DEBUG
|
||
Assert(m_index < m_size, COMP::COutOfBufferException());
|
||
#endif
|
||
return m_data[m_index++];
|
||
COMP_CATCHTHIS
|
||
}
|
||
|
||
// Description: Reset the state information (m_index, m_cur_*, ...) to the initial
|
||
// buffer position.
|
||
// Returns: Nothing.
|
||
void ResetState();
|
||
|
||
// Description: Returns the image height.
|
||
// Returns: The number of lines in the image.
|
||
unsigned short GetH() const { return m_NL; }
|
||
|
||
// Description: Returns the image width.
|
||
// Returns: The number of columns in the image.
|
||
unsigned short GetW() const { return m_NC; }
|
||
|
||
// Description: Returns the image depth.
|
||
// Returns: The number of used bits per pixel.
|
||
unsigned short GetNB() const { return m_NB; }
|
||
|
||
// Description: Similar to std::auto_ptr::size().
|
||
// Returns: The number of pixels in the image.
|
||
unsigned long GetSize() const { return m_size; }
|
||
|
||
// Description: Similar to std::auto_ptr::get().
|
||
// Returns: A pointer to the raw data.
|
||
unsigned short *Get() { return &m_data[0]; }
|
||
|
||
// Description: Gets the array of pointers to lines.
|
||
// Returns: A pointer to the array of line pointers.
|
||
unsigned short **GetP() { return &m_dataptr[0]; }
|
||
|
||
// Description: Set the pixels of the lines from line # i_from to line
|
||
// # i_to included to 0.
|
||
// The current index position is updated to point at the first
|
||
// pixel following the last pixel reset.
|
||
// Returns: Nothing.
|
||
void Zero(
|
||
const unsigned short &i_from, // first line to reset
|
||
const unsigned short &i_to // last line to reset
|
||
)
|
||
{
|
||
COMP_TRYTHIS
|
||
const unsigned long x_from = i_from * m_NC;
|
||
const unsigned long x_to = i_to * m_NC;
|
||
#ifdef _DEBUG
|
||
if (x_from != m_index)
|
||
std::cerr << "!!! x_from != m_index\n";
|
||
Assert(x_from == m_index, Util::CParamException());
|
||
Assert(x_to <= m_size, Util::CParamException());
|
||
#endif
|
||
for (unsigned long i = x_from; i < x_to; i++)
|
||
m_data[i] = 0;
|
||
m_index = x_to;
|
||
COMP_CATCHTHIS
|
||
}
|
||
|
||
// Description: Set the pixels between the current index and the specified index to 0.
|
||
// The current index position is updated.
|
||
// Returns: Nothing.
|
||
void ZeroPixels(
|
||
const unsigned long &i_from, // index of the first pixel to reset.
|
||
const unsigned long &i_to // index of the last pixel to reset.
|
||
)
|
||
{
|
||
COMP_TRYTHIS
|
||
#ifdef _DEBUG
|
||
Assert(i_from <= i_to && i_to < m_size, Util::CParamException());
|
||
#endif
|
||
for (m_index = i_from; m_index <= i_to;)
|
||
m_data[m_index++] = 0;
|
||
COMP_CATCHTHIS
|
||
}
|
||
};
|
||
|
||
} // end namespace
|
||
|
||
#endif
|