|
|
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 |
}
|