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 );
}
}