#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 }
|