Shinya Kitaoka 120a6e
#include <cmath>     // pow(-)</cmath>
Toshihiro Shimizu 890ddd
#include <stdexcept> /* std::domain_error(-) */</stdexcept>
Shinya Kitaoka 120a6e
#include <limits>    // std::numeric_limits</limits>
Toshihiro Shimizu 890ddd
#include <vector></vector>
Toshihiro Shimizu 890ddd
#include "igs_ifx_common.h" /* igs::image::rgba */
Toshihiro Shimizu 890ddd
#include "igs_level_auto_in_camera.h"
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Shinya Kitaoka 120a6e
namespace {
Shinya Kitaoka 120a6e
double level_value_(double value, double mul_max, bool act_sw, double in_min,
Shinya Kitaoka 120a6e
                    double in_max, double out_min, double out_max,
Shinya Kitaoka 120a6e
                    double gamma) {
Shinya Kitaoka 120a6e
  if (act_sw) {
Shinya Kitaoka 120a6e
    if (in_max == in_min) {
Shinya Kitaoka 120a6e
      value = in_max;
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      /* 制限(in_min〜in_max) */
Shinya Kitaoka 120a6e
      if (in_min < in_max) {
Shinya Kitaoka 120a6e
        if (value < in_min) {
Shinya Kitaoka 120a6e
          value = in_min;
Shinya Kitaoka 120a6e
        } else if (in_max < value) {
Shinya Kitaoka 120a6e
          value = in_max;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      } else {
Shinya Kitaoka 120a6e
        if (value < in_max) {
Shinya Kitaoka 120a6e
          value = in_max;
Shinya Kitaoka 120a6e
        } else if (in_min < value) {
Shinya Kitaoka 120a6e
          value = in_min;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      /* 正規化(0〜1) */
Shinya Kitaoka 120a6e
      value = (value - in_min) / (in_max - in_min);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      /* Gamma変換 */
Shinya Kitaoka 120a6e
      if ((1.0 != gamma) && (0.0 != gamma)) {
Shinya Kitaoka 120a6e
        value = pow(value, 1.0 / gamma);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    /* Outputの範囲にスケール変換 */
Shinya Kitaoka 120a6e
    value = out_min + value * (out_max - out_min);
Shinya Kitaoka 120a6e
    /* 0...1の間で制限かける */
Shinya Kitaoka 120a6e
    if (value < 0.0) {
Shinya Kitaoka 120a6e
      value = 0.0;
Shinya Kitaoka 120a6e
    } else if (1.0 < value) {
Shinya Kitaoka 120a6e
      value = 1.0;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  /* 0〜1.0 --> 0〜mul_maxスケール変換し、整数値化 */
Shinya Kitaoka 120a6e
  return floor(value * mul_max);
Toshihiro Shimizu 890ddd
}
shun-iwasawa 481b59
shun-iwasawa 481b59
//------------------------------------------------------------
shun-iwasawa 481b59
shun-iwasawa 481b59
struct LevelAutoValueF {
shun-iwasawa 481b59
  double in_min[4];
shun-iwasawa 481b59
  double out_min[4];
shun-iwasawa 481b59
  double gamma[4];
shun-iwasawa 481b59
  double in_max_minus_in_min[4];
shun-iwasawa 481b59
  double out_max_minus_out_min[4];
shun-iwasawa 481b59
  LevelAutoValueF(const int channels, const float *_in_min,
shun-iwasawa 481b59
                  const float *_in_max, const double *_in_min_shift,
shun-iwasawa 481b59
                  const double *_in_max_shift, const double *_out_min,
shun-iwasawa 481b59
                  const double *_out_max, const double *_gamma) {
shun-iwasawa 481b59
    for (int c = 0; c < channels; c++) {
shun-iwasawa 481b59
      in_min[c]                = _in_min[c] + _in_min_shift[c];
shun-iwasawa 481b59
      out_min[c]               = _out_min[c];
shun-iwasawa 481b59
      gamma[c]                 = _gamma[c];
shun-iwasawa 481b59
      in_max_minus_in_min[c]   = _in_max[c] + _in_max_shift[c] - in_min[c];
shun-iwasawa 481b59
      out_max_minus_out_min[c] = _out_max[c] - _out_min[c];
shun-iwasawa 481b59
    }
shun-iwasawa 481b59
  }
shun-iwasawa 481b59
shun-iwasawa 481b59
  inline float convert(const int c, float value) {
shun-iwasawa 481b59
    if (in_max_minus_in_min[c] == 0.0) {
shun-iwasawa 481b59
      value = in_min[c];
shun-iwasawa 481b59
    } else  // normalize
shun-iwasawa 481b59
      value = (value - in_min[c]) / in_max_minus_in_min[c];
shun-iwasawa 481b59
    // gamma transform
shun-iwasawa 481b59
    if ((1.0 != gamma[c]) && (0.0 != gamma[c]) && value > 0.0)
shun-iwasawa 481b59
      value = std::pow(value, 1.0 / gamma[c]);
shun-iwasawa 481b59
    // normalize to the output range
shun-iwasawa 481b59
    value = out_min[c] + value * out_max_minus_out_min[c];
shun-iwasawa 481b59
    return value;
shun-iwasawa 481b59
  }
shun-iwasawa 481b59
};
shun-iwasawa 481b59
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Shinya Kitaoka 120a6e
void level_ctable_template_(const unsigned int channels,
Shinya Kitaoka 120a6e
                            const bool *act_sw,          // user setting
Shinya Kitaoka 120a6e
                            const int *in_min,           // image pixel value
Shinya Kitaoka 120a6e
                            const int *in_max,           // image pixel value
luz paz 6454c4
                            const double *in_min_shift,  // user setting
luz paz 6454c4
                            const double *in_max_shift,  // user setting
luz paz 6454c4
                            const double *out_min,       // user setting
luz paz 6454c4
                            const double *out_max,       // user setting
luz paz 6454c4
                            const double *gamma,         // user setting
Shinya Kitaoka 120a6e
                            const unsigned int div_num,
Shinya Kitaoka 120a6e
                            std::vector<std::vector<unsigned int="">> &table_array</std::vector<unsigned>
Shinya Kitaoka 120a6e
                            /*
Shinya Kitaoka 120a6e
                            std::vector< std::vector<t> > &table_array</t>
Shinya Kitaoka 120a6e
                     とするとvc2005mdで他プログラムとのリンク時、
Shinya Kitaoka 120a6e
                            allocatorの2重定義でエラーとなる。
Shinya Kitaoka 120a6e
                            std::vector< std::vector<unsigned int=""> >&table_array</unsigned>
Shinya Kitaoka 120a6e
                     ならOK
Shinya Kitaoka 120a6e
                     2009-01-27
Shinya Kitaoka 120a6e
                    */
shun-iwasawa 481b59
) {
Shinya Kitaoka 120a6e
  const double div_val = static_cast<double>(div_num);</double>
Shinya Kitaoka 120a6e
  const double mul_val = div_val + 0.999999;
Shinya Kitaoka 120a6e
#if defined _WIN32  // vc compile_type
Shinya Kitaoka 120a6e
  double in_min_[4], in_max_[4];
Toshihiro Shimizu 890ddd
#else
Shinya Kitaoka 120a6e
  double in_min_[channels], in_max_[channels];
Toshihiro Shimizu 890ddd
#endif
Shinya Kitaoka 120a6e
  for (unsigned int cc = 0; cc < channels; ++cc) {
Shinya Kitaoka 120a6e
    in_min_[cc] = in_min_shift[cc] + in_min[cc] / div_val;
Shinya Kitaoka 120a6e
    in_max_[cc] = in_max_shift[cc] + in_max[cc] / div_val;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  table_array.resize(channels);
Shinya Kitaoka 120a6e
  for (unsigned int cc = 0; cc < channels; ++cc) {
Shinya Kitaoka 120a6e
    table_array[cc].resize(div_num + 1);
Shinya Kitaoka 120a6e
    for (unsigned int yy = 0; yy <= div_num; ++yy) {
Shinya Kitaoka 120a6e
      table_array[cc][yy] = static_cast<unsigned int="">(</unsigned>
Shinya Kitaoka 120a6e
          level_value_(yy / div_val, mul_val, act_sw[cc], in_min_[cc],
Shinya Kitaoka 120a6e
                       in_max_[cc], out_min[cc], out_max[cc], gamma[cc]));
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
template <class t=""></class>
Shinya Kitaoka 120a6e
void change_template_(T *image_array, const int height, const int width,
Shinya Kitaoka 120a6e
                      const int channels
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
                      ,
Shinya Kitaoka 120a6e
                      const bool *act_sw, const double *in_min_shift,
Shinya Kitaoka 120a6e
                      const double *in_max_shift, const double *out_min,
Shinya Kitaoka 120a6e
                      const double *out_max, const double *gamma
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
                      ,
Shinya Kitaoka 120a6e
                      const int camera_x, const int camera_y,
Shinya Kitaoka 120a6e
                      const int camera_w, const int camera_h) {
Toshihiro Shimizu 890ddd
/* 1.まずcameraエリア内の最大値、最小値を求める */
Toshihiro Shimizu 890ddd
#if defined _WIN32
Shinya Kitaoka 120a6e
  int in_min[4], in_max[4];
Toshihiro Shimizu 890ddd
#else
Shinya Kitaoka 120a6e
  int in_min[channels], in_max[channels];
Toshihiro Shimizu 890ddd
#endif
Shinya Kitaoka 120a6e
  T *image_crnt =
Shinya Kitaoka 120a6e
      image_array + camera_y * width * channels + camera_x * channels;
Shinya Kitaoka 120a6e
  for (int zz = 0; zz < channels; ++zz) {
Shinya Kitaoka 120a6e
    in_min[zz] = in_max[zz] = image_crnt[zz];
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  T *image_xx = 0;
Shinya Kitaoka 120a6e
  for (int yy = 0; yy < camera_h; ++yy) {
Shinya Kitaoka 120a6e
    image_xx = image_crnt;
Shinya Kitaoka 120a6e
    image_crnt += width * channels;
Shinya Kitaoka 120a6e
    for (int xx = 0; xx < camera_w; ++xx) {
Shinya Kitaoka 120a6e
      for (int zz = 0; zz < channels; ++zz) {
Shinya Kitaoka 120a6e
        if (image_xx[zz] < in_min[zz]) {
Shinya Kitaoka 120a6e
          in_min[zz] = image_xx[zz];
Shinya Kitaoka 120a6e
        } else if (in_max[zz] < image_xx[zz]) {
Shinya Kitaoka 120a6e
          in_max[zz] = image_xx[zz];
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      image_xx += channels;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  /* 2.最大値、最小値から変換テーブルを求める */
Shinya Kitaoka 120a6e
  std::vector<std::vector<unsigned int="">> table_array;</std::vector<unsigned>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  level_ctable_template_(channels, act_sw, in_min, in_max, in_min_shift,
Shinya Kitaoka 120a6e
                         in_max_shift, out_min, out_max, gamma,
Shinya Kitaoka 120a6e
                         std::numeric_limits<t>::max(), table_array);</t>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  /* 3.変換テーブルを使って画像全体をlevel変換する */
Shinya Kitaoka 120a6e
  image_crnt        = image_array;
Shinya Kitaoka 120a6e
  const int pixsize = height * width;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (igs::image::rgba::siz == channels) {
Shinya Kitaoka 120a6e
    using namespace igs::image::rgba;
Shinya Kitaoka 120a6e
    for (int ii = 0; ii < pixsize; ++ii, image_crnt += channels) {
Shinya Kitaoka 120a6e
      image_crnt[red] = static_cast<t>(table_array[0][image_crnt[red]]);</t>
Shinya Kitaoka 120a6e
      image_crnt[gre] = static_cast<t>(table_array[1][image_crnt[gre]]);</t>
Shinya Kitaoka 120a6e
      image_crnt[blu] = static_cast<t>(table_array[2][image_crnt[blu]]);</t>
Shinya Kitaoka 120a6e
      image_crnt[alp] = static_cast<t>(table_array[3][image_crnt[alp]]);</t>
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else if (igs::image::rgb::siz == channels) {
Shinya Kitaoka 120a6e
    using namespace igs::image::rgb;
Shinya Kitaoka 120a6e
    for (int ii = 0; ii < pixsize; ++ii, image_crnt += channels) {
Shinya Kitaoka 120a6e
      image_crnt[red] = static_cast<t>(table_array[0][image_crnt[red]]);</t>
Shinya Kitaoka 120a6e
      image_crnt[gre] = static_cast<t>(table_array[1][image_crnt[gre]]);</t>
Shinya Kitaoka 120a6e
      image_crnt[blu] = static_cast<t>(table_array[2][image_crnt[blu]]);</t>
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else if (1 == channels) { /* grayscale */
Shinya Kitaoka 120a6e
    for (int ii = 0; ii < pixsize; ++ii, ++image_crnt) {
Shinya Kitaoka 120a6e
      image_crnt[0] = static_cast<t>(table_array[0][image_crnt[0]]);</t>
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  table_array.clear();
Toshihiro Shimizu 890ddd
}
shun-iwasawa 481b59
shun-iwasawa 481b59
//------------------------------------------------------------
shun-iwasawa 481b59
shun-iwasawa 481b59
template <>
shun-iwasawa 481b59
void change_template_<float>(float *image_array, const int height,</float>
shun-iwasawa 481b59
                             const int width, const int channels,
shun-iwasawa 481b59
                             const bool *act_sw, const double *in_min_shift,
shun-iwasawa 481b59
                             const double *in_max_shift, const double *out_min,
shun-iwasawa 481b59
                             const double *out_max, const double *gamma,
shun-iwasawa 481b59
                             const int camera_x, const int camera_y,
shun-iwasawa 481b59
                             const int camera_w, const int camera_h) {
shun-iwasawa 481b59
  /* 1.まずcameraエリア内の最大値、最小値を求める */
shun-iwasawa 481b59
#if defined _WIN32
shun-iwasawa 481b59
  float in_min[4], in_max[4];
shun-iwasawa 481b59
#else
shun-iwasawa 481b59
  float in_min[channels], in_max[channels];
shun-iwasawa 481b59
#endif
shun-iwasawa 481b59
  float *image_crnt =
shun-iwasawa 481b59
      image_array + camera_y * width * channels + camera_x * channels;
shun-iwasawa 481b59
  for (int zz = 0; zz < channels; ++zz) {
shun-iwasawa 481b59
    in_min[zz] = in_max[zz] = image_crnt[zz];
shun-iwasawa 481b59
  }
shun-iwasawa 481b59
  float *image_xx = nullptr;
shun-iwasawa 481b59
  for (int yy = 0; yy < camera_h; ++yy) {
shun-iwasawa 481b59
    image_xx = image_crnt;
shun-iwasawa 481b59
    image_crnt += width * channels;
shun-iwasawa 481b59
    for (int xx = 0; xx < camera_w; ++xx) {
shun-iwasawa 481b59
      for (int zz = 0; zz < channels; ++zz) {
shun-iwasawa 481b59
        if (image_xx[zz] < in_min[zz]) {
shun-iwasawa 481b59
          in_min[zz] = image_xx[zz];
shun-iwasawa 481b59
        } else if (in_max[zz] < image_xx[zz]) {
shun-iwasawa 481b59
          in_max[zz] = image_xx[zz];
shun-iwasawa 481b59
        }
shun-iwasawa 481b59
      }
shun-iwasawa 481b59
      image_xx += channels;
shun-iwasawa 481b59
    }
shun-iwasawa 481b59
  }
shun-iwasawa 481b59
shun-iwasawa 481b59
  /* 2.最大値、最小値から変換テーブルを求める */
shun-iwasawa 481b59
  // std::vector<std::vector<unsigned int="">> table_array;</std::vector<unsigned>
shun-iwasawa 481b59
  //
shun-iwasawa 481b59
  // level_ctable_template_(channels, act_sw, in_min, in_max, in_min_shift,
shun-iwasawa 481b59
  //   in_max_shift, out_min, out_max, gamma,
shun-iwasawa 481b59
  //   std::numeric_limits<t>::max(), table_array);</t>
shun-iwasawa 481b59
shun-iwasawa 481b59
  LevelAutoValueF converter(channels, in_min, in_max, in_min_shift,
shun-iwasawa 481b59
                            in_max_shift, out_min, out_max, gamma);
shun-iwasawa 481b59
shun-iwasawa 481b59
  /* 画像全体をlevel変換する */
shun-iwasawa 481b59
  image_crnt        = image_array;
shun-iwasawa 481b59
  const int pixsize = height * width;
shun-iwasawa 481b59
shun-iwasawa 481b59
  if (igs::image::rgba::siz == channels) {
shun-iwasawa 481b59
    using namespace igs::image::rgba;
shun-iwasawa 481b59
    for (int ii = 0; ii < pixsize; ++ii, image_crnt += channels) {
shun-iwasawa 481b59
      image_crnt[red] = converter.convert(0, image_crnt[red]);
shun-iwasawa 481b59
      image_crnt[gre] = converter.convert(1, image_crnt[gre]);
shun-iwasawa 481b59
      image_crnt[blu] = converter.convert(2, image_crnt[blu]);
shun-iwasawa 481b59
      image_crnt[alp] = converter.convert(3, image_crnt[alp]);
shun-iwasawa 481b59
    }
shun-iwasawa 481b59
  } else if (igs::image::rgb::siz == channels) {
shun-iwasawa 481b59
    using namespace igs::image::rgb;
shun-iwasawa 481b59
    for (int ii = 0; ii < pixsize; ++ii, image_crnt += channels) {
shun-iwasawa 481b59
      image_crnt[red] = converter.convert(0, image_crnt[red]);
shun-iwasawa 481b59
      image_crnt[gre] = converter.convert(1, image_crnt[gre]);
shun-iwasawa 481b59
      image_crnt[blu] = converter.convert(2, image_crnt[blu]);
shun-iwasawa 481b59
    }
shun-iwasawa 481b59
  } else if (1 == channels) { /* grayscale */
shun-iwasawa 481b59
    for (int ii = 0; ii < pixsize; ++ii, ++image_crnt) {
shun-iwasawa 481b59
      image_crnt[0] = converter.convert(0, image_crnt[0]);
shun-iwasawa 481b59
    }
shun-iwasawa 481b59
  }
Toshihiro Shimizu 890ddd
}
shun-iwasawa 481b59
}  // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void igs::level_auto_in_camera::change(
shun-iwasawa 481b59
    void *image_array, const int height, const int width, const int channels,
shun-iwasawa 481b59
    const int bits,
shun-iwasawa 481b59
    const bool *act_sw,          // channels array
shun-iwasawa 481b59
    const double *in_min_shift,  // channels array
shun-iwasawa 481b59
    const double *in_max_shift,  // channels array
shun-iwasawa 481b59
    const double *out_min,       // channels array
shun-iwasawa 481b59
    const double *out_max,       // channels array
shun-iwasawa 481b59
    const double *gamma,         // channels array
Shinya Kitaoka 120a6e
    const int camera_x, const int camera_y, const int camera_w,
Shinya Kitaoka 120a6e
    const int camera_h) {
Shinya Kitaoka 120a6e
  if ((igs::image::rgba::siz != channels) &&
Shinya Kitaoka 120a6e
      (igs::image::rgb::siz != channels) && (1 != channels) /* grayscale */
shun-iwasawa 481b59
  ) {
Shinya Kitaoka 120a6e
    throw std::domain_error("Bad channels,Not rgba/rgb/grayscale");
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (std::numeric_limits<unsigned char="">::digits == bits) {</unsigned>
Shinya Kitaoka 120a6e
    change_template_(static_cast<unsigned *="" char="">(image_array), height, width,</unsigned>
Shinya Kitaoka 120a6e
                     channels, act_sw, in_min_shift, in_max_shift, out_min,
Shinya Kitaoka 120a6e
                     out_max, gamma, camera_x, camera_y, camera_w, camera_h);
Shinya Kitaoka 120a6e
  } else if (std::numeric_limits<unsigned short="">::digits == bits) {</unsigned>
Shinya Kitaoka 120a6e
    change_template_(static_cast<unsigned *="" short="">(image_array), height, width,</unsigned>
Shinya Kitaoka 120a6e
                     channels, act_sw, in_min_shift, in_max_shift, out_min,
Shinya Kitaoka 120a6e
                     out_max, gamma, camera_x, camera_y, camera_w, camera_h);
shun-iwasawa 481b59
  } else if (std::numeric_limits<float>::digits == bits) {</float>
shun-iwasawa 481b59
    change_template_(static_cast<float *="">(image_array), height, width, channels,</float>
shun-iwasawa 481b59
                     act_sw, in_min_shift, in_max_shift, out_min, out_max,
shun-iwasawa 481b59
                     gamma, camera_x, camera_y, camera_w, camera_h);
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    throw std::domain_error("Bad bits,Not uchar/ushort");
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}