123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899 |
- #include "imageblur.h"
- #include <QtMath>
- #include <QDebug>
- //边缘算法
- //i: 偏移
- //x: 当前位置
- //w: 范围(位置范围是0 -> w)
- //返回: x周边第i个的位置
- template <typename T>
- T ImageBlurUtility::Edge(T i, T x, T w)
- {
- //x周边第i个的位置
- T i_k = x + i;
- if (i_k < 0) i_k = -x;
- else if (i_k >= w) i_k = w - 1 - x;
- else i_k = i;
- return i_k;
- }
- //归一化
- void ImageBlurUtility::Normalization(std::vector<double> &kernels)
- {
- double sum = std::accumulate(kernels.begin(), kernels.end(), 0.0);
- if(qFuzzyCompare(sum, 0)) return;
- if(qFuzzyCompare(sum, 1.0)) return;
- std::transform(kernels.begin(), kernels.end(), kernels.begin(),
- [sum](double x){ return x/sum; });
- }
- //得到高斯核(把radius带入高斯公式求解)
- std::vector<double> GaussBlur::GetKernels(int radius)
- {
- static const double SQRT2PI = qSqrt(2.0 * 3.14159265358979323);
- double sigma = (double)radius / 3.0;
- double sigma2 = 2.0 * sigma * sigma;
- double sigmap = sigma * SQRT2PI;
-
- std::vector<double> kernels;
- for(int i = -radius; i <= radius; ++i)
- {
- kernels.push_back(qExp(-(double)(i * i) / sigma2) / sigmap);
- }
- return kernels;
- }
- void GaussBlur::Blur(QImage &image, int radius)
- {
- std::vector<double> kernels = GetKernels(radius);
- ImageBlurUtility::Normalization(kernels);
-
- typedef ImageBlurUtility::pixel_t pixel;
- typedef ImageBlurUtility::buff_t buff;
-
- pixel *pData = (pixel*)image.bits();
-
- //栈的空间小, 所以这里buffer分配到堆
- const int size = image.width() * image.height();
- buff *pBuffer = new buff[size];
-
- for(int inx = 0, y = 0; y < image.height(); ++y)
- {
- for(int x = 0; x < image.width(); ++x, ++inx)
- {
- for(int n = 0, i = -radius; i <= radius; ++i, ++n)
- {
- long i_k = ImageBlurUtility::Edge(i, x, image.width());
- long inx_k = inx + i_k;
- pBuffer[inx].r += pData[inx_k].r() * kernels[n];
- pBuffer[inx].g += pData[inx_k].g() * kernels[n];
- pBuffer[inx].b += pData[inx_k].b() * kernels[n];
- pBuffer[inx].a += pData[inx_k].a() * kernels[n];
- }
- }
- }
-
- for(int inx = 0, x = 0; x < image.width(); ++x)
- {
- for(int y = 0; y < image.height(); ++y)
- {
- inx = y * image.width() + x;
- buff buffer;
- for(int n = 0, i = -radius; i <= radius; ++i, ++n)
- {
- int i_k = ImageBlurUtility::Edge(i, y, image.height());
- int inx_k = inx + i_k * image.width();
- buffer.r += pBuffer[inx_k].r * kernels[n];
- buffer.g += pBuffer[inx_k].g * kernels[n];
- buffer.b += pBuffer[inx_k].b * kernels[n];
- buffer.a += pBuffer[inx_k].a * kernels[n];
- }
- pData[inx].Set(buffer.Red(), buffer.Green(), buffer.Blue(), buffer.Alpha());
- //pData[inx].Set(Clamp<int>(r), Clamp<int>(g), Clamp<int>(b), Clamp<int>(a));
- }
- }
- delete[] pBuffer;
- }
|