add PfmFile::gamma_correct(), PfmFile::apply_mask(), PNMImage::copy_channel_bits()

This commit is contained in:
David Rose 2015-04-25 07:23:54 -07:00
parent 38ac0401ce
commit 8876f0939e
6 changed files with 314 additions and 86 deletions

View File

@ -593,6 +593,71 @@ compute_planar_bounds(const LPoint2d &center, PN_float32 point_dist, PN_float32
return compute_planar_bounds(LCAST(PN_float32, center), point_dist, sample_radius, points_only);
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::gamma_correct
// Access: Published
// Description: Assuming the image was constructed with a gamma curve
// of from_gamma in the RGB channels, converts it to an
// image with a gamma curve of to_gamma in the RGB
// channels. Does not affect the alpha channel.
////////////////////////////////////////////////////////////////////
INLINE void PfmFile::
gamma_correct(float from_gamma, float to_gamma) {
apply_exponent(from_gamma / to_gamma);
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::gamma_correct_alpha
// Access: Published
// Description: Assuming the image was constructed with a gamma curve
// of from_gamma in the alpha channel, converts it to an
// image with a gamma curve of to_gamma in the alpha
// channel. Does not affect the RGB channels.
////////////////////////////////////////////////////////////////////
INLINE void PfmFile::
gamma_correct_alpha(float from_gamma, float to_gamma) {
apply_exponent(1.0, from_gamma / to_gamma);
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::apply_exponent
// Access: Published
// Description: Adjusts each channel of the image by raising the
// corresponding component value to the indicated
// exponent, such that L' = L ^ exponent.
////////////////////////////////////////////////////////////////////
INLINE void PfmFile::
apply_exponent(float gray_exponent) {
apply_exponent(gray_exponent, gray_exponent, gray_exponent, 1.0);
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::apply_exponent
// Access: Published
// Description: Adjusts each channel of the image by raising the
// corresponding component value to the indicated
// exponent, such that L' = L ^ exponent.
////////////////////////////////////////////////////////////////////
INLINE void PfmFile::
apply_exponent(float gray_exponent, float alpha_exponent) {
apply_exponent(gray_exponent, gray_exponent, gray_exponent, alpha_exponent);
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::apply_exponent
// Access: Published
// Description: Adjusts each channel of the image by raising the
// corresponding component value to the indicated
// exponent, such that L' = L ^ exponent. For a
// grayscale image, the blue_exponent value is used for
// the grayscale value, and red_exponent and
// green_exponent are unused.
////////////////////////////////////////////////////////////////////
INLINE void PfmFile::
apply_exponent(float c0_exponent, float c1_exponent, float c2_exponent) {
apply_exponent(c0_exponent, c1_exponent, c2_exponent, 1.0);
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::get_table
// Access: Public

View File

@ -1466,6 +1466,36 @@ merge(const PfmFile &other) {
}
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::apply_mask
// Access: Published
// Description: Wherever there is missing data in the other PfmFile,
// set this the corresponding point in this PfmFile to
// missing as well, so that this PfmFile has only points
// where both files have points.
//
// The point is set to "missing" by setting it the
// no_data_value.
////////////////////////////////////////////////////////////////////
void PfmFile::
apply_mask(const PfmFile &other) {
nassertv(is_valid() && other.is_valid());
nassertv(other._x_size == _x_size && other._y_size == _y_size);
if (!other._has_no_data_value || !_has_no_data_value) {
// Trivial no-op.
return;
}
for (int yi = 0; yi < _y_size; ++yi) {
for (int xi = 0; xi < _x_size; ++xi) {
if (!other.has_point(xi, yi)) {
set_point4(xi, yi, _no_data_value);
}
}
}
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::copy_channel
// Access: Published
@ -2101,7 +2131,11 @@ divide_sub_image(const PfmFile &copy, int xto, int yto,
for (y = ymin; y < ymax; y++) {
for (x = xmin; x < xmax; x++) {
if (has_point(x, y) && copy.has_point(x - xmin + xfrom, y - ymin + yfrom)) {
set_point1(x, y, get_point1(x, y) / copy.get_point1(x - xmin + xfrom, y - ymin + yfrom) * pixel_scale);
float val = get_point1(x, y) / copy.get_point1(x - xmin + xfrom, y - ymin + yfrom) * pixel_scale;
if (cnan(val)) {
val = 0.0f;
}
set_point1(x, y, val);
}
}
}
@ -2224,6 +2258,69 @@ operator *= (float multiplier) {
}
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::apply_exponent
// Access: Published
// Description: Adjusts each channel of the image by raising the
// corresponding component value to the indicated
// exponent, such that L' = L ^ exponent.
////////////////////////////////////////////////////////////////////
void PfmFile::
apply_exponent(float c0_exponent, float c1_exponent, float c2_exponent,
float c3_exponent) {
switch (_num_channels) {
case 1:
{
for (int yi = 0; yi < _y_size; ++yi) {
for (int xi = 0; xi < _x_size; ++xi) {
float *val = &_table[(yi * _x_size + xi)];
val[0] = cpow(val[0], c0_exponent);
}
}
}
break;
case 2:
{
for (int yi = 0; yi < _y_size; ++yi) {
for (int xi = 0; xi < _x_size; ++xi) {
float *val = &_table[(yi * _x_size + xi) * _num_channels];
val[0] = cpow(val[0], c0_exponent);
val[1] = cpow(val[1], c1_exponent);
}
}
}
break;
case 3:
{
for (int yi = 0; yi < _y_size; ++yi) {
for (int xi = 0; xi < _x_size; ++xi) {
float *val = &_table[(yi * _x_size + xi) * _num_channels];
val[0] = cpow(val[0], c0_exponent);
val[1] = cpow(val[1], c1_exponent);
val[2] = cpow(val[2], c2_exponent);
}
}
}
break;
case 4:
{
for (int yi = 0; yi < _y_size; ++yi) {
for (int xi = 0; xi < _x_size; ++xi) {
float *val = &_table[(yi * _x_size + xi) * _num_channels];
val[0] = cpow(val[0], c0_exponent);
val[1] = cpow(val[1], c1_exponent);
val[2] = cpow(val[2], c2_exponent);
val[3] = cpow(val[3], c3_exponent);
}
}
}
break;
}
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::output
// Access: Published

View File

@ -123,6 +123,7 @@ PUBLISHED:
BLOCKING void forward_distort(const PfmFile &dist, PN_float32 scale_factor = 1.0);
BLOCKING void reverse_distort(const PfmFile &dist, PN_float32 scale_factor = 1.0);
BLOCKING void merge(const PfmFile &other);
BLOCKING void apply_mask(const PfmFile &other);
BLOCKING void copy_channel(int to_channel, const PfmFile &other, int from_channel);
BLOCKING void copy_channel_masked(int to_channel, const PfmFile &other, int from_channel);
BLOCKING void apply_crop(int x_begin, int x_end, int y_begin, int y_end);
@ -155,6 +156,13 @@ PUBLISHED:
void operator *= (float multiplier);
INLINE void gamma_correct(float from_gamma, float to_gamma);
INLINE void gamma_correct_alpha(float from_gamma, float to_gamma);
INLINE void apply_exponent(float gray_exponent);
INLINE void apply_exponent(float gray_exponent, float alpha_exponent);
INLINE void apply_exponent(float c0_exponent, float c1_exponent, float c2_exponent);
void apply_exponent(float c0_exponent, float c1_exponent, float c2_exponent, float c3_exponent);
void output(ostream &out) const;
EXTENSION(PyObject *get_points() const);

View File

@ -152,6 +152,57 @@ copy_channel(const PNMImage &copy, int src_channel, int dest_channel) {
}
}
////////////////////////////////////////////////////////////////////
// Function: PNMImage::copy_channel_bits
// Access: Published
// Description: Copies some subset of the bits of the specified
// channel from one image into some subset of the bits
// of the specified channel in another image. Images
// must be the same size.
//
// If right_shift is negative, it means a left shift.
////////////////////////////////////////////////////////////////////
void PNMImage::
copy_channel_bits(const PNMImage &copy, int src_channel, int dest_channel, xelval src_mask, int right_shift) {
// Make sure the channels are in range
nassertv(src_channel >= 0 && src_channel <= 3);
nassertv(dest_channel >= 0 && dest_channel <= 3);
// Make sure that images are valid
if (!copy.is_valid() || !is_valid()) {
pnmimage_cat.error() << "One of the images is invalid!\n";
return;
}
// Make sure the images are the same size
if (_x_size != copy.get_x_size() || _y_size != copy.get_y_size()){
pnmimage_cat.error() << "Image size doesn't match!\n";
return;
}
// Do the actual copying.
if (right_shift >= 0) {
xelval dest_mask = ~(src_mask >> right_shift);
for (int x = 0; x < _x_size; x++) {
for (int y = 0; y < _y_size; y++) {
xelval src = copy.get_channel_val(x, y, src_channel);
xelval dest = get_channel_val(x, y, dest_channel);
dest = (dest & dest_mask) | ((src & src_mask) >> right_shift);
set_channel_val(x, y, dest_channel, dest);
}
}
} else {
int left_shift = -right_shift;
xelval dest_mask = ~(src_mask << left_shift);
for (int x = 0; x < _x_size; x++) {
for (int y = 0; y < _y_size; y++) {
xelval src = copy.get_channel_val(x, y, src_channel);
xelval dest = get_channel_val(x, y, dest_channel);
dest = (dest & dest_mask) | ((src & src_mask) << left_shift);
set_channel_val(x, y, dest_channel, dest);
}
}
}
}
////////////////////////////////////////////////////////////////////
// Function: PNMImage::copy_header_from
// Access: Published
@ -165,6 +216,12 @@ copy_header_from(const PNMImageHeader &header) {
clear();
PNMImageHeader::operator = (header);
if (_maxval == 0) {
_inv_maxval = 0.0f;
} else {
_inv_maxval = 1.0f / (float)_maxval;
}
if (has_alpha()) {
allocate_alpha();
}

View File

@ -90,6 +90,7 @@ PUBLISHED:
void copy_from(const PNMImage &copy);
void copy_channel(const PNMImage &copy, int src_channel, int dest_channel);
void copy_channel_bits(const PNMImage &copy, int src_channel, int dest_channel, xelval src_mask, int right_shift);
void copy_header_from(const PNMImageHeader &header);
void take_from(PNMImage &orig);