00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include <qimage.h>
00013 #include <qstring.h>
00014 #include <math.h>
00015
00016
00017 #include "blur.h"
00018
00019 void computeCoeffs( float sigma );
00020 void fillBuffer( QImage &image, int channel );
00021 void blurBuffer();
00022
00023 void blurRow( int row );
00024 void blurColumn( int column );
00025
00026 void blurRegionsInRow( int y );
00027 void blurRegionsInCol( int x );
00028
00029 void resetImageData( QImage &image, int channel, bool blurEdges);
00030
00031 float edgeValue(int x, int y);
00032
00033 float q, b0, b1, b2, b3, B;
00034 int width, height;
00035 float* buffer;
00036 float* rowBuffer;
00037 float* colBuffer;
00038
00039 float* regionRowBuffer;
00040 float* regionColBuffer;
00041
00042 QImage* edgeImage;
00043 int* regionMap;
00044 int regionCount;
00045 QPoint displayOffset;
00046 QSize fullRes;
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 void blurImage( QImage &image, float sigma )
00095 {
00096
00097
00098 blurImage( image, sigma, QPoint(0,0), image.size(), NULL, NULL, 0, false );
00099 }
00100
00101 void blurImage( QImage &image, float sigma,
00102 QPoint offset, QSize fullImageRes,
00103 QImage* edges, int* regions, int numRegions,
00104 bool targetEdges)
00105 {
00106 edgeImage = edges;
00107 regionMap = regions;
00108 regionCount = numRegions;
00109 displayOffset = offset;
00110 fullRes = fullImageRes;
00111
00112
00113 computeCoeffs(sigma);
00114
00115
00116 width = image.width();
00117 height = image.height();
00118
00119
00120
00121
00122 buffer = new float[ width * height ];
00123
00124 rowBuffer = new float[width];
00125 colBuffer = new float[height];
00126
00127 regionRowBuffer = new float[width * numRegions];
00128 regionColBuffer = new float[height * numRegions];
00129
00130
00131 int channel;
00132 for( channel = 0; channel <=2; channel++)
00133 {
00134
00135 fillBuffer( image, channel );
00136
00137
00138 blurBuffer();
00139
00140
00141 resetImageData(image, channel, targetEdges);
00142 }
00143
00144
00145 delete[] buffer;
00146 delete[] rowBuffer;
00147 delete[] colBuffer;
00148 }
00149
00150 void computeCoeffs( float sigma )
00151 {
00152
00153 if( sigma >= 2.5f )
00154 {
00155 q = 0.98711f*sigma - 0.96330f;
00156 }
00157 else
00158 {
00159 q = 3.97156f - 4.14554f * sqrt( 1.0f - 0.26891f*sigma );
00160 }
00161
00162
00163 b0 = 1.57825f + (2.44413f*q) + (1.4281f * q*q ) + (0.422205f * q*q*q );
00164 b1 = (2.44413f * q) + (2.85619f * q*q) + (1.26661 * q*q*q );
00165 b2 = -((1.4281 * q*q) + (1.26661 * q*q*q));
00166 b3 = 0.422205 * q*q*q;
00167
00168
00169 B = 1.0f - ((b1 + b2 + b3) / b0);
00170 }
00171
00172 void fillBuffer( QImage &image, int channel )
00173 {
00174
00175 float multiplier = 1.0f / 255.0f;
00176
00177
00178 int x, y;
00179 QRgb* rgb;
00180 uchar* scanLine;
00181 for( y=0; y<image.height(); y++)
00182 {
00183
00184 scanLine = image.scanLine(y);
00185 for( x=0; x<image.width(); x++)
00186 {
00187
00188 rgb = ((QRgb*)scanLine+x);
00189
00190
00191 int index = x + y*image.width();
00192
00193
00194 if( channel == 0 )
00195 buffer[index] = multiplier * qRed( *rgb );
00196 else if( channel == 1 )
00197 buffer[index] = multiplier * qGreen( *rgb );
00198 else
00199 buffer[index] = multiplier * qBlue( *rgb );
00200 }
00201 }
00202 }
00203
00204 void blurBuffer()
00205 {
00206
00207 int index;
00208
00209 if(regionMap == NULL || edgeImage == NULL )
00210 {
00211 for(index=0; index < height; index++)
00212 { blurRow( index ); }
00213
00214 for(index=0; index< width; index++)
00215 { blurColumn( index ); }
00216 }
00217 else
00218 {
00219 for(index=0; index < height; index++)
00220 { blurRegionsInRow( index ); }
00221
00222 for(index=0; index< width; index++)
00223 { blurRegionsInCol( index ); }
00224 }
00225 }
00226
00227 int regionIndex(int x, int y)
00228 {
00229 int edgeX = ((edgeImage->width()-1) * (x+displayOffset.x())) / (fullRes.width()-1);
00230 int edgeY = ((edgeImage->height()-1) * (y+displayOffset.y())) / (fullRes.height()-1);
00231 return edgeY*edgeImage->width() + edgeX;
00232 }
00233
00234 float edgeValue(int x, int y)
00235 {
00236
00237 float edgeX = ((edgeImage->width()-1.0f) * (x+displayOffset.x())) / (fullRes.width()-1);
00238 float edgeY = ((edgeImage->height()-1.0f) * (y+displayOffset.y())) / (fullRes.height()-1);
00239
00240
00241 int x1 = (int)edgeX;
00242 int y1 = (int)edgeY;
00243 int x2, y2;
00244 if( edgeX > x1 )
00245 x2 = x1+1;
00246 else
00247 x2 = x1;
00248 if( edgeY > y1 )
00249 y2 = y1+1;
00250 else
00251 y2 = y1;
00252
00253
00254 int index1, index2, index3, index4;
00255 index1 = x1 + y1*edgeImage->width();
00256 index2 = x2 + y1*edgeImage->width();
00257 index3 = x1 + y2*edgeImage->width();
00258 index4 = x2 + y2*edgeImage->width();
00259
00260
00261 float v1, v2, v3, v4;
00262 uchar* scanline = edgeImage->scanLine( y1 );
00263 QRgb* rgb = ((QRgb*)scanline+x1);
00264 v1 = ((float) qRed( *rgb )) / 255.0f;
00265 rgb = ((QRgb*)scanline+x2);
00266 v2 = ((float) qRed( *rgb )) / 255.0f;
00267
00268 scanline = edgeImage->scanLine( y2 );
00269 rgb = ((QRgb*)scanline+x1);
00270 v3 = ((float) qRed( *rgb )) / 255.0f;
00271 rgb = ((QRgb*)scanline+x2);
00272 v4 = ((float) qRed( *rgb )) / 255.0f;
00273
00274
00275 v1 = (edgeX-x1)*v2 + (1 - edgeX + x1)*v1;
00276 v3 = (edgeX-x1)*v4 + (1 - edgeX + x1)*v3;
00277
00278
00279 v1 = (edgeY-y1)*v3 + (1 - edgeY + y1)*v1;
00280
00281
00282 return v1;
00283 }
00284
00285 void blurRow( int row )
00286 {
00287 int i;
00288 int rtw = row*width;
00289
00290
00291 rowBuffer[0] = buffer[ 0 + rtw ];
00292 for(i=1; i<width; i++)
00293 {
00294 rowBuffer[i] = B*buffer[ i + rtw ] +
00295 ( b1*rowBuffer[ QMAX(i-1, 0) ] +
00296 b2 * rowBuffer[ QMAX(i-2, 0) ] +
00297 b3 * rowBuffer[ QMAX(i-3, 0) ]) / b0;
00298
00299 }
00300
00301
00302 for(i=width-1; i>=0; i--)
00303 {
00304 buffer[ i + rtw ] = B*rowBuffer[ i ] +
00305 ( b1 * buffer[ QMIN(i+1, width-1) + rtw ] +
00306 b2 * buffer[ QMIN(i+2, width-1) + rtw ] +
00307 b3 * buffer[ QMIN(i+3, width-1) + rtw ]) / b0;
00308 }
00309 }
00310
00311 void blurRegionsInRow( int y )
00312 {
00313
00314
00315
00316
00317 int yTimesWidth = y*width;
00318 int regionTimesWidth;
00319 int region,x,x2;
00320
00321
00322 for(region=0; region<regionCount; region++)
00323 {
00324 regionTimesWidth = region*width;
00325 int lastX = -1;
00326 for(x=0; x<width; x++)
00327 {
00328
00329
00330 if( region == regionMap[regionIndex(x, y)] )
00331 {
00332
00333 if( lastX < x-1)
00334 {
00335
00336 if(lastX == -1)
00337 {
00338 for(x2=0; x2<x; x2++) { regionRowBuffer[x2 + regionTimesWidth] = buffer[x + yTimesWidth]; }
00339 }
00340
00341 else
00342 {
00343 int xMid = lastX + ((x-1) - lastX)/2;
00344
00345 for(x2=lastX+1; x2<=xMid; x2++)
00346 { regionRowBuffer[x2 + regionTimesWidth] = buffer[lastX + yTimesWidth]; }
00347
00348 for(x2=xMid+1; x2<x; x2++)
00349 { regionRowBuffer[x2 + regionTimesWidth] = buffer[x + yTimesWidth]; }
00350 }
00351 }
00352
00353 regionRowBuffer[x + regionTimesWidth] = buffer[x + yTimesWidth];
00354 lastX = x;
00355 }
00356 }
00357
00358
00359 if( region != regionMap[regionIndex(width-1, y)] )
00360 {
00361 for(x2=lastX+1; x2<width; x2++)
00362 { regionRowBuffer[x2 + regionTimesWidth] = buffer[lastX + yTimesWidth]; }
00363 }
00364
00365 }
00366
00367
00368
00369
00370 for(region=0; region<regionCount; region++)
00371 {
00372 regionTimesWidth = region*width;
00373
00374
00375 rowBuffer[0] = regionRowBuffer[ 0 + regionTimesWidth ];
00376 for(x=1; x<width; x++)
00377 {
00378 rowBuffer[x] = B*regionRowBuffer[ x + regionTimesWidth ] +
00379 ( b1*rowBuffer[ QMAX(x-1, 0) ] +
00380 b2 * rowBuffer[ QMAX(x-2, 0) ] +
00381 b3 * rowBuffer[ QMAX(x-3, 0) ]) / b0;
00382 }
00383
00384
00385 for(x=width-1; x>=0; x--)
00386 {
00387 regionRowBuffer[ x + regionTimesWidth ] = B*rowBuffer[ x ] +
00388 ( b1 * regionRowBuffer[ QMIN(x+1, width-1) + regionTimesWidth ] +
00389 b2 * regionRowBuffer[ QMIN(x+2, width-1) + regionTimesWidth ] +
00390 b3 * regionRowBuffer[ QMIN(x+3, width-1) + regionTimesWidth ]) / b0;
00391 }
00392 }
00393
00394
00395
00396
00397 for(x=0; x<width; x++)
00398 {
00399 int ri = regionIndex(x,y);
00400 int region = regionMap[ri];
00401 float bufferVal = regionRowBuffer[ x + region*width ];
00402 buffer[x + yTimesWidth] = bufferVal;
00403
00404
00405 }
00406
00407 }
00408
00409 void blurColumn( int column )
00410 {
00411 int i;
00412
00413
00414 colBuffer[0] = buffer[ column + 0*width ];
00415 for(i=1; i<height; i++)
00416 {
00417 colBuffer[i] = B*buffer[ column + i*width ] +
00418 ( b1 * colBuffer[ QMAX(i-1, 0) ] +
00419 b2 * colBuffer[ QMAX(i-2, 0) ] +
00420 b3 * colBuffer[ QMAX(i-3, 0) ]) / b0;
00421 }
00422
00423
00424 for(i=height-1; i>=0; i--)
00425 {
00426 buffer[ column + i*width ] = B*colBuffer[ i ] +
00427 ( b1 * buffer[ column + QMIN(i+1, height-1)*width ] +
00428 b2 * buffer[ column + QMIN(i+2, height-1)*width ] +
00429 b3 * buffer[ column + QMIN(i+3, height-1)*width ]) / b0;
00430 }
00431
00432 }
00433
00434 void blurRegionsInCol( int x )
00435 {
00436
00437
00438
00439
00440
00441 int regionTimesHeight;
00442 int region,y,y2;
00443
00444
00445 for(region=0; region<regionCount; region++)
00446 {
00447 regionTimesHeight = region*height;
00448 int lastY = -1;
00449 for(y=0; y<height; y++)
00450 {
00451
00452
00453 if( region == regionMap[regionIndex(x, y)] )
00454 {
00455
00456 if( lastY < y-1)
00457 {
00458
00459 if(lastY == -1)
00460 {
00461 for(y2=0; y2<y; y2++) { regionColBuffer[y2 + regionTimesHeight] = buffer[x + y*width]; }
00462 }
00463
00464 else
00465 {
00466 int yMid = lastY + ((y-1) - lastY)/2;
00467
00468 for(y2=lastY+1; y2<=yMid; y2++)
00469 { regionColBuffer[y2 + regionTimesHeight] = buffer[x + lastY*width]; }
00470
00471 for(y2=yMid+1; y2<y; y2++)
00472 { regionColBuffer[y2 + regionTimesHeight] = buffer[x + y*width]; }
00473 }
00474 }
00475
00476 regionColBuffer[y + regionTimesHeight] = buffer[x + y*width];
00477 lastY = y;
00478 }
00479 }
00480
00481
00482 if( region != regionMap[regionIndex(x, height-1)] )
00483 {
00484 for(y2=lastY+1; y2<height; y2++)
00485 { regionColBuffer[y2 + regionTimesHeight] = buffer[x + lastY*width]; }
00486 }
00487
00488 }
00489
00490
00491
00492
00493 for(region=0; region<regionCount; region++)
00494 {
00495 regionTimesHeight = region*height;
00496
00497
00498 colBuffer[0] = regionColBuffer[ 0 + regionTimesHeight ];
00499 for(y=1; y<height; y++)
00500 {
00501 colBuffer[y] = B*regionColBuffer[ y + regionTimesHeight ] +
00502 ( b1 * colBuffer[ QMAX(y-1, 0) ] +
00503 b2 * colBuffer[ QMAX(y-2, 0) ] +
00504 b3 * colBuffer[ QMAX(y-3, 0) ]) / b0;
00505 }
00506
00507
00508 for(y=height-1; y>=0; y--)
00509 {
00510 regionColBuffer[ y + regionTimesHeight ] = B*colBuffer[ y ] +
00511 ( b1 * regionColBuffer[ QMIN(y+1, height-1) + regionTimesHeight ] +
00512 b2 * regionColBuffer[ QMIN(y+2, height-1) + regionTimesHeight ] +
00513 b3 * regionColBuffer[ QMIN(y+3, height-1) + regionTimesHeight ]) / b0;
00514 }
00515 }
00516
00517
00518
00519
00520 for(y=0; y<height; y++)
00521 {
00522 buffer[x + y*width] = regionColBuffer[y + regionMap[regionIndex(x,y)]*height];
00523 }
00524
00525 }
00526
00527 void resetImageData( QImage &image, int channel, bool blurEdges)
00528 {
00529
00530 int x, y;
00531 QRgb *rgb;
00532 uchar* imageScanline = NULL;
00533 for( y=0; y<image.height(); y++)
00534 {
00535 imageScanline = image.scanLine(y);
00536 for( x=0; x<image.width(); x++)
00537 {
00538
00539 rgb = ((QRgb*)imageScanline+x);
00540
00541
00542 int index = x + y*image.width();
00543
00544
00545 int blurredColor = QMAX( QMIN( ((int) (255*buffer[index])), 255 ), 0 );
00546
00547
00548 float alpha;
00549 if( edgeImage == NULL)
00550 alpha = 1.0f;
00551 else
00552 {
00553 alpha = edgeValue( x, y );
00554 if(!blurEdges)
00555 alpha = 1.0f - alpha;
00556 }
00557
00558
00559 if( channel == 0 )
00560 *rgb = qRgb( (int) (alpha*blurredColor + (1-alpha)*qRed(*rgb)),
00561 qGreen(*rgb), qBlue(*rgb) );
00562 else if( channel == 1 )
00563 *rgb = qRgb( qRed(*rgb),
00564 (int) (alpha*blurredColor + (1-alpha)*qGreen(*rgb)),
00565 qBlue(*rgb) );
00566 else
00567 *rgb = qRgb( qRed(*rgb), qGreen(*rgb),
00568 (int) (alpha*blurredColor + (1-alpha)*qBlue(*rgb)) );
00569 }
00570 }
00571 }
00572