Panda3D
|
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 }