www.pudn.com > PtOpenGuiSourceCode.zip > correct.cpp


/* Panorama_Tools	-	Generate, Edit and Convert Panoramic Images 
   Copyright (C) 1998,1999 - Helmut Dersch  der@fh-furtwangen.de 
    
   This program is free software; you can redistribute it and/or modify 
   it under the terms of the GNU General Public License as published by 
   the Free Software Foundation; either version 2, or (at your option) 
   any later version. 
 
   This program is distributed in the hope that it will be useful, 
   but WITHOUT ANY WARRANTY; without even the implied warranty of 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
   GNU General Public License for more details. 
 
   You should have received a copy of the GNU General Public License 
   along with this program; if not, write to the Free Software 
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */ 
 
/*------------------------------------------------------------*/ 
    
// Image changed to PTImage 
 
#include "filter.h" 
#include "mem.h" 
 
static void 	ShiftImage(TrformStr *TrPtr, int xoff, int yoff); 
static int 		getFrame( PTImage *im, int *xoff, int *yoff, int width, int height, int showprogress ); 
 
 
 
void 	correct	(TrformStr *TrPtr, cPrefs *prefs)  
{ 
 
	int 	i,j,k, kstart, kend, color; 
 
	double 	scale_params[2];			// scaling factors for resize; 
	double 	shear_params[2];			// shear values 
	double	radial_params[6];			// coefficients for polynomial correction (0,...3) 
										// and source width/2 (4) and correctionradius (5) 
	double  lum_params[2];				// parameters to correct luminance variation	 
 
	struct  fDesc stack[10];			// Parameters for execute stack function 
 
	int		destwidth, destheight; 
	int 	xoff, yoff; 
	double  xdoff, ydoff; 
	PTImage	im, *dest, *src; 
	fDesc	fD; 
 
	im.data = NULL;  
 
	src			= TrPtr->src; 
	dest		= TrPtr->dest; 
 
	// Apply filters, if required 
 
	TrPtr->success = 1; 
	 
	if( prefs->luminance ) 
	{ 
 
 
		destwidth 		= TrPtr->src->width; 
		destheight 		= TrPtr->src->height; 
 
		// Allocate memory for destination image 
		// If no further Xform: simply use SetDest 
		 
		if( !( 	prefs->resize 		|| 
				prefs->shear		|| 
				prefs->horizontal	|| 
				prefs->vertical 	|| 
				prefs->radial 		|| 
				prefs->cutFrame		|| 
				prefs->fourier)	)			 
		{ 
			if( SetDestImage(TrPtr, destwidth, destheight) != 0 )  
			{ 
				TrPtr->success = 0; 
				PrintError( "Not enough Memory."); 
				return;	 
			} 
		} 
		else // Further Xform requested: use separate new image 
		{ 
			memcpy( &im, TrPtr->src, sizeof(PTImage) ); 
			//im.data = (unsigned char**) /*my*/mem_malloc( im.dataSize ); 
			im.data = new unsigned char* [im.dataSize]; 
			if( im.data == NULL ) 
			{ 
				TrPtr->success = 0; 
				PrintError( "Not enough Memory."); 
				return;	 
			} 
			TrPtr->dest 	= &im; 
		} 
			 
		if( prefs->lum_params[0] ==  prefs->lum_params[1] && 
			prefs->lum_params[1] ==  prefs->lum_params[2] )  // Color independent 
		{ 
			lum_params[0] =  - prefs->lum_params[0] / ( (TrPtr->src->width/2.0) * (TrPtr->src->width/2.0) ); 
			lum_params[1] =    prefs->lum_params[0] / 2.0 ; 
			if( TrPtr->success != 0 ) 
			{ 
				filter( TrPtr, radlum, (void*) lum_params, 0 ); 
			} 
		} 
		else // Color dependent 
		{ 
			for(k=1; k<4; k++) 
			{	 
				lum_params[0] =  - prefs->lum_params[k-1] / ( (TrPtr->src->width/2.0) * (TrPtr->src->width/2.0) ); 
				lum_params[1] =   prefs->lum_params[k-1] / 2.0 ; 
				if( TrPtr->success != 0 ) 
				{ 
					filter( TrPtr, radlum, (void*) lum_params, k ); 
				} 
			} 
		} 
	} 
	 
	if( TrPtr->success	&&  prefs->fourier )	// Fourier filtering required 
	{ 
		if( prefs->luminance ) 
		{ 
			CopyImageData( src, &im ); 
			TrPtr->src = src; 
		} 
		 
		if( prefs->fourier_mode == _fresize ) 
		{ 
			if( prefs->width == 0 && prefs->height == 0 ) 
			{ 
				TrPtr->success = 0; 
				PrintError( "Zero Destination Image Size" ); 
				return; 
			} 
			 
			if( prefs->width  ) 
				destwidth 		= prefs->width; 
			else 
				destwidth 		= (double)TrPtr->src->width * (double)prefs->height / (double)TrPtr->src->height; 
			 
			if( prefs->height) 
				destheight 		= prefs->height; 
			else 
				destheight		= (double)TrPtr->src->height * (double)prefs->width / (double)TrPtr->src->width; 
		} 
		else 
		{ 
			destwidth 		= TrPtr->src->width; 
			destheight 		= TrPtr->src->height; 
		} 
 
		// Allocate memory for destination image 
		// If no further Xform: simply use SetDest 
		 
		if( !( 	prefs->resize 		|| 
				prefs->shear		|| 
				prefs->horizontal	|| 
				prefs->vertical 	|| 
				prefs->radial 		|| 
				prefs->cutFrame	)	)			 
		{ 
			if( SetDestImage(TrPtr, destwidth, destheight) != 0 )  
			{ 
				TrPtr->success = 0; 
				PrintError( "Not enough Memory."); 
				return;	 
			} 
		} 
		else // Further Xform requested: use separate new image 
		{ 
			if( prefs->luminance )  // since then we have allocated im already 
			{ 
				if( im.data ) 
					///*my*/mem_free( (void**)im.data ); 
					delete [] (void**)im.data ; 
			} 
			memcpy( &im, TrPtr->src, sizeof(PTImage) ); 
			im.width = destwidth; im.height = destheight; 
			im.bytesPerLine = im.width * im.bitsPerPixel/8; 
			im.dataSize = im.height * im.bytesPerLine; 
			//im.data = (unsigned char**) /*my*/mem_malloc( im.dataSize ); 
			im.data = new unsigned char*[im.dataSize]; 
			if( im.data == NULL ) 
			{ 
				TrPtr->success = 0; 
				PrintError( "Not enough Memory."); 
				return; 
			} 
			TrPtr->dest 	= &im; 
		} 
		 
		fourier( TrPtr, prefs ); 
	} 
 
 
		 
		 
 
	if( TrPtr->success		&& 
			( 	prefs->resize 		|| 
				prefs->shear		|| 
				prefs->horizontal	|| 
				prefs->vertical 	|| 
				prefs->radial 		|| 
				prefs->cutFrame)	)			// Displacement Xform requested 
	{ 
 
		// First check whether recent luminance or fourier filtering 
		if( prefs->luminance || prefs->fourier ) 
			TrPtr->src	= &im; 
		 
		TrPtr->dest = dest; 
 
		// Set destination image parameters 
			 
		// most Xforms: dest = src 
		 
		destwidth 		= TrPtr->src->width; 	destheight 		= TrPtr->src->height; 
 
		 
		if( prefs->cutFrame ) 
		{ 
			if( getFrame( TrPtr->src, &xoff, &yoff, prefs->fwidth, prefs->fheight, TrPtr->mode & _show_progress ) != 0 ) 
			{ 
				TrPtr->success = 0; 
				return; 
			} 
			//PrintError("x= %d, y= %d", xoff, yoff); 
			destwidth 		=  prefs->fwidth ; 	destheight 		=  prefs->fheight ; 
		} 
				 
 
		if(prefs->resize) 
		{ 
			if( prefs->width == 0 && prefs->height == 0 ) 
			{ 
				TrPtr->success = 0; 
				PrintError( "Zero Destination Image Size" ); 
				return; 
			} 
			 
			if( prefs->width  ) 
				destwidth 		= prefs->width; 
			else 
				destwidth 		= (double)TrPtr->src->width * (double)prefs->height / (double)TrPtr->src->height; 
			 
			if( prefs->height) 
				destheight 		= prefs->height; 
			else 
				destheight		= (double)TrPtr->src->height * (double)prefs->width / (double)TrPtr->src->width; 
		} 
		 
		if( destwidth <= 0 || destheight <= 0 ) 
		{ 
			TrPtr->success = 0; 
			PrintError( "Zero Destination Image Size" ); 
			return; 
		} 
 
 
 
		// Allocate memory for destination image 
 
		if( SetDestImage(TrPtr, destwidth, destheight) != 0 )  
		{ 
			TrPtr->success = 0; 
			PrintError( "Not enough Memory."); 
			goto _correct_exit; 
		} 
 
		 
		 
		if( isColorSpecific( prefs ) )  // Color dependent 
		{ 
			kstart 	= 1; 
			kend	= 4; 
		} 
		else // Color independent 
		{ 
			kstart	= 0; 
			kend	= 1; 
		} 
 
		for(k=kstart;kresize ) 
			{ 
				if(prefs->cutFrame) 
				{ 
					if( prefs->width ) 
						scale_params[0] = ((double)prefs->fwidth)/ prefs->width; 
					else 
						scale_params[0] = ((double)prefs->fheight)/ prefs->height; 
 
					if( prefs->height ) 
						scale_params[1] = ((double)prefs->fheight)/ prefs->height; 
					else 
						scale_params[1] = scale_params[0]; 
				} 
				else 
				{ 
					if( prefs->width ) 
						scale_params[0] = ((double)TrPtr->src->width)/ prefs->width; 
					else 
						scale_params[0] = ((double)TrPtr->src->height)/ prefs->height; 
						 
					if( prefs->height ) 
						scale_params[1] = ((double)TrPtr->src->height)/ prefs->height; 
					else 
						scale_params[1] = scale_params[0]; 
				} 
				SetDesc(stack[i],resize,scale_params); i++; 
			} 
 
			if( prefs->shear ) 
			{ 
				shear_params[0] = prefs->shear_x / TrPtr->src->height; 
				shear_params[1] = prefs->shear_y / TrPtr->src->width; 
				SetDesc(stack[i],shear,shear_params); i++; 
			} 
 
			if (prefs->horizontal) 
			{ 
				SetDesc(stack[i],horiz,&(prefs->horizontal_params[color]) ); i++; 
			} 
 
			if (prefs->vertical) 
			{ 
				SetDesc(stack[i],vert,&(prefs->vertical_params[color])); i++; 
			} 
 
 
			if( prefs->radial ) 
			{ 
				switch( prefs->correction_mode) 
				{ 
					case correction_mode_radial:    SetDesc(stack[i],radial, radial_params); i++; 
												    radial_params[4] = ( (double)( TrPtr->src->width < TrPtr->src->height ? 
													   TrPtr->src->width : TrPtr->src->height) ) / 2.0; 
												    break; 
					case correction_mode_vertical:	SetDesc(stack[i],vertical, radial_params); i++; 
													radial_params[4] = ((double)TrPtr->src->height) / 2.0; 
													break; 
					case correction_mode_deregister:SetDesc(stack[i],deregister, radial_params); i++; 
													radial_params[4] = ((double)TrPtr->src->height) / 2.0; 
													break; 
				} 
				for(j=0;j<4;j++) 
					radial_params[j] = prefs->radial_params[color][j]; 
				radial_params[5] = prefs->radial_params[color][4]; 
			} 
			if( prefs->cutFrame ) 
			{ 
				if( xoff != 0 ) 
				{ 
					xdoff = (double) xoff + 0.5 * ( prefs->fwidth - TrPtr->src->width ) ; 
					SetDesc(stack[i],horiz, &xdoff ); i++; 
				} 
 
				if( yoff != 0 ) 
				{ 
					ydoff = (double)yoff + 0.5 * ( prefs->fheight - TrPtr->src->height) ; 
					SetDesc(stack[i],vert,&ydoff); i++; 
				} 
				 
 
			} 
			stack[i].func = (trfn)NULL; 
 
			if( 	!prefs->resize 		&& 
					!prefs->shear		&& 
					!prefs->horizontal	&& 
					!prefs->vertical 	&& 
					!prefs->radial 		&& 
					prefs->cutFrame )	// Only cutframe 
			{ 
					ShiftImage(TrPtr, xoff, yoff); 
			} 
			else if( TrPtr->success != 0 && i != 0 ) 
			{ 
				fD.func = execute_stack; fD.param = stack; 
				transForm( TrPtr,  &fD, k); 
			} 
 
		} 
	} 
	 
 
	if( !prefs->luminance && !prefs->fourier && !prefs->cutFrame && i == 0 ) // We did nothing! 
	{ 
		TrPtr->success = 0; 
	}	 
 
	if( TrPtr->success == 0 && ! (TrPtr->mode & _destSupplied)) 
		//mem_free( (void**)TrPtr->dest->data ); 
		delete [] (void**)TrPtr->dest->data ; 
 
_correct_exit: 
 
	TrPtr->src 		= src; 
	TrPtr->dest 	= dest; 
 
 
	if( im.data != NULL ) 
		//mem_free((void**)im.data); 
		delete (void**)im.data; 
} 
 
 
 
int 	cutTheFrame	( PTImage *dest, PTImage *src, int width, int height, int showprogress ) 
{ 
	int xoff, yoff; 
	 
	if( width > src->width || height > src->height ) 
	{ 
		PrintError("Image smaller than Rectangle to cut"); 
		return -1; 
	} 
 
	if( getFrame( src, &xoff, &yoff, width, height, showprogress ) == 0 ) 
	{ 
		TrformStr	TrCrop; 
		 
		memcpy( dest, src, sizeof( PTImage ) ); 
		dest->width 			= width; 
		dest->height 			= height; 
		dest->bytesPerLine 		= dest->width * dest->bitsPerPixel/8; 
		dest->dataSize 			= dest->height * dest->bytesPerLine ; 
		//dest->data 				= (unsigned char**) /*my*/mem_malloc( dest->dataSize ); 
		dest->data 			= new unsigned char*[ dest->dataSize ]; 
		if( dest->data == NULL ) 
		{ 
			PrintError("Could not allocate %ld bytes", dest->dataSize ); 
			return -1; 
		} 
		TrCrop.src 	= src; 
		TrCrop.dest = dest; 
		TrCrop.success = 0; 
		 
		 
		ShiftImage( &TrCrop, xoff, yoff); 
		if( TrCrop.success == 1 ) 
		{ 
			return 0; 
		} 
		else 
		{ 
			//mem_free( (void**)dest->data ); 
			delete (void**)dest->data; 
			return -1; 
		} 
	} 
	else 
		return -1; 
} 
 
 
 
 
static int getFrame( PTImage *im, int *xoff, int *yoff, int width, int height, int showprogress ) 
{ 
	int xul, yul,x,y; 
	int xm=0,ym=0; 
	double obr = 0.0, br,brx; 
	int dy = im->height - height; 
	int dx = im->width - width; 
	int bpp = im->bitsPerPixel/8; 
	int fcb = bpp - 3; 
	register unsigned char *sr; 
	unsigned char *sry, *srx, *sl, *st, *sb; 
	register double result = 0.0; 
	char  percent[8];		// Number displayed by Progress reporter 
	 
	if(height > im->height || width > im->width) 
	{ 
		PrintError("Cut Frame: Wrong Parameters"); 
		return -1; 
	} 
 
	sry = *(im->data); 
	 
	if( showprogress ) 
		Progress( _initProgress, "Finding brightest rectangle" ); 
 
	result = 0.0;	 
	// Get upper left rectangle 
	for( y = 0; y < height; y++) 
	{ 
		sr = sry + y * im->bytesPerLine; 
		for( x= 0; x < width; x++ ) 
		{ 
			sr += fcb; 
			result += *(sr++); 
			result += *(sr++); 
			result += *(sr++); 
		} 
	} 
 
	brx = br = obr = result; 
 
	srx = sry; 
 
	for( xul = 0; xul <= dx; srx += bpp) 
	{ 
		if( showprogress ) 
		{	 
			sprintf( percent, "%d", (int) (xul * 100)/(dx>0?dx:1)); 
			if( ! Progress( _setProgress, percent ) ) 
			{ 
				return -1;	 
			} 
		} 
		else 
		{				 
			if( ! Progress( _idleProgress, 0) ) 
			{ 
					return -1; 
			} 
		} 
 
		br = brx; 
		st = srx; 
		 
		for( yul = 0; yul <= dy;  yul++) 
		{ 
			if( br > obr ) 
			{ 
				obr = br; 
				xm = xul; 
				ym = yul; 
			} 
			if( yul < dy )			// subtract top row, add bottom row 
			{ 
				st = srx + yul * im->bytesPerLine; 
				sb = st + height * im->bytesPerLine; 
				for( x = 0; x < width; x++) 
				{ 
			 		st += fcb; 
					br  -= *(st++); 
					br  -= *(st++); 
					br  -= *(st++); 
					 
					sb += fcb; 
					br  += *(sb++); 
					br  += *(sb++); 
					br  += *(sb++); 
				} 
			} 
		} 
		 
		xul++; 
		if( xul < dx )			// subtract left column, add right column 
		{ 
			sl = srx + fcb; 
			sr = srx + width * bpp + fcb; 
			for( y = 0; y < height; y++, sl += im->bytesPerLine, sr += im->bytesPerLine) 
			{ 
				brx -= sl[0]; 
				brx -= sl[1]; 
				brx -= sl[2]; 
				brx += sr[0]; 
				brx += sr[1]; 
				brx += sr[2]; 
			} 
		} 
	} 
	 
	*xoff = xm; 
	*yoff = ym; 
	if(showprogress) 
	{ 
		Progress( _disposeProgress, percent ); 
	}	 
	return 0; 
 
} 
 
static void ShiftImage(TrformStr *TrPtr, int xoff, int yoff) 
{ 
	register int x,y; 
	int cdy, csy; 
	unsigned char *dest, *src, *d,*s; 
	int bpp = TrPtr->src->bitsPerPixel/8; 
	int BitsPerChannel,channels,fcb; 
 
	GetBitsPerChannel( TrPtr->src, BitsPerChannel ); 
	GetChannels( TrPtr->src, channels); 
	fcb = channels-3; 
	 
	// Some checks: 
	 
	if( TrPtr->dest->width + xoff > TrPtr->src->width || 
	    TrPtr->dest->height + yoff > TrPtr->src->height || 
		TrPtr->src->bitsPerPixel != TrPtr->dest->bitsPerPixel ) 
	{ 
		PrintError( "Parameter Error"); 
		TrPtr->success = 0; 
		return; 
	} 
	 
	dest = *(TrPtr->dest->data); 
	src  = *(TrPtr->src->data); 
 
	if( BitsPerChannel == 8 ) 
	{ 
		for(y=0; ydest->height; y++) 
		{ 
			cdy = y * TrPtr->dest->bytesPerLine; 
			csy = (y+yoff) * TrPtr->src->bytesPerLine; 
			for(x=0; xdest->width; x++) 
			{ 
				d = dest + cdy + x*bpp; 
				s = src  + csy + (x+xoff)*bpp; 
				if(fcb) 
				{ 
					*(d++) = *(s++); 
				} 
				*(d++) = *(s++); 
				*(d++) = *(s++); 
				*(d++) = *(s++); 
			} 
		} 
	} 
	else // 16 
	{ 
		for(y=0; ydest->height; y++) 
		{ 
			cdy = y * TrPtr->dest->bytesPerLine; 
			csy = (y+yoff) * TrPtr->src->bytesPerLine; 
			for(x=0; xdest->width; x++) 
			{ 
				d = dest + cdy + x*bpp; 
				s = src  + csy + (x+xoff)*bpp; 
				if(fcb) 
				{ 
					*(((USHORT*)d)++) = *(((USHORT*)s)++); 
				} 
				*(((USHORT*)d)++) = *(((USHORT*)s)++); 
				*(((USHORT*)d)++) = *(((USHORT*)s)++); 
				*(((USHORT*)d)++) = *(((USHORT*)s)++); 
			} 
		} 
	} 
	 
	TrPtr->success = 1; 
} 
 
void SetCorrectDefaults( cPrefs *prefs ) 
{ 
	int i,k; 
			 
	prefs->magic 				= 20L; // from ANSI-version 
	prefs->radial 				= FALSE; 
	prefs->vertical = prefs->horizontal 	= FALSE; 
	for(i=0;i<3;i++){ 
		prefs->radial_params[i][0] 	= 1.0; 
		prefs->radial_params[i][4] 	= 1000.0; // Correction radius 
		prefs->vertical_params[i] 	= 0.0; 
		prefs->horizontal_params[i] 	= 0.0; 
		for(k=1;k<4;k++) 
			prefs->radial_params[i][k] = 0.0;		 
		prefs->lum_params[i]		= 0.0; 
	} 
	prefs->shear 	= prefs->resize 	= FALSE; 
	prefs->shear_x 	= prefs->shear_y 	= 0.0; 
	prefs->width 	= prefs->height 	= 0; 
	prefs->luminance			= FALSE; 
	prefs->correction_mode			= correction_mode_radial; 
	prefs->cutFrame				= FALSE; 
	prefs->fwidth				= 100; 
	prefs->fheight				= 100; 
	prefs->frame				= 0; 
	prefs->fourier				= 0; 
	prefs->fourier_mode			= _fremoveBlurr; 
	prefs->fourier_nf			= _nf_internal; 
	memset( &(prefs->psf), 0, sizeof( fullPath )); 
	memset( &(prefs->nff), 0, sizeof( fullPath )); 
	prefs->filterfactor			= 1.0; 
	prefs->fourier_frame			= 0.0; 
} 
 
// Check if colorspecific correction requested 
 
int isColorSpecific( cPrefs *cp ) 
{ 
	int result = FALSE; 
	int i; 
 
	if( cp->radial ) 
	{ 
		for( i=0; i<4; i++ ) 
		{ 
			if( cp->radial_params[0][i] != cp->radial_params[1][i] || cp->radial_params[1][i] != cp->radial_params[2][i] ) 
				result = TRUE; 
		} 
	} 
 
	if( cp->vertical ) 
	{ 
		if( cp->vertical_params[0] != cp->vertical_params[1] || cp->vertical_params[1] != cp->vertical_params[2]) 
				result = TRUE; 
	} 
 
	if( cp->horizontal ) 
	{ 
		if( cp->horizontal_params[0] != cp->horizontal_params[1] || cp->horizontal_params[1] != cp->horizontal_params[2]) 
				result = TRUE; 
	} 
	 
	return result; 
} 
 
// Set all color dependent values to color 0 
 
void SetEquColor( cPrefs *cP ) 
{ 
	int col,i; 
	 
	for(col = 1; col < 3; col++) 
	{ 
		for(i=0; i<4; i++) 
			cP->radial_params[col][i] 	= cP->radial_params[0][i]; 
		cP->vertical_params	[col] 		= cP->vertical_params[0]; 
		cP->horizontal_params[col] 		= cP->horizontal_params[0]; 
	} 
} 
 
 
// Restrict radial correction to monotonous interval 
 
void SetCorrectionRadius( cPrefs *cP ) 
{ 
	double a[4]; 
	int i,k; 
	 
	for( i=0; i<3; i++ ) 
	{ 
		for( k=0; k<4; k++ ) 
		{ 
			a[k] = 0.0;//1.0e-10; 
			if( cP->radial_params[i][k] != 0.0 ) 
			{ 
				a[k] = (k+1) * cP->radial_params[i][k]; 
			} 
		} 
		cP->radial_params[i][4] = smallestRoot( a ); 
	} 
}