AlbumShaper  1.0a3
Functions | Variables
redEye_internal.h File Reference
#include <qimage.h>
#include <qvaluestack.h>
#include <qpoint.h>
Include dependency graph for redEye_internal.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

void findRegionOfInterest (QPoint topLeftExtreme, QPoint bottomRightExtreme)
void findBlobs ()
void pushPixel (int x, int y, int id)
void sortBlobsByDecreasingSize ()
void findBestTwoBlobs ()
void desaturateBlobs ()
void desaturateEntireImage (QPoint topLeftExtreme, QPoint bottomRightExtreme)
bool IDedPixel (int x, int y)
double desaturateAlpha (int x, int y)

Variables

StatusWidgetstatus
int updateIncrement
int newProgress
QImage rawImage
QImage * editedImage
QPoint topLeft
QPoint bottomRight
int regionWidth
int regionHeight
int blobPixelCount
QPoint blobTopLeft
QPoint blobBottomRight
int * regionOfInterest
QValueStack< QPoint > spreadablePixels
QValueStack< int > blobIDs
QValueStack< int > blobSizes
QValueStack< double > blobAspectRatios
int blobCount
int * ids
int * sizes
double * ratios
int id1
int id2

Function Documentation

double desaturateAlpha ( int  x,
int  y 
)

Definition at line 572 of file redEye.cpp.

References IDedPixel().

Referenced by desaturateBlobs().

{
  int n = 0;
  if( IDedPixel(x  ,y  ) ) n++;
  
  if(n == 1)
    return 1.0;
  
  if( IDedPixel(x-1,y-1) ) n++;
  if( IDedPixel(x  ,y-1) ) n++;
  if( IDedPixel(x+1,y-1) ) n++;
  if( IDedPixel(x-1,y  ) ) n++;
  if( IDedPixel(x+1,y  ) ) n++;
  if( IDedPixel(x-1,y+1) ) n++;
  if( IDedPixel(x  ,y+1) ) n++;
  if( IDedPixel(x+1,y+1) ) n++;
  
  if( IDedPixel(x-2,y-2) ) n++;
  if( IDedPixel(x-1,y-2) ) n++;
  if( IDedPixel(x  ,y-2) ) n++;
  if( IDedPixel(x+1,y-2) ) n++;
  if( IDedPixel(x+2,y-2) ) n++;
  
  if( IDedPixel(x-2,y-1) ) n++;
  if( IDedPixel(x+2,y-1) ) n++;
  if( IDedPixel(x-2,y  ) ) n++;
  if( IDedPixel(x+2,y  ) ) n++;
  if( IDedPixel(x-2,y+1) ) n++;
  if( IDedPixel(x+2,y+1) ) n++;
  
  if( IDedPixel(x-2,y+2) ) n++;
  if( IDedPixel(x-1,y+2) ) n++;
  if( IDedPixel(x  ,y+2) ) n++;
  if( IDedPixel(x+1,y+2) ) n++;
  if( IDedPixel(x+2,y+2) ) n++;
  
  
  return ((double)n) / 25;
}
void desaturateBlobs ( )

Definition at line 612 of file redEye.cpp.

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

Referenced by removeRedeyeRegions().

{
  //desaturate bad pixels
  int x, y;
  double r;
  QRgb* rgb;
  uchar* scanLine;
  for( y = QMAX( topLeft.y()-1, 0); 
       y<= QMIN( bottomRight.y()+1, editedImage->height()-1 ); 
       y++)
  {
    scanLine = editedImage->scanLine(y);
    for( x =  QMAX( topLeft.x()-1, 0); 
         x <= QMIN( bottomRight.x()+1, editedImage->width()-1 ); 
         x++)
    {      
      double alpha = desaturateAlpha( x, y );
      if( alpha > 0)
      {
        rgb = ((QRgb*)scanLine+x);
        
        r = alpha*(0.05*qRed(*rgb) + 0.6*qGreen(*rgb) + 0.3*qBlue(*rgb)) +
          (1-alpha)*qRed(*rgb);
        *rgb = qRgb( (int)r,
                     qGreen(*rgb),
                     qBlue(*rgb) );
      } //alpha > 0
    } //x
  } //y  
}
void desaturateEntireImage ( QPoint  topLeftExtreme,
QPoint  bottomRightExtreme 
)

Definition at line 643 of file redEye.cpp.

References editedImage.

Referenced by removeRedeyeRegions().

{
  //desaturate bad pixels
  int x, y;
  QRgb* rgb;
  uchar* scanLine;
  for( y=topLeftExtreme.y(); y<=bottomRightExtreme.y(); y++)
  {
    scanLine = editedImage->scanLine(y);
    for( x=topLeftExtreme.x(); x<=bottomRightExtreme.x(); x++)
    {
      rgb = ((QRgb*)scanLine+x);
      if( qRed(*rgb) > 2*qGreen(*rgb) )
      {
        *rgb = qRgb( (int) (0.05*qRed(*rgb) + 0.6*qGreen(*rgb) + 0.3*qBlue(*rgb)),
                     qGreen(*rgb),
                     qBlue(*rgb) );
      } // > thresh
    } //x
  } //y
}
void findBestTwoBlobs ( )

Definition at line 506 of file redEye.cpp.

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

Referenced by removeRedeyeRegions().

{
  id1 = -1;
  id2 = -1;
  int i;
  
  //special case: 2 blobs found, both larger than 1 pixel
  if(blobCount == 2 &&
     sizes[0] > 1 &&
     sizes[1] > 1)
  {
    id1 = ids[0];
    id2 = ids[1];
  }
  else
  {
    for(i=0; i<blobCount-2; i++)
    {
      //once we hit blobs that are only one pixel large stop because they are probably just noise
      if( sizes[i+1] <= 1 ) break;
      
      double as1 = ratios[i];
      double as2 = ratios[i+1];

      if(as1 < 1) as1 = 1.0/as1;
      if(as2 < 1) as2 = 1.0/as2;
      
      if( //both blobs must be semi-circular, prefer those that are wider
          ratios[i] > 0.75 &&   ratios[i] < 2 &&
          ratios[i+1] > 0.75 && ratios[i+1] < 2 &&
          //both blobs must be similar in shape
          QMAX(as2,as1)/QMIN(as2,as1) < 2 &&
          //both blobs must be similar in size
          ((double)QMAX( sizes[i], sizes[i+1] )) / QMIN( sizes[i], sizes[i+1] ) < 1.5 &&
          //both blobs must be above a certain thresh size, this prevents selecting blobs that are very very tiny
          //if only tiny blobs are around we'll end up desaturating entire region
          QMAX( sizes[i], sizes[i+1] ) > 20 )
      {
        id1 = ids[i];
        id2 = ids[i+1];
        break;
      }    
    }
  }
  
  //Comment this sectionin to see what blobs were found and selected
/* cout << "-----\n";
  for(i=0; i<blobCount-1; i++)
  {
    if( ids[i] == id1 || ids[i] == id2 )
      cout << "--->";
    cout << "ID: " << ids[i] << "count: " << sizes[i] << " w:h: " << ratios[i] << "\n";      
  }*/
}
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().

{
  //create small matrix for region of interest
  regionWidth = bottomRight.x() - topLeft.x() + 1;
  regionHeight = bottomRight.y() - topLeft.y() + 1;  
  regionOfInterest = new int[ regionWidth * regionHeight ];
  
  //set all pixels that meet thresh to 1, all others to 0
  int x, y;
  int x2, y2;
  QRgb* rgb;
  uchar* scanLine;
  for( y=topLeft.y(); y<=bottomRight.y(); y++)
  {
    y2 = y - topLeft.y();
    
    scanLine = rawImage.scanLine(y);
    for( x=topLeft.x(); x<=bottomRight.x(); x++)
    {
    
      x2 = x - topLeft.x();
      
      rgb = ((QRgb*)scanLine+x);
      
      bool threshMet = qRed(*rgb) > 2*qGreen(*rgb) &&
                       qRed(*rgb) > MIN_RED_VAL;
      
      if(threshMet)
        regionOfInterest[ x2 + y2*regionWidth ] = 1;
      else
        regionOfInterest[ x2 + y2*regionWidth ] = 0;
    }
  } 
  
  //walk over region of interest and propogate blobs
  int nextValidID = 2;
  for(x = 0; x<regionWidth; x++)
  {
    for(y = 0; y<regionHeight; y++)
    {
      //if any blobs can be propogated handle them first
      while( !spreadablePixels.empty() )
      {
        QPoint point = spreadablePixels.pop();
        int id = regionOfInterest[ point.x() + point.y()*regionWidth ];
        
        pushPixel( point.x()-1, point.y()-1, id );
        pushPixel( point.x(),   point.y()-1, id );
        pushPixel( point.x()+1, point.y()-1, id );
        pushPixel( point.x()-1, point.y(), id );
        pushPixel( point.x()+1, point.y(), id );
        pushPixel( point.x()-1, point.y()+1, id );
        pushPixel( point.x(),   point.y()+1, id );
        pushPixel( point.x()+1, point.y()+1, id );
      }
      
      //if this pixel has met thresh and has not yet been assigned a unique ID,
      //assign it the next unique id and push all valid neighbors
      if( regionOfInterest[ x + y*regionWidth ] == 1 )
      {
        //print last blob stats
        if( nextValidID > 2)
        {
          blobIDs.push( (nextValidID - 1) );
          blobSizes.push( blobPixelCount );
          blobAspectRatios.push( ((double)(blobBottomRight.x() - blobTopLeft.x()+1)) / 
                                          (blobBottomRight.y() - blobTopLeft.y()+1) );
        }
        
        regionOfInterest[x + y*regionWidth] = nextValidID;
        pushPixel( x-1, y-1, nextValidID );
        pushPixel( x,   y-1, nextValidID );
        pushPixel( x+1, y-1, nextValidID );
        pushPixel( x-1, y, nextValidID );
        pushPixel( x+1, y, nextValidID );
        pushPixel( x-1, y+1, nextValidID );
        pushPixel( x,   y+1, nextValidID );
        pushPixel( x+1, y+1, nextValidID );
        nextValidID++;        
        
        blobPixelCount = 1;
        blobTopLeft = QPoint( x, y );
        blobBottomRight = QPoint( x, y );
      }
    } //y
  } //x
  
  //insert last blob stats
  if( nextValidID > 2)
  {
    blobIDs.push( (nextValidID - 1) );
    blobSizes.push( blobPixelCount );
    blobAspectRatios.push( ((double)(blobBottomRight.x() - blobTopLeft.x()+1)) / (blobBottomRight.y() - blobTopLeft.y()+1) );
  }
}
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().

{
  topLeft = QPoint(-1,-1);
  bottomRight = QPoint(-1,-1);
  
  int x, y;
  QRgb* rgb;
  uchar* scanLine;
  for( y=topLeftExtreme.y(); y<=bottomRightExtreme.y(); y++)
  {
    scanLine = rawImage.scanLine(y);
    for( x=topLeftExtreme.x(); x<=bottomRightExtreme.x(); x++)
    {
      rgb = ((QRgb*)scanLine+x);
      
      bool threshMet = qRed(*rgb) > 2*qGreen(*rgb) &&
                      qRed(*rgb) > MIN_RED_VAL;
      if(threshMet)
      {
        //first pixel
        if(topLeft.x() == -1) 
        {
          topLeft = QPoint(x,y);
          bottomRight = QPoint(x,y);
        }
        
        if(x < topLeft.x() ) topLeft.setX( x );
        if(y < topLeft.y() ) topLeft.setY( y );
        if(x > bottomRight.x() ) bottomRight.setX( x );
        if(y > bottomRight.y() ) bottomRight.setY( y );
      }
      
      //update status bar if significant progress has been made since last update
      newProgress++;
      if(newProgress >= updateIncrement)
      {
        newProgress = 0;
        status->incrementProgress();
        qApp->processEvents();  
      }
      
    }
  }  
}
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().

{
  if( x < topLeft.x() || y < topLeft.y() ||
      x > bottomRight.x() || y > bottomRight.y() )
    return false;
  
  int regionIndex = x - topLeft.x() + (y-topLeft.y())*regionWidth;
  return ( regionOfInterest[regionIndex] == id1 ||
           regionOfInterest[regionIndex] == id2 );
}
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().

{
  //if pixel off image or below thresh ignore push attempt
  if(  x < 0  || 
       y <  0 ||
       x >= regionWidth ||
       y >= regionHeight ||
       regionOfInterest[ x + y*regionWidth ] != 1 )
    return;
  
  //passes! set id and actually put pixel onto stack
  regionOfInterest[ x + y*regionWidth] = id;  
  spreadablePixels.push( QPoint( x, y ) );
  
  //increase blob pixel count and update topLeft and bottomRight
  blobPixelCount++;
  blobTopLeft.setX( QMIN( x, blobTopLeft.x() ) );
  blobTopLeft.setY( QMIN( y, blobTopLeft.y() ) );
  blobBottomRight.setX( QMAX( x, blobBottomRight.x() ) );
  blobBottomRight.setY( QMAX( y, blobBottomRight.y() ) );
}
void sortBlobsByDecreasingSize ( )

Definition at line 468 of file redEye.cpp.

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

Referenced by removeRedeyeRegions().

{
  blobCount = blobIDs.count();
  ids = new int[blobCount];
  sizes = new int[blobCount];
  ratios = new double[blobCount];
  
  int i,j;
  for(i=0; i<blobCount; i++)
  {
    ids[i] = blobIDs.pop();
    sizes[i] = blobSizes.pop();
    ratios[i] = blobAspectRatios.pop();
  }
  
  //quick and dirty bubble sort
  for(j = blobCount-1; j>0; j--)
  {
    for(i=0; i<j; i++)
    {
      if( sizes[i+1] > sizes[i] )
      {
        int t = sizes[i+1];
        sizes[i+1] = sizes[i];
        sizes[i] = t;
        
        t = ids[i+1];
        ids[i+1] = ids[i];
        ids[i] = t;
        
        double tR = ratios[i+1];
        ratios[i+1] = ratios[i];
        ratios[i] = tR;        
      }
    }
  }
}

Variable Documentation

QValueStack<double> blobAspectRatios

Definition at line 58 of file redEye_internal.h.

Referenced by findBlobs(), and sortBlobsByDecreasingSize().

Definition at line 50 of file redEye_internal.h.

Referenced by findBlobs(), and pushPixel().

int blobCount

Definition at line 63 of file redEye_internal.h.

Referenced by findBestTwoBlobs(), and sortBlobsByDecreasingSize().

QValueStack<int> blobIDs

Definition at line 56 of file redEye_internal.h.

Referenced by findBlobs(), and sortBlobsByDecreasingSize().

Definition at line 49 of file redEye_internal.h.

Referenced by findBlobs(), and pushPixel().

QValueStack<int> blobSizes

Definition at line 57 of file redEye_internal.h.

Referenced by findBlobs(), and sortBlobsByDecreasingSize().

QPoint blobTopLeft

Definition at line 50 of file redEye_internal.h.

Referenced by findBlobs(), and pushPixel().

QPoint bottomRight
QImage* editedImage
int id1

Definition at line 71 of file redEye_internal.h.

Referenced by findBestTwoBlobs(), IDedPixel(), and removeRedeyeRegions().

int id2

Definition at line 71 of file redEye_internal.h.

Referenced by findBestTwoBlobs(), and IDedPixel().

int* ids

Definition at line 64 of file redEye_internal.h.

Referenced by findBestTwoBlobs(), and sortBlobsByDecreasingSize().

double* ratios

Definition at line 66 of file redEye_internal.h.

Referenced by findBestTwoBlobs(), and sortBlobsByDecreasingSize().

QImage rawImage

Definition at line 34 of file redEye_internal.h.

Referenced by findBlobs(), findRegionOfInterest(), and removeRedeyeRegions().

Definition at line 47 of file redEye_internal.h.

Referenced by findBlobs(), and pushPixel().

Definition at line 52 of file redEye_internal.h.

Referenced by findBlobs(), IDedPixel(), and pushPixel().

Definition at line 47 of file redEye_internal.h.

Referenced by findBlobs(), IDedPixel(), and pushPixel().

int* sizes

Definition at line 65 of file redEye_internal.h.

Referenced by findBestTwoBlobs(), and sortBlobsByDecreasingSize().

QValueStack<QPoint> spreadablePixels

Definition at line 54 of file redEye_internal.h.

Referenced by findBlobs(), and pushPixel().

QPoint topLeft