#include // pow(-) #include /* std::domain_error(-) */ #include // std::numeric_limits #include #include "igs_level_auto.h" #include "igs_ifx_common.h" /* igs::image::rgba */ //------------------------------------------------------------ namespace { double level_value_(double value, double mul_max, bool act_sw, double in_min, double in_max, double out_min, double out_max, double gamma) { if (act_sw) { if (in_max == in_min) { value = in_max; } else { /* 制限(in_min〜in_max) */ if (in_min < in_max) { if (value < in_min) { value = in_min; } else if (in_max < value) { value = in_max; } } else { if (value < in_max) { value = in_max; } else if (in_min < value) { value = in_min; } } /* 正規化(0〜1) */ value = (value - in_min) / (in_max - in_min); /* Gamma変換 */ if ((1.0 != gamma) && (0.0 != gamma)) { value = pow(value, 1.0 / gamma); } } /* Outputの範囲にスケール変換 */ value = out_min + value * (out_max - out_min); /* 0...1の間で制限かける */ if (value < 0.0) { value = 0.0; } else if (1.0 < value) { value = 1.0; } } /* 0〜1.0 --> 0〜mul_maxスケール変換し、整数値化 */ return floor(value * mul_max); } //------------------------------------------------------------ void level_ctable_template_(const unsigned int channels, const bool *act_sw, // user setting const int *in_min, // image pixel value const int *in_max, // image pixel value const double *in_min_shift, // user setting const double *in_max_shift, // user setting const double *out_min, // user setting const double *out_max, // user setting const double *gamma, // user setting const unsigned int div_num, std::vector> &table_array /* std::vector< std::vector > &table_array とするとvc2005mdで他プログラムとのリンク時、 allocatorの2重定義でエラーとなる。 std::vector< std::vector >&table_array ならOK 2009-01-27 */ ) { const double div_val = static_cast(div_num); const double mul_val = div_val + 0.999999; #if defined _WIN32 // vc compile_type double in_min_[4], in_max_[4]; #else double in_min_[channels], in_max_[channels]; #endif for (unsigned int cc = 0; cc < channels; ++cc) { in_min_[cc] = in_min_shift[cc] + in_min[cc] / div_val; in_max_[cc] = in_max_shift[cc] + in_max[cc] / div_val; } table_array.resize(channels); for (unsigned int cc = 0; cc < channels; ++cc) { table_array[cc].resize(div_num + 1); for (unsigned int yy = 0; yy <= div_num; ++yy) { table_array[cc][yy] = static_cast( level_value_(yy / div_val, mul_val, act_sw[cc], in_min_[cc], in_max_[cc], out_min[cc], out_max[cc], gamma[cc])); } } } //------------------------------------------------------------ template void change_template_(T *image_array, const int height, const int width, const int channels, const bool *act_sw, const double *in_min_shift, const double *in_max_shift, const double *out_min, const double *out_max, const double *gamma) { /* 1.まず最大値、最小値を求める */ #if defined _WIN32 int in_min[4], in_max[4]; #else int in_min[channels], in_max[channels]; #endif for (int zz = 0; zz < channels; ++zz) { in_min[zz] = in_max[zz] = image_array[zz]; } T *image_crnt = image_array; for (int yy = 0; yy < height; ++yy) { for (int xx = 0; xx < width; ++xx) { for (int zz = 0; zz < channels; ++zz) { if (image_crnt[zz] < in_min[zz]) { in_min[zz] = image_crnt[zz]; } else if (in_max[zz] < image_crnt[zz]) { in_max[zz] = image_crnt[zz]; } } image_crnt += channels; } } /* 2.最大値、最小値から変換テーブルを求める */ std::vector> table_array; level_ctable_template_(channels, act_sw, in_min, in_max, in_min_shift, in_max_shift, out_min, out_max, gamma, std::numeric_limits::max(), table_array); /* 3.変換テーブルを使ってlevel変換する */ image_crnt = image_array; const int pixsize = height * width; if (igs::image::rgba::siz == channels) { using namespace igs::image::rgba; for (int ii = 0; ii < pixsize; ++ii, image_crnt += channels) { image_crnt[red] = static_cast(table_array[0][image_crnt[red]]); image_crnt[gre] = static_cast(table_array[1][image_crnt[gre]]); image_crnt[blu] = static_cast(table_array[2][image_crnt[blu]]); image_crnt[alp] = static_cast(table_array[3][image_crnt[alp]]); } } else if (igs::image::rgb::siz == channels) { using namespace igs::image::rgb; for (int ii = 0; ii < pixsize; ++ii, image_crnt += channels) { image_crnt[red] = static_cast(table_array[0][image_crnt[red]]); image_crnt[gre] = static_cast(table_array[1][image_crnt[gre]]); image_crnt[blu] = static_cast(table_array[2][image_crnt[blu]]); } } else if (1 == channels) { /* grayscale */ for (int ii = 0; ii < pixsize; ++ii, ++image_crnt) { image_crnt[0] = static_cast(table_array[0][image_crnt[0]]); } } table_array.clear(); } } void igs::level_auto::change(unsigned char *image_array, const int height, const int width, const int channels, const int bits, const bool *act_sw, // channels array const double *in_min_shift, // channels array const double *in_max_shift, // channels array const double *out_min, // channels array const double *out_max, // channels array const double *gamma // channels array ) { if ((igs::image::rgba::siz != channels) && (igs::image::rgb::siz != channels) && (1 != channels) /* grayscale */ ) { throw std::domain_error("Bad channels,Not rgba/rgb/grayscale"); } if (std::numeric_limits::digits == bits) { change_template_(image_array, height, width, channels, act_sw, in_min_shift, in_max_shift, out_min, out_max, gamma); } else if (std::numeric_limits::digits == bits) { change_template_(reinterpret_cast(image_array), height, width, channels, act_sw, in_min_shift, in_max_shift, out_min, out_max, gamma); } else { throw std::domain_error("Bad bits,Not uchar/ushort"); } }