Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Class Members | File Members

tilt.cpp File Reference

#include <qimage.h>
#include <qstring.h>
#include <qapplication.h>
#include <math.h>
#include "tilt.h"
#include "tilt_internal.h"
#include "../../gui/statusWidget.h"

Include dependency graph for tilt.cpp:

Include dependency graph

Go to the source code of this file.

Functions

QImage * correctImageTilt (QString filename, QPoint p1, QPoint p2, StatusWidget *status)
QRgb interpolatedPixelValue (double xp, double yp, QImage *image)
QRgb blendColors (QRgb color1, QRgb color2, double alpha)
DPoint findTwoLineIntersection (DPoint p1, DPoint p2, DPoint p3, DPoint p4)


Function Documentation

QRgb blendColors QRgb  color1,
QRgb  color2,
double  alpha
 

Definition at line 359 of file tilt.cpp.

Referenced by interpolatedPixelValue().

00360 {
00361   double alpha2 = 1.0-alpha;
00362   return qRgb( (int) QMAX( QMIN( 255, alpha2*qRed  (color1) + alpha*qRed(color2)   ), 0 ),
00363                (int) QMAX( QMIN( 255, alpha2*qGreen(color1) + alpha*qGreen(color2) ), 0 ),
00364                (int) QMAX( QMIN( 255, alpha2*qBlue (color1) + alpha*qBlue(color2)  ), 0 ) );
00365 }

QImage* correctImageTilt QString  filename,
QPoint  p1,
QPoint  p2,
StatusWidget status
 

Definition at line 100 of file tilt.cpp.

References bottomRight, editedImage, findTwoLineIntersection(), StatusWidget::incrementProgress(), interpolatedPixelValue(), newProgress, StatusWidget::setStatus(), StatusWidget::showProgressBar(), status, topLeft, updateIncrement, DPoint::x(), and DPoint::y().

Referenced by EditingInterface::finishCorrectTilt().

00102 {
00103   //first compute distance between two points or "radius"
00104   int dx = p2.x() - p1.x();
00105   int dy = p2.y() - p1.y();
00106   
00107   //determine tilt angle
00108   int delta = 0;
00109   
00110   //compute recirpocal of distance between points
00111   double recip_r = 1.0 / sqrt( (double) (dx*dx + dy*dy) );
00112   
00113   //compute angle with horizontal axis
00114   if( QABS(dx) > QABS(dy) )
00115   {
00116     delta = dy;
00117     if(dx > 0) delta = -delta;
00118   }
00119   //compute angle with vertical axis
00120   else
00121   {
00122     delta = dx;
00123     if(dy < 0) delta = -delta;
00124   }
00125   
00126   double sinTheta = (delta * recip_r);
00127   double theta = asin( sinTheta );
00128   double cosTheta = cos( theta );
00129   
00130   //if angle is 0 (improbable but possible) then quit now
00131   if( theta == 0 )
00132     return NULL;
00133   
00134   //load original and edited images
00135   QImage originalImage( filename );
00136   
00137   //convert to 32-bit depth if necessary
00138   if( originalImage.depth() < 32 ) { originalImage = originalImage.convertDepth( 32, Qt::AutoColor ); }
00139   
00140   QImage rotatedImage( originalImage.width(), originalImage.height(), originalImage.depth() );
00141   
00142   //setup progress bar
00143   QString statusMessage = qApp->translate( "correctImageTilt", "Correcting Tilt:" );
00144   status->showProgressBar( statusMessage, 200 );
00145   qApp->processEvents();  
00146   
00147   //during the first phase update the status bar for every 1% of image pixels that are processed
00148   int updateIncrement = (int) ( 0.01 * originalImage.width() * originalImage.height() );
00149   int newProgress = 0;
00150   
00151   //set each pixel to the rotated value
00152   double xp, yp;
00153   
00154   double w2 = 0.5 * rotatedImage.width();
00155   double h2 = 0.5 * rotatedImage.height();
00156   
00157   int x,y;
00158   uchar* scanLine;
00159   QRgb* rgb;
00160   for( y=0; y<rotatedImage.height(); y++)
00161   {   
00162     //iterate over each selected pixel in scanline
00163     scanLine = rotatedImage.scanLine(y);
00164     for( x=0; x<rotatedImage.width(); x++)
00165     {
00166       //compute unrotated coordinates
00167       xp = cosTheta*(x-w2) + sinTheta*(y-h2) + w2;
00168       yp = -sinTheta*(x-w2) + cosTheta*(y-h2) + h2;
00169 
00170       //set unrotated value
00171       rgb = ((QRgb*)scanLine+x);
00172       *rgb = interpolatedPixelValue( xp, yp, &originalImage);
00173 
00174       //update status bar if significant progress has been made since last update
00175       newProgress++;
00176       if(newProgress >= updateIncrement)
00177       {
00178         newProgress = 0;
00179         status->incrementProgress();
00180         qApp->processEvents();  
00181       }
00182       
00183     }
00184   }
00185   
00186   //find rotated corners
00187   double nTheta = -theta;
00188   double sinNTheta = sin( nTheta );
00189   double cosNTheta = cos( nTheta );
00190   
00191   DPoint topLeft = DPoint( cosNTheta*(-w2) + sinNTheta*(-h2) + w2,
00192                            -sinNTheta*(-w2) + cosNTheta*(-h2) + h2 );
00193 
00194   DPoint topRight = DPoint( cosNTheta*(w2) + sinNTheta*(-h2) + w2,                           
00195                             -sinNTheta*(w2) + cosNTheta*(-h2) + h2 );
00196   
00197   DPoint bottomLeft = DPoint( cosNTheta*(-w2) + sinNTheta*(h2) + w2,                           
00198                               -sinNTheta*(-w2) + cosNTheta*(h2) + h2 );
00199   
00200   DPoint bottomRight = DPoint( cosNTheta*(w2) + sinNTheta*(h2) + w2,                           
00201                                -sinNTheta*(w2) + cosNTheta*(h2) + h2 );
00202   
00203   //determine which of these points are which in their rotated form
00204   DPoint top, bottom, left, right;
00205   if( theta < 0 )
00206   {
00207     top = topRight;
00208     bottom = bottomLeft;
00209     left = topLeft;
00210     right = bottomRight;
00211   }
00212   else
00213   {
00214     top = topLeft;
00215     bottom = bottomRight;    
00216     left = bottomLeft;
00217     right = topRight;
00218   }
00219   
00220   //construct true corners
00221   DPoint trueTopLeft    ( 0, 0 );
00222   DPoint trueTopRight   ( rotatedImage.width()-1, 0 );
00223   DPoint trueBottomLeft ( 0, rotatedImage.height()-1 );
00224   DPoint trueBottomRight( rotatedImage.width()-1, rotatedImage.height()-1 );
00225   
00226   //find intersections with image boundary
00227   DPoint topEdgeL = findTwoLineIntersection( left, top, trueTopLeft, trueTopRight );
00228   DPoint topEdgeR = findTwoLineIntersection( top, right, trueTopLeft, trueTopRight );
00229                                             
00230   DPoint bottomEdgeL = findTwoLineIntersection( left, bottom, trueBottomLeft, trueBottomRight );
00231   DPoint bottomEdgeR = findTwoLineIntersection( bottom, right, trueBottomLeft, trueBottomRight );
00232 
00233   DPoint leftEdgeT = findTwoLineIntersection( left, top, trueTopLeft, trueBottomLeft );
00234   DPoint leftEdgeB = findTwoLineIntersection( left, bottom, trueTopLeft, trueBottomLeft );
00235     
00236   DPoint rightEdgeT = findTwoLineIntersection( right, top, trueTopRight, trueBottomRight );
00237   DPoint rightEdgeB = findTwoLineIntersection( right, bottom, trueTopRight, trueBottomRight );
00238   
00239   //shot rays out from image center to each true corner and find intersections with clipped corners
00240   DPoint center( (int)w2, (int)h2 );
00241   DPoint safeTopLeft     = findTwoLineIntersection( center, trueTopLeft, leftEdgeT, topEdgeL );
00242   DPoint safeTopRight    = findTwoLineIntersection( center, trueTopRight, rightEdgeT, topEdgeR );
00243   DPoint safeBottomLeft  = findTwoLineIntersection( center, trueBottomLeft, leftEdgeB, bottomEdgeL );
00244   DPoint safeBottomRight = findTwoLineIntersection( center, trueBottomRight, rightEdgeB, bottomEdgeR );
00245   
00246   //find constrained area
00247   double minY = QMAX( safeTopLeft.y(), safeTopRight.y() );
00248   double maxY = QMIN( safeBottomLeft.y(), safeBottomRight.y() );
00249   
00250   double minX = QMAX( safeTopLeft.x(), safeBottomLeft.x() );
00251   double maxX = QMIN( safeTopRight.x(), safeBottomRight.x() );
00252 
00253   //find contrained area in integer coordinates. this is semi-tricky.
00254   //if the minimum values decimal porition is nonzero then increment by one 
00255   // (eg 5.37 -> 6)
00256   int xMin = (int) minX;
00257   int xMax = (int) maxX;
00258   
00259   int yMin = (int) minY;
00260   int yMax = (int) maxY;
00261   
00262   if( xMin < minX ) xMin++;
00263   if( yMin < minY ) yMin++;
00264   
00265   //construct cropped rotated image
00266   QImage* editedImage = new QImage( xMax - xMin + 1,
00267                                     yMax - yMin + 1,
00268                                     rotatedImage.depth() );    
00269 
00270   //during the second phase update the status bar for every 1% of cropped pixels that are procesed
00271   updateIncrement = (int) ( 0.01 * editedImage->width() * editedImage->height() );
00272   newProgress = 0;
00273   
00274   int x2,y2;
00275   uchar* scanLine2;
00276   QRgb* rgb2;
00277 
00278   y2 = 0;
00279   for( y=yMin; y<=yMax; y++, y2++)
00280   {   
00281     //iterate over each selected pixel in scanline
00282     scanLine = rotatedImage.scanLine(y);
00283     scanLine2 = editedImage->scanLine(y2);
00284 
00285     x2 = 0;
00286     for( x=xMin; x<=xMax; x++, x2++)
00287     {
00288       rgb  = ((QRgb*)scanLine +x );
00289       rgb2 = ((QRgb*)scanLine2+x2);
00290       *rgb2 = *rgb;      
00291 
00292       //update status bar if significant progress has been made since last update
00293       newProgress++;
00294       if(newProgress >= updateIncrement)
00295       {
00296         newProgress = 0;
00297         status->incrementProgress();
00298         qApp->processEvents();  
00299       }
00300     
00301     }
00302   }
00303   
00304   //remove status bar
00305   status->setStatus( "" );
00306   qApp->processEvents();  
00307   
00308   //return pointer to edited image
00309   return editedImage;
00310 }

DPoint findTwoLineIntersection DPoint  p1,
DPoint  p2,
DPoint  p3,
DPoint  p4
 

Definition at line 367 of file tilt.cpp.

References DPoint::x(), and DPoint::y().

Referenced by correctImageTilt().

00369 {
00370   //----------------------------------------------
00371   //=== Case 1: neither line has a change in X ===
00372   //----------------------------------------------
00373   //If there is no change in x for both lines, 
00374   //either lines will NEVER or ALWAYS intersect.
00375   if(p1.x() == p2.x() &&
00376      p4.x() == p3.x())
00377   {
00378     //Ok, if their x values are equal, return 
00379     //intersection point as line A's point A.
00380     //Yes, this is a little arbitratry. But 
00381     //theoreticaly this section of code will almost
00382     //never be executed.
00383     if( p1.x() == p3.x() )
00384     { return DPoint( p1.x(), p1.y() ); }
00385     //Else lines will never intersect,
00386     //return pair (-32000,-32000)
00387     else
00388     { return DPoint( -32000, -32000 ); }
00389   } 
00390   //----------------------------------------------
00391   //Else, we know at least one of the lines 
00392   //does NOT have a slope of infinity!!!
00393   //----------------------------------------------
00394   
00395   //----------------------------------------------
00396   //=== Case 2: line A has no change in X      ===
00397   //----------------------------------------------
00398   //If line A has an infinite slope (no change in x)
00399   //we know line B does not have an infinite slope...
00400   else if( p1.x() == p2.x() )
00401   {
00402     double slopeB = ((double) (p4.y() - p3.y()) ) / (p4.x() - p3.x());
00403     
00404     double yInterceptB = p3.y() - slopeB*p3.x();
00405     
00406     //y = mx+b
00407     return DPoint( p2.x(), slopeB*p2.x() + yInterceptB );
00408   }
00409   //----------------------------------------------
00410   //=== Case 3: line B has no change in X      ===
00411   //----------------------------------------------
00412   //If line B has an infinite slope (no change in x)
00413   //we know line A does not have an infinite slope...
00414   else if( p4.x() == p3.x() )
00415   {
00416     double slopeA = ((double) (p2.y() - p1.y()) ) / (p2.x() - p1.x());
00417     
00418     double yInterceptA = p1.y() - slopeA*p1.x();
00419     
00420     //y = mx+b
00421     return DPoint( p4.x(), slopeA*p4.x() + yInterceptA );
00422   }
00423   //----------------------------------------------
00424   //=== Case 4: both lines have non infinite slopes ===
00425   //----------------------------------------------
00426   else
00427   {
00428     double slopeA = ((double) (p2.y() - p1.y()) ) / (p2.x() - p1.x());
00429     double slopeB = ((double) (p4.y() - p3.y()) ) / (p4.x() - p3.x());
00430     double yInterceptA = p1.y() - slopeA*p1.x();
00431     double yInterceptB = p3.y() - slopeB*p3.x();
00432     
00433     //y1 = mx1+b
00434     //y2 = nx2+c
00435     //at intersection y1=y2 and x1 = x2 so...
00436     //mx +b = nx + c
00437     //x(m-n) = c-b
00438     //x = (c-b)/(m-n)
00439     //where m and n are slope and
00440     //b and c are y-intercepts.
00441     //x = (c-b)/(m-n)
00442     double x = (yInterceptB - yInterceptA) / (slopeA - slopeB);
00443     return DPoint( x, (slopeA * x) + yInterceptA );
00444   }
00445 }

QRgb interpolatedPixelValue double  xp,
double  yp,
QImage *  image
 

Definition at line 312 of file tilt.cpp.

References blendColors().

Referenced by correctImageTilt().

00314 {
00315   //do boundary checking to 
00316   //ensure we don't read beyond image boundaries
00317   if(xp < 0 || xp >= image->width() ||
00318      yp < 0 || yp >= image->height() )
00319     return qRgb( 0, 0, 0 );
00320 
00321   //get four pixel colors, 
00322   int x = (int)xp;
00323   int y = (int)yp;
00324   
00325   uchar* scanLine1 = image->scanLine( y );
00326 
00327   uchar* scanLine2;
00328   if( y < image->height() - 1 )
00329     scanLine2 = image->scanLine( y+1 );
00330   else
00331     scanLine2 = scanLine1;
00332   
00333   QRgb p1,p2,p3,p4;
00334   
00335   p1 = *((QRgb*)scanLine1+x);
00336   p3 = *((QRgb*)scanLine2+x);
00337         
00338   if( x < image->width() - 1)
00339   {
00340     p2 = *((QRgb*)scanLine1+x+1);
00341     p4 = *((QRgb*)scanLine2+x+1);     
00342   }
00343   else
00344   {
00345     p2 = p1;
00346     p4 = p3;
00347   }
00348   
00349   //blend four colors
00350   double alphaY = yp - y;
00351   double alphaX = xp - x;
00352   
00353   p1 = blendColors( p1, p2, alphaX );
00354   p3 = blendColors( p3, p4, alphaX );
00355   p1 = blendColors( p1, p3, alphaY );
00356   return p1;
00357 }


Generated on Wed May 4 11:10:52 2005 for AlbumShaper by  doxygen 1.3.9.1