Panda3D
imageFixHiddenColor.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file imageFixHiddenColor.cxx
10  * @author drose
11  * @date 2003-03-13
12  */
13 
14 #include "imageFixHiddenColor.h"
15 #include "string_utils.h"
16 
17 /**
18  *
19  */
20 ImageFixHiddenColor::
21 ImageFixHiddenColor() : ImageFilter(true) {
22  set_program_brief("change the color of transparent pixels in an image");
23  set_program_description
24  ("This program is designed to fix the color channels of an "
25  "alpha-cutout image, making the \"color\" of the invisible part of the "
26  "image consistent with the rest of the image. It does this by "
27  "analyzing the RGB values of the image where alpha == 1, and using the "
28  "average of these values as the overall image color, which it then "
29  "applies to the image wherever alpha == 0. When the alpha value is "
30  "neither 1 nor 0, the pixel is ignored.\n\n"
31 
32  "This process is important for applications that filter the texture "
33  "size down by averaging neighboring pixels. If the color under the "
34  "alpha == 0 pixels is very different from the color elsewhere, this "
35  "kind of filtering can have a visible effect on the image's color, even "
36  "where alpha != 0.");
37 
38  add_option
39  ("alpha", "filename", 0,
40  "Specifies a separate filename that will be used in lieu of the "
41  "alpha channel on the source image. If this file has an alpha "
42  "channel, that alpha channel is used; otherwise, the grayscale "
43  "value of the image is used.",
44  &ImageFixHiddenColor::dispatch_filename, nullptr, &_alpha_filename);
45 
46  add_option
47  ("opaque", "alpha", 0,
48  "Specifies the minimum alpha value (in the range of 0 to 1) for a "
49  "pixel to be considered fully opaque. The default is 1.",
50  &ImageFixHiddenColor::dispatch_double, nullptr, &_min_opaque_alpha);
51 
52  add_option
53  ("transparent", "alpha", 0,
54  "Specifies the maximum alpha value (in the range of 0 to 1) for a "
55  "pixel to be considered fully transparent. The default is 0.",
56  &ImageFixHiddenColor::dispatch_double, nullptr, &_max_transparent_alpha);
57 
58  _min_opaque_alpha = 1.0;
59  _max_transparent_alpha = 0.0;
60 }
61 
62 /**
63  *
64  */
65 void ImageFixHiddenColor::
66 run() {
67  PNMImage alpha_image;
68 
69  if (_alpha_filename.empty()) {
70  // No separate alpha file is provided; use the base file's alpha channel.
71  if (!_image.has_alpha()) {
72  nout << "Image does not have an alpha channel.\n";
73  exit(1);
74  }
75  alpha_image = _image;
76 
77  } else {
78  // In this case, the alpha channel is in a separate file.
79  if (!alpha_image.read(_alpha_filename)) {
80  nout << "Unable to read " << _alpha_filename << ".\n";
81  exit(1);
82  }
83 
84  if (!alpha_image.has_alpha()) {
85  // Copy the grayscale value to the alpha channel for the benefit of the
86  // code below.
87  alpha_image.add_alpha();
88  int xi, yi;
89  for (yi = 0; yi < alpha_image.get_y_size(); ++yi) {
90  for (xi = 0; xi < alpha_image.get_x_size(); ++xi) {
91  alpha_image.set_alpha(xi, yi, alpha_image.get_gray(xi, yi));
92  }
93  }
94  }
95 
96  // Make sure the alpha image matches the size of the source image.
97  if (alpha_image.get_x_size() != _image.get_x_size() ||
98  alpha_image.get_y_size() != _image.get_y_size()) {
99  PNMImage scaled(_image.get_x_size(), _image.get_y_size(), alpha_image.get_num_channels());
100  scaled.quick_filter_from(alpha_image);
101  alpha_image = scaled;
102  }
103  }
104 
105  // First, get the average color of all the opaque pixels.
106  int count = 0;
107  LRGBColor color(0.0, 0.0, 0.0);
108  int xi, yi;
109  for (yi = 0; yi < _image.get_y_size(); ++yi) {
110  for (xi = 0; xi < _image.get_x_size(); ++xi) {
111  if (alpha_image.get_alpha(xi, yi) >= _min_opaque_alpha) {
112  color += _image.get_xel(xi, yi);
113  ++count;
114  }
115  }
116  }
117  if (count == 0) {
118  nout << "Image has no opaque pixels.\n";
119  exit(1);
120  }
121  color /= (double)count;
122  nout << " average color of " << count << " opaque pixels is " << color << "\n";
123 
124  // Now, apply that wherever there are transparent pixels.
125  count = 0;
126  for (yi = 0; yi < _image.get_y_size(); ++yi) {
127  for (xi = 0; xi < _image.get_x_size(); ++xi) {
128  if (alpha_image.get_alpha(xi, yi) <= _max_transparent_alpha) {
129  _image.set_xel(xi, yi, color);
130  ++count;
131  }
132  }
133  }
134  if (count == 0) {
135  nout << "Image has no transparent pixels.\n";
136  exit(1);
137  }
138  nout << " applied to " << count << " transparent pixels.\n";
139 
140  write_image(_image);
141 }
142 
143 
144 int main(int argc, char *argv[]) {
145  ImageFixHiddenColor prog;
146  prog.parse_command_line(argc, argv);
147  prog.run();
148  return 0;
149 }
The name of this class derives from the fact that we originally implemented it as a layer on top of t...
Definition: pnmImage.h:58
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_num_channels
Returns the number of channels in the image.
virtual void parse_command_line(int argc, char **argv)
Dispatches on each of the options on the command line, and passes the remaining parameters to handle_...
float get_gray(int x, int y) const
Returns the gray component color at the indicated pixel.
Definition: pnmImage.I:785
bool read(const Filename &filename, PNMFileType *type=nullptr, bool report_unknown_type=true)
Reads the indicated image filename.
Definition: pnmImage.cxx:278
This is the base class for a program that reads an image file, operates on it, and writes another ima...
Definition: imageFilter.h:26
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
int get_y_size() const
Returns the number of pixels in the Y direction.
void quick_filter_from(const PNMImage &copy, int xborder=0, int yborder=0)
Resizes from the given image, with a fixed radius of 0.5.
int get_x_size() const
Returns the number of pixels in the X direction.
static bool has_alpha(ColorType color_type)
This static variant of has_alpha() returns true if the indicated image type includes an alpha channel...
This program repairs an image's RGB values hidden behind an A value of 0.
void add_alpha()
Adds an alpha channel to the image, if it does not already have one.
Definition: pnmImage.I:274
void set_alpha(int x, int y, float a)
Sets the alpha component color only at the indicated pixel.
Definition: pnmImage.I:845
void write_image()
Writes the generated to the user's specified output filename.
Definition: imageWriter.I:18
float get_alpha(int x, int y) const
Returns the alpha component color at the indicated pixel.
Definition: pnmImage.I:795