www.pudn.com > CXIMAGE_SRC.ZIP > ximadsp.cpp


// xImaDsp.cpp : DSP functions 
/* 07/08/2001 v1.00 - ing.davide.pizzolato@libero.it 
 * CxImage version 5.00 23/Aug/2002 
 */ 
 
#include "ximage.h" 
 
#if CXIMAGE_SUPPORT_DSP 
 
//////////////////////////////////////////////////////////////////////////////// 
bool CxImage::Threshold(BYTE level) 
{ 
	if (!pDib) return false; 
	if (head.biBitCount == 1) return true; 
 
	GrayScale(); 
 
	CxImage tmp(head.biWidth,head.biHeight,1); 
 
	for (long y=0;ylevel) 
				tmp.SetPixelIndex(x,y,1); 
			else 
				tmp.SetPixelIndex(x,y,0); 
		} 
	} 
	tmp.SetPaletteIndex(0,0,0,0); 
	tmp.SetPaletteIndex(1,255,255,255); 
	Transfer(tmp); 
	return true; 
} 
//////////////////////////////////////////////////////////////////////////////// 
bool CxImage::SplitRGB(CxImage* r,CxImage* g,CxImage* b) 
{ 
	if (!pDib) return false; 
	if (r==NULL && g==NULL && b==NULL) return false; 
 
	CxImage tmpr(head.biWidth,head.biHeight,8); 
	CxImage tmpg(head.biWidth,head.biHeight,8); 
	CxImage tmpb(head.biWidth,head.biHeight,8); 
 
	RGBQUAD color; 
	for(long y=0; yTransfer(tmpr); 
	if (g) g->Transfer(tmpg); 
	if (b) b->Transfer(tmpb); 
 
	return true; 
} 
//////////////////////////////////////////////////////////////////////////////// 
bool CxImage::SplitYUV(CxImage* y,CxImage* u,CxImage* v) 
{ 
	if (!pDib) return false; 
	if (y==NULL && u==NULL && v==NULL) return false; 
 
	CxImage tmpy(head.biWidth,head.biHeight,8); 
	CxImage tmpu(head.biWidth,head.biHeight,8); 
	CxImage tmpv(head.biWidth,head.biHeight,8); 
 
	RGBQUAD color; 
	for(long yy=0; yyTransfer(tmpy); 
	if (u) u->Transfer(tmpu); 
	if (v) v->Transfer(tmpv); 
 
	return true; 
} 
//////////////////////////////////////////////////////////////////////////////// 
bool CxImage::SplitYIQ(CxImage* y,CxImage* i,CxImage* q) 
{ 
	if (!pDib) return false; 
	if (y==NULL && i==NULL && q==NULL) return false; 
 
	CxImage tmpy(head.biWidth,head.biHeight,8); 
	CxImage tmpi(head.biWidth,head.biHeight,8); 
	CxImage tmpq(head.biWidth,head.biHeight,8); 
 
	RGBQUAD color; 
	for(long yy=0; yyTransfer(tmpy); 
	if (i) i->Transfer(tmpi); 
	if (q) q->Transfer(tmpq); 
 
	return true; 
} 
//////////////////////////////////////////////////////////////////////////////// 
bool CxImage::SplitXYZ(CxImage* x,CxImage* y,CxImage* z) 
{ 
	if (!pDib) return false; 
	if (x==NULL && y==NULL && z==NULL) return false; 
 
	CxImage tmpx(head.biWidth,head.biHeight,8); 
	CxImage tmpy(head.biWidth,head.biHeight,8); 
	CxImage tmpz(head.biWidth,head.biHeight,8); 
 
	RGBQUAD color; 
	for(long yy=0; yyTransfer(tmpx); 
	if (y) y->Transfer(tmpy); 
	if (z) z->Transfer(tmpz); 
 
	return true; 
}//////////////////////////////////////////////////////////////////////////////// 
bool CxImage::SplitHSL(CxImage* h,CxImage* s,CxImage* l) 
{ 
	if (!pDib) return false; 
	if (h==NULL && s==NULL && l==NULL) return false; 
 
	CxImage tmph(head.biWidth,head.biHeight,8); 
	CxImage tmps(head.biWidth,head.biHeight,8); 
	CxImage tmpl(head.biWidth,head.biHeight,8); 
 
	RGBQUAD color; 
	for(long y=0; yTransfer(tmph); 
	if (s) s->Transfer(tmps); 
	if (l) l->Transfer(tmpl); 
 
	return true; 
} 
//////////////////////////////////////////////////////////////////////////////// 
#define  HSLMAX   255	/* H,L, and S vary over 0-HSLMAX */ 
#define  RGBMAX   255   /* R,G, and B vary over 0-RGBMAX */ 
                        /* HSLMAX BEST IF DIVISIBLE BY 6 */ 
                        /* RGBMAX, HSLMAX must each fit in a BYTE. */ 
/* Hue is undefined if Saturation is 0 (grey-scale) */ 
/* This value determines where the Hue scrollbar is */ 
/* initially set for achromatic colors */ 
#define UNDEFINED (HSLMAX*2/3) 
//////////////////////////////////////////////////////////////////////////////// 
RGBQUAD CxImage::RGBtoHSL(RGBQUAD lRGBColor) 
{ 
	BYTE R,G,B;					/* input RGB values */ 
	BYTE H,L,S;					/* output HSL values */ 
	BYTE cMax,cMin;				/* max and min RGB values */ 
	WORD Rdelta,Gdelta,Bdelta;	/* intermediate value: % of spread from max*/ 
 
	R = lRGBColor.rgbRed;	/* get R, G, and B out of DWORD */ 
	G = lRGBColor.rgbGreen; 
	B = lRGBColor.rgbBlue; 
 
	cMax = max( max(R,G), B);	/* calculate lightness */ 
	cMin = min( min(R,G), B); 
	L = (BYTE)((((cMax+cMin)*HSLMAX)+RGBMAX)/(2*RGBMAX)); 
 
	if (cMax==cMin){			/* r=g=b --> achromatic case */ 
		S = 0;					/* saturation */ 
		H = UNDEFINED;			/* hue */ 
	} else {					/* chromatic case */ 
		if (L <= (HSLMAX/2))	/* saturation */ 
			S = (BYTE)((((cMax-cMin)*HSLMAX)+((cMax+cMin)/2))/(cMax+cMin)); 
		else 
			S = (BYTE)((((cMax-cMin)*HSLMAX)+((2*RGBMAX-cMax-cMin)/2))/(2*RGBMAX-cMax-cMin)); 
		/* hue */ 
		Rdelta = (WORD)((((cMax-R)*(HSLMAX/6)) + ((cMax-cMin)/2) ) / (cMax-cMin)); 
		Gdelta = (WORD)((((cMax-G)*(HSLMAX/6)) + ((cMax-cMin)/2) ) / (cMax-cMin)); 
		Bdelta = (WORD)((((cMax-B)*(HSLMAX/6)) + ((cMax-cMin)/2) ) / (cMax-cMin)); 
 
		if (R == cMax) 
			H = (BYTE)(Bdelta - Gdelta); 
		else if (G == cMax) 
			H = (BYTE)((HSLMAX/3) + Rdelta - Bdelta); 
		else /* B == cMax */ 
			H = (BYTE)(((2*HSLMAX)/3) + Gdelta - Rdelta); 
 
//		if (H < 0) H += HSLMAX;     //always false 
		if (H > HSLMAX) H -= HSLMAX; 
	} 
	RGBQUAD hsl={L,S,H,0}; 
	return hsl; 
} 
//////////////////////////////////////////////////////////////////////////////// 
float CxImage::HueToRGB(float n1,float n2, float hue) 
{ 
	// fixed implementation for HSL2RGB routine 
	float rValue; 
 
	if (hue > 360) 
		hue = hue - 360; 
	else if (hue < 0) 
		hue = hue + 360; 
 
	if (hue < 60) 
		rValue = n1 + (n2-n1)*hue/60.0f; 
	else if (hue < 180) 
		rValue = n2; 
	else if (hue < 240) 
		rValue = n1+(n2-n1)*(240-hue)/60; 
	else 
		rValue = n1; 
 
	return rValue; 
} 
//////////////////////////////////////////////////////////////////////////////// 
RGBQUAD CxImage::HSLtoRGB(COLORREF cHSLColor) 
{ 
	return HSLtoRGB(RGBtoRGBQUAD(cHSLColor)); 
} 
//////////////////////////////////////////////////////////////////////////////// 
RGBQUAD CxImage::HSLtoRGB(RGBQUAD lHSLColor) 
{  
	// fixed implementation for HSL2RGB routine 
	float h,s,l; 
	float m1,m2; 
	BYTE r,g,b; 
 
	h = (float)lHSLColor.rgbRed * 360.0f/255.0f; 
	s = (float)lHSLColor.rgbGreen/255.0f; 
	l = (float)lHSLColor.rgbBlue/255.0f; 
 
	if (l <= 0.5)	m2 = l * (1+s); 
	else			m2 = l + s - l*s; 
 
	m1 = 2 * l - m2; 
 
	if (s == 0) { 
		r=g=b=(BYTE)(l*255.0f); 
	} else { 
		r = (BYTE)(HueToRGB(m1,m2,h+120) * 255.0f); 
		g = (BYTE)(HueToRGB(m1,m2,h) * 255.0f); 
		b = (BYTE)(HueToRGB(m1,m2,h-120) * 255.0f); 
	} 
 
	RGBQUAD rgb = {b,g,r,0}; 
	return rgb; 
} 
//////////////////////////////////////////////////////////////////////////////// 
RGBQUAD CxImage::YUVtoRGB(RGBQUAD lYUVColor) 
{ 
	int Y,U,V,R,G,B; 
	Y = lYUVColor.rgbRed; 
	U = lYUVColor.rgbGreen - 128; 
	V = lYUVColor.rgbBlue - 128; 
 
//	R = (int)(1.164 * Y + 2.018 * U); 
//	G = (int)(1.164 * Y - 0.813 * V - 0.391 * U); 
//	B = (int)(1.164 * Y + 1.596 * V); 
	R = (int)( Y + 1.403 * V); 
	G = (int)(Y - 0.344 * U - 0.714 * V); 
	B = (int)(Y + 1.770 * U); 
 
	R= min(255,max(0,R)); 
	G= min(255,max(0,G)); 
	B= min(255,max(0,B)); 
	RGBQUAD rgb={(BYTE)B,(BYTE)G,(BYTE)R,0}; 
	return rgb; 
} 
//////////////////////////////////////////////////////////////////////////////// 
RGBQUAD CxImage::RGBtoYUV(RGBQUAD lRGBColor) 
{ 
	int Y,U,V,R,G,B; 
	R = lRGBColor.rgbRed; 
	G = lRGBColor.rgbGreen; 
	B = lRGBColor.rgbBlue; 
 
//	Y = (int)( 0.257 * R + 0.504 * G + 0.098 * B); 
//	U = (int)( 0.439 * R - 0.368 * G - 0.071 * B + 128); 
//	V = (int)(-0.148 * R - 0.291 * G + 0.439 * B + 128); 
	Y = (int)(0.299 * R + 0.587 * G + 0.114 * B); 
	U = (int)((B-Y) * 0.565 + 128); 
	V = (int)((R-Y) * 0.713 + 128); 
 
	Y= min(255,max(0,Y)); 
	U= min(255,max(0,U)); 
	V= min(255,max(0,V)); 
	RGBQUAD yuv={(BYTE)V,(BYTE)U,(BYTE)Y,0}; 
	return yuv; 
} 
//////////////////////////////////////////////////////////////////////////////// 
RGBQUAD CxImage::YIQtoRGB(RGBQUAD lYIQColor) 
{ 
	int Y,I,Q,R,G,B; 
	Y = lYIQColor.rgbRed; 
	I = lYIQColor.rgbGreen - 128; 
	Q = lYIQColor.rgbBlue - 128; 
 
	R = (int)( Y + 0.956 * I + 0.621 * Q); 
	G = (int)( Y - 0.273 * I - 0.647 * Q); 
	B = (int)( Y - 1.104 * I + 1.701 * Q); 
 
	R= min(255,max(0,R)); 
	G= min(255,max(0,G)); 
	B= min(255,max(0,B)); 
	RGBQUAD rgb={(BYTE)B,(BYTE)G,(BYTE)R,0}; 
	return rgb; 
} 
//////////////////////////////////////////////////////////////////////////////// 
RGBQUAD CxImage::RGBtoYIQ(RGBQUAD lRGBColor) 
{ 
	int Y,I,Q,R,G,B; 
	R = lRGBColor.rgbRed; 
	G = lRGBColor.rgbGreen; 
	B = lRGBColor.rgbBlue; 
 
	Y = (int)( 0.2992 * R + 0.5868 * G + 0.1140 * B); 
	I = (int)( 0.5960 * R - 0.2742 * G - 0.3219 * B + 128); 
	Q = (int)( 0.2109 * R - 0.5229 * G + 0.3120 * B + 128); 
 
	Y= min(255,max(0,Y)); 
	I= min(255,max(0,I)); 
	Q= min(255,max(0,Q)); 
	RGBQUAD yiq={(BYTE)Q,(BYTE)I,(BYTE)Y,0}; 
	return yiq; 
} 
//////////////////////////////////////////////////////////////////////////////// 
RGBQUAD CxImage::XYZtoRGB(RGBQUAD lXYZColor) 
{ 
	int X,Y,Z,R,G,B; 
	X = lXYZColor.rgbRed; 
	Y = lXYZColor.rgbGreen; 
	Z = lXYZColor.rgbBlue; 
	double k=1.088751; 
 
	R = (int)(  3.240479 * X - 1.537150 * Y - 0.498535 * Z * k); 
	G = (int)( -0.969256 * X + 1.875992 * Y + 0.041556 * Z * k); 
	B = (int)(  0.055648 * X - 0.204043 * Y + 1.057311 * Z * k); 
 
	R= min(255,max(0,R)); 
	G= min(255,max(0,G)); 
	B= min(255,max(0,B)); 
	RGBQUAD rgb={(BYTE)B,(BYTE)G,(BYTE)R,0}; 
	return rgb; 
} 
//////////////////////////////////////////////////////////////////////////////// 
RGBQUAD CxImage::RGBtoXYZ(RGBQUAD lRGBColor) 
{ 
	int X,Y,Z,R,G,B; 
	R = lRGBColor.rgbRed; 
	G = lRGBColor.rgbGreen; 
	B = lRGBColor.rgbBlue; 
 
	X = (int)( 0.412453 * R + 0.357580 * G + 0.180423 * B); 
	Y = (int)( 0.212671 * R + 0.715160 * G + 0.072169 * B); 
	Z = (int)((0.019334 * R + 0.119193 * G + 0.950227 * B)*0.918483657); 
 
	//X= min(255,max(0,X)); 
	//Y= min(255,max(0,Y)); 
	//Z= min(255,max(0,Z)); 
	RGBQUAD xyz={(BYTE)Z,(BYTE)Y,(BYTE)X,0}; 
	return xyz; 
} 
//////////////////////////////////////////////////////////////////////////////// 
void CxImage::HuePalette(float correction) 
{ 
	if (head.biClrUsed==0) return; 
 
	for(DWORD j=0; j r) r=c.rgbRed; 
						if (c.rgbGreen > g) g=c.rgbGreen; 
						if (c.rgbBlue > b) b=c.rgbBlue; 
					} 
				} 
				c.rgbRed   = r; 
				c.rgbGreen = g; 
				c.rgbBlue  = b; 
				tmp.SetPixelColor(x,y,c); 
			} 
		} 
	} 
	Transfer(tmp); 
	return true; 
 
} 
//////////////////////////////////////////////////////////////////////////////// 
// thanks to Mwolski  
void CxImage::Mix(CxImage & imgsrc2, ImageOpType op, long lXOffset, long lYOffset) 
{ 
    long lWide = min(GetWidth(),imgsrc2.GetWidth()-lXOffset); 
    long lHeight = min(GetHeight(),imgsrc2.GetHeight()-lYOffset); 
 
    RGBQUAD rgbBackgrnd = GetTransColor(); 
    RGBQUAD rgb1, rgb2, rgbDest; 
 
    for(long lY=0;lYn) n=red[i]; 
		if (green && green[i]>n) n=green[i]; 
		if (blue && blue[i]>n) n=blue[i]; 
		if (gray && gray[i]>n) n=gray[i]; 
	} 
 
	return n; 
} 
//////////////////////////////////////////////////////////////////////////////// 
#ifndef __BORLANDC__ 
//////////////////////////////////////////////////////////////////////////////// 
bool CxImage::FFT2(CxImage* srcReal, CxImage* srcImag, CxImage* dstReal, CxImage* dstImag, 
				   long direction, bool bForceFFT, bool bMagnitude) 
{ 
	//check if there is something to convert 
	if (srcReal==NULL && srcImag==NULL) return false; 
 
	long w,h; 
	//get width and height 
	if (srcReal) { 
		w=srcReal->GetWidth(); 
		h=srcReal->GetHeight(); 
	} else { 
		w=srcImag->GetWidth(); 
		h=srcImag->GetHeight(); 
	} 
 
	bool bXpow2 = IsPowerof2(w); 
	bool bYpow2 = IsPowerof2(h); 
	//if bForceFFT, width AND height must be powers of 2 
	if (bForceFFT && !(bXpow2 && bYpow2)) { 
		long i; 
		 
		i=0; 
		while((1< copy the image 
	if (srcReal && dstReal) tmpReal->Copy(*srcReal,true,false,false); 
	if (srcImag && dstImag) tmpImag->Copy(*srcImag,true,false,false); 
 
	// dst&&src are empty -> create new one, else turn to GrayScale 
	if (srcReal==0 && dstReal==0){ 
		tmpReal = new CxImage(w,h,8); 
		tmpReal->Clear(0); 
		tmpReal->SetGrayPalette(); 
	} else { 
		if (!tmpReal->IsGrayScale()) tmpReal->GrayScale(); 
	} 
	if (srcImag==0 && dstImag==0){ 
		tmpImag = new CxImage(w,h,8); 
		tmpImag->Clear(0); 
		tmpImag->SetGrayPalette(); 
	} else { 
		if (!tmpImag->IsGrayScale()) tmpImag->GrayScale(); 
	} 
 
	if (!(tmpReal->IsValid() && tmpImag->IsValid())){ 
		if (srcReal==0 && dstReal==0) delete tmpReal; 
		if (srcImag==0 && dstImag==0) delete tmpImag; 
		return false; 
	} 
 
	//resample for FFT, if necessary  
	tmpReal->Resample(w,h,0); 
	tmpImag->Resample(w,h,0); 
 
	//ok, here we have 2 (w x h), grayscale images ready for a FFT 
 
	double* real; 
	double* imag; 
	long j,k,m; 
 
	_complex **grid; 
	//double mean = tmpReal->Mean(); 
	/* Allocate memory for the grid */ 
	grid = (_complex **)malloc(w * sizeof(_complex)); 
	for (k=0;kGetPixelIndex(k,j)-128; 
			grid[k][j].y = tmpImag->GetPixelIndex(k,j)-128; 
		} 
	} 
 
	//DFT buffers 
	double *real2,*imag2; 
	real2 = (double*)malloc(max(w,h) * sizeof(double)); 
	imag2 = (double*)malloc(max(w,h) * sizeof(double)); 
 
	/* Transform the rows */ 
	real = (double *)malloc(w * sizeof(double)); 
	imag = (double *)malloc(w * sizeof(double)); 
 
	m=0; 
	while((1<SetPixelIndex(k,j,(BYTE)max(0,min(255,(nn*(3+log(_cabs(grid[k][j]))))))); 
				if (grid[k][j].x==0){ 
					tmpImag->SetPixelIndex(k,j,(BYTE)max(0,min(255,(128+(atan(grid[k][j].y/0.0000000001)*nn))))); 
				} else { 
					tmpImag->SetPixelIndex(k,j,(BYTE)max(0,min(255,(128+(atan(grid[k][j].y/grid[k][j].x)*nn))))); 
				} 
			} else { 
				tmpReal->SetPixelIndex(k,j,(BYTE)max(0,min(255,(128 + grid[k][j].x*nn)))); 
				tmpImag->SetPixelIndex(k,j,(BYTE)max(0,min(255,(128 + grid[k][j].y*nn)))); 
			} 
		} 
	} 
 
	for (k=0;k> 1; 
	j = 0; 
	for (i=0;i>= 1; 
		} 
		j += k; 
	} 
 
	/* Compute the FFT */ 
	c1 = -1.0; 
	c2 = 0.0; 
	l2 = 1; 
	for (l=0;lGetWidth(); 
	long h = r->GetHeight(); 
 
	Create(w,h,24); 
 
	g->Resample(w,h); 
	b->Resample(w,h); 
 
	if (a) { 
		a->Resample(w,h); 
#if CXIMAGE_SUPPORT_ALPHA 
		AlphaCreate(); 
#endif //CXIMAGE_SUPPORT_ALPHA 
	} 
 
	RGBQUAD c; 
	for (long y=0;yGetPixelIndex(x,y); 
			c.rgbGreen=g->GetPixelIndex(x,y); 
			c.rgbBlue=b->GetPixelIndex(x,y); 
			switch (colorspace){ 
			case 1: 
				SetPixelColor(x,y,HSLtoRGB(c)); 
				break; 
			case 2: 
				SetPixelColor(x,y,YUVtoRGB(c)); 
				break; 
			case 3: 
				SetPixelColor(x,y,YIQtoRGB(c)); 
				break; 
			case 4: 
				SetPixelColor(x,y,XYZtoRGB(c)); 
				break; 
			default: 
				SetPixelColor(x,y,c); 
			} 
#if CXIMAGE_SUPPORT_ALPHA 
			if (a) AlphaSet(x,y,a->GetPixelIndex(x,y)); 
#endif //CXIMAGE_SUPPORT_ALPHA 
		} 
	} 
 
	return true; 
} 
//////////////////////////////////////////////////////////////////////////////// 
bool CxImage::Repair(float radius, long niterations, long colorspace) 
{ 
	if (!IsValid()) return false; 
 
	long w = GetWidth(); 
	long h = GetHeight(); 
 
	CxImage r,g,b; 
 
	r.Create(w,h,8); 
	g.Create(w,h,8); 
	b.Create(w,h,8); 
 
	switch (colorspace){ 
	case 1: 
		SplitHSL(&r,&g,&b); 
		break; 
	case 2: 
		SplitYUV(&r,&g,&b); 
		break; 
	case 3: 
		SplitYIQ(&r,&g,&b); 
		break; 
	case 4: 
		SplitXYZ(&r,&g,&b); 
		break; 
	default: 
		SplitRGB(&r,&g,&b); 
	} 
	 
	for (int i=0; iGetWidth()-1; 
	long h = ch->GetHeight()-1; 
 
	double correction,ix,iy,ixx,ixy,iyy,den,num; 
	int x,y,xy0,xp1,xm1,yp1,ym1; 
	for(x=1; xGetPixelIndex(x,y); 
			xm1 = ch->GetPixelIndex(x-1,y); 
			xp1 = ch->GetPixelIndex(x+1,y); 
			ym1 = ch->GetPixelIndex(x,y-1); 
			yp1 = ch->GetPixelIndex(x,y+1); 
 
			ix= (xp1-xm1)/2.0; 
			iy= (yp1-ym1)/2.0; 
			ixx= xp1 - 2.0* xy0 + xm1; 
			iyy= yp1 - 2.0* xy0 + ym1; 
			ixy=(ch->GetPixelIndex(x+1,y+1)+ch->GetPixelIndex(x-1,y-1)- 
				 ch->GetPixelIndex(x-1,y+1)-ch->GetPixelIndex(x+1,y-1))/4.0; 
 
			num= (1.0+iy*iy)*ixx - ix*iy*ixy + (1.0+ix*ix)*iyy; 
			den= 1.0+ix*ix+iy*iy; 
			correction = num/den; 
 
			tmp.SetPixelIndex(x,y,(BYTE)min(255,max(0,(xy0 + radius * correction)))); 
		} 
	} 
 
	for (x=0;x<=w;x++){ 
		tmp.SetPixelIndex(x,0,ch->GetPixelIndex(x,0)); 
		tmp.SetPixelIndex(x,h,ch->GetPixelIndex(x,h)); 
	} 
	for (y=0;y<=h;y++){ 
		tmp.SetPixelIndex(0,y,ch->GetPixelIndex(0,y)); 
		tmp.SetPixelIndex(w,y,ch->GetPixelIndex(w,y)); 
	} 
	ch->Transfer(tmp); 
	return true; 
} 
//////////////////////////////////////////////////////////////////////////////// 
#endif //CXIMAGE_SUPPORT_DSP