mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-13 18:56:17 +03:00
reference gaussian_blur implementation
radius meaning match graphicmagick, pixelmator other software and standard deviation from classic gaussian blur algorithm
This commit is contained in:
parent
e3793447fc
commit
7bc19c4019
|
@ -62,7 +62,7 @@ gblur(Imaging im, Imaging imOut, float floatRadius, int channels, int padding)
|
||||||
float *maskData = NULL;
|
float *maskData = NULL;
|
||||||
int y = 0;
|
int y = 0;
|
||||||
int x = 0;
|
int x = 0;
|
||||||
float z = 0;
|
int z = 0;
|
||||||
float sum = 0.0;
|
float sum = 0.0;
|
||||||
float dev = 0.0;
|
float dev = 0.0;
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ gblur(Imaging im, Imaging imOut, float floatRadius, int channels, int padding)
|
||||||
INT32 newPixelFinals;
|
INT32 newPixelFinals;
|
||||||
|
|
||||||
int radius = 0;
|
int radius = 0;
|
||||||
float remainder = 0.0;
|
int diameter = 0;
|
||||||
int hasAlpha = 0;
|
int hasAlpha = 0;
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
@ -92,49 +92,35 @@ gblur(Imaging im, Imaging imOut, float floatRadius, int channels, int padding)
|
||||||
radius of 5 instead of 25 lookups). So, we blur the lines first,
|
radius of 5 instead of 25 lookups). So, we blur the lines first,
|
||||||
then we blur the resulting columns. */
|
then we blur the resulting columns. */
|
||||||
|
|
||||||
/* first, round radius off to the next higher integer and hold the
|
|
||||||
remainder this is used so we can support float radius values
|
|
||||||
properly. */
|
|
||||||
|
|
||||||
remainder = floatRadius - ((int) floatRadius);
|
|
||||||
floatRadius = ceil(floatRadius);
|
|
||||||
|
|
||||||
/* Next, double the radius and offset by 2.0... that way "0" returns
|
/* Next, double the radius and offset by 2.0... that way "0" returns
|
||||||
the original image instead of a black one. We multiply it by 2.0
|
the original image instead of a black one. We multiply it by 2.0
|
||||||
so that it is a true "radius", not a diameter (the results match
|
so that it is a true "radius", not a diameter (the results match
|
||||||
other paint programs closer that way too). */
|
other paint programs closer that way too). */
|
||||||
radius = (int) ((floatRadius * 2.0) + 2.0);
|
radius = (int) ceil(floatRadius * 2.57);
|
||||||
|
diameter = radius * 2 + 1;
|
||||||
|
|
||||||
/* create the maskData for the gaussian curve */
|
/* create the maskData for the gaussian curve */
|
||||||
maskData = malloc(radius * sizeof(float));
|
maskData = malloc(diameter * sizeof(float));
|
||||||
/* FIXME: error checking */
|
for (x = 0; x < diameter; x++) {
|
||||||
for (x = 0; x < radius; x++) {
|
z = x - radius;
|
||||||
z = ((float) (x + 2) / ((float) radius));
|
dev = floatRadius * floatRadius;
|
||||||
dev = 0.5 + (((float) (radius * radius)) * 0.001);
|
/* http://en.wikipedia.org/wiki/Gaussian_blur
|
||||||
/* you can adjust this factor to change the shape/center-weighting
|
"1 / sqrt(2 * pi * dev)" is constant and will be eliminated by
|
||||||
of the gaussian */
|
normalization. */
|
||||||
maskData[x] = (float) pow((1.0 / sqrt(2.0 * 3.14159265359 * dev)),
|
maskData[x] = pow(2.718281828459, -z * z / (2 * dev));
|
||||||
((-(z - 1.0) * -(x - 1.0)) /
|
|
||||||
(2.0 * dev)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if there's any remainder, multiply the first/last values in
|
for (x = 0; x < diameter; x++) {
|
||||||
MaskData it. this allows us to support float radius values. */
|
|
||||||
if (remainder > 0.0) {
|
|
||||||
maskData[0] *= remainder;
|
|
||||||
maskData[radius - 1] *= remainder;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (x = 0; x < radius; x++) {
|
|
||||||
/* this is done separately now due to the correction for float
|
/* this is done separately now due to the correction for float
|
||||||
radius values above */
|
radius values above */
|
||||||
sum += maskData[x];
|
sum += maskData[x];
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < radius; i++) {
|
for (i = 0; i < diameter; i++) {
|
||||||
maskData[i] *= (1.0 / sum);
|
maskData[i] *= (1.0 / sum);
|
||||||
/* printf("%f\n", maskData[i]); */
|
// printf("%d %f\n", i, maskData[i]);
|
||||||
}
|
}
|
||||||
|
// printf("\n");
|
||||||
|
|
||||||
/* create a temporary memory buffer for the data for the first pass
|
/* create a temporary memory buffer for the data for the first pass
|
||||||
memset the buffer to 0 so we can use it directly with += */
|
memset the buffer to 0 so we can use it directly with += */
|
||||||
|
@ -148,10 +134,6 @@ gblur(Imaging im, Imaging imOut, float floatRadius, int channels, int padding)
|
||||||
/* be nice to other threads while you go off to lala land */
|
/* be nice to other threads while you go off to lala land */
|
||||||
ImagingSectionEnter(&cookie);
|
ImagingSectionEnter(&cookie);
|
||||||
|
|
||||||
/* memset(buffer, 0, sizeof(buffer)); */
|
|
||||||
|
|
||||||
newPixel[0] = newPixel[1] = newPixel[2] = newPixel[3] = 0;
|
|
||||||
|
|
||||||
/* perform a blur on each line, and place in the temporary storage buffer */
|
/* perform a blur on each line, and place in the temporary storage buffer */
|
||||||
for (y = 0; y < im->ysize; y++) {
|
for (y = 0; y < im->ysize; y++) {
|
||||||
if (channels == 1 && im->image8 != NULL) {
|
if (channels == 1 && im->image8 != NULL) {
|
||||||
|
@ -160,13 +142,11 @@ gblur(Imaging im, Imaging imOut, float floatRadius, int channels, int padding)
|
||||||
line = im->image32[y];
|
line = im->image32[y];
|
||||||
}
|
}
|
||||||
for (x = 0; x < im->xsize; x++) {
|
for (x = 0; x < im->xsize; x++) {
|
||||||
newPixel[0] = newPixel[1] = newPixel[2] = newPixel[3] = 0;
|
|
||||||
/* for each neighbor pixel, factor in its value/weighting to the
|
/* for each neighbor pixel, factor in its value/weighting to the
|
||||||
current pixel */
|
current pixel */
|
||||||
for (pix = 0; pix < radius; pix++) {
|
for (pix = 0; pix < diameter; pix++) {
|
||||||
/* figure the offset of this neighbor pixel */
|
/* figure the offset of this neighbor pixel */
|
||||||
offset =
|
offset = pix - radius;
|
||||||
(int) ((-((float) radius / 2.0) + (float) pix) + 0.5);
|
|
||||||
if (x + offset < 0)
|
if (x + offset < 0)
|
||||||
offset = -x;
|
offset = -x;
|
||||||
else if (x + offset >= im->xsize)
|
else if (x + offset >= im->xsize)
|
||||||
|
@ -201,10 +181,9 @@ gblur(Imaging im, Imaging imOut, float floatRadius, int channels, int padding)
|
||||||
newPixel[0] = newPixel[1] = newPixel[2] = newPixel[3] = 0;
|
newPixel[0] = newPixel[1] = newPixel[2] = newPixel[3] = 0;
|
||||||
/* for each neighbor pixel, factor in its value/weighting to the
|
/* for each neighbor pixel, factor in its value/weighting to the
|
||||||
current pixel */
|
current pixel */
|
||||||
for (pix = 0; pix < radius; pix++) {
|
for (pix = 0; pix < diameter; pix++) {
|
||||||
/* figure the offset of this neighbor pixel */
|
/* figure the offset of this neighbor pixel */
|
||||||
offset =
|
offset = pix - radius;
|
||||||
(int) (-((float) radius / 2.0) + (float) pix + 0.5);
|
|
||||||
if (y + offset < 0)
|
if (y + offset < 0)
|
||||||
offset = -y;
|
offset = -y;
|
||||||
else if (y + offset >= im->ysize)
|
else if (y + offset >= im->ysize)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user