From 626acf705f01c094ab93682ff20382b85e209b1c Mon Sep 17 00:00:00 2001 From: homm Date: Mon, 6 Oct 2014 20:55:59 +0400 Subject: [PATCH 01/15] convert tabs to spaces --- libImaging/UnsharpMask.c | 358 +++++++++++++++++++-------------------- 1 file changed, 179 insertions(+), 179 deletions(-) diff --git a/libImaging/UnsharpMask.c b/libImaging/UnsharpMask.c index 231826245..fc2b4b175 100644 --- a/libImaging/UnsharpMask.c +++ b/libImaging/UnsharpMask.c @@ -48,9 +48,9 @@ static inline UINT8 clip(double in) { if (in >= 255.0) - return (UINT8) 255; + return (UINT8) 255; if (in <= 0.0) - return (UINT8) 0; + return (UINT8) 0; return (UINT8) in; } @@ -108,31 +108,31 @@ gblur(Imaging im, Imaging imOut, float floatRadius, int channels, int padding) maskData = malloc(radius * sizeof(float)); /* FIXME: error checking */ for (x = 0; x < radius; x++) { - z = ((float) (x + 2) / ((float) radius)); - dev = 0.5 + (((float) (radius * radius)) * 0.001); - /* you can adjust this factor to change the shape/center-weighting - of the gaussian */ - maskData[x] = (float) pow((1.0 / sqrt(2.0 * 3.14159265359 * dev)), - ((-(z - 1.0) * -(x - 1.0)) / - (2.0 * dev))); + z = ((float) (x + 2) / ((float) radius)); + dev = 0.5 + (((float) (radius * radius)) * 0.001); + /* you can adjust this factor to change the shape/center-weighting + of the gaussian */ + maskData[x] = (float) pow((1.0 / sqrt(2.0 * 3.14159265359 * dev)), + ((-(z - 1.0) * -(x - 1.0)) / + (2.0 * dev))); } /* if there's any remainder, multiply the first/last values in MaskData it. this allows us to support float radius values. */ if (remainder > 0.0) { - maskData[0] *= remainder; - maskData[radius - 1] *= remainder; + maskData[0] *= remainder; + maskData[radius - 1] *= remainder; } for (x = 0; x < radius; x++) { - /* this is done separately now due to the correction for float - radius values above */ - sum += maskData[x]; + /* this is done separately now due to the correction for float + radius values above */ + sum += maskData[x]; } for (i = 0; i < radius; i++) { - maskData[i] *= (1.0 / sum); - /* printf("%f\n", maskData[i]); */ + maskData[i] *= (1.0 / sum); + /* printf("%f\n", maskData[i]); */ } /* create a temporary memory buffer for the data for the first pass @@ -140,9 +140,9 @@ gblur(Imaging im, Imaging imOut, float floatRadius, int channels, int padding) /* don't bother about alpha/padding */ buffer = calloc((size_t) (im->xsize * im->ysize * channels), - sizeof(float)); + sizeof(float)); if (buffer == NULL) - return ImagingError_MemoryError(); + return ImagingError_MemoryError(); /* be nice to other threads while you go off to lala land */ ImagingSectionEnter(&cookie); @@ -153,94 +153,94 @@ gblur(Imaging im, Imaging imOut, float floatRadius, int channels, int padding) /* perform a blur on each line, and place in the temporary storage buffer */ for (y = 0; y < im->ysize; y++) { - if (channels == 1 && im->image8 != NULL) { - line8 = (UINT8 *) im->image8[y]; - } else { - line = im->image32[y]; - } - 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 - current pixel */ - for (pix = 0; pix < radius; pix++) { - /* figure the offset of this neighbor pixel */ - offset = - (int) ((-((float) radius / 2.0) + (float) pix) + 0.5); - if (x + offset < 0) - offset = -x; - else if (x + offset >= im->xsize) - offset = im->xsize - x - 1; + if (channels == 1 && im->image8 != NULL) { + line8 = (UINT8 *) im->image8[y]; + } else { + line = im->image32[y]; + } + 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 + current pixel */ + for (pix = 0; pix < radius; pix++) { + /* figure the offset of this neighbor pixel */ + offset = + (int) ((-((float) radius / 2.0) + (float) pix) + 0.5); + if (x + offset < 0) + offset = -x; + else if (x + offset >= im->xsize) + offset = im->xsize - x - 1; - /* add (neighbor pixel value * maskData[pix]) to the current - pixel value */ - if (channels == 1) { - buffer[(y * im->xsize) + x] += - ((float) ((UINT8 *) & line8[x + offset])[0]) * - (maskData[pix]); - } else { - for (channel = 0; channel < channels; channel++) { - buffer[(y * im->xsize * channels) + - (x * channels) + channel] += - ((float) ((UINT8 *) & line[x + offset]) - [channel]) * (maskData[pix]); - } - } - } - } + /* add (neighbor pixel value * maskData[pix]) to the current + pixel value */ + if (channels == 1) { + buffer[(y * im->xsize) + x] += + ((float) ((UINT8 *) & line8[x + offset])[0]) * + (maskData[pix]); + } else { + for (channel = 0; channel < channels; channel++) { + buffer[(y * im->xsize * channels) + + (x * channels) + channel] += + ((float) ((UINT8 *) & line[x + offset]) + [channel]) * (maskData[pix]); + } + } + } + } } /* perform a blur on each column in the buffer, and place in the output image */ for (x = 0; x < im->xsize; x++) { - for (y = 0; y < im->ysize; y++) { - newPixel[0] = newPixel[1] = newPixel[2] = newPixel[3] = 0; - /* for each neighbor pixel, factor in its value/weighting to the - current pixel */ - for (pix = 0; pix < radius; pix++) { - /* figure the offset of this neighbor pixel */ - offset = - (int) (-((float) radius / 2.0) + (float) pix + 0.5); - if (y + offset < 0) - offset = -y; - else if (y + offset >= im->ysize) - offset = im->ysize - y - 1; - /* add (neighbor pixel value * maskData[pix]) to the current - pixel value */ - for (channel = 0; channel < channels; channel++) { - newPixel[channel] += - (buffer - [((y + offset) * im->xsize * channels) + - (x * channels) + channel]) * (maskData[pix]); - } - } - /* if the image is RGBX or RGBA, copy the 4th channel data to - newPixel, so it gets put in imOut */ - if (strcmp(im->mode, "RGBX") == 0 - || strcmp(im->mode, "RGBA") == 0) { - newPixel[3] = (float) ((UINT8 *) & line[x + offset])[3]; - } + for (y = 0; y < im->ysize; y++) { + newPixel[0] = newPixel[1] = newPixel[2] = newPixel[3] = 0; + /* for each neighbor pixel, factor in its value/weighting to the + current pixel */ + for (pix = 0; pix < radius; pix++) { + /* figure the offset of this neighbor pixel */ + offset = + (int) (-((float) radius / 2.0) + (float) pix + 0.5); + if (y + offset < 0) + offset = -y; + else if (y + offset >= im->ysize) + offset = im->ysize - y - 1; + /* add (neighbor pixel value * maskData[pix]) to the current + pixel value */ + for (channel = 0; channel < channels; channel++) { + newPixel[channel] += + (buffer + [((y + offset) * im->xsize * channels) + + (x * channels) + channel]) * (maskData[pix]); + } + } + /* if the image is RGBX or RGBA, copy the 4th channel data to + newPixel, so it gets put in imOut */ + if (strcmp(im->mode, "RGBX") == 0 + || strcmp(im->mode, "RGBA") == 0) { + newPixel[3] = (float) ((UINT8 *) & line[x + offset])[3]; + } - /* pack the channels into an INT32 so we can put them back in - the PIL image */ - newPixelFinals = 0; - if (channels == 1) { - newPixelFinals = clip(newPixel[0]); - } else { - /* for RGB, the fourth channel isn't used anyways, so just - pack a 0 in there, this saves checking the mode for each - pixel. */ - /* this doesn't work on little-endian machines... fix it! */ - newPixelFinals = - clip(newPixel[0]) | clip(newPixel[1]) << 8 | - clip(newPixel[2]) << 16 | clip(newPixel[3]) << 24; - } - /* set the resulting pixel in imOut */ - if (channels == 1) { - imOut->image8[y][x] = (UINT8) newPixelFinals; - } else { - imOut->image32[y][x] = newPixelFinals; - } - } + /* pack the channels into an INT32 so we can put them back in + the PIL image */ + newPixelFinals = 0; + if (channels == 1) { + newPixelFinals = clip(newPixel[0]); + } else { + /* for RGB, the fourth channel isn't used anyways, so just + pack a 0 in there, this saves checking the mode for each + pixel. */ + /* this doesn't work on little-endian machines... fix it! */ + newPixelFinals = + clip(newPixel[0]) | clip(newPixel[1]) << 8 | + clip(newPixel[2]) << 16 | clip(newPixel[3]) << 24; + } + /* set the resulting pixel in imOut */ + if (channels == 1) { + imOut->image8[y][x] = (UINT8) newPixelFinals; + } else { + imOut->image32[y][x] = newPixelFinals; + } + } } /* free the buffer */ @@ -258,29 +258,29 @@ Imaging ImagingGaussianBlur(Imaging im, Imaging imOut, float radius) int padding = 0; if (strcmp(im->mode, "RGB") == 0) { - channels = 3; - padding = 1; + channels = 3; + padding = 1; } else if (strcmp(im->mode, "RGBA") == 0) { - channels = 3; - padding = 1; + channels = 3; + padding = 1; } else if (strcmp(im->mode, "RGBX") == 0) { - channels = 3; - padding = 1; + channels = 3; + padding = 1; } else if (strcmp(im->mode, "CMYK") == 0) { - channels = 4; - padding = 0; + channels = 4; + padding = 0; } else if (strcmp(im->mode, "L") == 0) { - channels = 1; - padding = 0; + channels = 1; + padding = 0; } else - return ImagingError_ModeError(); + return ImagingError_ModeError(); return gblur(im, imOut, radius, channels, padding); } Imaging ImagingUnsharpMask(Imaging im, Imaging imOut, float radius, int percent, - int threshold) + int threshold) { ImagingSectionCookie cookie; @@ -302,28 +302,28 @@ ImagingUnsharpMask(Imaging im, Imaging imOut, float radius, int percent, INT32 newPixel = 0; if (strcmp(im->mode, "RGB") == 0) { - channels = 3; - padding = 1; + channels = 3; + padding = 1; } else if (strcmp(im->mode, "RGBA") == 0) { - channels = 3; - padding = 1; + channels = 3; + padding = 1; } else if (strcmp(im->mode, "RGBX") == 0) { - channels = 3; - padding = 1; + channels = 3; + padding = 1; } else if (strcmp(im->mode, "CMYK") == 0) { - channels = 4; - padding = 0; + channels = 4; + padding = 0; } else if (strcmp(im->mode, "L") == 0) { - channels = 1; - padding = 0; + channels = 1; + padding = 0; } else - return ImagingError_ModeError(); + return ImagingError_ModeError(); /* first, do a gaussian blur on the image, putting results in imOut temporarily */ result = gblur(im, imOut, radius, channels, padding); if (!result) - return NULL; + return NULL; /* now, go through each pixel, compare "normal" pixel to blurred pixel. if the difference is more than threshold values, apply @@ -333,63 +333,63 @@ ImagingUnsharpMask(Imaging im, Imaging imOut, float radius, int percent, ImagingSectionEnter(&cookie); for (y = 0; y < im->ysize; y++) { - if (channels == 1) { - lineIn8 = im->image8[y]; - lineOut8 = imOut->image8[y]; - } else { - lineIn = im->image32[y]; - lineOut = imOut->image32[y]; - } - for (x = 0; x < im->xsize; x++) { - newPixel = 0; - /* compare in/out pixels, apply sharpening */ - if (channels == 1) { - diff = - ((UINT8 *) & lineIn8[x])[0] - - ((UINT8 *) & lineOut8[x])[0]; - if (abs(diff) > threshold) { - /* add the diff*percent to the original pixel */ - imOut->image8[y][x] = - clip((((UINT8 *) & lineIn8[x])[0]) + - (diff * ((float) percent) / 100.0)); - } else { - /* newPixel is the same as imIn */ - imOut->image8[y][x] = ((UINT8 *) & lineIn8[x])[0]; - } - } + if (channels == 1) { + lineIn8 = im->image8[y]; + lineOut8 = imOut->image8[y]; + } else { + lineIn = im->image32[y]; + lineOut = imOut->image32[y]; + } + for (x = 0; x < im->xsize; x++) { + newPixel = 0; + /* compare in/out pixels, apply sharpening */ + if (channels == 1) { + diff = + ((UINT8 *) & lineIn8[x])[0] - + ((UINT8 *) & lineOut8[x])[0]; + if (abs(diff) > threshold) { + /* add the diff*percent to the original pixel */ + imOut->image8[y][x] = + clip((((UINT8 *) & lineIn8[x])[0]) + + (diff * ((float) percent) / 100.0)); + } else { + /* newPixel is the same as imIn */ + imOut->image8[y][x] = ((UINT8 *) & lineIn8[x])[0]; + } + } - else { - for (channel = 0; channel < channels; channel++) { - diff = (int) ((((UINT8 *) & lineIn[x])[channel]) - - (((UINT8 *) & lineOut[x])[channel])); - if (abs(diff) > threshold) { - /* add the diff*percent to the original pixel - this may not work for little-endian systems, fix it! */ - newPixel = - newPixel | - clip((float) (((UINT8 *) & lineIn[x])[channel]) - + - (diff * - (((float) percent / - 100.0)))) << (channel * 8); - } else { - /* newPixel is the same as imIn - this may not work for little-endian systems, fix it! */ - newPixel = - newPixel | ((UINT8 *) & lineIn[x])[channel] << - (channel * 8); - } - } - if (strcmp(im->mode, "RGBX") == 0 - || strcmp(im->mode, "RGBA") == 0) { - /* preserve the alpha channel - this may not work for little-endian systems, fix it! */ - newPixel = - newPixel | ((UINT8 *) & lineIn[x])[channel] << 24; - } - imOut->image32[y][x] = newPixel; - } - } + else { + for (channel = 0; channel < channels; channel++) { + diff = (int) ((((UINT8 *) & lineIn[x])[channel]) - + (((UINT8 *) & lineOut[x])[channel])); + if (abs(diff) > threshold) { + /* add the diff*percent to the original pixel + this may not work for little-endian systems, fix it! */ + newPixel = + newPixel | + clip((float) (((UINT8 *) & lineIn[x])[channel]) + + + (diff * + (((float) percent / + 100.0)))) << (channel * 8); + } else { + /* newPixel is the same as imIn + this may not work for little-endian systems, fix it! */ + newPixel = + newPixel | ((UINT8 *) & lineIn[x])[channel] << + (channel * 8); + } + } + if (strcmp(im->mode, "RGBX") == 0 + || strcmp(im->mode, "RGBA") == 0) { + /* preserve the alpha channel + this may not work for little-endian systems, fix it! */ + newPixel = + newPixel | ((UINT8 *) & lineIn[x])[channel] << 24; + } + imOut->image32[y][x] = newPixel; + } + } } ImagingSectionLeave(&cookie); From 05c99131e0e053acfd3c23895a28bd424f529d69 Mon Sep 17 00:00:00 2001 From: homm Date: Mon, 6 Oct 2014 21:27:08 +0400 Subject: [PATCH 02/15] fix blur for RGBA & RGBX --- libImaging/UnsharpMask.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/libImaging/UnsharpMask.c b/libImaging/UnsharpMask.c index fc2b4b175..e3e975ef0 100644 --- a/libImaging/UnsharpMask.c +++ b/libImaging/UnsharpMask.c @@ -79,6 +79,7 @@ gblur(Imaging im, Imaging imOut, float floatRadius, int channels, int padding) int radius = 0; float remainder = 0.0; + int hasAlpha = 0; int i; @@ -189,6 +190,10 @@ gblur(Imaging im, Imaging imOut, float floatRadius, int channels, int padding) } } + if (strcmp(im->mode, "RGBX") == 0 || strcmp(im->mode, "RGBA") == 0) { + hasAlpha = 1; + } + /* perform a blur on each column in the buffer, and place in the output image */ for (x = 0; x < im->xsize; x++) { @@ -204,6 +209,7 @@ gblur(Imaging im, Imaging imOut, float floatRadius, int channels, int padding) offset = -y; else if (y + offset >= im->ysize) offset = im->ysize - y - 1; + /* add (neighbor pixel value * maskData[pix]) to the current pixel value */ for (channel = 0; channel < channels; channel++) { @@ -215,9 +221,8 @@ gblur(Imaging im, Imaging imOut, float floatRadius, int channels, int padding) } /* if the image is RGBX or RGBA, copy the 4th channel data to newPixel, so it gets put in imOut */ - if (strcmp(im->mode, "RGBX") == 0 - || strcmp(im->mode, "RGBA") == 0) { - newPixel[3] = (float) ((UINT8 *) & line[x + offset])[3]; + if (hasAlpha) { + newPixel[3] = (float) ((UINT8 *) & im->image32[y][x])[3]; } /* pack the channels into an INT32 so we can put them back in From ddae12928ae7dd919086ffcc4c0ec940e9024360 Mon Sep 17 00:00:00 2001 From: homm Date: Wed, 8 Oct 2014 06:49:56 +0400 Subject: [PATCH 03/15] add detailed test for blur and simple test for sharp --- Tests/images/color_snakes.png | Bin 0 -> 1311 bytes Tests/test_imageops_usm.py | 34 +++++++++++++++++++++++++++++++--- 2 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 Tests/images/color_snakes.png diff --git a/Tests/images/color_snakes.png b/Tests/images/color_snakes.png new file mode 100644 index 0000000000000000000000000000000000000000..bf3a351964f4d9ce61ef88222d133f66b45e4b2b GIT binary patch literal 1311 zcmZ`(Uue@n9KONSnKDEL_YYZ&;#+e`*WsF_f!eCwSm*2}cA~N@z0SC_iAhRRL73vp z1QC^qj0rwDL>LV8!HGV|UVKu)M<)m}WeDP%h@y9C*Tv8UlH7g2@4Mgc`z3eNLxabf zsdfqg(A<|yr16`Ksiv*?c_Z}Z1%5S7#8NQ;7HM8|a#(cNsA16JV8Pm7S!8{k1hN!UHEdNc z&}3bCTrb*Dh9QY+SEWu{&23~VSXEotAS4mUvmC4^Lyo$Mj6^n-WtEyMqiAZbr>p{z zhVrOjTUf`}O^1716aH7EBO8@uZWAlsL{hnsMwYG>NefOER9oUj*N`9H=txBs*Yk#n zEDOt|?yAI#`T3cRG}56^Rp15vg5#!&oyw%HT1{Te&mXOqzzcc=r1ip(>L4wXP;o Date: Wed, 8 Oct 2014 15:05:48 +0400 Subject: [PATCH 04/15] round pixel values --- Tests/test_imageops_usm.py | 18 +++++++++--------- libImaging/UnsharpMask.c | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Tests/test_imageops_usm.py b/Tests/test_imageops_usm.py index d1bdacd52..5164af015 100644 --- a/Tests/test_imageops_usm.py +++ b/Tests/test_imageops_usm.py @@ -66,7 +66,7 @@ class TestImageOpsUsm(PillowTestCase): def test_blur_accuracy(self): - i = snakes._new(ImageOps.gaussian_blur(snakes, .9)) + i = snakes._new(ImageOps.gaussian_blur(snakes, 1)) # Alpha channel must match whole. self.assertEqual(i.split()[3], snakes.split()[3]) # These pixels surrounded with pixels with 255 intensity. @@ -77,14 +77,14 @@ class TestImageOpsUsm(PillowTestCase): self.assertEqual(i.im.getpixel((x, y))[c], 255) # Fuzzy match. gp = lambda x, y: i.im.getpixel((x, y)) - self.assertTrue(212 <= gp(7, 4)[0] <= 214) - self.assertTrue(212 <= gp(7, 5)[2] <= 214) - self.assertTrue(212 <= gp(7, 6)[2] <= 214) - self.assertTrue(212 <= gp(7, 7)[1] <= 214) - self.assertTrue(212 <= gp(8, 4)[0] <= 214) - self.assertTrue(212 <= gp(8, 5)[2] <= 214) - self.assertTrue(212 <= gp(8, 6)[2] <= 214) - self.assertTrue(212 <= gp(8, 7)[1] <= 214) + self.assertTrue(211 <= gp(7, 4)[0] <= 213) + self.assertTrue(211 <= gp(7, 5)[2] <= 213) + self.assertTrue(211 <= gp(7, 6)[2] <= 213) + self.assertTrue(211 <= gp(7, 7)[1] <= 213) + self.assertTrue(211 <= gp(8, 4)[0] <= 213) + self.assertTrue(211 <= gp(8, 5)[2] <= 213) + self.assertTrue(211 <= gp(8, 6)[2] <= 213) + self.assertTrue(211 <= gp(8, 7)[1] <= 213) if __name__ == '__main__': unittest.main() diff --git a/libImaging/UnsharpMask.c b/libImaging/UnsharpMask.c index e3e975ef0..0e0eb66e4 100644 --- a/libImaging/UnsharpMask.c +++ b/libImaging/UnsharpMask.c @@ -51,7 +51,7 @@ static inline UINT8 clip(double in) return (UINT8) 255; if (in <= 0.0) return (UINT8) 0; - return (UINT8) in; + return (UINT8) (in + 0.5); } static Imaging From bef7e1dce8a47f3136b5b9d94d6e821aa2d7a0d0 Mon Sep 17 00:00:00 2001 From: homm Date: Wed, 8 Oct 2014 17:40:33 +0400 Subject: [PATCH 05/15] cache hasAlpha for ImagingUnsharpMask --- libImaging/UnsharpMask.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libImaging/UnsharpMask.c b/libImaging/UnsharpMask.c index 0e0eb66e4..76d630a8f 100644 --- a/libImaging/UnsharpMask.c +++ b/libImaging/UnsharpMask.c @@ -293,6 +293,7 @@ ImagingUnsharpMask(Imaging im, Imaging imOut, float radius, int percent, int channel = 0; int channels = 0; int padding = 0; + int hasAlpha = 0; int x = 0; int y = 0; @@ -337,6 +338,10 @@ ImagingUnsharpMask(Imaging im, Imaging imOut, float radius, int percent, ImagingSectionEnter(&cookie); + if (strcmp(im->mode, "RGBX") == 0 || strcmp(im->mode, "RGBA") == 0) { + hasAlpha = 1; + } + for (y = 0; y < im->ysize; y++) { if (channels == 1) { lineIn8 = im->image8[y]; @@ -385,8 +390,7 @@ ImagingUnsharpMask(Imaging im, Imaging imOut, float radius, int percent, (channel * 8); } } - if (strcmp(im->mode, "RGBX") == 0 - || strcmp(im->mode, "RGBA") == 0) { + if (hasAlpha) { /* preserve the alpha channel this may not work for little-endian systems, fix it! */ newPixel = From 7bc19c4019a8000ced8752d5d85ab4b3655d1d4c Mon Sep 17 00:00:00 2001 From: homm Date: Sat, 11 Oct 2014 23:03:51 +0400 Subject: [PATCH 06/15] reference gaussian_blur implementation radius meaning match graphicmagick, pixelmator other software and standard deviation from classic gaussian blur algorithm --- libImaging/UnsharpMask.c | 61 +++++++++++++--------------------------- 1 file changed, 20 insertions(+), 41 deletions(-) diff --git a/libImaging/UnsharpMask.c b/libImaging/UnsharpMask.c index 76d630a8f..c6a279cd4 100644 --- a/libImaging/UnsharpMask.c +++ b/libImaging/UnsharpMask.c @@ -62,7 +62,7 @@ gblur(Imaging im, Imaging imOut, float floatRadius, int channels, int padding) float *maskData = NULL; int y = 0; int x = 0; - float z = 0; + int z = 0; float sum = 0.0; float dev = 0.0; @@ -78,7 +78,7 @@ gblur(Imaging im, Imaging imOut, float floatRadius, int channels, int padding) INT32 newPixelFinals; int radius = 0; - float remainder = 0.0; + int diameter = 0; int hasAlpha = 0; 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, 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 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 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 */ - maskData = malloc(radius * sizeof(float)); - /* FIXME: error checking */ - for (x = 0; x < radius; x++) { - z = ((float) (x + 2) / ((float) radius)); - dev = 0.5 + (((float) (radius * radius)) * 0.001); - /* you can adjust this factor to change the shape/center-weighting - of the gaussian */ - maskData[x] = (float) pow((1.0 / sqrt(2.0 * 3.14159265359 * dev)), - ((-(z - 1.0) * -(x - 1.0)) / - (2.0 * dev))); + maskData = malloc(diameter * sizeof(float)); + for (x = 0; x < diameter; x++) { + z = x - radius; + dev = floatRadius * floatRadius; + /* http://en.wikipedia.org/wiki/Gaussian_blur + "1 / sqrt(2 * pi * dev)" is constant and will be eliminated by + normalization. */ + maskData[x] = pow(2.718281828459, -z * z / (2 * dev)); } - /* if there's any remainder, multiply the first/last values in - 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++) { + for (x = 0; x < diameter; x++) { /* this is done separately now due to the correction for float radius values above */ sum += maskData[x]; } - for (i = 0; i < radius; i++) { + for (i = 0; i < diameter; i++) { 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 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 */ 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 */ for (y = 0; y < im->ysize; y++) { 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]; } 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 current pixel */ - for (pix = 0; pix < radius; pix++) { + for (pix = 0; pix < diameter; pix++) { /* figure the offset of this neighbor pixel */ - offset = - (int) ((-((float) radius / 2.0) + (float) pix) + 0.5); + offset = pix - radius; if (x + offset < 0) offset = -x; 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; /* for each neighbor pixel, factor in its value/weighting to the current pixel */ - for (pix = 0; pix < radius; pix++) { + for (pix = 0; pix < diameter; pix++) { /* figure the offset of this neighbor pixel */ - offset = - (int) (-((float) radius / 2.0) + (float) pix + 0.5); + offset = pix - radius; if (y + offset < 0) offset = -y; else if (y + offset >= im->ysize) From b1b5db16cd35ea458f40b9aec8716c6fe7cbcb85 Mon Sep 17 00:00:00 2001 From: homm Date: Sun, 12 Oct 2014 00:49:45 +0400 Subject: [PATCH 07/15] padding not using anywhere --- libImaging/UnsharpMask.c | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/libImaging/UnsharpMask.c b/libImaging/UnsharpMask.c index c6a279cd4..7600826b7 100644 --- a/libImaging/UnsharpMask.c +++ b/libImaging/UnsharpMask.c @@ -55,7 +55,7 @@ static inline UINT8 clip(double in) } static Imaging -gblur(Imaging im, Imaging imOut, float floatRadius, int channels, int padding) +gblur(Imaging im, Imaging imOut, float floatRadius, int channels) { ImagingSectionCookie cookie; @@ -125,7 +125,7 @@ gblur(Imaging im, Imaging imOut, float floatRadius, int channels, int padding) /* create a temporary memory buffer for the data for the first pass memset the buffer to 0 so we can use it directly with += */ - /* don't bother about alpha/padding */ + /* don't bother about alpha */ buffer = calloc((size_t) (im->xsize * im->ysize * channels), sizeof(float)); if (buffer == NULL) @@ -239,27 +239,21 @@ gblur(Imaging im, Imaging imOut, float floatRadius, int channels, int padding) Imaging ImagingGaussianBlur(Imaging im, Imaging imOut, float radius) { int channels = 0; - int padding = 0; if (strcmp(im->mode, "RGB") == 0) { channels = 3; - padding = 1; } else if (strcmp(im->mode, "RGBA") == 0) { channels = 3; - padding = 1; } else if (strcmp(im->mode, "RGBX") == 0) { channels = 3; - padding = 1; } else if (strcmp(im->mode, "CMYK") == 0) { channels = 4; - padding = 0; } else if (strcmp(im->mode, "L") == 0) { channels = 1; - padding = 0; } else return ImagingError_ModeError(); - return gblur(im, imOut, radius, channels, padding); + return gblur(im, imOut, radius, channels); } Imaging @@ -271,7 +265,6 @@ ImagingUnsharpMask(Imaging im, Imaging imOut, float radius, int percent, Imaging result; int channel = 0; int channels = 0; - int padding = 0; int hasAlpha = 0; int x = 0; @@ -288,25 +281,20 @@ ImagingUnsharpMask(Imaging im, Imaging imOut, float radius, int percent, if (strcmp(im->mode, "RGB") == 0) { channels = 3; - padding = 1; } else if (strcmp(im->mode, "RGBA") == 0) { channels = 3; - padding = 1; } else if (strcmp(im->mode, "RGBX") == 0) { channels = 3; - padding = 1; } else if (strcmp(im->mode, "CMYK") == 0) { channels = 4; - padding = 0; } else if (strcmp(im->mode, "L") == 0) { channels = 1; - padding = 0; } else return ImagingError_ModeError(); /* first, do a gaussian blur on the image, putting results in imOut temporarily */ - result = gblur(im, imOut, radius, channels, padding); + result = gblur(im, imOut, radius, channels); if (!result) return NULL; From 5bb0cfa17aa22b7fd1351af2a1150824de34b9a9 Mon Sep 17 00:00:00 2001 From: homm Date: Sun, 12 Oct 2014 02:05:13 +0400 Subject: [PATCH 08/15] remove pseudo vcs --- libImaging/UnsharpMask.c | 35 ----------------------------------- 1 file changed, 35 deletions(-) diff --git a/libImaging/UnsharpMask.c b/libImaging/UnsharpMask.c index 7600826b7..ede49af5b 100644 --- a/libImaging/UnsharpMask.c +++ b/libImaging/UnsharpMask.c @@ -9,41 +9,6 @@ #include "Python.h" #include "Imaging.h" -#define PILUSMVERSION "0.6.1" - -/* version history - -0.6.1 converted to C and added to PIL 1.1.7 - -0.6.0 fixed/improved float radius support (oops!) - now that radius can be a float (properly), changed radius value to - be an actual radius (instead of diameter). So, you should get - similar results from PIL_usm as from other paint programs when - using the SAME values (no doubling of radius required any more). - Be careful, this may "break" software if you had it set for 2x - or 5x the radius as was recommended with earlier versions. - made PILusm thread-friendly (release GIL before lengthly operations, - and re-acquire it before returning to Python). This makes a huge - difference with multi-threaded applications on dual-processor - or "Hyperthreading"-enabled systems (Pentium4, Xeon, etc.) - -0.5.0 added support for float radius values! - -0.4.0 tweaked gaussian curve calculation to be closer to consistent shape - across a wide range of radius values - -0.3.0 changed deviation calculation in gausian algorithm to be dynamic - _gblur now adds 1 to the user-supplied radius before using it so - that a value of "0" returns the original image instead of a - black one. - fixed handling of alpha channel in RGBX, RGBA images - improved speed of gblur by reducing unnecessary checks and assignments - -0.2.0 fixed L-mode image support - -0.1.0 initial release - -*/ static inline UINT8 clip(double in) { From 091b15f9d5afb3e49d47e7f93b19b464af21d7cb Mon Sep 17 00:00:00 2001 From: homm Date: Sun, 12 Oct 2014 02:59:21 +0400 Subject: [PATCH 09/15] rename vars --- libImaging/UnsharpMask.c | 50 ++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/libImaging/UnsharpMask.c b/libImaging/UnsharpMask.c index ede49af5b..52379a21c 100644 --- a/libImaging/UnsharpMask.c +++ b/libImaging/UnsharpMask.c @@ -20,16 +20,14 @@ static inline UINT8 clip(double in) } static Imaging -gblur(Imaging im, Imaging imOut, float floatRadius, int channels) +gblur(Imaging im, Imaging imOut, float radius, int channels) { ImagingSectionCookie cookie; float *maskData = NULL; int y = 0; int x = 0; - int z = 0; float sum = 0.0; - float dev = 0.0; float *buffer = NULL; @@ -42,12 +40,10 @@ gblur(Imaging im, Imaging imOut, float floatRadius, int channels) int offset = 0; INT32 newPixelFinals; - int radius = 0; - int diameter = 0; + int effectiveRadius = 0; + int window = 0; int hasAlpha = 0; - int i; - /* Do the gaussian blur */ /* For a symmetrical gaussian blur, instead of doing a radius*radius @@ -57,33 +53,33 @@ gblur(Imaging im, Imaging imOut, float floatRadius, int channels) radius of 5 instead of 25 lookups). So, we blur the lines first, then we blur the resulting columns. */ - /* 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 - so that it is a true "radius", not a diameter (the results match - other paint programs closer that way too). */ - radius = (int) ceil(floatRadius * 2.57); - diameter = radius * 2 + 1; + /* Only pixels in effective radius from source pixel are accounted. + The Gaussian values outside 3 x radius is near zero. */ + effectiveRadius = (int) ceil(radius * 2.57); + /* Window is number of pixels forming the result pixel on one axis. + It is source pixel and effective radius in both directions. */ + window = effectiveRadius * 2 + 1; /* create the maskData for the gaussian curve */ - maskData = malloc(diameter * sizeof(float)); - for (x = 0; x < diameter; x++) { - z = x - radius; - dev = floatRadius * floatRadius; + maskData = malloc(window * sizeof(float)); + for (pix = 0; pix < window; pix++) { + offset = pix - effectiveRadius; /* http://en.wikipedia.org/wiki/Gaussian_blur "1 / sqrt(2 * pi * dev)" is constant and will be eliminated by normalization. */ - maskData[x] = pow(2.718281828459, -z * z / (2 * dev)); + maskData[pix] = pow(2.718281828459, + -offset * offset / (2 * radius * radius)); } - for (x = 0; x < diameter; x++) { + for (pix = 0; pix < window; pix++) { /* this is done separately now due to the correction for float radius values above */ - sum += maskData[x]; + sum += maskData[pix]; } - for (i = 0; i < diameter; i++) { - maskData[i] *= (1.0 / sum); - // printf("%d %f\n", i, maskData[i]); + for (pix = 0; pix < window; pix++) { + maskData[pix] *= (1.0 / sum); + // printf("%d %f\n", pix, maskData[pix]); } // printf("\n"); @@ -109,9 +105,9 @@ gblur(Imaging im, Imaging imOut, float floatRadius, int channels) for (x = 0; x < im->xsize; x++) { /* for each neighbor pixel, factor in its value/weighting to the current pixel */ - for (pix = 0; pix < diameter; pix++) { + for (pix = 0; pix < window; pix++) { /* figure the offset of this neighbor pixel */ - offset = pix - radius; + offset = pix - effectiveRadius; if (x + offset < 0) offset = -x; else if (x + offset >= im->xsize) @@ -146,9 +142,9 @@ gblur(Imaging im, Imaging imOut, float floatRadius, int channels) newPixel[0] = newPixel[1] = newPixel[2] = newPixel[3] = 0; /* for each neighbor pixel, factor in its value/weighting to the current pixel */ - for (pix = 0; pix < diameter; pix++) { + for (pix = 0; pix < window; pix++) { /* figure the offset of this neighbor pixel */ - offset = pix - radius; + offset = pix - effectiveRadius; if (y + offset < 0) offset = -y; else if (y + offset >= im->ysize) From 84b9f16bfdeadbaeb7e0773b87c38c7201e1fbdc Mon Sep 17 00:00:00 2001 From: homm Date: Sun, 12 Oct 2014 03:29:20 +0400 Subject: [PATCH 10/15] add effective_scale to all APIs --- PIL/ImageFilter.py | 5 +++-- PIL/ImageOps.py | 9 ++++++--- _imaging.c | 5 +++-- libImaging/Imaging.h | 3 ++- libImaging/UnsharpMask.c | 11 ++++++----- 5 files changed, 20 insertions(+), 13 deletions(-) diff --git a/PIL/ImageFilter.py b/PIL/ImageFilter.py index 1e0154d12..fed165831 100644 --- a/PIL/ImageFilter.py +++ b/PIL/ImageFilter.py @@ -149,11 +149,12 @@ class GaussianBlur(Filter): """ name = "GaussianBlur" - def __init__(self, radius=2): + def __init__(self, radius=2, effective_scale=None): self.radius = radius + self.effective_scale = effective_scale def filter(self, image): - return image.gaussian_blur(self.radius) + return image.gaussian_blur(self.radius, self.effective_scale) class UnsharpMask(Filter): diff --git a/PIL/ImageOps.py b/PIL/ImageOps.py index b3afd9e95..9a83687c1 100644 --- a/PIL/ImageOps.py +++ b/PIL/ImageOps.py @@ -413,15 +413,18 @@ def solarize(image, threshold=128): # -------------------------------------------------------------------- # PIL USM components, from Kevin Cazabon. -def gaussian_blur(im, radius=None): - """ PIL_usm.gblur(im, [radius])""" +def gaussian_blur(im, radius=None, effective_scale=None): + """ PIL_usm.gblur(im, [radius], [effective_scale])""" if radius is None: radius = 5.0 + if effective_scale is None: + effective_scale = 2.6 + im.load() - return im.im.gaussian_blur(radius) + return im.im.gaussian_blur(radius, effective_scale) gblur = gaussian_blur diff --git a/_imaging.c b/_imaging.c index 1759d4c8d..d7ec1747e 100644 --- a/_imaging.c +++ b/_imaging.c @@ -863,7 +863,8 @@ _gaussian_blur(ImagingObject* self, PyObject* args) Imaging imOut; float radius = 0; - if (!PyArg_ParseTuple(args, "f", &radius)) + float effectiveScale = 2.6; + if (!PyArg_ParseTuple(args, "f|f", &radius, &effectiveScale)) return NULL; imIn = self->image; @@ -871,7 +872,7 @@ _gaussian_blur(ImagingObject* self, PyObject* args) if (!imOut) return NULL; - if (!ImagingGaussianBlur(imIn, imOut, radius)) + if (!ImagingGaussianBlur(imIn, imOut, radius, effectiveScale)) return NULL; return PyImagingNew(imOut); diff --git a/libImaging/Imaging.h b/libImaging/Imaging.h index d958387c9..8c3bea475 100644 --- a/libImaging/Imaging.h +++ b/libImaging/Imaging.h @@ -263,7 +263,8 @@ extern Imaging ImagingFilter( FLOAT32 offset, FLOAT32 divisor); extern Imaging ImagingFlipLeftRight(Imaging imOut, Imaging imIn); extern Imaging ImagingFlipTopBottom(Imaging imOut, Imaging imIn); -extern Imaging ImagingGaussianBlur(Imaging im, Imaging imOut, float radius); +extern Imaging ImagingGaussianBlur(Imaging im, Imaging imOut, float radius, + float effectiveScale); extern Imaging ImagingGetBand(Imaging im, int band); extern int ImagingGetBBox(Imaging im, int bbox[4]); typedef struct { int x, y; INT32 count; INT32 pixel; } ImagingColorItem; diff --git a/libImaging/UnsharpMask.c b/libImaging/UnsharpMask.c index 52379a21c..8c75b600d 100644 --- a/libImaging/UnsharpMask.c +++ b/libImaging/UnsharpMask.c @@ -20,7 +20,7 @@ static inline UINT8 clip(double in) } static Imaging -gblur(Imaging im, Imaging imOut, float radius, int channels) +gblur(Imaging im, Imaging imOut, float radius, float effectiveScale, int channels) { ImagingSectionCookie cookie; @@ -55,7 +55,7 @@ gblur(Imaging im, Imaging imOut, float radius, int channels) /* Only pixels in effective radius from source pixel are accounted. The Gaussian values outside 3 x radius is near zero. */ - effectiveRadius = (int) ceil(radius * 2.57); + effectiveRadius = (int) ceil(radius * effectiveScale); /* Window is number of pixels forming the result pixel on one axis. It is source pixel and effective radius in both directions. */ window = effectiveRadius * 2 + 1; @@ -197,7 +197,8 @@ gblur(Imaging im, Imaging imOut, float radius, int channels) return imOut; } -Imaging ImagingGaussianBlur(Imaging im, Imaging imOut, float radius) +Imaging ImagingGaussianBlur(Imaging im, Imaging imOut, float radius, + float effectiveScale) { int channels = 0; @@ -214,7 +215,7 @@ Imaging ImagingGaussianBlur(Imaging im, Imaging imOut, float radius) } else return ImagingError_ModeError(); - return gblur(im, imOut, radius, channels); + return gblur(im, imOut, radius, effectiveScale, channels); } Imaging @@ -255,7 +256,7 @@ ImagingUnsharpMask(Imaging im, Imaging imOut, float radius, int percent, /* first, do a gaussian blur on the image, putting results in imOut temporarily */ - result = gblur(im, imOut, radius, channels); + result = gblur(im, imOut, radius, 2.6, channels); if (!result) return NULL; From c42991120a96985340d4820d9d9d329fb3d97dee Mon Sep 17 00:00:00 2001 From: homm Date: Sun, 12 Oct 2014 14:00:34 +0400 Subject: [PATCH 11/15] fix tests and set default effective_scale value for gaussian filter --- PIL/ImageFilter.py | 2 +- Tests/test_imageops_usm.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/PIL/ImageFilter.py b/PIL/ImageFilter.py index fed165831..e3b867737 100644 --- a/PIL/ImageFilter.py +++ b/PIL/ImageFilter.py @@ -154,7 +154,7 @@ class GaussianBlur(Filter): self.effective_scale = effective_scale def filter(self, image): - return image.gaussian_blur(self.radius, self.effective_scale) + return image.gaussian_blur(self.radius, self.effective_scale or 2.6) class UnsharpMask(Filter): diff --git a/Tests/test_imageops_usm.py b/Tests/test_imageops_usm.py index 5164af015..4645b3d6e 100644 --- a/Tests/test_imageops_usm.py +++ b/Tests/test_imageops_usm.py @@ -66,15 +66,15 @@ class TestImageOpsUsm(PillowTestCase): def test_blur_accuracy(self): - i = snakes._new(ImageOps.gaussian_blur(snakes, 1)) + i = snakes._new(ImageOps.gaussian_blur(snakes, .7)) # Alpha channel must match whole. self.assertEqual(i.split()[3], snakes.split()[3]) # These pixels surrounded with pixels with 255 intensity. - # They must be 255. + # They must be very close to 255. for x, y, c in [(1, 0, 1), (2, 0, 1), (7, 8, 1), (8, 8, 1), (2, 9, 1), (7, 3, 0), (8, 3, 0), (5, 8, 0), (5, 9, 0), (1, 3, 0), (4, 3, 2), (4, 2, 2)]: - self.assertEqual(i.im.getpixel((x, y))[c], 255) + self.assertGreaterEqual(i.im.getpixel((x, y))[c], 250) # Fuzzy match. gp = lambda x, y: i.im.getpixel((x, y)) self.assertTrue(211 <= gp(7, 4)[0] <= 213) From 51984f4aa83362b9d122241692511cd50b868c57 Mon Sep 17 00:00:00 2001 From: homm Date: Sun, 12 Oct 2014 14:14:56 +0400 Subject: [PATCH 12/15] fix radius == 0 --- libImaging/UnsharpMask.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/libImaging/UnsharpMask.c b/libImaging/UnsharpMask.c index 8c75b600d..1b29fbd3c 100644 --- a/libImaging/UnsharpMask.c +++ b/libImaging/UnsharpMask.c @@ -64,11 +64,15 @@ gblur(Imaging im, Imaging imOut, float radius, float effectiveScale, int channel maskData = malloc(window * sizeof(float)); for (pix = 0; pix < window; pix++) { offset = pix - effectiveRadius; - /* http://en.wikipedia.org/wiki/Gaussian_blur - "1 / sqrt(2 * pi * dev)" is constant and will be eliminated by - normalization. */ - maskData[pix] = pow(2.718281828459, - -offset * offset / (2 * radius * radius)); + if (radius) { + /* http://en.wikipedia.org/wiki/Gaussian_blur + "1 / sqrt(2 * pi * dev)" is constant and will be eliminated + by normalization. */ + maskData[pix] = pow(2.718281828459, + -offset * offset / (2 * radius * radius)); + } else { + maskData[pix] = 1; + } } for (pix = 0; pix < window; pix++) { From bc246853441e599a7e605b7e269abf3fb8974382 Mon Sep 17 00:00:00 2001 From: homm Date: Sun, 12 Oct 2014 14:21:13 +0400 Subject: [PATCH 13/15] do sum calculation in same loop as maskData calculation --- libImaging/UnsharpMask.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/libImaging/UnsharpMask.c b/libImaging/UnsharpMask.c index 1b29fbd3c..15d707dd2 100644 --- a/libImaging/UnsharpMask.c +++ b/libImaging/UnsharpMask.c @@ -73,11 +73,6 @@ gblur(Imaging im, Imaging imOut, float radius, float effectiveScale, int channel } else { maskData[pix] = 1; } - } - - for (pix = 0; pix < window; pix++) { - /* this is done separately now due to the correction for float - radius values above */ sum += maskData[pix]; } From e38a64b21bb5ec746d97c8663b79f6cd939f7a94 Mon Sep 17 00:00:00 2001 From: homm Date: Sun, 12 Oct 2014 15:13:37 +0400 Subject: [PATCH 14/15] round values with initial .5 this improves performance and readabillity --- libImaging/UnsharpMask.c | 50 +++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 29 deletions(-) diff --git a/libImaging/UnsharpMask.c b/libImaging/UnsharpMask.c index 15d707dd2..907f0d29d 100644 --- a/libImaging/UnsharpMask.c +++ b/libImaging/UnsharpMask.c @@ -10,15 +10,6 @@ #include "Imaging.h" -static inline UINT8 clip(double in) -{ - if (in >= 255.0) - return (UINT8) 255; - if (in <= 0.0) - return (UINT8) 0; - return (UINT8) (in + 0.5); -} - static Imaging gblur(Imaging im, Imaging imOut, float radius, float effectiveScale, int channels) { @@ -138,7 +129,7 @@ gblur(Imaging im, Imaging imOut, float radius, float effectiveScale, int channel output image */ for (x = 0; x < im->xsize; x++) { for (y = 0; y < im->ysize; y++) { - newPixel[0] = newPixel[1] = newPixel[2] = newPixel[3] = 0; + newPixel[0] = newPixel[1] = newPixel[2] = newPixel[3] = .5; /* for each neighbor pixel, factor in its value/weighting to the current pixel */ for (pix = 0; pix < window; pix++) { @@ -158,31 +149,23 @@ gblur(Imaging im, Imaging imOut, float radius, float effectiveScale, int channel (x * channels) + channel]) * (maskData[pix]); } } - /* if the image is RGBX or RGBA, copy the 4th channel data to - newPixel, so it gets put in imOut */ - if (hasAlpha) { - newPixel[3] = (float) ((UINT8 *) & im->image32[y][x])[3]; - } - /* pack the channels into an INT32 so we can put them back in - the PIL image */ - newPixelFinals = 0; if (channels == 1) { - newPixelFinals = clip(newPixel[0]); + imOut->image8[y][x] = (UINT8)(newPixel[0]); } else { + /* if the image is RGBX or RGBA, copy the 4th channel data to + newPixel, so it gets put in imOut */ + if (hasAlpha) { + newPixel[3] = (float) ((UINT8 *) & im->image32[y][x])[3]; + } + /* for RGB, the fourth channel isn't used anyways, so just pack a 0 in there, this saves checking the mode for each pixel. */ - /* this doesn't work on little-endian machines... fix it! */ - newPixelFinals = - clip(newPixel[0]) | clip(newPixel[1]) << 8 | - clip(newPixel[2]) << 16 | clip(newPixel[3]) << 24; - } - /* set the resulting pixel in imOut */ - if (channels == 1) { - imOut->image8[y][x] = (UINT8) newPixelFinals; - } else { - imOut->image32[y][x] = newPixelFinals; + /* this might don't work on little-endian machines... fix it! */ + imOut->image32[y][x] = + (UINT8)(newPixel[0]) | (UINT8)(newPixel[1]) << 8 | + (UINT8)(newPixel[2]) << 16 | (UINT8)(newPixel[3]) << 24; } } } @@ -196,6 +179,15 @@ gblur(Imaging im, Imaging imOut, float radius, float effectiveScale, int channel return imOut; } +static inline UINT8 clip(double in) +{ + if (in >= 255.0) + return (UINT8) 255; + if (in <= 0.0) + return (UINT8) 0; + return (UINT8) (in + 0.5); +} + Imaging ImagingGaussianBlur(Imaging im, Imaging imOut, float radius, float effectiveScale) { From d07c9c2e4e9614ad6be6bf049e584a87a4bf810c Mon Sep 17 00:00:00 2001 From: homm Date: Thu, 16 Oct 2014 16:00:29 +0400 Subject: [PATCH 15/15] unused --- libImaging/UnsharpMask.c | 1 - 1 file changed, 1 deletion(-) diff --git a/libImaging/UnsharpMask.c b/libImaging/UnsharpMask.c index 907f0d29d..b951a549a 100644 --- a/libImaging/UnsharpMask.c +++ b/libImaging/UnsharpMask.c @@ -29,7 +29,6 @@ gblur(Imaging im, Imaging imOut, float radius, float effectiveScale, int channel float newPixel[4]; int channel = 0; int offset = 0; - INT32 newPixelFinals; int effectiveRadius = 0; int window = 0;