/* $Id: qdnlfilt.c 3735 2010-08-11 00:12:39Z flaterco $
qdnlfilt -- quick and dirty nonlinear image smoothing
Copyright (C) 1996 David Flater.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You can obtain a copy of the GNU General Public License from
.
Description
-----------
This is the third program in the quick & dirty image processing
series. This one does adaptive smoothing using a simpler algorithm
than the one used by pnmnlfilt.
qdnlfilt version 1 works ONLY on 8-bit rawbits pixmaps and
graymaps with maxval = 255, and ONLY on stdin and stdout.
Usage: qdnlfilt factor < input > output
Nonlinear sharpening is not supported because it's a bonehead
thing to do. Linear sharpening works better.
Factor Result
------ ------
<0.0 Illegal
0.0 No operation
0.2 Light nonlinear smoothing
0.8 Heavy nonlinear smoothing
1.0 Maximum smoothing
>1.0 Illegal
To compile: gcc -O2 -s -o qdnlfilt qdnlfilt.c
Version 3 2010-08-10
Renamed getline to resolve clash with stdio.h; minor cleanups.
Version 2 2000-02-21
Hastily added code to avoid choking on comments in PNM files.
Version 1 1996-11-10
*/
#include
#include
#include
#include
#ifdef MSDOS
#include
#include
#endif
unsigned char *prev, *this, *next;
int linlen;
void
usage ()
{
fprintf (stderr, "Usage: qdnlfilt factor < input > output\n\
\n\
Factor Result\n\
------ ------\n\
<0.0 Illegal\n\
0.0 No operation\n\
0.2 Light nonlinear smoothing\n\
0.8 Heavy nonlinear smoothing\n\
1.0 Maximum smoothing\n\
>1.0 Illegal\n");
exit (-1);
}
void
bogus ()
{
fprintf (stderr,
"qdnlfilt works ONLY on 8-bit rawbits pixmaps and\n");
fprintf (stderr,
"graymaps with maxval = 255, and ONLY on stdin and stdout.\n");
exit (-1);
}
void
qdgetline () {
unsigned char *temp;
temp = prev;
prev = this;
this = next;
next = temp;
assert (fread (next, 1, linlen, stdin) == linlen);
}
void
getnoncommentline (char buf[1000]) {
do
assert (fgets (buf, 1000, stdin));
while (buf[0] == '#');
}
int
main (int argc, char **argv)
{
int width, height, maxval, grayflag = 0, disp, x, y;
float factor, noise, variance;
char magicnum[3], buf[1000];
if (argc != 2)
usage ();
if (sscanf (argv[1], "%f", &factor) != 1)
usage ();
if (factor < 0.0 || factor > 1.0)
usage ();
noise = factor * 255.0;
noise = noise * noise / 9.0;
#ifdef MSDOS
setmode (fileno (stdin), O_BINARY);
setmode (fileno (stdout), O_BINARY);
#endif
getnoncommentline (buf);
if (sscanf (buf, "%2s", magicnum) != 1) {
fprintf (stderr, "Error getting header data\n");
bogus();
}
getnoncommentline (buf);
if (sscanf (buf, "%d %d", &width, &height) != 2) {
fprintf (stderr, "Error getting header data\n");
bogus();
}
getnoncommentline (buf);
if (sscanf (buf, "%d", &maxval) != 1) {
fprintf (stderr, "Error getting header data\n");
bogus();
}
if (strcmp (magicnum, "P5") != 0 && strcmp (magicnum, "P6") != 0) {
fprintf (stderr, "Bad magic number\n");
bogus ();
}
if (maxval != 255) {
fprintf (stderr, "Maxval != 255\n");
bogus ();
}
if (magicnum[1] == '5')
grayflag = 1;
printf ("%s\n%d %d\n%d\n", magicnum, width, height, maxval);
if (width < 3 || height < 3) {
/* Too small to do anything with; echo stdin to stdout */
int tval;
while ((tval = getchar ()) != EOF)
assert (putchar (tval) != EOF);
fflush (stdout);
exit (0);
}
disp = (grayflag? 1 : 3);
linlen = width * disp;
assert (prev = malloc (linlen));
assert (this = malloc (linlen));
assert (next = malloc (linlen));
qdgetline();
qdgetline();
assert (fwrite (this, 1, linlen, stdout) == linlen);
for (y=1; y 0.0) {
temp = mean + (variance * ((float)(this[x]) - mean)) /
(variance + noise) + 0.5;
assert (putchar ((int)temp) != EOF);
} else
assert (putchar ((int)(this[x])) != EOF);
} else {
float rmean, gmean, bmean, temp;
int xx = x * 3;
variance = 0.0;
rmean = prev[xx-disp] + this[xx-disp] + next[xx-disp]
+ prev[xx] + this[xx] + next[xx]
+ prev[xx+disp] + this[xx+disp] + next[xx+disp];
rmean /= 9.0;
temp = (float)(prev[xx-disp]) - rmean;
variance += temp * temp;
temp = (float)(this[xx-disp]) - rmean;
variance += temp * temp;
temp = (float)(next[xx-disp]) - rmean;
variance += temp * temp;
temp = (float)(prev[xx]) - rmean;
variance += temp * temp;
temp = (float)(this[xx]) - rmean;
variance += temp * temp;
temp = (float)(next[xx]) - rmean;
variance += temp * temp;
temp = (float)(prev[xx+disp]) - rmean;
variance += temp * temp;
temp = (float)(this[xx+disp]) - rmean;
variance += temp * temp;
temp = (float)(next[xx+disp]) - rmean;
variance += temp * temp;
xx++;
gmean = prev[xx-disp] + this[xx-disp] + next[xx-disp]
+ prev[xx] + this[xx] + next[xx]
+ prev[xx+disp] + this[xx+disp] + next[xx+disp];
gmean /= 9.0;
temp = (float)(prev[xx-disp]) - gmean;
variance += temp * temp;
temp = (float)(this[xx-disp]) - gmean;
variance += temp * temp;
temp = (float)(next[xx-disp]) - gmean;
variance += temp * temp;
temp = (float)(prev[xx]) - gmean;
variance += temp * temp;
temp = (float)(this[xx]) - gmean;
variance += temp * temp;
temp = (float)(next[xx]) - gmean;
variance += temp * temp;
temp = (float)(prev[xx+disp]) - gmean;
variance += temp * temp;
temp = (float)(this[xx+disp]) - gmean;
variance += temp * temp;
temp = (float)(next[xx+disp]) - gmean;
variance += temp * temp;
xx++;
bmean = prev[xx-disp] + this[xx-disp] + next[xx-disp]
+ prev[xx] + this[xx] + next[xx]
+ prev[xx+disp] + this[xx+disp] + next[xx+disp];
bmean /= 9.0;
temp = (float)(prev[xx-disp]) - bmean;
variance += temp * temp;
temp = (float)(this[xx-disp]) - bmean;
variance += temp * temp;
temp = (float)(next[xx-disp]) - bmean;
variance += temp * temp;
temp = (float)(prev[xx]) - bmean;
variance += temp * temp;
temp = (float)(this[xx]) - bmean;
variance += temp * temp;
temp = (float)(next[xx]) - bmean;
variance += temp * temp;
temp = (float)(prev[xx+disp]) - bmean;
variance += temp * temp;
temp = (float)(this[xx+disp]) - bmean;
variance += temp * temp;
temp = (float)(next[xx+disp]) - bmean;
variance += temp * temp;
variance /= 27.0;
if (variance > 0.0) {
temp = rmean + (variance * ((float)(this[3*x]) - rmean)) /
(variance + noise) + 0.5;
assert (putchar ((int)temp) != EOF);
temp = gmean + (variance * ((float)(this[3*x+1]) - gmean)) /
(variance + noise) + 0.5;
assert (putchar ((int)temp) != EOF);
temp = bmean + (variance * ((float)(this[3*x+2]) - bmean)) /
(variance + noise) + 0.5;
assert (putchar ((int)temp) != EOF);
} else {
assert (putchar ((int)(this[3*x])) != EOF);
assert (putchar ((int)(this[3*x+1])) != EOF);
assert (putchar ((int)(this[3*x+2])) != EOF);
}
}
}
for (x=linlen-disp; x