imageFixHiddenColor.cxx 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  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. #include "imageFixHiddenColor.h"
  14. #include "string_utils.h"
  15. /**
  16. *
  17. */
  18. ImageFixHiddenColor::
  19. ImageFixHiddenColor() : ImageFilter(true) {
  20. set_program_brief("change the color of transparent pixels in an image");
  21. set_program_description
  22. ("This program is designed to fix the color channels of an "
  23. "alpha-cutout image, making the \"color\" of the invisible part of the "
  24. "image consistent with the rest of the image. It does this by "
  25. "analyzing the RGB values of the image where alpha == 1, and using the "
  26. "average of these values as the overall image color, which it then "
  27. "applies to the image wherever alpha == 0. When the alpha value is "
  28. "neither 1 nor 0, the pixel is ignored.\n\n"
  29. "This process is important for applications that filter the texture "
  30. "size down by averaging neighboring pixels. If the color under the "
  31. "alpha == 0 pixels is very different from the color elsewhere, this "
  32. "kind of filtering can have a visible effect on the image's color, even "
  33. "where alpha != 0.");
  34. add_option
  35. ("alpha", "filename", 0,
  36. "Specifies a separate filename that will be used in lieu of the "
  37. "alpha channel on the source image. If this file has an alpha "
  38. "channel, that alpha channel is used; otherwise, the grayscale "
  39. "value of the image is used.",
  40. &ImageFixHiddenColor::dispatch_filename, nullptr, &_alpha_filename);
  41. add_option
  42. ("opaque", "alpha", 0,
  43. "Specifies the minimum alpha value (in the range of 0 to 1) for a "
  44. "pixel to be considered fully opaque. The default is 1.",
  45. &ImageFixHiddenColor::dispatch_double, nullptr, &_min_opaque_alpha);
  46. add_option
  47. ("transparent", "alpha", 0,
  48. "Specifies the maximum alpha value (in the range of 0 to 1) for a "
  49. "pixel to be considered fully transparent. The default is 0.",
  50. &ImageFixHiddenColor::dispatch_double, nullptr, &_max_transparent_alpha);
  51. _min_opaque_alpha = 1.0;
  52. _max_transparent_alpha = 0.0;
  53. }
  54. /**
  55. *
  56. */
  57. void ImageFixHiddenColor::
  58. run() {
  59. PNMImage alpha_image;
  60. if (_alpha_filename.empty()) {
  61. // No separate alpha file is provided; use the base file's alpha channel.
  62. if (!_image.has_alpha()) {
  63. nout << "Image does not have an alpha channel.\n";
  64. exit(1);
  65. }
  66. alpha_image = _image;
  67. } else {
  68. // In this case, the alpha channel is in a separate file.
  69. if (!alpha_image.read(_alpha_filename)) {
  70. nout << "Unable to read " << _alpha_filename << ".\n";
  71. exit(1);
  72. }
  73. if (!alpha_image.has_alpha()) {
  74. // Copy the grayscale value to the alpha channel for the benefit of the
  75. // code below.
  76. alpha_image.add_alpha();
  77. int xi, yi;
  78. for (yi = 0; yi < alpha_image.get_y_size(); ++yi) {
  79. for (xi = 0; xi < alpha_image.get_x_size(); ++xi) {
  80. alpha_image.set_alpha(xi, yi, alpha_image.get_gray(xi, yi));
  81. }
  82. }
  83. }
  84. // Make sure the alpha image matches the size of the source image.
  85. if (alpha_image.get_x_size() != _image.get_x_size() ||
  86. alpha_image.get_y_size() != _image.get_y_size()) {
  87. PNMImage scaled(_image.get_x_size(), _image.get_y_size(), alpha_image.get_num_channels());
  88. scaled.quick_filter_from(alpha_image);
  89. alpha_image = scaled;
  90. }
  91. }
  92. // First, get the average color of all the opaque pixels.
  93. int count = 0;
  94. LRGBColor color(0.0, 0.0, 0.0);
  95. int xi, yi;
  96. for (yi = 0; yi < _image.get_y_size(); ++yi) {
  97. for (xi = 0; xi < _image.get_x_size(); ++xi) {
  98. if (alpha_image.get_alpha(xi, yi) >= _min_opaque_alpha) {
  99. color += _image.get_xel(xi, yi);
  100. ++count;
  101. }
  102. }
  103. }
  104. if (count == 0) {
  105. nout << "Image has no opaque pixels.\n";
  106. exit(1);
  107. }
  108. color /= (double)count;
  109. nout << " average color of " << count << " opaque pixels is " << color << "\n";
  110. // Now, apply that wherever there are transparent pixels.
  111. count = 0;
  112. for (yi = 0; yi < _image.get_y_size(); ++yi) {
  113. for (xi = 0; xi < _image.get_x_size(); ++xi) {
  114. if (alpha_image.get_alpha(xi, yi) <= _max_transparent_alpha) {
  115. _image.set_xel(xi, yi, color);
  116. ++count;
  117. }
  118. }
  119. }
  120. if (count == 0) {
  121. nout << "Image has no transparent pixels.\n";
  122. exit(1);
  123. }
  124. nout << " applied to " << count << " transparent pixels.\n";
  125. write_image(_image);
  126. }
  127. int main(int argc, char *argv[]) {
  128. ImageFixHiddenColor prog;
  129. prog.parse_command_line(argc, argv);
  130. prog.run();
  131. return 0;
  132. }