#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 107 of file redEye.cpp. |
|
Definition at line 376 of file redEye.cpp. References IDedPixel(). Referenced by desaturateBlobs(). 00377 { 00378 int n = 0; 00379 if( IDedPixel(x ,y ) ) n++; 00380 00381 if(n == 1) 00382 return 1.0; 00383 00384 if( IDedPixel(x-1,y-1) ) n++; 00385 if( IDedPixel(x ,y-1) ) n++; 00386 if( IDedPixel(x+1,y-1) ) n++; 00387 if( IDedPixel(x-1,y ) ) n++; 00388 if( IDedPixel(x+1,y ) ) n++; 00389 if( IDedPixel(x-1,y+1) ) n++; 00390 if( IDedPixel(x ,y+1) ) n++; 00391 if( IDedPixel(x+1,y+1) ) n++; 00392 00393 if( IDedPixel(x-2,y-2) ) n++; 00394 if( IDedPixel(x-1,y-2) ) n++; 00395 if( IDedPixel(x ,y-2) ) n++; 00396 if( IDedPixel(x+1,y-2) ) n++; 00397 if( IDedPixel(x+2,y-2) ) n++; 00398 00399 if( IDedPixel(x-2,y-1) ) n++; 00400 if( IDedPixel(x+2,y-1) ) n++; 00401 if( IDedPixel(x-2,y ) ) n++; 00402 if( IDedPixel(x+2,y ) ) n++; 00403 if( IDedPixel(x-2,y+1) ) n++; 00404 if( IDedPixel(x+2,y+1) ) n++; 00405 00406 if( IDedPixel(x-2,y+2) ) n++; 00407 if( IDedPixel(x-1,y+2) ) n++; 00408 if( IDedPixel(x ,y+2) ) n++; 00409 if( IDedPixel(x+1,y+2) ) n++; 00410 if( IDedPixel(x+2,y+2) ) n++; 00411 00412 00413 return ((double)n) / 25; 00414 }
|
|
Definition at line 416 of file redEye.cpp. References bottomRight, desaturateAlpha(), editedImage, and topLeft. Referenced by removeRedeyeRegions(). 00417 { 00418 //desaturate bad pixels 00419 int x, y; 00420 double r; 00421 QRgb* rgb; 00422 uchar* scanLine; 00423 for( y = QMAX( topLeft.y()-1, 0); 00424 y<= QMIN( bottomRight.y()+1, editedImage->height()-1 ); 00425 y++) 00426 { 00427 scanLine = editedImage->scanLine(y); 00428 for( x = QMAX( topLeft.x()-1, 0); 00429 x <= QMIN( bottomRight.x()+1, editedImage->width()-1 ); 00430 x++) 00431 { 00432 double alpha = desaturateAlpha( x, y ); 00433 if( alpha > 0) 00434 { 00435 rgb = ((QRgb*)scanLine+x); 00436 00437 r = alpha*(0.05*qRed(*rgb) + 0.6*qGreen(*rgb) + 0.3*qBlue(*rgb)) + 00438 (1-alpha)*qRed(*rgb); 00439 *rgb = qRgb( (int)r, 00440 qGreen(*rgb), 00441 qBlue(*rgb) ); 00442 } //alpha > 0 00443 } //x 00444 } //y 00445 }
|
|
Definition at line 447 of file redEye.cpp. References editedImage. Referenced by removeRedeyeRegions(). 00448 { 00449 //desaturate bad pixels 00450 int x, y; 00451 QRgb* rgb; 00452 uchar* scanLine; 00453 for( y=topLeftExtreme.y(); y<=bottomRightExtreme.y(); y++) 00454 { 00455 scanLine = editedImage->scanLine(y); 00456 for( x=topLeftExtreme.x(); x<=bottomRightExtreme.x(); x++) 00457 { 00458 rgb = ((QRgb*)scanLine+x); 00459 if( qRed(*rgb) > 2*qGreen(*rgb) ) 00460 { 00461 *rgb = qRgb( (int) (0.05*qRed(*rgb) + 0.6*qGreen(*rgb) + 0.3*qBlue(*rgb)), 00462 qGreen(*rgb), 00463 qBlue(*rgb) ); 00464 } // > thresh 00465 } //x 00466 } //y 00467 }
|
|
Definition at line 310 of file redEye.cpp. References blobCount, id1, id2, ids, ratios, and sizes. Referenced by removeRedeyeRegions(). 00311 { 00312 id1 = -1; 00313 id2 = -1; 00314 int i; 00315 00316 //special case: 2 blobs found, both larger than 1 pixel 00317 if(blobCount == 2 && 00318 sizes[0] > 1 && 00319 sizes[1] > 1) 00320 { 00321 id1 = ids[0]; 00322 id2 = ids[1]; 00323 } 00324 else 00325 { 00326 for(i=0; i<blobCount-2; i++) 00327 { 00328 //once we hit blobs that are only one pixel large stop because they are probably just noise 00329 if( sizes[i+1] <= 1 ) break; 00330 00331 double as1 = ratios[i]; 00332 double as2 = ratios[i+1]; 00333 00334 if(as1 < 1) as1 = 1.0/as1; 00335 if(as2 < 1) as2 = 1.0/as2; 00336 00337 if( //both blobs must be semi-circular, prefer those that are wider 00338 ratios[i] > 0.75 && ratios[i] < 2 && 00339 ratios[i+1] > 0.75 && ratios[i+1] < 2 && 00340 //both blobs must be similar in shape 00341 QMAX(as2,as1)/QMIN(as2,as1) < 2 && 00342 //both blobs must be similar in size 00343 ((double)QMAX( sizes[i], sizes[i+1] )) / QMIN( sizes[i], sizes[i+1] ) < 1.5 && 00344 //both blobs must be above a certain thresh size, this prevents selecting blobs that are very very tiny 00345 //if only tiny blobs are around we'll end up desaturating entire region 00346 QMAX( sizes[i], sizes[i+1] ) > 20 ) 00347 { 00348 id1 = ids[i]; 00349 id2 = ids[i+1]; 00350 break; 00351 } 00352 } 00353 } 00354 00355 //Comment this sectionin to see what blobs were found and selected 00356 /* cout << "-----\n"; 00357 for(i=0; i<blobCount-1; i++) 00358 { 00359 if( ids[i] == id1 || ids[i] == id2 ) 00360 cout << "--->"; 00361 cout << "ID: " << ids[i] << "count: " << sizes[i] << " w:h: " << ratios[i] << "\n"; 00362 }*/ 00363 }
|
|
Definition at line 177 of file redEye.cpp. References blobAspectRatios, blobBottomRight, blobIDs, blobPixelCount, blobSizes, blobTopLeft, bottomRight, pushPixel(), rawImage, regionHeight, regionOfInterest, regionWidth, spreadablePixels, and topLeft. Referenced by removeRedeyeRegions(). 00178 { 00179 //create small matrix for region of interest 00180 regionWidth = bottomRight.x() - topLeft.x() + 1; 00181 regionHeight = bottomRight.y() - topLeft.y() + 1; 00182 regionOfInterest = new int[ regionWidth * regionHeight ]; 00183 00184 //set all pixels that meet thresh to 1, all others to 0 00185 int x, y; 00186 int x2, y2; 00187 QRgb* rgb; 00188 uchar* scanLine; 00189 for( y=topLeft.y(); y<=bottomRight.y(); y++) 00190 { 00191 y2 = y - topLeft.y(); 00192 00193 scanLine = rawImage.scanLine(y); 00194 for( x=topLeft.x(); x<=bottomRight.x(); x++) 00195 { 00196 00197 x2 = x - topLeft.x(); 00198 00199 rgb = ((QRgb*)scanLine+x); 00200 00201 bool threshMet = qRed(*rgb) > 2*qGreen(*rgb) && 00202 qRed(*rgb) > MIN_RED_VAL; 00203 00204 if(threshMet) 00205 regionOfInterest[ x2 + y2*regionWidth ] = 1; 00206 else 00207 regionOfInterest[ x2 + y2*regionWidth ] = 0; 00208 } 00209 } 00210 00211 //walk over region of interest and propogate blobs 00212 int nextValidID = 2; 00213 for(x = 0; x<regionWidth; x++) 00214 { 00215 for(y = 0; y<regionHeight; y++) 00216 { 00217 //if any blobs can be propogated handle them first 00218 while( !spreadablePixels.empty() ) 00219 { 00220 QPoint point = spreadablePixels.pop(); 00221 int id = regionOfInterest[ point.x() + point.y()*regionWidth ]; 00222 00223 pushPixel( point.x()-1, point.y()-1, id ); 00224 pushPixel( point.x(), point.y()-1, id ); 00225 pushPixel( point.x()+1, point.y()-1, id ); 00226 pushPixel( point.x()-1, point.y(), id ); 00227 pushPixel( point.x()+1, point.y(), id ); 00228 pushPixel( point.x()-1, point.y()+1, id ); 00229 pushPixel( point.x(), point.y()+1, id ); 00230 pushPixel( point.x()+1, point.y()+1, id ); 00231 } 00232 00233 //if this pixel has met thresh and has not yet been assigned a unique ID, 00234 //assign it the next unique id and push all valid neighbors 00235 if( regionOfInterest[ x + y*regionWidth ] == 1 ) 00236 { 00237 //print last blob stats 00238 if( nextValidID > 2) 00239 { 00240 blobIDs.push( (nextValidID - 1) ); 00241 blobSizes.push( blobPixelCount ); 00242 blobAspectRatios.push( ((double)(blobBottomRight.x() - blobTopLeft.x()+1)) / (blobBottomRight.y() - blobTopLeft.y()+1) ); 00243 } 00244 00245 regionOfInterest[x + y*regionWidth] = nextValidID; 00246 pushPixel( x-1, y-1, nextValidID ); 00247 pushPixel( x, y-1, nextValidID ); 00248 pushPixel( x+1, y-1, nextValidID ); 00249 pushPixel( x-1, y, nextValidID ); 00250 pushPixel( x+1, y, nextValidID ); 00251 pushPixel( x-1, y+1, nextValidID ); 00252 pushPixel( x, y+1, nextValidID ); 00253 pushPixel( x+1, y+1, nextValidID ); 00254 nextValidID++; 00255 00256 blobPixelCount = 1; 00257 blobTopLeft = QPoint( x, y ); 00258 blobBottomRight = QPoint( x, y ); 00259 } 00260 } //y 00261 } //x 00262 00263 //insert last blob stats 00264 if( nextValidID > 2) 00265 { 00266 blobIDs.push( (nextValidID - 1) ); 00267 blobSizes.push( blobPixelCount ); 00268 blobAspectRatios.push( ((double)(blobBottomRight.x() - blobTopLeft.x()+1)) / (blobBottomRight.y() - blobTopLeft.y()+1) ); 00269 } 00270 }
|
|
Definition at line 110 of file redEye.cpp. References bottomRight, StatusWidget::incrementProgress(), newProgress, rawImage, status, and topLeft. Referenced by removeRedeyeRegions(). 00111 { 00112 topLeft = QPoint(-1,-1); 00113 bottomRight = QPoint(-1,-1); 00114 00115 int x, y; 00116 QRgb* rgb; 00117 uchar* scanLine; 00118 for( y=topLeftExtreme.y(); y<=bottomRightExtreme.y(); y++) 00119 { 00120 scanLine = rawImage.scanLine(y); 00121 for( x=topLeftExtreme.x(); x<=bottomRightExtreme.x(); x++) 00122 { 00123 rgb = ((QRgb*)scanLine+x); 00124 00125 bool threshMet = qRed(*rgb) > 2*qGreen(*rgb) && 00126 qRed(*rgb) > MIN_RED_VAL; 00127 if(threshMet) 00128 { 00129 //first pixel 00130 if(topLeft.x() == -1) 00131 { 00132 topLeft = QPoint(x,y); 00133 bottomRight = QPoint(x,y); 00134 } 00135 00136 if(x < topLeft.x() ) topLeft.setX( x ); 00137 if(y < topLeft.y() ) topLeft.setY( y ); 00138 if(x > bottomRight.x() ) bottomRight.setX( x ); 00139 if(y > bottomRight.y() ) bottomRight.setY( y ); 00140 } 00141 00142 //update status bar if significant progress has been made since last update 00143 newProgress++; 00144 if(newProgress >= updateIncrement) 00145 { 00146 newProgress = 0; 00147 status->incrementProgress(); 00148 qApp->processEvents(); 00149 } 00150 00151 } 00152 } 00153 }
|
|
Definition at line 365 of file redEye.cpp. References bottomRight, id1, regionIndex(), regionOfInterest, and topLeft. Referenced by desaturateAlpha(). 00366 { 00367 if( x < topLeft.x() || y < topLeft.y() || 00368 x > bottomRight.x() || y > bottomRight.y() ) 00369 return false; 00370 00371 int regionIndex = x - topLeft.x() + (y-topLeft.y())*regionWidth; 00372 return ( regionOfInterest[regionIndex] == id1 || 00373 regionOfInterest[regionIndex] == id2 ); 00374 }
|
|
Definition at line 155 of file redEye.cpp. References blobBottomRight, blobPixelCount, blobTopLeft, regionHeight, regionOfInterest, regionWidth, and spreadablePixels. Referenced by findBlobs(). 00156 { 00157 //if pixel off image or below thresh ignore push attempt 00158 if( x < 0 || 00159 y < 0 || 00160 x >= regionWidth || 00161 y >= regionHeight || 00162 regionOfInterest[ x + y*regionWidth ] != 1 ) 00163 return; 00164 00165 //passes! set id and actually put pixel onto stack 00166 regionOfInterest[ x + y*regionWidth] = id; 00167 spreadablePixels.push( QPoint( x, y ) ); 00168 00169 //increase blob pixel count and update topLeft and bottomRight 00170 blobPixelCount++; 00171 blobTopLeft.setX( QMIN( x, blobTopLeft.x() ) ); 00172 blobTopLeft.setY( QMIN( y, blobTopLeft.y() ) ); 00173 blobBottomRight.setX( QMAX( x, blobBottomRight.x() ) ); 00174 blobBottomRight.setY( QMAX( y, blobBottomRight.y() ) ); 00175 }
|
|
Definition at line 22 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(). 00025 { 00026 //store handle to status widget 00027 status = statusWidget; 00028 00029 //load original image 00030 rawImage = QImage( filename ); 00031 00032 //sanity check: unable to load image 00033 if(rawImage.isNull()) { return NULL; } 00034 00035 //sanity check: make sure topLeftExtreme and bottomRightExtreme are within image boundary 00036 topLeftExtreme.setX( QMAX( topLeftExtreme.x(), 0 ) ); 00037 topLeftExtreme.setY( QMAX( topLeftExtreme.y(), 0 ) ); 00038 bottomRightExtreme.setX( QMIN( bottomRightExtreme.x(), rawImage.width()-1 ) ); 00039 bottomRightExtreme.setY( QMIN( bottomRightExtreme.y(), rawImage.height()-1 ) ); 00040 00041 //setup progress bar 00042 QString statusMessage = qApp->translate( "removeRedeyeRegions", "Removing Red-Eye:" ); 00043 status->showProgressBar( statusMessage, 100 ); 00044 qApp->processEvents(); 00045 00046 //update progress bar for every 1% of completion 00047 updateIncrement = (int) ( 0.01 * 00048 ( bottomRightExtreme.x() - topLeftExtreme.x() + 1 ) * 00049 ( bottomRightExtreme.y() - topLeftExtreme.y() + 1 ) ); 00050 newProgress = 0; 00051 00052 //find region of interest: constrain search box to boundary that actually contains red enough pixels 00053 findRegionOfInterest(topLeftExtreme, bottomRightExtreme); 00054 00055 //if no pixels were found then immediately return a NULL pointer signaling no change 00056 if(topLeft.x() == -1) 00057 { 00058 //hide progress bar 00059 status->setStatus( "" ); 00060 qApp->processEvents(); 00061 00062 return NULL; 00063 } 00064 00065 //load an editing image 00066 //two images mus be loaded becuase pixel values are replaced 00067 //using a compbination of niehgbors and their own in order 00068 //to avoid sharp lines at the edge of the saturated region 00069 editedImage = new QImage( filename ); 00070 00071 //sanity check: unable to allocated edited image 00072 if( editedImage == NULL) 00073 { 00074 //hide progress bar 00075 status->setStatus( "" ); 00076 qApp->processEvents(); 00077 00078 return NULL; 00079 } 00080 00081 findBlobs(); 00082 sortBlobsByDecreasingSize(); 00083 findBestTwoBlobs(); 00084 00085 //if we found two good blobs then desaturate those only 00086 if(id1 != -1) 00087 { 00088 desaturateBlobs(); 00089 } 00090 //else desaturate all pixels above thresh within selection area 00091 else 00092 { 00093 desaturateEntireImage(topLeftExtreme, bottomRightExtreme); 00094 } 00095 00096 //remove status bar 00097 status->setStatus( "" ); 00098 qApp->processEvents(); 00099 00100 //return pointer to edited image 00101 return editedImage; 00102 }
|
|
Definition at line 272 of file redEye.cpp. References blobAspectRatios, blobCount, blobIDs, blobSizes, ids, ratios, and sizes. Referenced by removeRedeyeRegions(). 00273 { 00274 blobCount = blobIDs.count(); 00275 ids = new int[blobCount]; 00276 sizes = new int[blobCount]; 00277 ratios = new double[blobCount]; 00278 00279 int i,j; 00280 for(i=0; i<blobCount; i++) 00281 { 00282 ids[i] = blobIDs.pop(); 00283 sizes[i] = blobSizes.pop(); 00284 ratios[i] = blobAspectRatios.pop(); 00285 } 00286 00287 //quick and dirty bubble sort 00288 for(j = blobCount-1; j>0; j--) 00289 { 00290 for(i=0; i<j; i++) 00291 { 00292 if( sizes[i+1] > sizes[i] ) 00293 { 00294 int t = sizes[i+1]; 00295 sizes[i+1] = sizes[i]; 00296 sizes[i] = t; 00297 00298 t = ids[i+1]; 00299 ids[i+1] = ids[i]; 00300 ids[i] = t; 00301 00302 double tR = ratios[i+1]; 00303 ratios[i+1] = ratios[i]; 00304 ratios[i] = tR; 00305 } 00306 } 00307 } 00308 }
|