00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include <qimage.h>
00013 #include <qstring.h>
00014 #include <qapplication.h>
00015 #include <math.h>
00016
00017
00018 #include "tilt.h"
00019 #include "tilt_internal.h"
00020 #include "../../gui/statusWidget.h"
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100 QImage* correctImageTilt( QString filename, QPoint p1, QPoint p2,
00101 StatusWidget* status)
00102 {
00103
00104 int dx = p2.x() - p1.x();
00105 int dy = p2.y() - p1.y();
00106
00107
00108 int delta = 0;
00109
00110
00111 double recip_r = 1.0 / sqrt( (double) (dx*dx + dy*dy) );
00112
00113
00114 if( QABS(dx) > QABS(dy) )
00115 {
00116 delta = dy;
00117 if(dx > 0) delta = -delta;
00118 }
00119
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
00131 if( theta == 0 )
00132 return NULL;
00133
00134
00135 QImage originalImage( filename );
00136 QImage rotatedImage( originalImage.width(), originalImage.height(), originalImage.depth() );
00137
00138
00139 QString statusMessage = qApp->translate( "correctImageTilt", "Correcting Tilt:" );
00140 status->showProgressBar( statusMessage, 200 );
00141 qApp->processEvents();
00142
00143
00144 int updateIncrement = (int) ( 0.01 * originalImage.width() * originalImage.height() );
00145 int newProgress = 0;
00146
00147
00148 double xp, yp;
00149
00150 double w2 = 0.5 * rotatedImage.width();
00151 double h2 = 0.5 * rotatedImage.height();
00152
00153 int x,y;
00154 uchar* scanLine;
00155 QRgb* rgb;
00156 for( y=0; y<rotatedImage.height(); y++)
00157 {
00158
00159 scanLine = rotatedImage.scanLine(y);
00160 for( x=0; x<rotatedImage.width(); x++)
00161 {
00162
00163 xp = cosTheta*(x-w2) + sinTheta*(y-h2) + w2;
00164 yp = -sinTheta*(x-w2) + cosTheta*(y-h2) + h2;
00165
00166
00167 rgb = ((QRgb*)scanLine+x);
00168 *rgb = interpolatedPixelValue( xp, yp, &originalImage);
00169
00170
00171 newProgress++;
00172 if(newProgress >= updateIncrement)
00173 {
00174 newProgress = 0;
00175 status->incrementProgress();
00176 qApp->processEvents();
00177 }
00178
00179 }
00180 }
00181
00182
00183 double nTheta = -theta;
00184 double sinNTheta = sin( nTheta );
00185 double cosNTheta = cos( nTheta );
00186
00187 DPoint topLeft = DPoint( cosNTheta*(-w2) + sinNTheta*(-h2) + w2,
00188 -sinNTheta*(-w2) + cosNTheta*(-h2) + h2 );
00189
00190 DPoint topRight = DPoint( cosNTheta*(w2) + sinNTheta*(-h2) + w2,
00191 -sinNTheta*(w2) + cosNTheta*(-h2) + h2 );
00192
00193 DPoint bottomLeft = DPoint( cosNTheta*(-w2) + sinNTheta*(h2) + w2,
00194 -sinNTheta*(-w2) + cosNTheta*(h2) + h2 );
00195
00196 DPoint bottomRight = DPoint( cosNTheta*(w2) + sinNTheta*(h2) + w2,
00197 -sinNTheta*(w2) + cosNTheta*(h2) + h2 );
00198
00199
00200 DPoint top, bottom, left, right;
00201 if( theta < 0 )
00202 {
00203 top = topRight;
00204 bottom = bottomLeft;
00205 left = topLeft;
00206 right = bottomRight;
00207 }
00208 else
00209 {
00210 top = topLeft;
00211 bottom = bottomRight;
00212 left = bottomLeft;
00213 right = topRight;
00214 }
00215
00216
00217 DPoint trueTopLeft ( 0, 0 );
00218 DPoint trueTopRight ( rotatedImage.width()-1, 0 );
00219 DPoint trueBottomLeft ( 0, rotatedImage.height()-1 );
00220 DPoint trueBottomRight( rotatedImage.width()-1, rotatedImage.height()-1 );
00221
00222
00223 DPoint topEdgeL = findTwoLineIntersection( left, top, trueTopLeft, trueTopRight );
00224 DPoint topEdgeR = findTwoLineIntersection( top, right, trueTopLeft, trueTopRight );
00225
00226 DPoint bottomEdgeL = findTwoLineIntersection( left, bottom, trueBottomLeft, trueBottomRight );
00227 DPoint bottomEdgeR = findTwoLineIntersection( bottom, right, trueBottomLeft, trueBottomRight );
00228
00229 DPoint leftEdgeT = findTwoLineIntersection( left, top, trueTopLeft, trueBottomLeft );
00230 DPoint leftEdgeB = findTwoLineIntersection( left, bottom, trueTopLeft, trueBottomLeft );
00231
00232 DPoint rightEdgeT = findTwoLineIntersection( right, top, trueTopRight, trueBottomRight );
00233 DPoint rightEdgeB = findTwoLineIntersection( right, bottom, trueTopRight, trueBottomRight );
00234
00235
00236 DPoint center( (int)w2, (int)h2 );
00237 DPoint safeTopLeft = findTwoLineIntersection( center, trueTopLeft, leftEdgeT, topEdgeL );
00238 DPoint safeTopRight = findTwoLineIntersection( center, trueTopRight, rightEdgeT, topEdgeR );
00239 DPoint safeBottomLeft = findTwoLineIntersection( center, trueBottomLeft, leftEdgeB, bottomEdgeL );
00240 DPoint safeBottomRight = findTwoLineIntersection( center, trueBottomRight, rightEdgeB, bottomEdgeR );
00241
00242
00243 double minY = QMAX( safeTopLeft.y(), safeTopRight.y() );
00244 double maxY = QMIN( safeBottomLeft.y(), safeBottomRight.y() );
00245
00246 double minX = QMAX( safeTopLeft.x(), safeBottomLeft.x() );
00247 double maxX = QMIN( safeTopRight.x(), safeBottomRight.x() );
00248
00249
00250
00251
00252 int xMin = (int) minX;
00253 int xMax = (int) maxX;
00254
00255 int yMin = (int) minY;
00256 int yMax = (int) maxY;
00257
00258 if( xMin < minX ) xMin++;
00259 if( yMin < minY ) yMin++;
00260
00261
00262 QImage* editedImage = new QImage( xMax - xMin + 1,
00263 yMax - yMin + 1,
00264 rotatedImage.depth() );
00265
00266
00267 updateIncrement = (int) ( 0.01 * editedImage->width() * editedImage->height() );
00268 newProgress = 0;
00269
00270 int x2,y2;
00271 uchar* scanLine2;
00272 QRgb* rgb2;
00273
00274 y2 = 0;
00275 for( y=yMin; y<=yMax; y++, y2++)
00276 {
00277
00278 scanLine = rotatedImage.scanLine(y);
00279 scanLine2 = editedImage->scanLine(y2);
00280
00281 x2 = 0;
00282 for( x=xMin; x<=xMax; x++, x2++)
00283 {
00284 rgb = ((QRgb*)scanLine +x );
00285 rgb2 = ((QRgb*)scanLine2+x2);
00286 *rgb2 = *rgb;
00287
00288
00289 newProgress++;
00290 if(newProgress >= updateIncrement)
00291 {
00292 newProgress = 0;
00293 status->incrementProgress();
00294 qApp->processEvents();
00295 }
00296
00297 }
00298 }
00299
00300
00301 status->setStatus( "" );
00302 qApp->processEvents();
00303
00304
00305 return editedImage;
00306 }
00307
00308 QRgb interpolatedPixelValue( double xp, double yp,
00309 QImage* image )
00310 {
00311
00312
00313 if(xp < 0 || xp >= image->width() ||
00314 yp < 0 || yp >= image->height() )
00315 return qRgb( 0, 0, 0 );
00316
00317
00318 int x = (int)xp;
00319 int y = (int)yp;
00320
00321 uchar* scanLine1 = image->scanLine( y );
00322
00323 uchar* scanLine2;
00324 if( y < image->height() - 1 )
00325 scanLine2 = image->scanLine( y+1 );
00326 else
00327 scanLine2 = scanLine1;
00328
00329 QRgb p1,p2,p3,p4;
00330
00331 p1 = *((QRgb*)scanLine1+x);
00332 p3 = *((QRgb*)scanLine2+x);
00333
00334 if( x < image->width() - 1)
00335 {
00336 p2 = *((QRgb*)scanLine1+x+1);
00337 p4 = *((QRgb*)scanLine2+x+1);
00338 }
00339 else
00340 {
00341 p2 = p1;
00342 p4 = p3;
00343 }
00344
00345
00346 double alphaY = yp - y;
00347 double alphaX = xp - x;
00348
00349 p1 = blendColors( p1, p2, alphaX );
00350 p3 = blendColors( p3, p4, alphaX );
00351 p1 = blendColors( p1, p3, alphaY );
00352 return p1;
00353 }
00354
00355 QRgb blendColors( QRgb color1, QRgb color2, double alpha )
00356 {
00357 double alpha2 = 1.0-alpha;
00358 return qRgb( (int) QMAX( QMIN( 255, alpha2*qRed (color1) + alpha*qRed(color2) ), 0 ),
00359 (int) QMAX( QMIN( 255, alpha2*qGreen(color1) + alpha*qGreen(color2) ), 0 ),
00360 (int) QMAX( QMIN( 255, alpha2*qBlue (color1) + alpha*qBlue(color2) ), 0 ) );
00361 }
00362
00363 DPoint findTwoLineIntersection(DPoint p1, DPoint p2,
00364 DPoint p3, DPoint p4)
00365 {
00366
00367
00368
00369
00370
00371 if(p1.x() == p2.x() &&
00372 p4.x() == p3.x())
00373 {
00374
00375
00376
00377
00378
00379 if( p1.x() == p3.x() )
00380 { return DPoint( p1.x(), p1.y() ); }
00381
00382
00383 else
00384 { return DPoint( -32000, -32000 ); }
00385 }
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396 else if( p1.x() == p2.x() )
00397 {
00398 double slopeB = ((double) (p4.y() - p3.y()) ) / (p4.x() - p3.x());
00399
00400 double yInterceptB = p3.y() - slopeB*p3.x();
00401
00402
00403 return DPoint( p2.x(), slopeB*p2.x() + yInterceptB );
00404 }
00405
00406
00407
00408
00409
00410 else if( p4.x() == p3.x() )
00411 {
00412 double slopeA = ((double) (p2.y() - p1.y()) ) / (p2.x() - p1.x());
00413
00414 double yInterceptA = p1.y() - slopeA*p1.x();
00415
00416
00417 return DPoint( p4.x(), slopeA*p4.x() + yInterceptA );
00418 }
00419
00420
00421
00422 else
00423 {
00424 double slopeA = ((double) (p2.y() - p1.y()) ) / (p2.x() - p1.x());
00425 double slopeB = ((double) (p4.y() - p3.y()) ) / (p4.x() - p3.x());
00426 double yInterceptA = p1.y() - slopeA*p1.x();
00427 double yInterceptB = p3.y() - slopeB*p3.x();
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438 double x = (yInterceptB - yInterceptA) / (slopeA - slopeB);
00439 return DPoint( x, (slopeA * x) + yInterceptA );
00440 }
00441 }
00442
00443 DPoint::DPoint()
00444 { xpos=0; ypos=0; }
00445
00446 DPoint::DPoint( double x, double y )
00447 {
00448 this->xpos = x;
00449 this->ypos = y;
00450 }
00451
00452 double DPoint::x() const { return xpos; }
00453 double DPoint::y() const { return ypos; }
00454
00455
00456