void mtbalign(const pfs::Frame& image1, const pfs::Frame& image2,
              const double quantile, const int noise, const int shift_bits,
              int &shift_x, int &shift_y)
{
    Array2D8u img1lum;
    Array2D8u img2lum;

    int median1 = getLum(image1, img1lum, quantile);
    int median2 = getLum(image2, img2lum, quantile);

    PRINT_DEBUG("align::medians, image 1: " << median1 << ", image 2: " << median2);
    getExpShift(img1lum, median1,
                img2lum, median2,
                noise, shift_bits, shift_x, shift_y);

    PRINT_DEBUG("align::done, final shift is (" << shift_x << "," << shift_y <<")");
}
	// Re-apply the changes in selection, hue, saturation and luminosity on a fresh palette
	void redraw()
	{
		pal_preview->setPalette(palette);
		pal_preview->getPalette().shift(getHue(),
		                                pal_preview->getSelectionStart(), pal_preview->getSelectionEnd());
		pal_preview->getPalette().saturate(getSat(),
		                                   pal_preview->getSelectionStart(), pal_preview->getSelectionEnd());
		pal_preview->getPalette().illuminate(getLum(),
		                                     pal_preview->getSelectionStart(), pal_preview->getSelectionEnd());
		pal_preview->draw();
	}
void UnsharpMasking::applyPtmRGB(const PyramidCoeff& redCoeff, const PyramidCoeff& greenCoeff, const PyramidCoeff& blueCoeff, const QSize* mipMapSize, const PyramidNormals& normals, const RenderingInfo& info, unsigned char* buffer)
{
	int offsetBuf = 0;
	const PTMCoefficient* redPtr = redCoeff.getLevel(info.level);
	const PTMCoefficient* greenPtr = greenCoeff.getLevel(info.level);
	const PTMCoefficient* bluePtr = blueCoeff.getLevel(info.level);
	const vcg::Point3f* normalsPtr = normals.getLevel(info.level);
    float* lumMap = new float[info.width*info.height];
	int width = mipMapSize[info.level].width();
	if (type == 0) //classic unsharp masking
	{
        float* uvMap = new float[info.width*info.height*2];
		LightMemoized lVec(info.light.X(), info.light.Y());
        
		#pragma omp parallel for schedule(static,CHUNK)
		for (int y = info.offy; y < info.offy + info.height; y++)
		{
            int offsetBuf = (y-info.offy)*info.width<<2;
			int offset = y * width + info.offx;
			int offset2 = (y - info.offy)*info.width;
			for (int x = info.offx; x < info.offx + info.width; x++)
			{
				float r = redPtr[offset].evalPoly(lVec) / 255.0;//evalPoly((int*)&(redPtr[offset][0]), info.light.X(), info.light.Y()) / 255.0;
                float g = greenPtr[offset].evalPoly(lVec) / 255.0;//evalPoly((int*)&(greenPtr[offset][0]), info.light.X(), info.light.Y()) / 255.0;
                float b = bluePtr[offset].evalPoly(lVec) / 255.0;//evalPoly((int*)&(bluePtr[offset][0]), info.light.X(), info.light.Y()) / 255.0;
				getYUV(r, g, b, lumMap[offset2], uvMap[offset2*2], uvMap[offset2*2 + 1]);
				offset++;
				offset2++;
			}
		}
		enhancedLuminance(lumMap, info.width, info.height, info.mode);
		bool flag = (info.mode == LUM_UNSHARP_MODE || info.mode == SMOOTH_MODE || info.mode == CONTRAST_MODE || info.mode == ENHANCED_MODE);
		if (flag)
		{
			#pragma omp parallel for schedule(static,CHUNK)
			for (int y = info.offy; y < info.offy + info.height; y++)
			{
				int offsetBuf = (y-info.offy)*info.width<<2;
				int offset2 =(y - info.offy)*info.width; 
				for (int x = info.offx; x < info.offx + info.width; x++)
				{
					for (int i = 0; i < 3; i++)
						buffer[offsetBuf + i] = tobyte(lumMap[offset2] * 255.0);
					buffer[offsetBuf + 3] = 255;
					offsetBuf += 4;
					offset2++;
				}
			}
		}
		else
		{
			#pragma omp parallel for schedule(static,CHUNK)
			for (int y = info.offy; y < info.offy + info.height; y++)
			{
				int offsetBuf = (y-info.offy)*info.width<<2;
				int offset2 =(y - info.offy)*info.width; 
				for (int x = info.offx; x < info.offx + info.width; x++)
				{
					float r, g, b;
					getRGB(lumMap[offset2], uvMap[offset2*2], uvMap[offset2*2 +1], r, g, b);
					buffer[offsetBuf] = tobyte(r*255);
					buffer[offsetBuf + 1] = tobyte(g*255);
					buffer[offsetBuf + 2] = tobyte(b*255);
					buffer[offsetBuf + 3] = 255;
					offsetBuf += 4;
					offset2++;
				}
			}
		}
		delete[] uvMap;
	}
	else //luminance unsharp masking
	{
        #pragma omp parallel for schedule(static,CHUNK)
		for (int y = info.offy; y < info.offy + info.height; y++)
		{
			int offset= y * width + info.offx;
			int offset2 = (y - info.offy)*info.width;
			for (int x = info.offx; x < info.offx + info.width; x++)
			{
				lumMap[offset2] = getLum(normalsPtr[offset], info.light);
				offset++;
				offset2++;
			}
		}
		enhancedLuminance(lumMap, info.width, info.height, info.mode);
		bool flag = (info.mode == LUM_UNSHARP_MODE || info.mode == SMOOTH_MODE || info.mode == CONTRAST_MODE || info.mode == ENHANCED_MODE);
		LightMemoized lVec(info.light.X(), info.light.Y());
		if (flag)
		{
			#pragma omp parallel for schedule(static,CHUNK)
			for (int y = info.offy; y < info.offy + info.height; y++)
			{
				int offsetBuf = (y-info.offy)*info.width<<2;
				int offset = y * width + info.offx;
				int offset2 = (y - info.offy)*info.width;
				for (int x = info.offx; x < info.offx + info.width; x++)
				{
					float lum = lumMap[offset2];
					for (int i = 0; i < 3; i++)
						buffer[offsetBuf + i] = tobyte(lum / 2.0 * 255.0);
					buffer[offsetBuf + 3] = 255;
					offsetBuf += 4;
					offset++;
					offset2++;
				}
			}
		}
		else
		{
			#pragma omp parallel for schedule(static,CHUNK)
			for (int y = info.offy; y < info.offy + info.height; y++)
			{
				int offsetBuf = (y-info.offy)*info.width<<2;
				int offset = y * width + info.offx;
				int offset2 = (y - info.offy)*info.width;
				for (int x = info.offx; x < info.offx + info.width; x++)
				{
					float lum = lumMap[offset2];
					buffer[offsetBuf] = tobyte(redPtr[offset].evalPoly(lVec)*lum);//evalPoly((int*)&(redPtr[offset][0]), info.light.X(), info.light.Y()) * lum);
					buffer[offsetBuf + 1] = tobyte(greenPtr[offset].evalPoly(lVec)*lum);//evalPoly((int*)&(greenPtr[offset][0]), info.light.X(), info.light.Y()) * lum);
					buffer[offsetBuf + 2] = tobyte(bluePtr[offset].evalPoly(lVec)*lum);//evalPoly((int*)&(bluePtr[offset][0]), info.light.X(), info.light.Y()) * lum);
					buffer[offsetBuf + 3] = 255;
					offsetBuf += 4;
					offset++;
					offset2++;
				}
			}
		}
	}
	delete[] lumMap;
}