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