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_ifx_common.h" /* igs::image::rgba */
Toshihiro Shimizu 890ddd
#include "igs_level_auto_in_camera.h"
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] = static_cast<unsigned int="">(</unsigned>
Toshihiro Shimizu 890ddd
				level_value_(
Toshihiro Shimizu 890ddd
					yy / div_val, mul_val, act_sw[cc], in_min_[cc], in_max_[cc], out_min[cc], out_max[cc], 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, const int height, const int width, const int channels
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	,
Toshihiro Shimizu 890ddd
	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
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	,
Toshihiro Shimizu 890ddd
	const int camera_x, const int camera_y, const int camera_w, const int camera_h)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
/* 1.まずcameraエリア内の最大値、最小値を求める */
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
	T *image_crnt = image_array +
Toshihiro Shimizu 890ddd
					camera_y * width * channels + camera_x * channels;
Toshihiro Shimizu 890ddd
	for (int zz = 0; zz < channels; ++zz) {
Toshihiro Shimizu 890ddd
		in_min[zz] = in_max[zz] = image_crnt[zz];
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	T *image_xx = 0;
Toshihiro Shimizu 890ddd
	for (int yy = 0; yy < camera_h; ++yy) {
Toshihiro Shimizu 890ddd
		image_xx = image_crnt;
Toshihiro Shimizu 890ddd
		image_crnt += width * channels;
Toshihiro Shimizu 890ddd
		for (int xx = 0; xx < camera_w; ++xx) {
Toshihiro Shimizu 890ddd
			for (int zz = 0; zz < channels; ++zz) {
Toshihiro Shimizu 890ddd
				if (image_xx[zz] < in_min[zz]) {
Toshihiro Shimizu 890ddd
					in_min[zz] = image_xx[zz];
Toshihiro Shimizu 890ddd
				} else if (in_max[zz] < image_xx[zz]) {
Toshihiro Shimizu 890ddd
					in_max[zz] = image_xx[zz];
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
			image_xx += 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_in_camera::change(
Toshihiro Shimizu 890ddd
	void *image_array
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	,
Toshihiro Shimizu 890ddd
	const int height, const int width, const int channels, const int bits
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	,
Toshihiro Shimizu 890ddd
	const bool *act_sw // channels array
Toshihiro Shimizu 890ddd
	,
Toshihiro Shimizu 890ddd
	const double *in_min_shift // channels array
Toshihiro Shimizu 890ddd
	,
Toshihiro Shimizu 890ddd
	const double *in_max_shift // channels array
Toshihiro Shimizu 890ddd
	,
Toshihiro Shimizu 890ddd
	const double *out_min // channels array
Toshihiro Shimizu 890ddd
	,
Toshihiro Shimizu 890ddd
	const double *out_max // channels array
Toshihiro Shimizu 890ddd
	,
Toshihiro Shimizu 890ddd
	const double *gamma // channels array
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	,
Toshihiro Shimizu 890ddd
	const int camera_x, const int camera_y, const int camera_w, const int camera_h)
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
			static_cast<unsigned *="" char="">(image_array), height, width, channels, act_sw, in_min_shift, in_max_shift, out_min, out_max, gamma, camera_x, camera_y, camera_w, camera_h);</unsigned>
Toshihiro Shimizu 890ddd
	} else if (std::numeric_limits<unsigned short="">::digits == bits) {</unsigned>
Toshihiro Shimizu 890ddd
		change_template_(
Toshihiro Shimizu 890ddd
			static_cast<unsigned *="" short="">(image_array), height, width, channels, act_sw, in_min_shift, in_max_shift, out_min, out_max, gamma, camera_x, camera_y, camera_w, camera_h);</unsigned>
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		throw std::domain_error("Bad bits,Not uchar/ushort");
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}