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