Changeset View
Changeset View
Standalone View
Standalone View
imagelib/effects/blitz.cpp
Show First 20 Lines • Show All 60 Lines • ▼ Show 20 Line(s) | |||||
61 | dealings in ImageMagick without prior written authorization from the | 61 | dealings in ImageMagick without prior written authorization from the | ||
62 | ImageMagick Studio. | 62 | ImageMagick Studio. | ||
63 | */ | 63 | */ | ||
64 | 64 | | |||
65 | #include "blitz.h" | 65 | #include "blitz.h" | ||
66 | 66 | | |||
67 | #include <QColor> | 67 | #include <QColor> | ||
68 | #include <cmath> | 68 | #include <cmath> | ||
69 | #include <omp.h> | ||||
69 | 70 | | |||
70 | #define M_SQ2PI 2.50662827463100024161235523934010416269302368164062 | 71 | #define M_SQ2PI 2.50662827463100024161235523934010416269302368164062 | ||
71 | #define M_EPSILON 1.0e-6 | 72 | #define M_EPSILON 1.0e-6 | ||
72 | 73 | | |||
73 | #define CONVOLVE_ACC(weight, pixel) \ | 74 | #define CONVOLVE_ACC(weight, pixel) \ | ||
74 | r+=((weight))*(qRed((pixel))); g+=((weight))*(qGreen((pixel))); \ | 75 | r+=((weight))*(qRed((pixel))); g+=((weight))*(qGreen((pixel))); \ | ||
75 | b+=((weight))*(qBlue((pixel))); | 76 | b+=((weight))*(qBlue((pixel))); | ||
76 | 77 | | |||
▲ Show 20 Lines • Show All 158 Lines • ▼ Show 20 Line(s) | 127 | { | |||
235 | delete[] equalize_map; | 236 | delete[] equalize_map; | ||
236 | return(true); | 237 | return(true); | ||
237 | } | 238 | } | ||
238 | 239 | | |||
239 | //-------------------------------------------------------------------------------- | 240 | //-------------------------------------------------------------------------------- | ||
240 | 241 | | |||
241 | QImage Blitz::blur(QImage &img, int radius) | 242 | QImage Blitz::blur(QImage &img, int radius) | ||
242 | { | 243 | { | ||
243 | QRgb *p1, *p2; | 244 | if (img.isNull()) { | ||
244 | int x, y, w, h, mx, my, mw, mh, mt, xx, yy; | | |||
245 | int a, r, g, b; | | |||
246 | int *as, *rs, *gs, *bs; | | |||
247 | | ||||
248 | if(radius < 1 || img.isNull() || img.width() < (radius << 1)) { | | |||
249 | return(img); | 245 | return (img); | ||
250 | } | 246 | } | ||
251 | 247 | | |||
252 | w = img.width(); | | |||
253 | h = img.height(); | | |||
254 | | ||||
255 | if(img.depth() < 8) { | 248 | if (img.depth() < 8) { | ||
256 | img = img.convertToFormat(QImage::Format_Indexed8); | 249 | img = img.convertToFormat(QImage::Format_Indexed8); | ||
257 | } | 250 | } | ||
258 | QImage buffer(w, h, img.hasAlphaChannel() ? | | |||
259 | QImage::Format_ARGB32 : QImage::Format_RGB32); | | |||
260 | | ||||
261 | as = new int[w]; | | |||
262 | rs = new int[w]; | | |||
263 | gs = new int[w]; | | |||
264 | bs = new int[w]; | | |||
265 | 251 | | |||
266 | QVector<QRgb> colorTable; | 252 | QVector<QRgb> colorTable; | ||
267 | if(img.format() == QImage::Format_Indexed8) { | 253 | if (img.format() == QImage::Format_Indexed8) { | ||
268 | colorTable = img.colorTable(); | 254 | colorTable = img.colorTable(); | ||
269 | } | 255 | } | ||
270 | 256 | | |||
271 | for(y = 0; y < h; y++){ | 257 | auto width = img.width(); | ||
272 | my = y - radius; | 258 | auto height = img.height(); | ||
273 | mh = (radius << 1) + 1; | 259 | | ||
260 | QImage buffer(width, height, img.hasAlphaChannel() ? QImage::Format_ARGB32 : QImage::Format_RGB32); | ||||
261 | | ||||
262 | const auto img_format = img.format(); | ||||
263 | | ||||
264 | int *as = new int[width]; | ||||
265 | int *rs = new int[width]; | ||||
266 | int *gs = new int[width]; | ||||
267 | int *bs = new int[width]; | ||||
268 | | ||||
269 | QRgb *p1 , *p2; | ||||
270 | | ||||
271 | for (auto y = 0; y < height; ++y) { | ||||
272 | auto my = y - radius; | ||||
273 | auto mh = (radius << 1) + 1; | ||||
274 | | ||||
274 | if(my < 0){ | 275 | if (my < 0) { | ||
275 | mh += my; | 276 | mh += my; | ||
276 | my = 0; | 277 | my = 0; | ||
277 | } | 278 | } | ||
278 | if((my + mh) > h) { | 279 | | ||
279 | mh = h - my; | 280 | if ((my + mh) > height) { | ||
281 | mh = height - my; | ||||
280 | } | 282 | } | ||
281 | 283 | | |||
282 | p1 = (QRgb *)buffer.scanLine(y); | 284 | p1 = (QRgb*)buffer.scanLine(y); | ||
283 | memset(as, 0, static_cast<unsigned int> (w) * sizeof(int)); | | |||
284 | memset(rs, 0, static_cast<unsigned int> (w) * sizeof(int)); | | |||
285 | memset(gs, 0, static_cast<unsigned int> (w) * sizeof(int)); | | |||
286 | memset(bs, 0, static_cast<unsigned int> (w) * sizeof(int)); | | |||
287 | 285 | | |||
288 | if(img.format() == QImage::Format_ARGB32_Premultiplied){ | 286 | memset(as, 0, static_cast<unsigned int>(width) * sizeof(int)); | ||
287 | memset(rs, 0, static_cast<unsigned int>(width) * sizeof(int)); | ||||
288 | memset(gs, 0, static_cast<unsigned int>(width) * sizeof(int)); | ||||
289 | memset(bs, 0, static_cast<unsigned int>(width) * sizeof(int)); | ||||
290 | | ||||
291 | | ||||
292 | switch (img_format) { | ||||
293 | case QImage::Format_ARGB32_Premultiplied: { | ||||
289 | QRgb pixel; | 294 | QRgb pixel; | ||
290 | for(yy = 0; yy < mh; yy++){ | 295 | for (auto i = 0; i < mh; i++) { | ||
291 | p2 = (QRgb *)img.scanLine(yy + my); | 296 | p2 = (QRgb *)img.scanLine(i + my); | ||
292 | for(x = 0; x < w; x++, p2++){ | 297 | #pragma omp for | ||
298 | for (auto j = 0; j < width; ++j) { | ||||
299 | p2++; | ||||
293 | pixel = convertFromPremult(*p2); | 300 | pixel = convertFromPremult(*p2); | ||
294 | as[x] += qAlpha(pixel); | 301 | as[j] += qAlpha(pixel); | ||
295 | rs[x] += qRed(pixel); | 302 | rs[j] += qRed(pixel) * qRed(pixel); | ||
296 | gs[x] += qGreen(pixel); | 303 | gs[j] += qGreen(pixel) * qGreen(pixel); | ||
297 | bs[x] += qBlue(pixel); | 304 | bs[j] += qBlue(pixel) * qBlue(pixel); | ||
298 | } | 305 | } | ||
299 | } | 306 | } | ||
307 | break; | ||||
300 | } | 308 | } | ||
301 | else if(img.format() == QImage::Format_Indexed8){ | 309 | | ||
310 | case QImage::Format_Indexed8: { | ||||
302 | QRgb pixel; | 311 | QRgb pixel; | ||
303 | unsigned char *ptr; | 312 | unsigned char *ptr; | ||
304 | for(yy = 0; yy < mh; yy++){ | 313 | for (auto i = 0; i < mh; ++i) { | ||
305 | ptr = img.scanLine(yy + my); | 314 | ptr = img.scanLine(i + my); | ||
306 | for(x = 0; x < w; x++, ptr++){ | 315 | #pragma omp for | ||
316 | for (auto j = 0; j < width; ++j) { | ||||
317 | ptr++; | ||||
307 | pixel = colorTable[*ptr]; | 318 | pixel = colorTable[*ptr]; | ||
308 | as[x] += qAlpha(pixel); | 319 | as[j] += qAlpha(pixel); | ||
309 | rs[x] += qRed(pixel); | 320 | rs[j] += qRed(pixel) * qRed(pixel); | ||
310 | gs[x] += qGreen(pixel); | 321 | gs[j] += qGreen(pixel) * qGreen(pixel); | ||
311 | bs[x] += qBlue(pixel); | 322 | bs[j] += qBlue(pixel) * qBlue(pixel); | ||
312 | } | 323 | } | ||
313 | } | 324 | } | ||
325 | break; | ||||
314 | } | 326 | } | ||
315 | else{ | 327 | | ||
316 | for(yy = 0; yy < mh; yy++){ | 328 | default: { | ||
317 | p2 = (QRgb *)img.scanLine(yy + my); | 329 | for (auto i = 0; i < mh; ++i) { | ||
318 | for(x = 0; x < w; x++, p2++){ | 330 | p2 = (QRgb *)img.scanLine(i + my); | ||
319 | as[x] += qAlpha(*p2); | 331 | #pragma omp for | ||
320 | rs[x] += qRed(*p2); | 332 | for (auto j = 0; j < width; j++) { | ||
321 | gs[x] += qGreen(*p2); | 333 | p2++; | ||
322 | bs[x] += qBlue(*p2); | 334 | as[j] += qAlpha(*p2); | ||
335 | rs[j] += qRed(*p2); | ||||
336 | gs[j] += qGreen(*p2); | ||||
337 | bs[j] += qBlue(*p2); | ||||
323 | } | 338 | } | ||
324 | } | 339 | } | ||
340 | break; | ||||
325 | } | 341 | } | ||
342 | } | ||||
343 | | ||||
344 | #pragma omp for | ||||
345 | for (auto i = 0; i < width; ++i) { | ||||
346 | auto a{0}; | ||||
347 | auto r{0}; | ||||
348 | auto g{0}; | ||||
349 | auto b{0}; | ||||
350 | | ||||
351 | auto mx = i - radius; | ||||
352 | auto mw = (radius << 1) + 1; | ||||
326 | 353 | | |||
327 | for(x = 0; x < w; x++){ | | |||
328 | a = r = g = b = 0; | | |||
329 | mx = x - radius; | | |||
330 | mw = (radius << 1) + 1; | | |||
331 | if(mx < 0){ | 354 | if (mx < 0) { | ||
332 | mw += mx; | 355 | mw += mx; | ||
333 | mx = 0; | 356 | mx = 0; | ||
334 | } | 357 | } | ||
335 | if((mx + mw) > w) { | 358 | | ||
336 | mw = w - mx; | 359 | if ((mx + mw) > width) { | ||
360 | mw = width - mx; | ||||
337 | } | 361 | } | ||
338 | mt = mw * mh; | 362 | | ||
339 | for(xx = mx; xx < (mw + mx); xx++){ | 363 | for (auto j = mx; j < (mw + mx); ++j) { | ||
340 | a += as[xx]; | 364 | a += as[j]; | ||
341 | r += rs[xx]; | 365 | r += rs[j]; | ||
342 | g += gs[xx]; | 366 | g += gs[j]; | ||
343 | b += bs[xx]; | 367 | b += bs[j]; | ||
344 | } | 368 | } | ||
369 | | ||||
370 | auto mt = mw * mh; | ||||
371 | | ||||
345 | a = a / mt; | 372 | a = a / mt; | ||
346 | r = r / mt; | 373 | r = r / mt; | ||
347 | g = g / mt; | 374 | g = g / mt; | ||
348 | b = b / mt; | 375 | b = b / mt; | ||
349 | *p1++ = qRgba(r, g, b, a); | 376 | | ||
377 | *p1++ = qRgba(std::sqrt(r), std::sqrt(g), std::sqrt(b), a); | ||||
350 | } | 378 | } | ||
351 | } | 379 | } | ||
380 | | ||||
352 | delete[] as; | 381 | delete[] as; | ||
353 | delete[] rs; | 382 | delete[] rs; | ||
354 | delete[] gs; | 383 | delete[] gs; | ||
355 | delete[] bs; | 384 | delete[] bs; | ||
356 | 385 | | |||
357 | return(buffer); | 386 | return (buffer); | ||
358 | } | 387 | } | ||
359 | 388 | | |||
360 | //-------------------------------------------------------------------------------- | 389 | //-------------------------------------------------------------------------------- | ||
361 | 390 | | |||
362 | int defaultConvolveMatrixSize(float radius, float sigma, bool quality) | 391 | int defaultConvolveMatrixSize(float radius, float sigma, bool quality) | ||
363 | { | 392 | { | ||
364 | int i, matrix_size; | 393 | int i, matrix_size; | ||
365 | float normalize, value; | 394 | float normalize, value; | ||
▲ Show 20 Lines • Show All 326 Lines • Show Last 20 Lines |