add histogram/palette options

This commit is contained in:
David Rose 2004-03-19 01:49:12 +00:00
parent c1583ac567
commit b38732a6e1
3 changed files with 265 additions and 0 deletions

View File

@ -217,3 +217,121 @@ INLINE void PNMImageHeader::
set_type(PNMFileType *type) {
_type = type;
}
////////////////////////////////////////////////////////////////////
// Function: PNMImageHeader::record_color
// Access: Protected
// Description: Records the indicated color in the histogram.
////////////////////////////////////////////////////////////////////
INLINE void PNMImageHeader::
record_color(PNMImageHeader::Histogram &hist,
const PNMImageHeader::PixelSpec &color) {
Histogram::iterator hi = hist.find(color);
if (hi == hist.end()) {
hist.insert(Histogram::value_type(color, 1));
} else {
(*hi).second++;
}
}
////////////////////////////////////////////////////////////////////
// Function: PNMImageHeader::PixelSpec::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE PNMImageHeader::PixelSpec::
PixelSpec(xelval gray) :
_red(gray),
_green(gray),
_blue(gray),
_alpha(0)
{
}
////////////////////////////////////////////////////////////////////
// Function: PNMImageHeader::PixelSpec::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE PNMImageHeader::PixelSpec::
PixelSpec(xelval gray, xelval alpha) :
_red(gray),
_green(gray),
_blue(gray),
_alpha(alpha)
{
}
////////////////////////////////////////////////////////////////////
// Function: PNMImageHeader::PixelSpec::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE PNMImageHeader::PixelSpec::
PixelSpec(xelval red, xelval green, xelval blue) :
_red(red),
_green(green),
_blue(blue),
_alpha(0)
{
}
////////////////////////////////////////////////////////////////////
// Function: PNMImageHeader::PixelSpec::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE PNMImageHeader::PixelSpec::
PixelSpec(xelval red, xelval green, xelval blue, xelval alpha) :
_red(red),
_green(green),
_blue(blue),
_alpha(alpha)
{
}
////////////////////////////////////////////////////////////////////
// Function: PNMImageHeader::PixelSpec::Copy Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE PNMImageHeader::PixelSpec::
PixelSpec(const PixelSpec &copy) :
_red(copy._red),
_green(copy._green),
_blue(copy._blue),
_alpha(copy._alpha)
{
}
////////////////////////////////////////////////////////////////////
// Function: PNMImageHeader::PixelSpec::Copy Assignment Operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE void PNMImageHeader::PixelSpec::
operator = (const PixelSpec &copy) {
_red = copy._red;
_green = copy._green;
_blue = copy._blue;
_alpha = copy._alpha;
}
////////////////////////////////////////////////////////////////////
// Function: PNMImageHeader::PixelSpec::Comparison Operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE bool PNMImageHeader::PixelSpec::
operator < (const PixelSpec &other) const {
if (_red != other._red) {
return _red < other._red;
}
if (_green != other._green) {
return _green < other._green;
}
if (_blue != other._blue) {
return _blue < other._blue;
}
return _alpha < other._alpha;
}

View File

@ -347,6 +347,11 @@ make_writer(ostream *file, bool owns_file, const Filename &filename,
delete file;
}
if (!writer->is_valid()) {
delete writer;
writer = NULL;
}
return writer;
}
@ -383,3 +388,114 @@ output(ostream &out) const {
out << "image: " << _x_size << " by " << _y_size << " pixels, "
<< _num_channels << " channels, " << _maxval << " maxval.";
}
////////////////////////////////////////////////////////////////////
// Function: PNMImageHeader::compute_histogram
// Access: Protected
// Description: Computes a histogram of the colors used in the
// indicated rgb/grayscale array and/or alpha array.
// This is most likely to be useful in a PNMWriter
// class, but it is defined at this level in case it has
// general utilty for PNMImages.
//
// The max_colors parameter, if greater than zero,
// limits the maximum number of colors we are interested
// in. If we encounter more than this number of colors,
// the function aborts before completion and returns
// false; otherwise, it returns true.
////////////////////////////////////////////////////////////////////
bool PNMImageHeader::
compute_histogram(PNMImageHeader::Histogram &hist,
xel *array, xelval *alpha, int max_colors) {
int num_pixels = _x_size * _y_size;
switch (get_color_type()) {
case CT_invalid:
return false;
case CT_grayscale:
for (int pi = 0; pi < num_pixels; pi++) {
record_color(hist, PixelSpec(PPM_GETB(array[pi])));
if (max_colors > 0 && (int)hist.size() > max_colors) {
return false;
}
}
return true;
case CT_two_channel:
for (int pi = 0; pi < num_pixels; pi++) {
record_color(hist, PixelSpec(PPM_GETB(array[pi]), alpha[pi]));
if (max_colors > 0 && (int)hist.size() > max_colors) {
return false;
}
}
return true;
case CT_color:
for (int pi = 0; pi < num_pixels; pi++) {
record_color(hist, PixelSpec(PPM_GETR(array[pi]), PPM_GETG(array[pi]), PPM_GETB(array[pi])));
if (max_colors > 0 && (int)hist.size() > max_colors) {
return false;
}
}
return true;
case CT_four_channel:
for (int pi = 0; pi < num_pixels; pi++) {
record_color(hist, PixelSpec(PPM_GETR(array[pi]), PPM_GETG(array[pi]), PPM_GETB(array[pi]), alpha[pi]));
if (max_colors > 0 && (int)hist.size() > max_colors) {
return false;
}
}
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////
// Function: PNMImageHeader::compute_palette
// Access: Protected
// Description: Returns a linear list of all of the colors in the
// image, similar to compute_histogram().
////////////////////////////////////////////////////////////////////
bool PNMImageHeader::
compute_palette(PNMImageHeader::Palette &palette,
xel *array, xelval *alpha, int max_colors) {
Histogram hist;
int num_pixels = _x_size * _y_size;
// In case there are already entries in the palette, preserve them.
Palette::const_iterator pi;
for (pi = palette.begin(); pi != palette.end(); ++pi) {
hist.insert(Histogram::value_type(*pi, num_pixels + 1));
}
if (!compute_histogram(hist, array, alpha, max_colors)) {
return false;
}
// Now append the new entries discovered in the histogram onto the
// end of the palette.
palette.reserve(hist.size());
Histogram::const_iterator hi;
for (hi = hist.begin(); hi != hist.end(); ++hi) {
if ((*hi).second <= num_pixels) {
palette.push_back((*hi).first);
}
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: PNMImageHeader::PixelSpec::output
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void PNMImageHeader::PixelSpec::
output(ostream &out) const {
out << "(" << _red << ", " << _green << ", " << _blue << ", " << _alpha << ")";
}

View File

@ -96,7 +96,33 @@ public:
void output(ostream &out) const;
public:
// These classes are used internally, but must be declared public
// for fiddly reasons.
class PixelSpec {
public:
INLINE PixelSpec(xelval gray);
INLINE PixelSpec(xelval gray, xelval alpha);
INLINE PixelSpec(xelval red, xelval green, xelval blue);
INLINE PixelSpec(xelval red, xelval green, xelval blue, xelval alpha);
INLINE PixelSpec(const PixelSpec &copy);
INLINE void operator = (const PixelSpec &copy);
INLINE bool operator < (const PixelSpec &other) const;
void output(ostream &out) const;
xelval _red, _green, _blue, _alpha;
};
typedef pmap<PixelSpec, int> Histogram;
typedef pvector<PixelSpec> Palette;
protected:
bool compute_histogram(Histogram &hist, xel *array, xelval *alpha,
int max_colors = 0);
bool compute_palette(Palette &palette, xel *array, xelval *alpha,
int max_colors = 0);
INLINE void record_color(Histogram &hist, const PixelSpec &color);
int _x_size, _y_size;
int _num_channels;
xelval _maxval;
@ -108,6 +134,11 @@ INLINE ostream &operator << (ostream &out, const PNMImageHeader &header) {
return out;
}
INLINE ostream &operator << (ostream &out, const PNMImageHeader::PixelSpec &pixel) {
pixel.output(out);
return out;
}
#include "pnmImageHeader.I"
#endif