imageblur.cpp 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. #include "imageblur.h"
  2. #include <QtMath>
  3. #include <QDebug>
  4. //边缘算法
  5. //i: 偏移
  6. //x: 当前位置
  7. //w: 范围(位置范围是0 -> w)
  8. //返回: x周边第i个的位置
  9. template <typename T>
  10. T ImageBlurUtility::Edge(T i, T x, T w)
  11. {
  12. //x周边第i个的位置
  13. T i_k = x + i;
  14. if (i_k < 0) i_k = -x;
  15. else if (i_k >= w) i_k = w - 1 - x;
  16. else i_k = i;
  17. return i_k;
  18. }
  19. //归一化
  20. void ImageBlurUtility::Normalization(std::vector<double> &kernels)
  21. {
  22. double sum = std::accumulate(kernels.begin(), kernels.end(), 0.0);
  23. if(qFuzzyCompare(sum, 0)) return;
  24. if(qFuzzyCompare(sum, 1.0)) return;
  25. std::transform(kernels.begin(), kernels.end(), kernels.begin(),
  26. [sum](double x){ return x/sum; });
  27. }
  28. //得到高斯核(把radius带入高斯公式求解)
  29. std::vector<double> GaussBlur::GetKernels(int radius)
  30. {
  31. static const double SQRT2PI = qSqrt(2.0 * 3.14159265358979323);
  32. double sigma = (double)radius / 3.0;
  33. double sigma2 = 2.0 * sigma * sigma;
  34. double sigmap = sigma * SQRT2PI;
  35. std::vector<double> kernels;
  36. for(int i = -radius; i <= radius; ++i)
  37. {
  38. kernels.push_back(qExp(-(double)(i * i) / sigma2) / sigmap);
  39. }
  40. return kernels;
  41. }
  42. void GaussBlur::Blur(QImage &image, int radius)
  43. {
  44. std::vector<double> kernels = GetKernels(radius);
  45. ImageBlurUtility::Normalization(kernels);
  46. typedef ImageBlurUtility::pixel_t pixel;
  47. typedef ImageBlurUtility::buff_t buff;
  48. pixel *pData = (pixel*)image.bits();
  49. //栈的空间小, 所以这里buffer分配到堆
  50. const int size = image.width() * image.height();
  51. buff *pBuffer = new buff[size];
  52. for(int inx = 0, y = 0; y < image.height(); ++y)
  53. {
  54. for(int x = 0; x < image.width(); ++x, ++inx)
  55. {
  56. for(int n = 0, i = -radius; i <= radius; ++i, ++n)
  57. {
  58. long i_k = ImageBlurUtility::Edge(i, x, image.width());
  59. long inx_k = inx + i_k;
  60. pBuffer[inx].r += pData[inx_k].r() * kernels[n];
  61. pBuffer[inx].g += pData[inx_k].g() * kernels[n];
  62. pBuffer[inx].b += pData[inx_k].b() * kernels[n];
  63. pBuffer[inx].a += pData[inx_k].a() * kernels[n];
  64. }
  65. }
  66. }
  67. for(int inx = 0, x = 0; x < image.width(); ++x)
  68. {
  69. for(int y = 0; y < image.height(); ++y)
  70. {
  71. inx = y * image.width() + x;
  72. buff buffer;
  73. for(int n = 0, i = -radius; i <= radius; ++i, ++n)
  74. {
  75. int i_k = ImageBlurUtility::Edge(i, y, image.height());
  76. int inx_k = inx + i_k * image.width();
  77. buffer.r += pBuffer[inx_k].r * kernels[n];
  78. buffer.g += pBuffer[inx_k].g * kernels[n];
  79. buffer.b += pBuffer[inx_k].b * kernels[n];
  80. buffer.a += pBuffer[inx_k].a * kernels[n];
  81. }
  82. pData[inx].Set(buffer.Red(), buffer.Green(), buffer.Blue(), buffer.Alpha());
  83. //pData[inx].Set(Clamp<int>(r), Clamp<int>(g), Clamp<int>(b), Clamp<int>(a));
  84. }
  85. }
  86. delete[] pBuffer;
  87. }