Blame filter.blur.inc.c

ea5919
ea5919
ea5919
int toPowerOf2(int x) {
4ca57e
  int xx;
ea5919
  for(xx = 1; x > 1; x >>= 1)
ea5919
    xx <<= 1;
ea5919
  return xx;
ea5919
}
ea5919
ea5919
ea5919
ea5919
void fft(double *real, int realStep, double *img, int imgStep, int count, int invert) {
4ca57e
  if (count < 2 || !realStep || !imgStep) return;
ea5919
  count = toPowerOf2(count);
ea5919
ea5919
  // check order
ea5919
  int flipReal = 0;
ea5919
  if (realStep < 0) {
ea5919
    flipReal = 1;
ea5919
    real += realStep*(count - 1);
ea5919
    realStep = -realStep;
ea5919
  }
ea5919
  int flipImg = 0;
ea5919
  if (imgStep < 0) {
ea5919
    flipImg = 1;
ea5919
    img += imgStep*(count - 1);
ea5919
    imgStep = -imgStep;
ea5919
  }
ea5919
4ca57e
  double *realEnd = real + count*realStep;
4ca57e
  double *imgEnd  = img  + count*imgStep;
ea5919
ea5919
  // flip if step was negative
ea5919
  if (flipReal)
ea5919
    for(double *i = real, *j = realEnd - realStep; i < j; i += realStep, j -= realStep)
ea5919
      { double x = *i; *i = *j; *j = x; }
ea5919
  if (flipImg)
ea5919
    for(double *i = img, *j = imgEnd - imgStep; i < j; i += imgStep, j -= imgStep)
ea5919
      { double x = *i; *i = *j; *j = x; }
ea5919
ea5919
4ca57e
  // bit-reversal permutation
4ca57e
  for(int i=0, j=0; i < count; ++i) {
4ca57e
    if (j > i) {
ea5919
      double x, *a, *b;
ea5919
      a = real + i*realStep; b = real + j*realStep; x = *a; *a = *b; *b = x;
ea5919
      a = img  + i*imgStep;  b = img  + j*imgStep;  x = *a; *a = *b; *b = x;
ea5919
    }
4ca57e
    int m = count/2;
4ca57e
    while(m >= 1 && j >= m)
4ca57e
      { j -= m; m /= 2; }
4ca57e
    j += m;
4ca57e
  }
4ca57e
4ca57e
  double k = invert ? PI : -PI;
4ca57e
  for(int mmax = 1; mmax < count; mmax *= 2) {
4ca57e
    // rotation coefficients
4ca57e
    double angle = k/mmax;
4ca57e
    double wpR = sin(0.5*angle), wpI = sin(angle);
4ca57e
    wpR *= wpR*2;
4ca57e
4ca57e
    double wR = 1, wI = 0;
4ca57e
    int mmaxRealStep  = mmax*realStep;
4ca57e
    int mmaxRealStep2 = 2*mmaxRealStep;
4ca57e
    int mmaxImgStep   = mmax*imgStep;
4ca57e
    int mmaxImgStep2  = 2*mmaxImgStep;
4ca57e
    for(int m = 0; m < mmax; ++m) {
4ca57e
      // rotate w
4ca57e
      double wwR = wR;
4ca57e
      wR = wR - wwR*wpR - wI*wpI,
ea5919
      wI = wI + wwR*wpI - wI*wpR;
4ca57e
      // process subsequences
4ca57e
      for( double *iR = real + m*realStep,
4ca57e
                  *iI = img  + m*imgStep,
4ca57e
                  *jR = iR + mmaxRealStep,
ea5919
                  *jI = iI + mmaxImgStep;
ea5919
           iR < realEnd;
ea5919
           iR += mmaxRealStep2,
ea5919
           iI += mmaxImgStep2,
ea5919
           jR += mmaxRealStep2,
ea5919
           jI += mmaxImgStep2 )
ea5919
      {
4ca57e
        // radix
4ca57e
        double tR = *jR*wR - *jI*wI;
4ca57e
        double tI = *jR*wI + *jI*wR;
4ca57e
        *jR = *iR - tR;
4ca57e
        *jI = *iI - tI;
4ca57e
        *iR += tR;
4ca57e
        *iI += tI;
4ca57e
      }
4ca57e
    }
4ca57e
  }
4ca57e
4ca57e
  // reverse order
ea5919
  if (!flipReal)
ea5919
    for(double *i = real, *j = realEnd - realStep; i < j; i += realStep, j -= realStep)
ea5919
      { double x = *i; *i = *j; *j = x; }
ea5919
  if (!flipImg)
ea5919
    for(double *i = img, *j = imgEnd - imgStep; i < j; i += imgStep, j -= imgStep)
ea5919
      { double x = *i; *i = *j; *j = x; }
ea5919
4ca57e
  // divide by count to complete back-FFT
4ca57e
  if (invert) {
4ca57e
    double k = 1.0/count;
4ca57e
    for(double *i = real; i < realEnd; i += realStep)
4ca57e
      *i *= k;
4ca57e
    for(double *i = img; i < imgEnd; i += imgStep)
4ca57e
      *i *= k;
4ca57e
  }
ea5919
}
ea5919
ea5919
ea5919
void fft2d(double *real, int realColStep, int realRowStep, double *img, int imgColStep, int imgRowStep, int rows, int cols, int invert) {
4ca57e
  if (rows < 1 || cols < 1 || !realColStep || !imgColStep || !realRowStep || imgRowStep) return;
ea5919
  rows = toPowerOf2(rows);
ea5919
  cols = toPowerOf2(cols);
ea5919
4ca57e
  // fft rows
4ca57e
  if (cols > 1)
4ca57e
    for(double *r = real, *i = img, *end = real + rows*realRowStep; r < end; r += realRowStep, i += imgRowStep)
4ca57e
      fft(r, realColStep, i, imgColStep, cols, invert);
4ca57e
  // fft cols
4ca57e
  if (rows > 1)
4ca57e
    for(double *r = real, *i = img, *end = real + cols*realColStep; r < end; r += realColStep, i += imgColStep)
4ca57e
      fft(r, realRowStep, i, imgRowStep, rows, invert);
ea5919
}
ea5919
ea5919
ea5919
double preGauss(double x, double r) {
ea5919
  if (fabs(r) < IMG_PRECISION)
ea5919
    return fabs(x) < IMG_PRECISION ? 1 : 0;
ea5919
  return exp(-0.5*x*x/(r*r));
ea5919
}
ea5919
ea5919
ea5919
double gauss(double x, double r) {
ea5919
  static const double k = 1/sqrt(2*PI);
ea5919
  return k*preGauss(x, r)/fabs(r);
ea5919
}
ea5919
ea5919
ea5919
void gaussBlurRows(double *row, int colStep, int rowStep, int cols, int rows, double size) {
ea5919
  if (!(size > IMG_PRECISION)) return;
ea5919
  int cnt = cols + 2*(int)ceil(size*4 - IMG_PRECISION);
ea5919
  int p2cnt = toPowerOf2(cnt);
ea5919
  if (p2cnt < cnt) p2cnt <<= 1;
ea5919
  cnt = p2cnt;
ea5919
ea5919
  double *buf = (double*)calloc(1, sizeof(double)*4*cnt);
ea5919
  double *pat = buf + 2*cnt;
ea5919
  pat[0]   = preGauss(0,     size);
ea5919
  pat[cnt] = preGauss(cnt/2, size);
ea5919
  for(int i = 2; i < cnt; i += 2)
ea5919
    pat[i] = pat[cnt*2 - i] = preGauss(i, size);
ea5919
  fft(pat, 2, pat+1, 2, cnt, FALSE);
ea5919
ea5919
  double *buf0 = buf + (cnt - cols);
ea5919
  double *buf1 = buf0 + (cols - 1)*2;
ea5919
  for(int i = 0; i < rows; ++i) {
ea5919
    for(int ch = 0; ch < 4; ++ch) {
ea5919
      memset(buf, 0, sizeof(double)*2*cnt);
ea5919
      double *chrow = row + i*rowStep + ch;
ea5919
      for(int j = 0; j < cols; ++j)
ea5919
        buf0[j*2] = chrow[j*colStep];
ea5919
      for(double v = *buf0, *b = buf;      b < buf0; b += 2) *b = v;
ea5919
      for(double v = *buf1, *b = buf1 + 2; b < pat;  b += 2) *b = v;
ea5919
      fft(buf, 2, buf+1, 2, cnt, FALSE);
ea5919
      for(double *b = buf, *p = pat; b < pat; b += 2, p += 2) {
ea5919
        double bR = b[0], bI = b[1];
ea5919
        b[0] = bR*p[0] - bI*p[1];
ea5919
        b[1] = bR*p[1] + bI*p[0];
ea5919
      }
ea5919
      fft(buf, 2, buf+1, 2, cnt, TRUE);
ea5919
      for(int j = 0; j < cols; ++j) {
ea5919
        double *b = buf0 + j*2;
ea5919
        chrow[j*colStep] = sqrt(b[0]*b[0] + b[1]*b[1]);
ea5919
      }
ea5919
    }
ea5919
  }
ea5919
  free(buf);
ea5919
}
ea5919
ea5919
ea5919
void filterBlurGauss(Img *img, double sx, double sy) {
ea5919
  if (!img->data) return;
ea5919
  sx = fabs(sx);
ea5919
  sy = fabs(sy);
ea5919
  if (!(sx > IMG_PRECISION) && !(sy > IMG_PRECISION)) return;
ea5919
ea5919
  filterMulAlpha(img);
ea5919
  gaussBlurRows(img->data, 4, 4*img->w, img->w, img->h, sx);
ea5919
  gaussBlurRows(img->data, 4*img->w, 4, img->h, img->w, sy);
ea5919
  filterDivAlpha(img);
ea5919
}
ea5919
ea5919