00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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 #include "qimageblitz.h"
00060 #include "private/blitz_p.h"
00061 #include <QString>
00062 #include <QVector>
00063
00064
00065
00066 typedef struct
00067 {
00068 quint32 red, green, blue, alpha;
00069 } IntegerPixel;
00070
00071 typedef struct
00072 {
00073 quint16 red, green, blue, alpha;
00074 } ShortPixel;
00075
00076 typedef struct
00077 {
00078
00079
00080 quint8 red, green, blue, alpha;
00081 } CharPixel;
00082
00083 typedef struct
00084 {
00085 quint32 red, green, blue, alpha;
00086 } HistogramListItem;
00087
00088
00089 bool Blitz::equalize(QImage &img)
00090 {
00091 if(img.isNull())
00092 return(false);
00093
00094 HistogramListItem *histogram;
00095 IntegerPixel *map;
00096 IntegerPixel intensity, high, low;
00097 CharPixel *equalize_map;
00098 int i, count;
00099 QRgb pixel, *dest;
00100 unsigned char r, g, b;
00101
00102 if(img.depth() < 32){
00103 img = img.convertToFormat(img.hasAlphaChannel() ?
00104 QImage::Format_ARGB32 :
00105 QImage::Format_RGB32);
00106 }
00107 count = img.width()*img.height();
00108
00109 map = new IntegerPixel[256];
00110 histogram = new HistogramListItem[256];
00111 equalize_map = new CharPixel[256];
00112
00113
00114 memset(histogram, 0, 256*sizeof(HistogramListItem));
00115 dest = (QRgb *)img.bits();
00116
00117 if(img.format() == QImage::Format_ARGB32_Premultiplied){
00118 for(i=0; i < count; ++i, ++dest){
00119 pixel = BlitzPrivate::convertFromPremult(*dest);
00120 histogram[qRed(pixel)].red++;
00121 histogram[qGreen(pixel)].green++;
00122 histogram[qBlue(pixel)].blue++;
00123 histogram[qAlpha(pixel)].alpha++;
00124 }
00125 }
00126 else{
00127 for(i=0; i < count; ++i){
00128 pixel = *dest++;
00129 histogram[qRed(pixel)].red++;
00130 histogram[qGreen(pixel)].green++;
00131 histogram[qBlue(pixel)].blue++;
00132 histogram[qAlpha(pixel)].alpha++;
00133 }
00134 }
00135
00136
00137 memset(&intensity, 0, sizeof(IntegerPixel));
00138 for(i=0; i < 256; ++i){
00139 intensity.red += histogram[i].red;
00140 intensity.green += histogram[i].green;
00141 intensity.blue += histogram[i].blue;
00142 map[i] = intensity;
00143 }
00144
00145 low = map[0];
00146 high = map[255];
00147 memset(equalize_map, 0, 256*sizeof(CharPixel));
00148 for(i=0; i < 256; ++i){
00149 if(high.red != low.red)
00150 equalize_map[i].red=(unsigned char)
00151 ((255*(map[i].red-low.red))/(high.red-low.red));
00152 if(high.green != low.green)
00153 equalize_map[i].green=(unsigned char)
00154 ((255*(map[i].green-low.green))/(high.green-low.green));
00155 if(high.blue != low.blue)
00156 equalize_map[i].blue=(unsigned char)
00157 ((255*(map[i].blue-low.blue))/(high.blue-low.blue));
00158 }
00159
00160
00161 dest = (QRgb *)img.bits();
00162 if(img.format() == QImage::Format_ARGB32_Premultiplied){
00163 for(i=0; i < count; ++i, ++dest){
00164 pixel = BlitzPrivate::convertFromPremult(*dest);
00165 r = (low.red != high.red) ? equalize_map[qRed(pixel)].red :
00166 qRed(pixel);
00167 g = (low.green != high.green) ? equalize_map[qGreen(pixel)].green :
00168 qGreen(pixel);
00169 b = (low.blue != high.blue) ? equalize_map[qBlue(pixel)].blue :
00170 qBlue(pixel);
00171 *dest = BlitzPrivate::convertToPremult(qRgba(r, g, b, qAlpha(pixel)));
00172 }
00173 }
00174 else{
00175 for(i=0; i < count; ++i){
00176 pixel = *dest;
00177 r = (low.red != high.red) ? equalize_map[qRed(pixel)].red :
00178 qRed(pixel);
00179 g = (low.green != high.green) ? equalize_map[qGreen(pixel)].green :
00180 qGreen(pixel);
00181 b = (low.blue != high.blue) ? equalize_map[qBlue(pixel)].blue :
00182 qBlue(pixel);
00183 *dest++ = qRgba(r, g, b, qAlpha(pixel));
00184 }
00185 }
00186
00187 delete[] histogram;
00188 delete[] map;
00189 delete[] equalize_map;
00190 return(true);
00191 }
00192
00193 bool Blitz::normalize(QImage &img)
00194 {
00195 if(img.isNull())
00196 return(false);
00197
00198 IntegerPixel intensity;
00199 HistogramListItem *histogram;
00200 CharPixel *normalize_map;
00201 ShortPixel high, low;
00202
00203 uint threshold_intensity;
00204 int i, count;
00205 QRgb pixel, *dest;
00206 unsigned char r, g, b;
00207
00208 if(img.depth() < 32){
00209 img = img.convertToFormat(img.hasAlphaChannel() ?
00210 QImage::Format_ARGB32 :
00211 QImage::Format_RGB32);
00212 }
00213 count = img.width()*img.height();
00214
00215 histogram = new HistogramListItem[256];
00216 normalize_map = new CharPixel[256];
00217
00218
00219 memset(histogram, 0, 256*sizeof(HistogramListItem));
00220 dest = (QRgb *)img.bits();
00221
00222 if(img.format() == QImage::Format_ARGB32_Premultiplied){
00223 for(i=0; i < count; ++i, ++dest){
00224 pixel = BlitzPrivate::convertFromPremult(*dest);
00225 histogram[qRed(pixel)].red++;
00226 histogram[qGreen(pixel)].green++;
00227 histogram[qBlue(pixel)].blue++;
00228 histogram[qAlpha(pixel)].alpha++;
00229 }
00230 }
00231 else{
00232 for(i=0; i < count; ++i){
00233 pixel = *dest++;
00234 histogram[qRed(pixel)].red++;
00235 histogram[qGreen(pixel)].green++;
00236 histogram[qBlue(pixel)].blue++;
00237 histogram[qAlpha(pixel)].alpha++;
00238 }
00239 }
00240
00241
00242 threshold_intensity = count/1000;
00243
00244 memset(&intensity, 0, sizeof(IntegerPixel));
00245 for(low.red=0; low.red < 256; ++low.red){
00246 intensity.red += histogram[low.red].red;
00247 if(intensity.red > threshold_intensity)
00248 break;
00249 }
00250 memset(&intensity, 0, sizeof(IntegerPixel));
00251 for(high.red=255; high.red >= 0; --high.red){
00252 intensity.red += histogram[high.red].red;
00253 if(intensity.red > threshold_intensity)
00254 break;
00255 }
00256 memset(&intensity, 0, sizeof(IntegerPixel));
00257 for(low.green=low.red; low.green < high.red; ++low.green){
00258 intensity.green += histogram[low.green].green;
00259 if(intensity.green > threshold_intensity)
00260 break;
00261 }
00262 memset(&intensity, 0, sizeof(IntegerPixel));
00263 for(high.green=high.red; high.green != low.red; --high.green){
00264 intensity.green += histogram[high.green].green;
00265 if(intensity.green > threshold_intensity)
00266 break;
00267 }
00268 memset(&intensity, 0, sizeof(IntegerPixel));
00269 for(low.blue=low.green; low.blue < high.green; ++low.blue){
00270 intensity.blue += histogram[low.blue].blue;
00271 if(intensity.blue > threshold_intensity)
00272 break;
00273 }
00274 memset(&intensity, 0, sizeof(IntegerPixel));
00275 for(high.blue=high.green; high.blue != low.green; --high.blue){
00276 intensity.blue += histogram[high.blue].blue;
00277 if(intensity.blue > threshold_intensity)
00278 break;
00279 }
00280
00281 delete[] histogram;
00282
00283
00284 for(i=0; i < 256; i++){
00285 if(i < low.red)
00286 normalize_map[i].red = 0;
00287 else{
00288 if(i > high.red)
00289 normalize_map[i].red = 255;
00290 else if(low.red != high.red)
00291 normalize_map[i].red = (255*(i-low.red))/
00292 (high.red-low.red);
00293 }
00294
00295 if(i < low.green)
00296 normalize_map[i].green = 0;
00297 else{
00298 if(i > high.green)
00299 normalize_map[i].green = 255;
00300 else if(low.green != high.green)
00301 normalize_map[i].green = (255*(i-low.green))/
00302 (high.green-low.green);
00303 }
00304
00305 if(i < low.blue)
00306 normalize_map[i].blue = 0;
00307 else{
00308 if(i > high.blue)
00309 normalize_map[i].blue = 255;
00310 else if(low.blue != high.blue)
00311 normalize_map[i].blue = (255*(i-low.blue))/
00312 (high.blue-low.blue);
00313 }
00314 }
00315
00316
00317 dest = (QRgb *)img.bits();
00318 if(img.format() == QImage::Format_ARGB32_Premultiplied){
00319 for(i=0; i < count; ++i, ++dest){
00320 pixel = BlitzPrivate::convertFromPremult(*dest);
00321 r = (low.red != high.red) ? normalize_map[qRed(pixel)].red :
00322 qRed(pixel);
00323 g = (low.green != high.green) ? normalize_map[qGreen(pixel)].green :
00324 qGreen(pixel);
00325 b = (low.blue != high.blue) ? normalize_map[qBlue(pixel)].blue :
00326 qBlue(pixel);
00327 *dest = BlitzPrivate::convertToPremult(qRgba(r, g, b, qAlpha(pixel)));
00328 }
00329 }
00330 else{
00331 for(i=0; i < count; ++i){
00332 pixel = *dest;
00333 r = (low.red != high.red) ? normalize_map[qRed(pixel)].red :
00334 qRed(pixel);
00335 g = (low.green != high.green) ? normalize_map[qGreen(pixel)].green :
00336 qGreen(pixel);
00337 b = (low.blue != high.blue) ? normalize_map[qBlue(pixel)].blue :
00338 qBlue(pixel);
00339 *dest++ = qRgba(r, g, b, qAlpha(pixel));
00340 }
00341 }
00342
00343 delete[] normalize_map;
00344 return(true);
00345 }
00346
00347 QImage Blitz::oilPaint(QImage &img, float radius,
00348 EffectQuality quality)
00349 {
00350 int matrix_size = BlitzPrivate::defaultConvolveMatrixSize(radius, 0.5,
00351 quality == High);
00352 int i, x, y, w, h, matrix_x, matrix_y;
00353 int edge = matrix_size/2;
00354 unsigned int max, value;
00355 QRgb *dest, *src, *s, **scanblock;
00356
00357 w = img.width();
00358 h = img.height();
00359 if(w < 3 || h < 3){
00360 qWarning("Blitz::oilPaint(): Image is too small!");
00361 return(img);
00362 }
00363
00364 if(img.format() == QImage::Format_ARGB32_Premultiplied)
00365 img = img.convertToFormat(QImage::Format_ARGB32);
00366 else if(img.depth() < 32){
00367 img = img.convertToFormat(img.hasAlphaChannel() ?
00368 QImage::Format_ARGB32 :
00369 QImage::Format_RGB32);
00370 }
00371 QImage buffer(w, h, img.format());
00372
00373 scanblock = new QRgb* [matrix_size];
00374 unsigned int *histogram = new unsigned int[256];
00375
00376 for(y=0; y < h; ++y){
00377 src = (QRgb *)img.scanLine(y);
00378 dest = (QRgb *)buffer.scanLine(y);
00379
00380
00381 for(x=y-edge, i=0; x <= y+edge; ++i, ++x){
00382 scanblock[i] = (QRgb *)
00383 img.scanLine((x < 0) ? 0 : (x > h-1) ? h-1 : x);
00384 }
00385
00386
00387
00388 for(x=0; x-edge < 0 ; ++x){
00389 (void)memset(histogram, 0, 256*sizeof(unsigned int));
00390 max = 0;
00391 for(matrix_y = 0; matrix_y < matrix_size; ++matrix_y){
00392 s = scanblock[matrix_y];
00393 matrix_x = -edge;
00394 while(x+matrix_x < 0){
00395 value = qGray(*s);
00396 histogram[value]++;
00397 if(histogram[value] > max){
00398 max = histogram[value];
00399 *dest = *s;
00400 }
00401 ++matrix_x;
00402 }
00403 while(matrix_x <= edge){
00404 value = qGray(*s);
00405 histogram[value]++;
00406 if(histogram[value] > max){
00407 max = histogram[value];
00408 *dest = *s;
00409 }
00410 ++matrix_x; ++s;
00411 }
00412 }
00413 ++dest;
00414 }
00415
00416
00417
00418 for(; x+edge < w; ++x){
00419 (void)memset(histogram, 0, 256*sizeof(unsigned int));
00420 max = 0;
00421 for(matrix_y = 0; matrix_y < matrix_size; ++matrix_y){
00422 s = scanblock[matrix_y] + (x-edge);
00423 for(matrix_x = -edge; matrix_x <= edge; ++matrix_x, ++s){
00424 value = qGray(*s);
00425 histogram[value]++;
00426 if(histogram[value] > max){
00427 max = histogram[value];
00428 *dest = *s;
00429 }
00430 }
00431 }
00432 ++dest;
00433 }
00434
00435
00436
00437 for(; x < w; ++x){
00438 (void)memset(histogram, 0, 256*sizeof(unsigned int));
00439 max = 0;
00440 for(matrix_y = 0; matrix_y < matrix_size; ++matrix_y){
00441 s = scanblock[matrix_y];
00442 s += x-edge;
00443 matrix_x = -edge;
00444 while(x+matrix_x < w){
00445 value = qGray(*s);
00446 histogram[value]++;
00447 if(histogram[value] > max){
00448 max = histogram[value];
00449 *dest = *s;
00450 }
00451 ++matrix_x, ++s;
00452 }
00453 --s;
00454 while(matrix_x <= edge){
00455 value = qGray(*s);
00456 histogram[value]++;
00457 if(histogram[value] > max){
00458 max = histogram[value];
00459 *dest = *s;
00460 }
00461 ++matrix_x;
00462 }
00463 }
00464 ++dest;
00465 }
00466 }
00467
00468 delete[] histogram;
00469 delete[] scanblock;
00470 return(buffer);
00471 }
00472