Panda3D

imageFixHiddenColor.cxx

00001 // Filename: imageFixHiddenColor.cxx
00002 // Created by:  drose (13Mar03)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "imageFixHiddenColor.h"
00016 #include "string_utils.h"
00017 #include "pystub.h"
00018 
00019 ////////////////////////////////////////////////////////////////////
00020 //     Function: ImageFixHiddenColor::Constructor
00021 //       Access: Public
00022 //  Description:
00023 ////////////////////////////////////////////////////////////////////
00024 ImageFixHiddenColor::
00025 ImageFixHiddenColor() : ImageFilter(true) {
00026   set_program_description
00027     ("This program is designed to fix the color channels of an "
00028      "alpha-cutout image, making the \"color\" of the invisible part of the "
00029      "image consistent with the rest of the image.  It does this by "
00030      "analyzing the RGB values of the image where alpha == 1, and using the "
00031      "average of these values as the overall image color, which it then "
00032      "applies to the image wherever alpha == 0.  When the alpha value is "
00033      "neither 1 nor 0, the pixel is ignored.\n\n"
00034 
00035      "This process is important for applications that filter the texture "
00036      "size down by averaging neighboring pixels.  If the color under the "
00037      "alpha == 0 pixels is very different from the color elsewhere, this "
00038      "kind of filtering can have a visible effect on the image's color, even "
00039      "where alpha != 0.");
00040 
00041   add_option
00042     ("alpha", "filename", 0,
00043      "Specifies a separate filename that will be used in lieu of the "
00044      "alpha channel on the source image.  If this file has an alpha "
00045      "channel, that alpha channel is used; otherwise, the grayscale "
00046      "value of the image is used.",
00047      &ImageFixHiddenColor::dispatch_filename, NULL, &_alpha_filename);
00048 
00049   add_option
00050     ("opaque", "alpha", 0,
00051      "Specifies the minimum alpha value (in the range of 0 to 1) for a "
00052      "pixel to be considered fully opaque.  The default is 1.",
00053      &ImageFixHiddenColor::dispatch_double, NULL, &_min_opaque_alpha);
00054 
00055   add_option
00056     ("transparent", "alpha", 0,
00057      "Specifies the maximum alpha value (in the range of 0 to 1) for a "
00058      "pixel to be considered fully transparent.  The default is 0.",
00059      &ImageFixHiddenColor::dispatch_double, NULL, &_max_transparent_alpha);
00060 
00061   _min_opaque_alpha = 1.0;
00062   _max_transparent_alpha = 0.0;
00063 }
00064 
00065 ////////////////////////////////////////////////////////////////////
00066 //     Function: ImageFixHiddenColor::run
00067 //       Access: Public
00068 //  Description:
00069 ////////////////////////////////////////////////////////////////////
00070 void ImageFixHiddenColor::
00071 run() {
00072   PNMImage alpha_image;
00073 
00074   if (_alpha_filename.empty()) {
00075     // No separate alpha file is provided; use the base file's alpha
00076     // channel.
00077     if (!_image.has_alpha()) {
00078       nout << "Image does not have an alpha channel.\n";
00079       exit(1);
00080     }
00081     alpha_image = _image;
00082 
00083   } else {
00084     // In this case, the alpha channel is in a separate file.
00085     if (!alpha_image.read(_alpha_filename)) {
00086       nout << "Unable to read " << _alpha_filename << ".\n";
00087       exit(1);
00088     }
00089 
00090     if (!alpha_image.has_alpha()) {
00091       // Copy the grayscale value to the alpha channel for the benefit
00092       // of the code below.
00093       alpha_image.add_alpha();
00094       int xi, yi;
00095       for (yi = 0; yi < alpha_image.get_y_size(); ++yi) {
00096         for (xi = 0; xi < alpha_image.get_x_size(); ++xi) {
00097           alpha_image.set_alpha(xi, yi, alpha_image.get_gray(xi, yi));
00098         }
00099       }
00100     }
00101 
00102     // Make sure the alpha image matches the size of the source image.
00103     if (alpha_image.get_x_size() != _image.get_x_size() ||
00104         alpha_image.get_y_size() != _image.get_y_size()) {
00105       PNMImage scaled(_image.get_x_size(), _image.get_y_size(), alpha_image.get_num_channels());
00106       scaled.quick_filter_from(alpha_image);
00107       alpha_image = scaled;
00108     }
00109   }
00110 
00111   // First, get the average color of all the opaque pixels.
00112   int count = 0;
00113   LRGBColord color(0.0, 0.0, 0.0);
00114   int xi, yi;
00115   for (yi = 0; yi < _image.get_y_size(); ++yi) {
00116     for (xi = 0; xi < _image.get_x_size(); ++xi) {
00117       if (alpha_image.get_alpha(xi, yi) >= _min_opaque_alpha) {
00118         color += _image.get_xel(xi, yi);
00119         ++count;
00120       }
00121     }
00122   }
00123   if (count == 0) {
00124     nout << "Image has no opaque pixels.\n";
00125     exit(1);
00126   }
00127   color /= (double)count;
00128   nout << "  average color of " << count << " opaque pixels is " << color << "\n";
00129   
00130   // Now, apply that wherever there are transparent pixels.
00131   count = 0;
00132   for (yi = 0; yi < _image.get_y_size(); ++yi) {
00133     for (xi = 0; xi < _image.get_x_size(); ++xi) {
00134       if (alpha_image.get_alpha(xi, yi) <= _max_transparent_alpha) {
00135         _image.set_xel(xi, yi, color);
00136         ++count;
00137       }
00138     }
00139   }
00140   if (count == 0) {
00141     nout << "Image has no transparent pixels.\n";
00142     exit(1);
00143   }
00144   nout << "  applied to " << count << " transparent pixels.\n";
00145     
00146   write_image(_image);
00147 }
00148 
00149 
00150 int main(int argc, char *argv[]) {
00151   // A call to pystub() to force libpystub.so to be linked in.
00152   pystub();
00153 
00154   ImageFixHiddenColor prog;
00155   prog.parse_command_line(argc, argv);
00156   prog.run();
00157   return 0;
00158 }
 All Classes Functions Variables Enumerations