mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-11-01 16:37:32 +03:00
157 lines
4.9 KiB
C
157 lines
4.9 KiB
C
/* PILusm, a gaussian blur and unsharp masking library for PIL
|
|
By Kevin Cazabon, copyright 2003
|
|
kevin_cazabon@hotmail.com
|
|
kevin@cazabon.com */
|
|
|
|
/* Originally released under LGPL. Graciously donated to PIL
|
|
for distribution under the standard PIL license in 2009." */
|
|
|
|
#include "Python.h"
|
|
#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);
|
|
}
|
|
|
|
Imaging ImagingGaussianBlur(Imaging im, Imaging imOut, float radius,
|
|
int passes)
|
|
{
|
|
float sigma2, L, l, a;
|
|
|
|
sigma2 = radius * radius / passes;
|
|
// from http://www.mia.uni-saarland.de/Publications/gwosdek-ssvm11.pdf
|
|
// [7] Box length.
|
|
L = sqrt(12.0 * sigma2 + 1.0);
|
|
// [11] Integer part of box radius.
|
|
l = floor((L - 1.0) / 2.0);
|
|
// [14], [Fig. 2] Fractional part of box radius.
|
|
a = (2 * l + 1) * (l * (l + 1) - 3 * sigma2);
|
|
a /= 6 * (sigma2 - (l + 1) * (l + 1));
|
|
|
|
return ImagingBoxBlur(imOut, im, l + a, passes);
|
|
}
|
|
|
|
|
|
Imaging
|
|
ImagingUnsharpMask(Imaging im, Imaging imOut, float radius, int percent,
|
|
int threshold)
|
|
{
|
|
ImagingSectionCookie cookie;
|
|
|
|
Imaging result;
|
|
int channel = 0;
|
|
int channels = 0;
|
|
int hasAlpha = 0;
|
|
|
|
int x = 0;
|
|
int y = 0;
|
|
|
|
int *lineIn = NULL;
|
|
int *lineOut = NULL;
|
|
UINT8 *lineIn8 = NULL;
|
|
UINT8 *lineOut8 = NULL;
|
|
|
|
int diff = 0;
|
|
|
|
INT32 newPixel = 0;
|
|
|
|
if (strcmp(im->mode, "RGB") == 0) {
|
|
channels = 3;
|
|
} else if (strcmp(im->mode, "RGBA") == 0) {
|
|
channels = 3;
|
|
} else if (strcmp(im->mode, "RGBX") == 0) {
|
|
channels = 3;
|
|
} else if (strcmp(im->mode, "CMYK") == 0) {
|
|
channels = 4;
|
|
} else if (strcmp(im->mode, "L") == 0) {
|
|
channels = 1;
|
|
} else
|
|
return ImagingError_ModeError();
|
|
|
|
/* first, do a gaussian blur on the image, putting results in imOut
|
|
temporarily */
|
|
result = ImagingGaussianBlur(im, imOut, radius, 3);
|
|
if (!result)
|
|
return NULL;
|
|
|
|
/* now, go through each pixel, compare "normal" pixel to blurred
|
|
pixel. if the difference is more than threshold values, apply
|
|
the OPPOSITE correction to the amount of blur, multiplied by
|
|
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];
|
|
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 (hasAlpha) {
|
|
/* 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);
|
|
|
|
return imOut;
|
|
}
|