histogram stuff

This commit is contained in:
David Rose 2009-11-09 01:11:37 +00:00
parent 62f6e4dbe7
commit a789df141d
5 changed files with 376 additions and 20 deletions

View File

@ -615,6 +615,44 @@ set_channel_val(int x, int y, int channel, xelval value) {
}
}
////////////////////////////////////////////////////////////////////
// Function: PNMImage::get_pixel
// Access: Published
// Description: Returns the (r, g, b, a) pixel value at the indicated
// pixel, using a PixelSpec object.
////////////////////////////////////////////////////////////////////
PNMImage::PixelSpec PNMImage::
get_pixel(int x, int y) const {
switch (_num_channels) {
case 1:
return PixelSpec(get_gray_val(x, y));
case 2:
return PixelSpec(get_gray_val(x, y), get_alpha_val(x, y));
case 3:
return PixelSpec(get_xel_val(x, y));
case 4:
return PixelSpec(get_xel_val(x, y), get_alpha_val(x, y));
}
return PixelSpec(0);
}
////////////////////////////////////////////////////////////////////
// Function: PNMImage::set_pixel
// Access: Published
// Description: Sets the (r, g, b, a) pixel value at the indicated
// pixel, using a PixelSpec object.
////////////////////////////////////////////////////////////////////
void PNMImage::
set_pixel(int x, int y, const PixelSpec &pixel) {
xel p;
PPM_ASSIGN(p, pixel._red, pixel._green, pixel._blue);
set_xel_val(x, y, p);
if (_alpha != NULL) {
set_alpha_val(x, y, pixel._alpha);
}
}
////////////////////////////////////////////////////////////////////
// Function: PNMImage::blend
// Access: Published
@ -1064,6 +1102,33 @@ expand_border(int left, int right, int bottom, int top,
take_from(new_image);
}
////////////////////////////////////////////////////////////////////
// Function: PNMImage::make_histogram
// Access: Published
// Description: Computes a histogram of the colors used in the
// image.
////////////////////////////////////////////////////////////////////
void PNMImage::
make_histogram(PNMImage::Histogram &histogram) {
HistMap hist_map;
PixelCount pixels;
int num_pixels = _x_size * _y_size;
compute_histogram(hist_map, _array, _alpha);
pixels.reserve(hist_map.size());
HistMap::const_iterator hi;
for (hi = hist_map.begin(); hi != hist_map.end(); ++hi) {
if ((*hi).second <= num_pixels) {
pixels.push_back(PixelSpecCount((*hi).first, (*hi).second));
}
}
sort(pixels.begin(), pixels.end());
histogram.swap(pixels, hist_map);
}
////////////////////////////////////////////////////////////////////
// Function: PNMImage::setup_rc
// Access: Private

View File

@ -144,6 +144,9 @@ PUBLISHED:
xelval get_channel_val(int x, int y, int channel) const;
void set_channel_val(int x, int y, int channel, xelval value);
PixelSpec get_pixel(int x, int y) const;
void set_pixel(int x, int y, const PixelSpec &pixel);
// The corresponding get_xel(), set_xel(), get_red(), etc. functions
// automatically scale their values by get_maxval() into the range
// [0..1].
@ -224,6 +227,8 @@ PUBLISHED:
void quick_filter_from(const PNMImage &copy,
int xborder = 0, int yborder = 0);
void make_histogram(Histogram &hist);
private:
INLINE void allocate_array();
INLINE void allocate_alpha();

View File

@ -241,11 +241,11 @@ set_type(PNMFileType *type) {
// Description: Records the indicated color in the histogram.
////////////////////////////////////////////////////////////////////
INLINE void PNMImageHeader::
record_color(PNMImageHeader::Histogram &hist,
record_color(PNMImageHeader::HistMap &hist,
const PNMImageHeader::PixelSpec &color) {
// First, try to add the color with a count of 0, in case it does
// not already exist in the table.
Histogram::iterator hi = hist.insert(Histogram::value_type(color, 0)).first;
HistMap::iterator hi = hist.insert(HistMap::value_type(color, 0)).first;
// Now that either succeeded or failed, but either way hi is now the
// iterator to the count value in the table associated with the
@ -255,7 +255,7 @@ record_color(PNMImageHeader::Histogram &hist,
////////////////////////////////////////////////////////////////////
// Function: PNMImageHeader::PixelSpec::Constructor
// Access: Public
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE PNMImageHeader::PixelSpec::
@ -269,7 +269,7 @@ PixelSpec(xelval gray_value) :
////////////////////////////////////////////////////////////////////
// Function: PNMImageHeader::PixelSpec::Constructor
// Access: Public
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE PNMImageHeader::PixelSpec::
@ -283,7 +283,7 @@ PixelSpec(xelval gray_value, xelval alpha) :
////////////////////////////////////////////////////////////////////
// Function: PNMImageHeader::PixelSpec::Constructor
// Access: Public
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE PNMImageHeader::PixelSpec::
@ -297,7 +297,7 @@ PixelSpec(xelval red, xelval green, xelval blue) :
////////////////////////////////////////////////////////////////////
// Function: PNMImageHeader::PixelSpec::Constructor
// Access: Public
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE PNMImageHeader::PixelSpec::
@ -309,9 +309,37 @@ PixelSpec(xelval red, xelval green, xelval blue, xelval alpha) :
{
}
////////////////////////////////////////////////////////////////////
// Function: PNMImageHeader::PixelSpec::Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE PNMImageHeader::PixelSpec::
PixelSpec(const xel &rgb) :
_red(PPM_GETR(rgb)),
_green(PPM_GETG(rgb)),
_blue(PPM_GETB(rgb)),
_alpha(0)
{
}
////////////////////////////////////////////////////////////////////
// Function: PNMImageHeader::PixelSpec::Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE PNMImageHeader::PixelSpec::
PixelSpec(const xel &rgb, xelval alpha) :
_red(PPM_GETR(rgb)),
_green(PPM_GETG(rgb)),
_blue(PPM_GETB(rgb)),
_alpha(alpha)
{
}
////////////////////////////////////////////////////////////////////
// Function: PNMImageHeader::PixelSpec::Copy Constructor
// Access: Public
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE PNMImageHeader::PixelSpec::
@ -325,7 +353,7 @@ PixelSpec(const PixelSpec &copy) :
////////////////////////////////////////////////////////////////////
// Function: PNMImageHeader::PixelSpec::Copy Assignment Operator
// Access: Public
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE void PNMImageHeader::PixelSpec::
@ -338,7 +366,7 @@ operator = (const PixelSpec &copy) {
////////////////////////////////////////////////////////////////////
// Function: PNMImageHeader::PixelSpec::Comparison Operator
// Access: Public
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE bool PNMImageHeader::PixelSpec::
@ -354,3 +382,209 @@ operator < (const PixelSpec &other) const {
}
return _alpha < other._alpha;
}
////////////////////////////////////////////////////////////////////
// Function: PNMImageHeader::PixelSpec::get_red
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE xelval PNMImageHeader::PixelSpec::
get_red() const {
return _red;
}
////////////////////////////////////////////////////////////////////
// Function: PNMImageHeader::PixelSpec::get_green
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE xelval PNMImageHeader::PixelSpec::
get_green() const {
return _green;
}
////////////////////////////////////////////////////////////////////
// Function: PNMImageHeader::PixelSpec::get_blue
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE xelval PNMImageHeader::PixelSpec::
get_blue() const {
return _blue;
}
////////////////////////////////////////////////////////////////////
// Function: PNMImageHeader::PixelSpec::get_alpha
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE xelval PNMImageHeader::PixelSpec::
get_alpha() const {
return _alpha;
}
////////////////////////////////////////////////////////////////////
// Function: PNMImageHeader::PixelSpec::set_red
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE void PNMImageHeader::PixelSpec::
set_red(xelval red) {
_red = red;
}
////////////////////////////////////////////////////////////////////
// Function: PNMImageHeader::PixelSpec::set_green
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE void PNMImageHeader::PixelSpec::
set_green(xelval green) {
_green = green;
}
////////////////////////////////////////////////////////////////////
// Function: PNMImageHeader::PixelSpec::set_blue
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE void PNMImageHeader::PixelSpec::
set_blue(xelval blue) {
_blue = blue;
}
////////////////////////////////////////////////////////////////////
// Function: PNMImageHeader::PixelSpec::set_alpha
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE void PNMImageHeader::PixelSpec::
set_alpha(xelval alpha) {
_alpha = alpha;
}
////////////////////////////////////////////////////////////////////
// Function: PNMImageHeader::PixelSpec::operator []
// Access: Published
// Description: Indexes numerically into the components, in the order
// R, G, B, A. This also makes the PixelSpec work like
// a tuple in Python.
////////////////////////////////////////////////////////////////////
INLINE xelval PNMImageHeader::PixelSpec::
operator [](int n) const {
nassertr(n >= 0 && n < size(), 0);
return (&_red)[n];
}
////////////////////////////////////////////////////////////////////
// Function: PNMImageHeader::PixelSpec::size
// Access: Published, Static
// Description: Specifies the number of components in the PixelSpec;
// this is always 4, regardless of the type of image it
// was taken from.
////////////////////////////////////////////////////////////////////
INLINE int PNMImageHeader::PixelSpec::
size() {
return 4;
}
// Interrogate seems to have some problem with the syntax of this
// method. Whatever, we don't need it.
#ifndef CPPPARSER
////////////////////////////////////////////////////////////////////
// Function: PNMImageHeader::PixelSpecCount::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE PNMImageHeader::PixelSpecCount::
PixelSpecCount(const PNMImageHeader::PixelSpec &pixel, int count) :
_pixel(pixel),
_count(count)
{
}
#endif // CPPPARSER
////////////////////////////////////////////////////////////////////
// Function: PNMImageHeader::PixelSpecCount::operator <
// Access: Public
// Description: Used to sort the pixels in order from most common to
// least common.
////////////////////////////////////////////////////////////////////
INLINE bool PNMImageHeader::PixelSpecCount::
operator < (const PNMImageHeader::PixelSpecCount &other) const {
return _count > other._count;
}
////////////////////////////////////////////////////////////////////
// Function: PNMImageHeader::Histogram::Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE PNMImageHeader::Histogram::
Histogram() {
}
////////////////////////////////////////////////////////////////////
// Function: PNMImageHeader::Histogram::get_num_pixels
// Access: Published
// Description: Returns the number of unique pixel colors in the
// histogram.
////////////////////////////////////////////////////////////////////
INLINE int PNMImageHeader::Histogram::
get_num_pixels() const {
return _pixels.size();
}
////////////////////////////////////////////////////////////////////
// Function: PNMImageHeader::Histogram::get_pixel
// Access: Published
// Description: Returns the nth unique pixel color in the histogram.
// These are ordered by default from most common to
// least common.
////////////////////////////////////////////////////////////////////
INLINE const PNMImageHeader::PixelSpec &PNMImageHeader::Histogram::
get_pixel(int n) const {
nassertr(n >= 0 && n < _pixels.size(), _pixels[0]._pixel);
return _pixels[n]._pixel;
}
////////////////////////////////////////////////////////////////////
// Function: PNMImageHeader::Histogram::get_count
// Access: Published
// Description: Returns the number of occurrences in the image of the
// nth unique pixel color in the histogram.
////////////////////////////////////////////////////////////////////
INLINE int PNMImageHeader::Histogram::
get_count(int n) const {
nassertr(n >= 0 && n < _pixels.size(), 0);
return _pixels[n]._count;
}
////////////////////////////////////////////////////////////////////
// Function: PNMImageHeader::Histogram::get_count
// Access: Published
// Description: Returns the number of occurrences in the image of the
// indicated pixel color.
////////////////////////////////////////////////////////////////////
INLINE int PNMImageHeader::Histogram::
get_count(const PNMImageHeader::PixelSpec &pixel) const {
HistMap::const_iterator hi;
hi = _hist_map.find(pixel);
if (hi == _hist_map.end()) {
return 0;
}
return (*hi).second;
}
////////////////////////////////////////////////////////////////////
// Function: PNMImageHeader::Histogram::swap
// Access: Public
// Description: Swaps the data in the Histogram with the indicated
// data. This is normally used to load the Histogram
// data initially in PNMImage::make_histogram().
////////////////////////////////////////////////////////////////////
INLINE void PNMImageHeader::Histogram::
swap(PixelCount &pixels, HistMap &hist_map) {
_pixels.swap(pixels);
_hist_map.swap(hist_map);
}

View File

@ -437,6 +437,9 @@ output(ostream &out) const {
// class, but it is defined at this level in case it has
// general utilty for PNMImages.
//
// Also see PNMImage::make_histogram(), which is a
// higher-level function.
//
// 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,
@ -444,7 +447,7 @@ output(ostream &out) const {
// false; otherwise, it returns true.
////////////////////////////////////////////////////////////////////
bool PNMImageHeader::
compute_histogram(PNMImageHeader::Histogram &hist,
compute_histogram(PNMImageHeader::HistMap &hist,
xel *array, xelval *alpha, int max_colors) {
int num_pixels = _x_size * _y_size;
int pi;
@ -502,14 +505,14 @@ compute_histogram(PNMImageHeader::Histogram &hist,
bool PNMImageHeader::
compute_palette(PNMImageHeader::Palette &palette,
xel *array, xelval *alpha, int max_colors) {
Histogram hist;
HistMap 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));
hist.insert(HistMap::value_type(*pi, num_pixels + 1));
}
if (!compute_histogram(hist, array, alpha, max_colors)) {
@ -519,7 +522,7 @@ compute_palette(PNMImageHeader::Palette &palette,
// Now append the new entries discovered in the histogram onto the
// end of the palette.
palette.reserve(hist.size());
Histogram::const_iterator hi;
HistMap::const_iterator hi;
for (hi = hist.begin(); hi != hist.end(); ++hi) {
if ((*hi).second <= num_pixels) {
palette.push_back((*hi).first);

View File

@ -103,32 +103,81 @@ PUBLISHED:
void output(ostream &out) const;
public:
// These classes are used internally, but must be declared public
// for fiddly reasons.
// Contains a single pixel specification used in compute_histogram()
// and make_histogram(). Note that pixels are stored by integer
// value, not by floating-point scaled value.
class PixelSpec {
public:
PUBLISHED:
INLINE PixelSpec(xelval gray_value);
INLINE PixelSpec(xelval gray_value, xelval alpha);
INLINE PixelSpec(xelval red, xelval green, xelval blue);
INLINE PixelSpec(xelval red, xelval green, xelval blue, xelval alpha);
INLINE PixelSpec(const xel &rgb);
INLINE PixelSpec(const xel &rgb, xelval alpha);
INLINE PixelSpec(const PixelSpec &copy);
INLINE void operator = (const PixelSpec &copy);
INLINE bool operator < (const PixelSpec &other) const;
INLINE xelval get_red() const;
INLINE xelval get_green() const;
INLINE xelval get_blue() const;
INLINE xelval get_alpha() const;
INLINE void set_red(xelval red);
INLINE void set_green(xelval green);
INLINE void set_blue(xelval blue);
INLINE void set_alpha(xelval alpha);
INLINE xelval operator [](int n) const;
INLINE static int size();
void output(ostream &out) const;
public:
xelval _red, _green, _blue, _alpha;
};
typedef pmap<PixelSpec, int> Histogram;
// Associates a pixel specification with an appearance count, for
// use in Histogram, below.
class PixelSpecCount {
public:
INLINE PixelSpecCount(const PixelSpec &pixel, int count);
INLINE bool operator < (const PixelSpecCount &other) const;
PixelSpec _pixel;
int _count;
};
typedef pmap<PixelSpec, int> HistMap;
typedef pvector<PixelSpecCount> PixelCount;
typedef pvector<PixelSpec> Palette;
// Used to return a pixel histogram in PNMImage::get_histogram().
class Histogram {
PUBLISHED:
INLINE Histogram();
INLINE int get_num_pixels() const;
INLINE const PixelSpec &get_pixel(int n) const;
INLINE int get_count(int n) const;
INLINE int get_count(const PixelSpec &pixel) const;
MAKE_SEQ(get_pixels, get_num_pixels, get_pixel);
public:
INLINE void swap(PixelCount &pixels, HistMap &hist_map);
private:
PixelCount _pixels;
HistMap _hist_map;
};
protected:
bool compute_histogram(Histogram &hist, xel *array, xelval *alpha,
bool compute_histogram(HistMap &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);
INLINE void record_color(HistMap &hist, const PixelSpec &color);
int _x_size, _y_size;
int _num_channels;