Main Page | Namespace List | Class Hierarchy | Class List | File List | Class Members | File Members

redEye.cpp File Reference

#include <qimage.h>
#include <qstring.h>
#include <qapplication.h>
#include "redEye.h"
#include "redEye_internal.h"
#include "../../gui/statusWidget.h"

Include dependency graph for redEye.cpp:

Go to the source code of this file.

Defines

#define MIN_RED_VAL   40

Functions

QImage * removeRedeyeRegions (QString filename, QPoint topLeftExtreme, QPoint bottomRightExtreme, StatusWidget *statusWidget)
void findRegionOfInterest (QPoint topLeftExtreme, QPoint bottomRightExtreme)
void pushPixel (int x, int y, int id)
void findBlobs ()
void sortBlobsByDecreasingSize ()
void findBestTwoBlobs ()
bool IDedPixel (int x, int y)
double desaturateAlpha (int x, int y)
void desaturateBlobs ()
void desaturateEntireImage (QPoint topLeftExtreme, QPoint bottomRightExtreme)


Define Documentation

#define MIN_RED_VAL   40
 

Definition at line 302 of file redEye.cpp.

Referenced by findBlobs(), and findRegionOfInterest().


Function Documentation

double desaturateAlpha int  x,
int  y
 

Definition at line 572 of file redEye.cpp.

References IDedPixel().

Referenced by desaturateBlobs().

00573 { 00574 int n = 0; 00575 if( IDedPixel(x ,y ) ) n++; 00576 00577 if(n == 1) 00578 return 1.0; 00579 00580 if( IDedPixel(x-1,y-1) ) n++; 00581 if( IDedPixel(x ,y-1) ) n++; 00582 if( IDedPixel(x+1,y-1) ) n++; 00583 if( IDedPixel(x-1,y ) ) n++; 00584 if( IDedPixel(x+1,y ) ) n++; 00585 if( IDedPixel(x-1,y+1) ) n++; 00586 if( IDedPixel(x ,y+1) ) n++; 00587 if( IDedPixel(x+1,y+1) ) n++; 00588 00589 if( IDedPixel(x-2,y-2) ) n++; 00590 if( IDedPixel(x-1,y-2) ) n++; 00591 if( IDedPixel(x ,y-2) ) n++; 00592 if( IDedPixel(x+1,y-2) ) n++; 00593 if( IDedPixel(x+2,y-2) ) n++; 00594 00595 if( IDedPixel(x-2,y-1) ) n++; 00596 if( IDedPixel(x+2,y-1) ) n++; 00597 if( IDedPixel(x-2,y ) ) n++; 00598 if( IDedPixel(x+2,y ) ) n++; 00599 if( IDedPixel(x-2,y+1) ) n++; 00600 if( IDedPixel(x+2,y+1) ) n++; 00601 00602 if( IDedPixel(x-2,y+2) ) n++; 00603 if( IDedPixel(x-1,y+2) ) n++; 00604 if( IDedPixel(x ,y+2) ) n++; 00605 if( IDedPixel(x+1,y+2) ) n++; 00606 if( IDedPixel(x+2,y+2) ) n++; 00607 00608 00609 return ((double)n) / 25; 00610 }

void desaturateBlobs  ) 
 

Definition at line 612 of file redEye.cpp.

References bottomRight, desaturateAlpha(), editedImage, and topLeft.

Referenced by removeRedeyeRegions().

00613 { 00614 //desaturate bad pixels 00615 int x, y; 00616 double r; 00617 QRgb* rgb; 00618 uchar* scanLine; 00619 for( y = QMAX( topLeft.y()-1, 0); 00620 y<= QMIN( bottomRight.y()+1, editedImage->height()-1 ); 00621 y++) 00622 { 00623 scanLine = editedImage->scanLine(y); 00624 for( x = QMAX( topLeft.x()-1, 0); 00625 x <= QMIN( bottomRight.x()+1, editedImage->width()-1 ); 00626 x++) 00627 { 00628 double alpha = desaturateAlpha( x, y ); 00629 if( alpha > 0) 00630 { 00631 rgb = ((QRgb*)scanLine+x); 00632 00633 r = alpha*(0.05*qRed(*rgb) + 0.6*qGreen(*rgb) + 0.3*qBlue(*rgb)) + 00634 (1-alpha)*qRed(*rgb); 00635 *rgb = qRgb( (int)r, 00636 qGreen(*rgb), 00637 qBlue(*rgb) ); 00638 } //alpha > 0 00639 } //x 00640 } //y 00641 }

void desaturateEntireImage QPoint  topLeftExtreme,
QPoint  bottomRightExtreme
 

Definition at line 643 of file redEye.cpp.

References editedImage.

Referenced by removeRedeyeRegions().

00644 { 00645 //desaturate bad pixels 00646 int x, y; 00647 QRgb* rgb; 00648 uchar* scanLine; 00649 for( y=topLeftExtreme.y(); y<=bottomRightExtreme.y(); y++) 00650 { 00651 scanLine = editedImage->scanLine(y); 00652 for( x=topLeftExtreme.x(); x<=bottomRightExtreme.x(); x++) 00653 { 00654 rgb = ((QRgb*)scanLine+x); 00655 if( qRed(*rgb) > 2*qGreen(*rgb) ) 00656 { 00657 *rgb = qRgb( (int) (0.05*qRed(*rgb) + 0.6*qGreen(*rgb) + 0.3*qBlue(*rgb)), 00658 qGreen(*rgb), 00659 qBlue(*rgb) ); 00660 } // > thresh 00661 } //x 00662 } //y 00663 }

void findBestTwoBlobs  ) 
 

Definition at line 506 of file redEye.cpp.

References blobCount, id1, id2, ids, ratios, and sizes.

Referenced by removeRedeyeRegions().

00507 { 00508 id1 = -1; 00509 id2 = -1; 00510 int i; 00511 00512 //special case: 2 blobs found, both larger than 1 pixel 00513 if(blobCount == 2 && 00514 sizes[0] > 1 && 00515 sizes[1] > 1) 00516 { 00517 id1 = ids[0]; 00518 id2 = ids[1]; 00519 } 00520 else 00521 { 00522 for(i=0; i<blobCount-2; i++) 00523 { 00524 //once we hit blobs that are only one pixel large stop because they are probably just noise 00525 if( sizes[i+1] <= 1 ) break; 00526 00527 double as1 = ratios[i]; 00528 double as2 = ratios[i+1]; 00529 00530 if(as1 < 1) as1 = 1.0/as1; 00531 if(as2 < 1) as2 = 1.0/as2; 00532 00533 if( //both blobs must be semi-circular, prefer those that are wider 00534 ratios[i] > 0.75 && ratios[i] < 2 && 00535 ratios[i+1] > 0.75 && ratios[i+1] < 2 && 00536 //both blobs must be similar in shape 00537 QMAX(as2,as1)/QMIN(as2,as1) < 2 && 00538 //both blobs must be similar in size 00539 ((double)QMAX( sizes[i], sizes[i+1] )) / QMIN( sizes[i], sizes[i+1] ) < 1.5 && 00540 //both blobs must be above a certain thresh size, this prevents selecting blobs that are very very tiny 00541 //if only tiny blobs are around we'll end up desaturating entire region 00542 QMAX( sizes[i], sizes[i+1] ) > 20 ) 00543 { 00544 id1 = ids[i]; 00545 id2 = ids[i+1]; 00546 break; 00547 } 00548 } 00549 } 00550 00551 //Comment this sectionin to see what blobs were found and selected 00552 /* cout << "-----\n"; 00553 for(i=0; i<blobCount-1; i++) 00554 { 00555 if( ids[i] == id1 || ids[i] == id2 ) 00556 cout << "--->"; 00557 cout << "ID: " << ids[i] << "count: " << sizes[i] << " w:h: " << ratios[i] << "\n"; 00558 }*/ 00559 }

void findBlobs  ) 
 

Definition at line 372 of file redEye.cpp.

References blobAspectRatios, blobBottomRight, blobIDs, blobPixelCount, blobSizes, blobTopLeft, bottomRight, MIN_RED_VAL, pushPixel(), rawImage, regionHeight, regionOfInterest, regionWidth, spreadablePixels, and topLeft.

Referenced by removeRedeyeRegions().

00373 { 00374 //create small matrix for region of interest 00375 regionWidth = bottomRight.x() - topLeft.x() + 1; 00376 regionHeight = bottomRight.y() - topLeft.y() + 1; 00377 regionOfInterest = new int[ regionWidth * regionHeight ]; 00378 00379 //set all pixels that meet thresh to 1, all others to 0 00380 int x, y; 00381 int x2, y2; 00382 QRgb* rgb; 00383 uchar* scanLine; 00384 for( y=topLeft.y(); y<=bottomRight.y(); y++) 00385 { 00386 y2 = y - topLeft.y(); 00387 00388 scanLine = rawImage.scanLine(y); 00389 for( x=topLeft.x(); x<=bottomRight.x(); x++) 00390 { 00391 00392 x2 = x - topLeft.x(); 00393 00394 rgb = ((QRgb*)scanLine+x); 00395 00396 bool threshMet = qRed(*rgb) > 2*qGreen(*rgb) && 00397 qRed(*rgb) > MIN_RED_VAL; 00398 00399 if(threshMet) 00400 regionOfInterest[ x2 + y2*regionWidth ] = 1; 00401 else 00402 regionOfInterest[ x2 + y2*regionWidth ] = 0; 00403 } 00404 } 00405 00406 //walk over region of interest and propogate blobs 00407 int nextValidID = 2; 00408 for(x = 0; x<regionWidth; x++) 00409 { 00410 for(y = 0; y<regionHeight; y++) 00411 { 00412 //if any blobs can be propogated handle them first 00413 while( !spreadablePixels.empty() ) 00414 { 00415 QPoint point = spreadablePixels.pop(); 00416 int id = regionOfInterest[ point.x() + point.y()*regionWidth ]; 00417 00418 pushPixel( point.x()-1, point.y()-1, id ); 00419 pushPixel( point.x(), point.y()-1, id ); 00420 pushPixel( point.x()+1, point.y()-1, id ); 00421 pushPixel( point.x()-1, point.y(), id ); 00422 pushPixel( point.x()+1, point.y(), id ); 00423 pushPixel( point.x()-1, point.y()+1, id ); 00424 pushPixel( point.x(), point.y()+1, id ); 00425 pushPixel( point.x()+1, point.y()+1, id ); 00426 } 00427 00428 //if this pixel has met thresh and has not yet been assigned a unique ID, 00429 //assign it the next unique id and push all valid neighbors 00430 if( regionOfInterest[ x + y*regionWidth ] == 1 ) 00431 { 00432 //print last blob stats 00433 if( nextValidID > 2) 00434 { 00435 blobIDs.push( (nextValidID - 1) ); 00436 blobSizes.push( blobPixelCount ); 00437 blobAspectRatios.push( ((double)(blobBottomRight.x() - blobTopLeft.x()+1)) / 00438 (blobBottomRight.y() - blobTopLeft.y()+1) ); 00439 } 00440 00441 regionOfInterest[x + y*regionWidth] = nextValidID; 00442 pushPixel( x-1, y-1, nextValidID ); 00443 pushPixel( x, y-1, nextValidID ); 00444 pushPixel( x+1, y-1, nextValidID ); 00445 pushPixel( x-1, y, nextValidID ); 00446 pushPixel( x+1, y, nextValidID ); 00447 pushPixel( x-1, y+1, nextValidID ); 00448 pushPixel( x, y+1, nextValidID ); 00449 pushPixel( x+1, y+1, nextValidID ); 00450 nextValidID++; 00451 00452 blobPixelCount = 1; 00453 blobTopLeft = QPoint( x, y ); 00454 blobBottomRight = QPoint( x, y ); 00455 } 00456 } //y 00457 } //x 00458 00459 //insert last blob stats 00460 if( nextValidID > 2) 00461 { 00462 blobIDs.push( (nextValidID - 1) ); 00463 blobSizes.push( blobPixelCount ); 00464 blobAspectRatios.push( ((double)(blobBottomRight.x() - blobTopLeft.x()+1)) / (blobBottomRight.y() - blobTopLeft.y()+1) ); 00465 } 00466 }

void findRegionOfInterest QPoint  topLeftExtreme,
QPoint  bottomRightExtreme
 

Definition at line 305 of file redEye.cpp.

References bottomRight, StatusWidget::incrementProgress(), MIN_RED_VAL, newProgress, rawImage, status, topLeft, and updateIncrement.

Referenced by removeRedeyeRegions().

00306 { 00307 topLeft = QPoint(-1,-1); 00308 bottomRight = QPoint(-1,-1); 00309 00310 int x, y; 00311 QRgb* rgb; 00312 uchar* scanLine; 00313 for( y=topLeftExtreme.y(); y<=bottomRightExtreme.y(); y++) 00314 { 00315 scanLine = rawImage.scanLine(y); 00316 for( x=topLeftExtreme.x(); x<=bottomRightExtreme.x(); x++) 00317 { 00318 rgb = ((QRgb*)scanLine+x); 00319 00320 bool threshMet = qRed(*rgb) > 2*qGreen(*rgb) && 00321 qRed(*rgb) > MIN_RED_VAL; 00322 if(threshMet) 00323 { 00324 //first pixel 00325 if(topLeft.x() == -1) 00326 { 00327 topLeft = QPoint(x,y); 00328 bottomRight = QPoint(x,y); 00329 } 00330 00331 if(x < topLeft.x() ) topLeft.setX( x ); 00332 if(y < topLeft.y() ) topLeft.setY( y ); 00333 if(x > bottomRight.x() ) bottomRight.setX( x ); 00334 if(y > bottomRight.y() ) bottomRight.setY( y ); 00335 } 00336 00337 //update status bar if significant progress has been made since last update 00338 newProgress++; 00339 if(newProgress >= updateIncrement) 00340 { 00341 newProgress = 0; 00342 status->incrementProgress(); 00343 qApp->processEvents(); 00344 } 00345 00346 } 00347 } 00348 }

bool IDedPixel int  x,
int  y
 

Definition at line 561 of file redEye.cpp.

References bottomRight, id1, id2, regionIndex(), regionOfInterest, regionWidth, and topLeft.

Referenced by desaturateAlpha().

00562 { 00563 if( x < topLeft.x() || y < topLeft.y() || 00564 x > bottomRight.x() || y > bottomRight.y() ) 00565 return false; 00566 00567 int regionIndex = x - topLeft.x() + (y-topLeft.y())*regionWidth; 00568 return ( regionOfInterest[regionIndex] == id1 || 00569 regionOfInterest[regionIndex] == id2 ); 00570 }

void pushPixel int  x,
int  y,
int  id
 

Definition at line 350 of file redEye.cpp.

References blobBottomRight, blobPixelCount, blobTopLeft, regionHeight, regionOfInterest, regionWidth, and spreadablePixels.

Referenced by findBlobs().

00351 { 00352 //if pixel off image or below thresh ignore push attempt 00353 if( x < 0 || 00354 y < 0 || 00355 x >= regionWidth || 00356 y >= regionHeight || 00357 regionOfInterest[ x + y*regionWidth ] != 1 ) 00358 return; 00359 00360 //passes! set id and actually put pixel onto stack 00361 regionOfInterest[ x + y*regionWidth] = id; 00362 spreadablePixels.push( QPoint( x, y ) ); 00363 00364 //increase blob pixel count and update topLeft and bottomRight 00365 blobPixelCount++; 00366 blobTopLeft.setX( QMIN( x, blobTopLeft.x() ) ); 00367 blobTopLeft.setY( QMIN( y, blobTopLeft.y() ) ); 00368 blobBottomRight.setX( QMAX( x, blobBottomRight.x() ) ); 00369 blobBottomRight.setY( QMAX( y, blobBottomRight.y() ) ); 00370 }

QImage* removeRedeyeRegions QString  filename,
QPoint  topLeftExtreme,
QPoint  bottomRightExtreme,
StatusWidget statusWidget
 

Definition at line 206 of file redEye.cpp.

References desaturateBlobs(), desaturateEntireImage(), editedImage, findBestTwoBlobs(), findBlobs(), findRegionOfInterest(), id1, newProgress, rawImage, StatusWidget::setStatus(), StatusWidget::showProgressBar(), sortBlobsByDecreasingSize(), status, topLeft, and updateIncrement.

Referenced by EditingInterface::removeRedeye().

00209 { 00210 //store handle to status widget 00211 status = statusWidget; 00212 00213 //load original image 00214 rawImage = QImage( filename ); 00215 00216 //sanity check: unable to load image 00217 if(rawImage.isNull()) { return NULL; } 00218 00219 //convert to 32-bit depth if necessary 00220 if( rawImage.depth() < 32 ) { rawImage = rawImage.convertDepth( 32, Qt::AutoColor ); } 00221 00222 //sanity check: make sure topLeftExtreme and bottomRightExtreme are within image boundary 00223 topLeftExtreme.setX( QMAX( topLeftExtreme.x(), 0 ) ); 00224 topLeftExtreme.setY( QMAX( topLeftExtreme.y(), 0 ) ); 00225 bottomRightExtreme.setX( QMIN( bottomRightExtreme.x(), rawImage.width()-1 ) ); 00226 bottomRightExtreme.setY( QMIN( bottomRightExtreme.y(), rawImage.height()-1 ) ); 00227 00228 //setup progress bar 00229 QString statusMessage = qApp->translate( "removeRedeyeRegions", "Removing Red-Eye:" ); 00230 status->showProgressBar( statusMessage, 100 ); 00231 qApp->processEvents(); 00232 00233 //update progress bar for every 1% of completion 00234 updateIncrement = (int) ( 0.01 * 00235 ( bottomRightExtreme.x() - topLeftExtreme.x() + 1 ) * 00236 ( bottomRightExtreme.y() - topLeftExtreme.y() + 1 ) ); 00237 newProgress = 0; 00238 00239 //find region of interest: constrain search box to boundary that actually contains red enough pixels 00240 findRegionOfInterest(topLeftExtreme, bottomRightExtreme); 00241 00242 //if no pixels were found then immediately return a NULL pointer signaling no change 00243 if(topLeft.x() == -1) 00244 { 00245 //hide progress bar 00246 status->setStatus( "" ); 00247 qApp->processEvents(); 00248 00249 return NULL; 00250 } 00251 00252 //load an editing image 00253 //two images mus be loaded becuase pixel values are replaced 00254 //using a compbination of niehgbors and their own in order 00255 //to avoid sharp lines at the edge of the saturated region 00256 editedImage = new QImage( filename ); 00257 00258 //sanity check: unable to allocated edited image 00259 if( editedImage == NULL) 00260 { 00261 //hide progress bar 00262 status->setStatus( "" ); 00263 qApp->processEvents(); 00264 00265 return NULL; 00266 } 00267 00268 //convert to 32-bit depth if necessary 00269 if( editedImage->depth() < 32 ) 00270 { 00271 QImage* tmp = editedImage; 00272 editedImage = new QImage( tmp->convertDepth( 32, Qt::AutoColor ) ); 00273 delete tmp; tmp=NULL; 00274 } 00275 00276 findBlobs(); 00277 sortBlobsByDecreasingSize(); 00278 findBestTwoBlobs(); 00279 00280 //if we found two good blobs then desaturate those only 00281 if(id1 != -1) 00282 { 00283 desaturateBlobs(); 00284 } 00285 //else desaturate all pixels above thresh within selection area 00286 else 00287 { 00288 desaturateEntireImage(topLeftExtreme, bottomRightExtreme); 00289 } 00290 00291 //remove status bar 00292 status->setStatus( "" ); 00293 qApp->processEvents(); 00294 00295 //return pointer to edited image 00296 return editedImage; 00297 }

void sortBlobsByDecreasingSize  ) 
 

Definition at line 468 of file redEye.cpp.

References blobAspectRatios, blobCount, blobIDs, blobSizes, ids, ratios, and sizes.

Referenced by removeRedeyeRegions().

00469 { 00470 blobCount = blobIDs.count(); 00471 ids = new int[blobCount]; 00472 sizes = new int[blobCount]; 00473 ratios = new double[blobCount]; 00474 00475 int i,j; 00476 for(i=0; i<blobCount; i++) 00477 { 00478 ids[i] = blobIDs.pop(); 00479 sizes[i] = blobSizes.pop(); 00480 ratios[i] = blobAspectRatios.pop(); 00481 } 00482 00483 //quick and dirty bubble sort 00484 for(j = blobCount-1; j>0; j--) 00485 { 00486 for(i=0; i<j; i++) 00487 { 00488 if( sizes[i+1] > sizes[i] ) 00489 { 00490 int t = sizes[i+1]; 00491 sizes[i+1] = sizes[i]; 00492 sizes[i] = t; 00493 00494 t = ids[i+1]; 00495 ids[i+1] = ids[i]; 00496 ids[i] = t; 00497 00498 double tR = ratios[i+1]; 00499 ratios[i+1] = ratios[i]; 00500 ratios[i] = tR; 00501 } 00502 } 00503 } 00504 }


Generated on Sun Mar 4 19:43:02 2007 for AlbumShaper by doxygen 1.3.7