Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "trop.h"
Toshihiro Shimizu 890ddd
#include "tpixelutils.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/* NOTE: Scale operations can be performed using Look-Up-Tables.
Toshihiro Shimizu 890ddd
         This is convenient for 8-bit channels, but perhaps not for 16-bit ones:
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
            In the 32-bit case, we perform max 256 channel operations,
Toshihiro Shimizu 890ddd
            equal to performing plain scale on a 16 x 16 image.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
            In the 64-bit case, the cost is 65536 channel operations,
Toshihiro Shimizu 890ddd
            equal to performing plain scale on a 256 x 256 image.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
         The raster size is used to discriminate LUT usage in the latter case
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
namespace
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename chan=""></typename>
Toshihiro Shimizu 890ddd
void buildLUT(Chan *lut, double a, double k, int chanLow, int chanHigh)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int i, max = (std::numeric_limits<chan>::max)();</chan>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	a += 0.5; //round rather than trunc
Toshihiro Shimizu 890ddd
	for (i = 0; i <= max; ++i)
Toshihiro Shimizu 890ddd
		lut[i] = tcrop((int)(a + i * k), chanLow, chanHigh);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename t=""></typename>
Toshihiro Shimizu 890ddd
void do_greyScale_lut(TRasterPT<t> rout, TRasterPT<t> rin,</t></t>
Toshihiro Shimizu 890ddd
					  double a, double k, int out0, int out1)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(rout->getSize() == rin->getSize());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	typedef typename T::Channel Channel;
Toshihiro Shimizu 890ddd
	int chanValuesCount = T::maxChannelValue + 1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int fac = chanValuesCount / 256;
Toshihiro Shimizu 890ddd
	out0 = tmax(fac * out0, 0), out1 = tmin(fac * out1, T::maxChannelValue);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Build lut
Toshihiro Shimizu 890ddd
	Channel *lut = new Channel[chanValuesCount];
Toshihiro Shimizu 890ddd
	buildLUT(lut, a, k, out0, out1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Perform scale
Toshihiro Shimizu 890ddd
	T *in, *end, *out;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int y, lx = rin->getLx(), ly = rin->getLy();
Toshihiro Shimizu 890ddd
	for (y = 0; y < ly; ++y) {
Toshihiro Shimizu 890ddd
		in = rin->pixels(y), end = in + lx, out = rout->pixels(y);
Toshihiro Shimizu 890ddd
		for (; in < end; ++in, ++out)
Toshihiro Shimizu 890ddd
			out->value = lut[in->value];
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	delete[] lut;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename t=""></typename>
Toshihiro Shimizu 890ddd
void do_greyAdjust(TRasterPT<t> rout, TRasterPT<t> rin,</t></t>
Toshihiro Shimizu 890ddd
				   const int in0, const int in1, const int out0, const int out1)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	typedef typename T::Channel Channel;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	assert(rout->getSize() == rin->getSize());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Build scale parameters
Toshihiro Shimizu 890ddd
	double k = (out1 - out0) / (double)(in1 - in0);
Toshihiro Shimizu 890ddd
	double a = out0 - k * in0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	do_greyScale_lut(rout, rin, a, k, out0, out1);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename t=""></typename>
Toshihiro Shimizu 890ddd
void do_rgbmScale_lut(TRasterPT<t> rout, TRasterPT<t> rin,</t></t>
Toshihiro Shimizu 890ddd
					  const double *a, const double *k,
Toshihiro Shimizu 890ddd
					  const int *out0, const int *out1)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(rout->getSize() == rin->getSize());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	typedef typename T::Channel Channel;
Toshihiro Shimizu 890ddd
	int m, max = T::maxChannelValue, chanValuesCount = max + 1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int fac = chanValuesCount / 256;
Toshihiro Shimizu 890ddd
	int out0R = tmax(fac * out0[0], 0), out1R = tmin(fac * out1[0], T::maxChannelValue);
Toshihiro Shimizu 890ddd
	int out0G = tmax(fac * out0[1], 0), out1G = tmin(fac * out1[1], T::maxChannelValue);
Toshihiro Shimizu 890ddd
	int out0B = tmax(fac * out0[2], 0), out1B = tmin(fac * out1[2], T::maxChannelValue);
Toshihiro Shimizu 890ddd
	int out0M = tmax(fac * out0[3], 0), out1M = tmin(fac * out1[3], T::maxChannelValue);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Build luts
Toshihiro Shimizu 890ddd
	Channel *lut_r = new Channel[chanValuesCount];
Toshihiro Shimizu 890ddd
	buildLUT(lut_r, a[0], k[0], out0R, out1R);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	Channel *lut_g = new Channel[chanValuesCount];
Toshihiro Shimizu 890ddd
	buildLUT(lut_g, a[1], k[1], out0G, out1G);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	Channel *lut_b = new Channel[chanValuesCount];
Toshihiro Shimizu 890ddd
	buildLUT(lut_b, a[2], k[2], out0B, out1B);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	Channel *lut_m = new Channel[chanValuesCount];
Toshihiro Shimizu 890ddd
	buildLUT(lut_m, a[3], k[3], out0M, out1M);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Retrieve de/premultiplication luts
Toshihiro Shimizu 890ddd
	const double *lut_prem = premultiplyTable<channel>();</channel>
Toshihiro Shimizu 890ddd
	const double *lut_deprem = depremultiplyTable<channel>();</channel>
Toshihiro Shimizu 890ddd
	double premFac, depremFac;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Process raster
Toshihiro Shimizu 890ddd
	int y, lx = rin->getLx(), ly = rin->getLy();
Toshihiro Shimizu 890ddd
	T *in, *end, *out;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (y = 0; y < ly; ++y) {
Toshihiro Shimizu 890ddd
		in = rin->pixels(y), end = in + lx, out = rout->pixels(y);
Toshihiro Shimizu 890ddd
		for (; in < end; ++in, ++out) {
Toshihiro Shimizu 890ddd
			m = lut_m[in->m];
Toshihiro Shimizu 890ddd
			depremFac = lut_deprem[in->m];
Toshihiro Shimizu 890ddd
			premFac = lut_prem[m];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			out->r = premFac * lut_r[tmin((int)(in->r * depremFac), max)];
Toshihiro Shimizu 890ddd
			out->g = premFac * lut_g[tmin((int)(in->g * depremFac), max)];
Toshihiro Shimizu 890ddd
			out->b = premFac * lut_b[tmin((int)(in->b * depremFac), max)];
Toshihiro Shimizu 890ddd
			out->m = m;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	delete[] lut_r;
Toshihiro Shimizu 890ddd
	delete[] lut_g;
Toshihiro Shimizu 890ddd
	delete[] lut_b;
Toshihiro Shimizu 890ddd
	delete[] lut_m;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename t=""></typename>
Toshihiro Shimizu 890ddd
void do_rgbmScale(TRasterPT<t> rout, TRasterPT<t> rin,</t></t>
Toshihiro Shimizu 890ddd
				  const double *a, const double *k,
Toshihiro Shimizu 890ddd
				  const int *out0, const int *out1)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(rout->getSize() == rin->getSize());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	typedef typename T::Channel Channel;
Toshihiro Shimizu 890ddd
	int m, chanValuesCount = T::maxChannelValue + 1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int fac = chanValuesCount / 256;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int out0R = tmax(fac * out0[0], 0), out1R = tmin(fac * out1[0], T::maxChannelValue);
Toshihiro Shimizu 890ddd
	int out0G = tmax(fac * out0[1], 0), out1G = tmin(fac * out1[1], T::maxChannelValue);
Toshihiro Shimizu 890ddd
	int out0B = tmax(fac * out0[2], 0), out1B = tmin(fac * out1[2], T::maxChannelValue);
Toshihiro Shimizu 890ddd
	int out0M = tmax(fac * out0[3], 0), out1M = tmin(fac * out1[3], T::maxChannelValue);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Retrieve de/premultiplication luts
Toshihiro Shimizu 890ddd
	const double *lut_prem = premultiplyTable<channel>();</channel>
Toshihiro Shimizu 890ddd
	const double *lut_deprem = depremultiplyTable<channel>();</channel>
Toshihiro Shimizu 890ddd
	double premFac, depremFac;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Process raster
Toshihiro Shimizu 890ddd
	int y, lx = rin->getLx(), ly = rin->getLy();
Toshihiro Shimizu 890ddd
	T *in, *end, *out;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (y = 0; y < ly; ++y) {
Toshihiro Shimizu 890ddd
		in = rin->pixels(y), end = in + lx, out = rout->pixels(y);
Toshihiro Shimizu 890ddd
		for (; in < end; ++in, ++out) {
Toshihiro Shimizu 890ddd
			m = tcrop((int)(a[3] + k[3] * in->m), out0M, out1M);
Toshihiro Shimizu 890ddd
			depremFac = lut_deprem[in->m];
Toshihiro Shimizu 890ddd
			premFac = lut_prem[m];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			out->r = premFac * tcrop((int)(a[0] + k[0] * in->r * depremFac), out0R, out1R);
Toshihiro Shimizu 890ddd
			out->g = premFac * tcrop((int)(a[1] + k[1] * in->g * depremFac), out0G, out1G);
Toshihiro Shimizu 890ddd
			out->b = premFac * tcrop((int)(a[2] + k[2] * in->b * depremFac), out0B, out1B);
Toshihiro Shimizu 890ddd
			out->m = m;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename scalefunc="" t,="" typename=""></typename>
Toshihiro Shimizu 890ddd
void do_rgbmAdjust(TRasterPT<t> rout, TRasterPT<t> rin, ScaleFunc scaleFunc,</t></t>
Toshihiro Shimizu 890ddd
				   const int *in0, const int *in1, const int *out0, const int *out1)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(rout->getSize() == rin->getSize());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double a[5], k[5];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Build scale parameters
Toshihiro Shimizu 890ddd
	int i;
Toshihiro Shimizu 890ddd
	for (i = 0; i < 5; ++i) {
Toshihiro Shimizu 890ddd
		k[i] = (out1[i] - out0[i]) / (double)(in1[i] - in0[i]);
Toshihiro Shimizu 890ddd
		a[i] = out0[i] - k[i] * in0[i];
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	for (i = 1; i < 4; ++i) {
Toshihiro Shimizu 890ddd
		a[i] += k[i] * a[0];
Toshihiro Shimizu 890ddd
		k[i] *= k[0];
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Ensure that the output is cropped according to output params
Toshihiro Shimizu 890ddd
	int out0i[4], out1i[4];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	out0i[0] = tmax(out0[0], tcrop((int)(a[0] + k[0] * out0[1]), 0, 255));
Toshihiro Shimizu 890ddd
	out1i[0] = tmin(out1[0], tcrop((int)(a[0] + k[0] * out1[1]), 0, 255));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	out0i[1] = tmax(out0[0], tcrop((int)(a[0] + k[0] * out0[2]), 0, 255));
Toshihiro Shimizu 890ddd
	out1i[1] = tmin(out1[0], tcrop((int)(a[0] + k[0] * out1[2]), 0, 255));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	out0i[2] = tmax(out0[0], tcrop((int)(a[0] + k[0] * out0[3]), 0, 255));
Toshihiro Shimizu 890ddd
	out1i[2] = tmin(out1[0], tcrop((int)(a[0] + k[0] * out1[3]), 0, 255));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	out0i[3] = out0[4];
Toshihiro Shimizu 890ddd
	out1i[3] = out1[4];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	scaleFunc(rout, rin, &a[1], &k[1], out0i, out1i);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
} //namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void TRop::rgbmScale(TRasterP rout, TRasterP rin,
Toshihiro Shimizu 890ddd
					 const double *k, const double *a, const int *out0, const int *out1)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (rout->getSize() != rin->getSize())
Toshihiro Shimizu 890ddd
		throw TRopException("size mismatch");
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	rout->lock();
Toshihiro Shimizu 890ddd
	rin->lock();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if ((TRaster32P)rout && (TRaster32P)rin)
Toshihiro Shimizu 890ddd
		do_rgbmScale_lut<tpixel32>(rout, rin, a, k, out0, out1);</tpixel32>
Toshihiro Shimizu 890ddd
	else if ((TRaster64P)rout && (TRaster64P)rin) {
Toshihiro Shimizu 890ddd
		if (rin->getLx() * rin->getLy() < TPixel64::maxChannelValue)
Toshihiro Shimizu 890ddd
			do_rgbmScale<tpixel64>(rout, rin, a, k, out0, out1);</tpixel64>
Toshihiro Shimizu 890ddd
		else
Toshihiro Shimizu 890ddd
			do_rgbmScale_lut<tpixel64>(rout, rin, a, k, out0, out1);</tpixel64>
Toshihiro Shimizu 890ddd
	} else if ((TRasterGR8P)rout && (TRasterGR8P)rin)
Toshihiro Shimizu 890ddd
		do_greyScale_lut<tpixelgr8>(rout, rin, a[0], k[0], out0[0], out1[0]);</tpixelgr8>
Toshihiro Shimizu 890ddd
	else if ((TRasterGR16P)rout && (TRasterGR16P)rin)
Toshihiro Shimizu 890ddd
		do_greyScale_lut<tpixelgr16>(rout, rin, a[0], k[0], out0[0], out1[0]);</tpixelgr16>
Toshihiro Shimizu 890ddd
	else {
Toshihiro Shimizu 890ddd
		rout->unlock();
Toshihiro Shimizu 890ddd
		rin->unlock();
Toshihiro Shimizu 890ddd
		throw TRopException("pixel type mismatch");
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	rout->unlock();
Toshihiro Shimizu 890ddd
	rin->unlock();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void TRop::rgbmScale(TRasterP rout, TRasterP rin,
Toshihiro Shimizu 890ddd
					 double kr, double kg, double kb, double km,
Toshihiro Shimizu 890ddd
					 double ar, double ag, double ab, double am)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	double k[4], a[4];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	a[0] = ar, a[1] = ag, a[2] = ab, a[3] = am;
Toshihiro Shimizu 890ddd
	k[0] = kr, k[1] = kg, k[2] = kb, k[3] = km;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int out0[4], out1[4];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	out0[0] = out0[1] = out0[2] = out0[3] = 0;
Toshihiro Shimizu 890ddd
	out1[0] = out1[1] = out1[2] = out1[3] = 255;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	rgbmScale(rout, rin, k, a, out0, out1);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void TRop::rgbmAdjust(TRasterP rout, TRasterP rin,
Toshihiro Shimizu 890ddd
					  const int *in0, const int *in1, const int *out0, const int *out1)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (rout->getSize() != rin->getSize())
Toshihiro Shimizu 890ddd
		throw TRopException("size mismatch");
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	rout->lock();
Toshihiro Shimizu 890ddd
	rin->lock();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if ((TRaster32P)rout && (TRaster32P)rin)
Toshihiro Shimizu 890ddd
		do_rgbmAdjust<tpixel32>(rout, rin, &do_rgbmScale_lut<tpixel32>, in0, in1, out0, out1);</tpixel32></tpixel32>
Toshihiro Shimizu 890ddd
	else if ((TRaster64P)rout && (TRaster64P)rin) {
Toshihiro Shimizu 890ddd
		if (rin->getLx() * rin->getLy() < TPixel64::maxChannelValue)
Toshihiro Shimizu 890ddd
			do_rgbmAdjust<tpixel64>(rout, rin, &do_rgbmScale<tpixel64>, in0, in1, out0, out1);</tpixel64></tpixel64>
Toshihiro Shimizu 890ddd
		else
Toshihiro Shimizu 890ddd
			do_rgbmAdjust<tpixel64>(rout, rin, &do_rgbmScale_lut<tpixel64>, in0, in1, out0, out1);</tpixel64></tpixel64>
Toshihiro Shimizu 890ddd
	} else if ((TRasterGR8P)rout && (TRasterGR8P)rin)
Toshihiro Shimizu 890ddd
		do_greyAdjust<tpixelgr8>(rout, rin, in0[0], in1[0], out0[0], out1[0]);</tpixelgr8>
Toshihiro Shimizu 890ddd
	else if ((TRasterGR16P)rout && (TRasterGR16P)rin)
Toshihiro Shimizu 890ddd
		do_greyAdjust<tpixelgr16>(rout, rin, in0[0], in1[0], out0[0], out1[0]);</tpixelgr16>
Toshihiro Shimizu 890ddd
	else {
Toshihiro Shimizu 890ddd
		rout->unlock();
Toshihiro Shimizu 890ddd
		rin->unlock();
Toshihiro Shimizu 890ddd
		throw TRopException("pixel type mismatch");
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	rout->unlock();
Toshihiro Shimizu 890ddd
	rin->unlock();
Toshihiro Shimizu 890ddd
}