Blame simple/imgfilters/filter.bw.inc.c

14902d
14902d
14902d
void filterExpand(Img *dst, Img *src, int l, int r, int t, int b) {
14902d
  if (!src->data) return;
14902d
  if (l < 0) l = 0;
14902d
  if (r < 0) r = 0;
14902d
  if (t < 0) t = 0;
14902d
  if (b < 0) b = 0;
14902d
14902d
  int w = src->w + l + r;
14902d
  int h = src->h + t + b;
14902d
  if (dst->w != w || dst->h != h) imgInit(dst, w, h);
14902d
14902d
  double *ps = src->data, *pd = dst->data + w*t*4;
14902d
  for(int y = 0; y < src->h; ++y) {
14902d
    memcpy(pd, ps, 4*sizeof(double)*src->w);
14902d
    for(double *p = ps, *e = p + 4*l; p < e; p += 4)
14902d
      memcpy(p, pd, 4*sizeof(double));
14902d
    ps += (src->w-1)*4;
14902d
    pd += w*4;
14902d
    for(double *e = pd, *p = e - r*4; p < e; p += 4)
14902d
      memcpy(p, ps, 4*sizeof(double));
14902d
    ps += 4;
14902d
  }
14902d
14902d
  for(int y = 0; y < t; ++y)
14902d
    memcpy(imgPixel(dst, 0, y), imgPixel(dst, 0, t), 4*sizeof(double)*w);
14902d
  for(int y = h-b; y < h; ++y)
14902d
    memcpy(imgPixel(dst, 0, y), imgPixel(dst, 0, h-b-1), 4*sizeof(double)*w);
14902d
}
14902d
14902d
14902d
void filterArea(Img *dst, Img *src) {
14902d
  int w = dst->w > src->w ? dst->w : src->w;
14902d
  int h = dst->h > src->h ? dst->h : src->h;
14902d
  if (dst->w < w || dst->h < h)
14902d
    imgInit(dst, w, h);
14902d
  int gap = (w - src->w)*4;
14902d
14902d
  double *pd = dst->data, *ps = src->data;
14902d
  memcpy(pd, ps, 4*sizeof(*ps)); ps += 4; pd += 4;
14902d
  for(double *e = ps + 4*(src->w - 1); ps < e; ++ps, ++pd)
14902d
    *pd = *ps + *(pd - 4);
14902d
  pd += gap;
14902d
14902d
  for(int y = 1; y < src->h; ++y) {
14902d
    for(int i = 0; i < 4; ++i, ++ps, ++pd)
14902d
      *pd = *ps + *(pd - w*4);
14902d
    for(double *e = ps + 4*(src->w - 1); ps < e; ++ps, ++pd)
14902d
      *pd = *ps + *(pd - 4) + *(pd - w*4) - *(pd - (w+1)*4);
14902d
    pd += gap;
14902d
  }
14902d
}
14902d
14902d
14902d
void pixelAreaAvg(double *pixel, Img *areaImg, int x0, int y0, int x1, int y1) {
14902d
  if (x0 < 0) x0 = 0;
14902d
  if (y0 < 0) y0 = 0;
14902d
  if (x1 >= areaImg->w) x1 = areaImg->w - 1;
14902d
  if (y1 >= areaImg->h) y1 = areaImg->h - 1;
14902d
  if (x1 < x0 || y1 < y0) { memset(pixel, 0, sizeof(*pixel)*4); return; }
14902d
  double k = 1.0/((x1 - x0 + 1)*(y1 - y0 + 1));
14902d
14902d
  if (x0) {
14902d
    if (y0) {
14902d
      --x0; --y0;
14902d
      double *p00 = imgPixel(areaImg, x0, y0);
14902d
      double *p01 = imgPixel(areaImg, x0, y1);
14902d
      double *p10 = imgPixel(areaImg, x1, y0);
14902d
      double *p11 = imgPixel(areaImg, x1, y1);
14902d
      for(int i = 0; i < 4; ++i)
14902d
        pixel[i] = (p00[i] + p11[i] - p01[i] - p10[i])*k;
14902d
      return;
14902d
    }
14902d
    double *p0 = imgPixel(areaImg, x0-1, y1);
14902d
    double *p1 = imgPixel(areaImg, x1, y1);
14902d
    for(int i = 0; i < 4; ++i)
14902d
      pixel[i] = (p1[i] - p0[i])*k;
14902d
  } else
14902d
  if (y0) {
14902d
    double *p0 = imgPixel(areaImg, x1, y0-1);
14902d
    double *p1 = imgPixel(areaImg, x1, y1);
14902d
    for(int i = 0; i < 4; ++i)
14902d
      pixel[i] = (p1[i] - p0[i])*k;
14902d
  } else {
14902d
    double *p = imgPixel(areaImg, x1, y1);
14902d
    for(int i = 0; i < 4; ++i)
14902d
      pixel[i] = p[i]*k;
14902d
  }
14902d
}
14902d
14902d
14902d
void filterBW(Img *img, int size, double k) {
14902d
  if (!img->data) return;
14902d
14902d
  Img area = {};
14902d
  filterArea(&area, img);
14902d
14902d
  char *res = malloc(img->w * img->h);
14902d
  double sum[2][4] = {};
14902d
  int count[2] = {};
14902d
14902d
  k *= 3;
14902d
  double avg[4] = {};
14902d
  char *r = res;
14902d
  for(int y = 0; y < img->h; ++y) {
14902d
    for(int x = 0; x < img->w; ++x) {
14902d
      pixelAreaAvg(avg, &area, x - size, y - size, x + size, y + size);
14902d
      double a = avg[0] + avg[1] + avg[2];
14902d
      double *c = imgPixel(img, x, y);
14902d
      double cb = c[0] + c[1] + c[2];
14902d
      int value = (cb > a + k);
14902d
      for(int i = 0; i < 4; ++i)
14902d
        sum[value][i] += c[i];
14902d
      ++count[value];
14902d
      *r++ = value;
14902d
    }
14902d
  }
14902d
  imgDestroy(&area);
14902d
14902d
  for(int j = 0; j < 2; ++j)
14902d
    if (count[j])
14902d
      for(int i = 0; i < 4; ++i)
14902d
        sum[j][i] /= count[j];
14902d
14902d
  double *p = img->data;
14902d
  for(char *r = res, *e = r + img->w*img->h; r < e; ++r, p += 4)
14902d
    memcpy(p, sum[(int)*r], sizeof(*sum));
14902d
  free(res);
14902d
}
14902d
14902d
14902d
int bwGenerate(int argc, char **argv) {
14902d
  char *inFile = "", *outFile = "";
14902d
  double sub = 1.0/32;
14902d
  double k = -0.1;
14902d
  ArgDesc descs[] = {
14902d
    { 'i', &inFile, &pargString, "path to input image" },
14902d
    { 'o', &outFile, &pargString, "path to output image" },
14902d
    { 's', &sub, &pargDouble, "subrect size (relative to image size, default: 0.03)" },
14902d
    { 'k', &k, &pargDouble, "threshold shift (default: -0.1)" },
14902d
    {}
14902d
  };
14902d
14902d
  if (!parseArgs(descs, argc, argv) || !inFile[0] || !outFile[0]) {
14902d
    printUsage(descs);
14902d
    return FALSE;
14902d
  }
14902d
14902d
  Img img = {};
14902d
  if (!imgLoad(&img, inFile))
14902d
    return FALSE;
14902d
14902d
  filterBW(&img, (img.w + img.h)*sub/4, k);
14902d
14902d
  if (!imgSave(&img, outFile)) {
14902d
    imgDestroy(&img);
14902d
    return FALSE;
14902d
  }
14902d
14902d
  imgDestroy(&img);
14902d
  return TRUE;
14902d
}