00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include <qimage.h>
00013 #include <qstring.h>
00014 #include <qapplication.h>
00015
00016
00017 #include "redEye.h"
00018 #include "redEye_internal.h"
00019 #include "../../gui/statusWidget.h"
00020
00021
00022 QImage* removeRedeyeRegions( QString filename,
00023 QPoint topLeftExtreme, QPoint bottomRightExtreme,
00024 StatusWidget* statusWidget )
00025 {
00026
00027 status = statusWidget;
00028
00029
00030 rawImage = QImage( filename );
00031
00032
00033 if(rawImage.isNull()) { return NULL; }
00034
00035
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
00042 QString statusMessage = qApp->translate( "removeRedeyeRegions", "Removing Red-Eye:" );
00043 status->showProgressBar( statusMessage, 100 );
00044 qApp->processEvents();
00045
00046
00047 updateIncrement = (int) ( 0.01 *
00048 ( bottomRightExtreme.x() - topLeftExtreme.x() + 1 ) *
00049 ( bottomRightExtreme.y() - topLeftExtreme.y() + 1 ) );
00050 newProgress = 0;
00051
00052
00053 findRegionOfInterest(topLeftExtreme, bottomRightExtreme);
00054
00055
00056 if(topLeft.x() == -1)
00057 {
00058
00059 status->setStatus( "" );
00060 qApp->processEvents();
00061
00062 return NULL;
00063 }
00064
00065
00066
00067
00068
00069 editedImage = new QImage( filename );
00070
00071
00072 if( editedImage == NULL)
00073 {
00074
00075 status->setStatus( "" );
00076 qApp->processEvents();
00077
00078 return NULL;
00079 }
00080
00081 findBlobs();
00082 sortBlobsByDecreasingSize();
00083 findBestTwoBlobs();
00084
00085
00086 if(id1 != -1)
00087 {
00088 desaturateBlobs();
00089 }
00090
00091 else
00092 {
00093 desaturateEntireImage(topLeftExtreme, bottomRightExtreme);
00094 }
00095
00096
00097 status->setStatus( "" );
00098 qApp->processEvents();
00099
00100
00101 return editedImage;
00102 }
00103
00104
00105
00106
00107 #define MIN_RED_VAL 40
00108
00109
00110 void findRegionOfInterest(QPoint topLeftExtreme, QPoint bottomRightExtreme)
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
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
00143 newProgress++;
00144 if(newProgress >= updateIncrement)
00145 {
00146 newProgress = 0;
00147 status->incrementProgress();
00148 qApp->processEvents();
00149 }
00150
00151 }
00152 }
00153 }
00154
00155 void pushPixel(int x, int y, int id)
00156 {
00157
00158 if( x < 0 ||
00159 y < 0 ||
00160 x >= regionWidth ||
00161 y >= regionHeight ||
00162 regionOfInterest[ x + y*regionWidth ] != 1 )
00163 return;
00164
00165
00166 regionOfInterest[ x + y*regionWidth] = id;
00167 spreadablePixels.push( QPoint( x, y ) );
00168
00169
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 }
00176
00177 void findBlobs()
00178 {
00179
00180 regionWidth = bottomRight.x() - topLeft.x() + 1;
00181 regionHeight = bottomRight.y() - topLeft.y() + 1;
00182 regionOfInterest = new int[ regionWidth * regionHeight ];
00183
00184
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
00212 int nextValidID = 2;
00213 for(x = 0; x<regionWidth; x++)
00214 {
00215 for(y = 0; y<regionHeight; y++)
00216 {
00217
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
00234
00235 if( regionOfInterest[ x + y*regionWidth ] == 1 )
00236 {
00237
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 }
00261 }
00262
00263
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 }
00271
00272 void sortBlobsByDecreasingSize()
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
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 }
00309
00310 void findBestTwoBlobs()
00311 {
00312 id1 = -1;
00313 id2 = -1;
00314 int i;
00315
00316
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
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(
00338 ratios[i] > 0.75 && ratios[i] < 2 &&
00339 ratios[i+1] > 0.75 && ratios[i+1] < 2 &&
00340
00341 QMAX(as2,as1)/QMIN(as2,as1) < 2 &&
00342
00343 ((double)QMAX( sizes[i], sizes[i+1] )) / QMIN( sizes[i], sizes[i+1] ) < 1.5 &&
00344
00345
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
00356
00357
00358
00359
00360
00361
00362
00363 }
00364
00365 bool IDedPixel( int x, int y)
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 }
00375
00376 double desaturateAlpha(int x, int y)
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 }
00415
00416 void desaturateBlobs()
00417 {
00418
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 }
00443 }
00444 }
00445 }
00446
00447 void desaturateEntireImage(QPoint topLeftExtreme, QPoint bottomRightExtreme)
00448 {
00449
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 }
00465 }
00466 }
00467 }
00468
00469
00470
00471
00472
00473