April 5, 2008
WikiAdjusting Contrast
Adjusting Contrast
Step by Step
Contrast correction is used to enhance the visual appearance of an image. Contrast modification of an image is defined as
si = contrast*(gi-average) +average
where si is the ith graylevel value of the contrast enhanced image, gi is gthe ith graylevel value of the original image and average is the mean value of the original image given. In the example below, we supply a predefined average value for the image although we could possibly compute average of the image. This is explained more in details in pixelbypixel:class3:Histogram. We then remove this value from the original pixel and next, the averaged removed pixel is multiplied by the specified contrast parameter. The last step the program implements is to add back the average to the contrast corrected pixel and store this result in the structure.
contrast = (float)mousepoint.h/100;
for(x=0;x<640;x++){
for(y=0;y<480;y++){
ourGetPixel(x,y,&R,&G,&B,imageRowBytes,imageBaseAddress);
// geting the color value of a pixel in our image buffer ,
// note that we need to pass
average = 127;
// adjusting the contrast by drifting away from
// the 127 middle point
temp = (contrast * (float)(R - average)+average);
// checking its between 0-255 or making it so.
if (temp > 255) temp = 255; else if (temp < 0) temp = 0;
R = temp;
temp = (contrast * (float)(G -average)+average);
if (temp > 255) temp = 255; else if (temp < 0) temp = 0;
G = temp;
temp = (contrast * (float)(B -average)+average);
if (temp > 255) temp = 255; else if (temp < 0) temp = 0;
B = temp;
ourSetPixel(x,y,R,G,B,bufferRowBytes,bufferBaseAddress);
// address in memory of the begining of the pixel data
}
}
Source Code
/***************************** Adjusting Contrast.c Mac *************************/
void Initialize(void); // function prototypes
void DrawLine( void );
void doEventLoop( void );
void DrawToBuffer(void);
void CopyToWindow (void);
int ourRandom( int min, int max );
void ourSetPixel(unsigned short horizontal,unsigned short vertical,unsigned char R,unsigned char G,unsigned char B,unsigned short rowbytes,Ptr pixbase);
void ourGetPixel(unsigned short horizontal,unsigned short vertical,unsigned char* R,unsigned char* G,unsigned char* B,unsigned short rowbytes,Ptr pixbase);
void ImportFile(GWorldPtr destWorld,int left,int top,int right, int bottom);
//globals
WindowPtr ourWindow;
Rect windRect;
GWorldPtr ourBuffer,ourImage;
int count=0;
void DrawToBuffer(void) // this is where the interesting stuff happens, this is where we actually set our pixels
{
long x , y,temp, average;
Point mousepoint;
unsigned short bufferRowBytes,imageRowBytes ;
Ptr bufferBaseAddress,imageBaseAddress;
PixMapHandle bufferPixmap, imagePixmap;
unsigned char R,G,B;
float contrast;
count++;
GetMouse(&mousepoint);
bufferPixmap=GetGWorldPixMap(ourBuffer); // getting the pixel map of our buffer GWorld so that we can access the pixels
bufferRowBytes = ((*(bufferPixmap))->rowBytes) & 0x7fff; * getting the number of bytes in each row of the pixel map. This is then used to * calculate the location in memory of specific pixels
bufferBaseAddress = GetPixBaseAddr(bufferPixmap ); // getting the base address in memory of the begining of the pixel data
imagePixmap=GetGWorldPixMap(ourImage); // getting the pixel map of our buffer GWorld so that we can access the pixels
imageRowBytes = ((*(imagePixmap))->rowBytes) & 0x7fff; * getting the number of bytes in each row of the pixel map. This is then used to * calculate the location in memory of specific pixels
imageBaseAddress = GetPixBaseAddr(imagePixmap );
contrast = (float)mousepoint.h/100;
for(x=0;x<640;x++){
for(y=0;y<480;y++){
ourGetPixel(x,y,&R,&G,&B,imageRowBytes,imageBaseAddress); // geting the color value of a pixel in our image buffer , note that we need to pass
average = 127; // adjusting the contrast by drifting away from the 127 middle point
temp = (contrast * (float)(R - average)+average); // checking its between 0-255 or making it so.
if (temp > 255) temp = 255; else if (temp < 0) temp = 0;
R = temp;
temp = (contrast * (float)(G -average)+average);
if (temp > 255) temp = 255; else if (temp < 0) temp = 0;
G = temp;
temp = (contrast * (float)(B -average)+average);
if (temp > 255) temp = 255; else if (temp < 0) temp = 0;
B = temp;
ourSetPixel(x,y,R,G,B,bufferRowBytes,bufferBaseAddress); // address in memory of the begining of the pixel data
}
}
}
void CopyToWindow (void){ // copy all our buffer to the window, completely replaceing
// everything that was there
Rect sourceRect,destRect;
SetPortWindowPort(ourWindow);
GetPortBounds( GetWindowPort(ourWindow), &destRect );
GetPortBounds( ourBuffer, &sourceRect );
CopyBits( GetPortBitMapForCopyBits( ourBuffer ), GetPortBitMapForCopyBits(GetWindowPort(ourWindow)),
&sourceRect, &destRect, srcCopy, NULL );
}
void main( void )
{
Initialize();
doEventLoop();
}
void Initialize(void){
OSErr error;
SetRect(&windRect,100,100,740,580);
InitCursor();
ourWindow = NewCWindow( 0L, &windRect, "\pAdjust Contrast", true, noGrowDocProc,(WindowPtr)-1L, true, 0L );
if ( ourWindow == nil ) ExitToShell();
ShowWindow( ourWindow );
SetPortWindowPort( ourWindow );
SetRect(&windRect,0,0,640,480);
error =NewGWorld(&ourBuffer, 32, &windRect, nil, nil,0 ); // creating our offscreen buffer
if (error != noErr ) ExitToShell();
error =NewGWorld(&ourImage, 32, &windRect, nil, nil,0 );
if (error != noErr ) ExitToShell();
ImportFile(ourImage,0,0,640,480); // Calling our method that opens a picture file and returns a picture handle
}
/*************** The Event Loop ***************/
void doEventLoop()
{
EventRecord anEvent;
WindowPtr evtWind;
short clickArea;
Rect screenRect;
Point thePoint;
for (;;){
if (WaitNextEvent( everyEvent, &anEvent, 0, nil )){
if (anEvent.what == mouseDown){
clickArea = FindWindow( anEvent.where, &evtWind );
if (clickArea == inDrag){
GetRegionBounds( GetGrayRgn(), &screenRect );
DragWindow( evtWind, anEvent.where, &screenRect );
}
else if (clickArea == inContent){
if (evtWind != FrontWindow())
SelectWindow( evtWind );
else{
thePoint = anEvent.where;
GlobalToLocal( &thePoint );
}
}
else if (clickArea == inGoAway)
if (TrackGoAway( evtWind, anEvent.where ))
return;
}
}
DrawToBuffer(); // after checking for various events we call our drawing finctions
CopyToWindow();
}
}
int ourRandom( int min, int max ){ // method that returns a random number between min and max
return( (Random()+32768) /((32768*2/) (max-min)))+ min;
}
void ourSetPixel(unsigned short horizontal,unsigned short vertical,unsigned char R,unsigned char G,unsigned char B,unsigned short rowbytes,Ptr pixbase){
Ptr AdressOfRed;
AdressOfRed = rowbytes * vertical +pixbase+horizontal*4+1;
*(AdressOfRed)=R;
*(AdressOfRed+1)=G;
*(AdressOfRed+2)=B;
}
void ourGetPixel(unsigned short horizontal,unsigned short vertical,unsigned char* R,unsigned char* G,unsigned char* B,unsigned short rowbytes,Ptr pixbase){
Ptr AdressOfRed;
AdressOfRed = rowbytes * vertical +pixbase+horizontal*4+1;
*R=*(AdressOfRed);
*G=*(AdressOfRed+1);
*B=*(AdressOfRed+2);
}
void ImportFile(GWorldPtr destWorld,int left,int top,int right, int bottom){ // this method imports a file and returns a picture handle . it uses Quicktime so it can
// import almost any file format including JPG , Pict, Photoshop, EPS, BMP, GIF and many more.
Rect recti; // you must have the QuickTime.lib in your project to compile, and have Quicktime installed to run
PicHandle theNewPic;
OSErr myError;
ComponentInstance gi;
FSSpec fsp;
Point where;
AEKeyword myKeyword;
DescType myActualType;
Size myActualSize ;
NavReplyRecord navreply;
where.h=200; where.v=100; /* where the Standard File dialog window goes */
NavGetFile (NULL, &navreply,NULL,NULL,NULL,NULL,NULL,NULL);
if (AEGetNthPtr(&(navreply.selection), 1, typeFSS, &myKeyword, &myActualType, &fsp, sizeof(fsp), &myActualSize)!= noErr) SysBeep(10);
myError=GetGraphicsImporterForFile(&fsp,&gi);
myError=GraphicsImportGetAsPicture (gi,&theNewPic);
CloseComponent(gi);
SetRect(&recti,left,top,right,bottom);
SetPort((GrafPtr)destWorld);
DrawPicture(theNewPic,&recti); // drawing the imported picture onto the second buffer
KillPicture(theNewPic);
}
Continue Reading
Back to Archive