#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) |
|
|
Definition at line 302 of file redEye.cpp. |
|
||||||||||||
|
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 }
|
|
|
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 }
|
|
||||||||||||
|
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 }
|
|
|
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 }
|
|
|
Definition at line 372 of file redEye.cpp. References blobAspectRatios, blobBottomRight, blobIDs, blobPixelCount, blobSizes, blobTopLeft, bottomRight, 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 }
|
|
||||||||||||
|
Definition at line 305 of file redEye.cpp. References bottomRight, StatusWidget::incrementProgress(), newProgress, rawImage, status, and topLeft. 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 }
|
|
||||||||||||
|
Definition at line 561 of file redEye.cpp. References bottomRight, id1, regionIndex(), regionOfInterest, 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 }
|
|
||||||||||||||||
|
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 }
|
|
||||||||||||||||||||
|
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 }
|
|
|
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 }
|
1.3.9.1