mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-25 01:16:16 +03:00
Support I mode for BuiltinFilter
This commit is contained in:
parent
8df8b43edb
commit
d0b41da094
BIN
Tests/images/hopper_emboss_I.png
Normal file
BIN
Tests/images/hopper_emboss_I.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
BIN
Tests/images/hopper_emboss_more_I.png
Normal file
BIN
Tests/images/hopper_emboss_more_I.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
|
@ -30,15 +30,16 @@ from .helper import assert_image_equal, hopper
|
|||
ImageFilter.UnsharpMask(10),
|
||||
),
|
||||
)
|
||||
@pytest.mark.parametrize("mode", ("L", "RGB", "CMYK"))
|
||||
@pytest.mark.parametrize("mode", ("L", "I", "RGB", "CMYK"))
|
||||
def test_sanity(filter_to_apply, mode):
|
||||
im = hopper(mode)
|
||||
out = im.filter(filter_to_apply)
|
||||
assert out.mode == im.mode
|
||||
assert out.size == im.size
|
||||
if mode != "I" or isinstance(filter_to_apply, ImageFilter.BuiltinFilter):
|
||||
out = im.filter(filter_to_apply)
|
||||
assert out.mode == im.mode
|
||||
assert out.size == im.size
|
||||
|
||||
|
||||
@pytest.mark.parametrize("mode", ("L", "RGB", "CMYK"))
|
||||
@pytest.mark.parametrize("mode", ("L", "I", "RGB", "CMYK"))
|
||||
def test_sanity_error(mode):
|
||||
with pytest.raises(TypeError):
|
||||
im = hopper(mode)
|
||||
|
@ -130,10 +131,12 @@ def test_kernel_not_enough_coefficients():
|
|||
ImageFilter.Kernel((3, 3), (0, 0))
|
||||
|
||||
|
||||
@pytest.mark.parametrize("mode", ("L", "LA", "RGB", "CMYK"))
|
||||
@pytest.mark.parametrize("mode", ("L", "LA", "I", "RGB", "CMYK"))
|
||||
def test_consistency_3x3(mode):
|
||||
with Image.open("Tests/images/hopper.bmp") as source:
|
||||
with Image.open("Tests/images/hopper_emboss.bmp") as reference:
|
||||
reference_name = "hopper_emboss"
|
||||
reference_name += "_I.png" if mode == "I" else ".bmp"
|
||||
with Image.open("Tests/images/" + reference_name) as reference:
|
||||
kernel = ImageFilter.Kernel(
|
||||
(3, 3),
|
||||
# fmt: off
|
||||
|
@ -146,16 +149,20 @@ def test_consistency_3x3(mode):
|
|||
source = source.split() * 2
|
||||
reference = reference.split() * 2
|
||||
|
||||
assert_image_equal(
|
||||
Image.merge(mode, source[: len(mode)]).filter(kernel),
|
||||
Image.merge(mode, reference[: len(mode)]),
|
||||
)
|
||||
if mode == "I":
|
||||
source = source[0].convert(mode)
|
||||
else:
|
||||
source = Image.merge(mode, source[: len(mode)])
|
||||
reference = Image.merge(mode, reference[: len(mode)])
|
||||
assert_image_equal(source.filter(kernel), reference)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("mode", ("L", "LA", "RGB", "CMYK"))
|
||||
@pytest.mark.parametrize("mode", ("L", "LA", "I", "RGB", "CMYK"))
|
||||
def test_consistency_5x5(mode):
|
||||
with Image.open("Tests/images/hopper.bmp") as source:
|
||||
with Image.open("Tests/images/hopper_emboss_more.bmp") as reference:
|
||||
reference_name = "hopper_emboss_more"
|
||||
reference_name += "_I.png" if mode == "I" else ".bmp"
|
||||
with Image.open("Tests/images/" + reference_name) as reference:
|
||||
kernel = ImageFilter.Kernel(
|
||||
(5, 5),
|
||||
# fmt: off
|
||||
|
@ -170,10 +177,12 @@ def test_consistency_5x5(mode):
|
|||
source = source.split() * 2
|
||||
reference = reference.split() * 2
|
||||
|
||||
assert_image_equal(
|
||||
Image.merge(mode, source[: len(mode)]).filter(kernel),
|
||||
Image.merge(mode, reference[: len(mode)]),
|
||||
)
|
||||
if mode == "I":
|
||||
source = source[0].convert(mode)
|
||||
else:
|
||||
source = Image.merge(mode, source[: len(mode)])
|
||||
reference = Image.merge(mode, reference[: len(mode)])
|
||||
assert_image_equal(source.filter(kernel), reference)
|
||||
|
||||
|
||||
def test_invalid_box_blur_filter():
|
||||
|
|
|
@ -37,6 +37,17 @@ clip8(float in) {
|
|||
return (UINT8)in;
|
||||
}
|
||||
|
||||
static inline INT32
|
||||
clip32(float in) {
|
||||
if (in <= 0.0) {
|
||||
return 0;
|
||||
}
|
||||
if (in >= pow(2, 31) - 1) {
|
||||
return pow(2, 31) - 1;
|
||||
}
|
||||
return (INT32)in;
|
||||
}
|
||||
|
||||
Imaging
|
||||
ImagingExpand(Imaging imIn, int xmargin, int ymargin, int mode) {
|
||||
Imaging imOut;
|
||||
|
@ -96,8 +107,8 @@ ImagingExpand(Imaging imIn, int xmargin, int ymargin, int mode) {
|
|||
void
|
||||
ImagingFilter3x3(Imaging imOut, Imaging im, const float *kernel, float offset) {
|
||||
#define KERNEL1x3(in0, x, kernel, d) \
|
||||
(_i2f((UINT8)in0[x - d]) * (kernel)[0] + _i2f((UINT8)in0[x]) * (kernel)[1] + \
|
||||
_i2f((UINT8)in0[x + d]) * (kernel)[2])
|
||||
(_i2f(in0[x - d]) * (kernel)[0] + _i2f(in0[x]) * (kernel)[1] + \
|
||||
_i2f(in0[x + d]) * (kernel)[2])
|
||||
|
||||
int x = 0, y = 0;
|
||||
|
||||
|
@ -105,21 +116,40 @@ ImagingFilter3x3(Imaging imOut, Imaging im, const float *kernel, float offset) {
|
|||
if (im->bands == 1) {
|
||||
// Add one time for rounding
|
||||
offset += 0.5;
|
||||
for (y = 1; y < im->ysize - 1; y++) {
|
||||
UINT8 *in_1 = (UINT8 *)im->image[y - 1];
|
||||
UINT8 *in0 = (UINT8 *)im->image[y];
|
||||
UINT8 *in1 = (UINT8 *)im->image[y + 1];
|
||||
UINT8 *out = (UINT8 *)imOut->image[y];
|
||||
if (im->type == IMAGING_TYPE_INT32) {
|
||||
for (y = 1; y < im->ysize - 1; y++) {
|
||||
INT32 *in_1 = (INT32 *)im->image[y - 1];
|
||||
INT32 *in0 = (INT32 *)im->image[y];
|
||||
INT32 *in1 = (INT32 *)im->image[y + 1];
|
||||
INT32 *out = (INT32 *)imOut->image[y];
|
||||
|
||||
out[0] = in0[0];
|
||||
for (x = 1; x < im->xsize - 1; x++) {
|
||||
float ss = offset;
|
||||
ss += KERNEL1x3(in1, x, &kernel[0], 1);
|
||||
ss += KERNEL1x3(in0, x, &kernel[3], 1);
|
||||
ss += KERNEL1x3(in_1, x, &kernel[6], 1);
|
||||
out[x] = clip8(ss);
|
||||
out[0] = in0[0];
|
||||
for (x = 1; x < im->xsize - 1; x++) {
|
||||
float ss = offset;
|
||||
ss += KERNEL1x3(in1, x, &kernel[0], 1);
|
||||
ss += KERNEL1x3(in0, x, &kernel[3], 1);
|
||||
ss += KERNEL1x3(in_1, x, &kernel[6], 1);
|
||||
out[x] = clip32(ss);
|
||||
}
|
||||
out[x] = in0[x];
|
||||
}
|
||||
} else {
|
||||
for (y = 1; y < im->ysize - 1; y++) {
|
||||
UINT8 *in_1 = (UINT8 *)im->image[y - 1];
|
||||
UINT8 *in0 = (UINT8 *)im->image[y];
|
||||
UINT8 *in1 = (UINT8 *)im->image[y + 1];
|
||||
UINT8 *out = (UINT8 *)imOut->image[y];
|
||||
|
||||
out[0] = in0[0];
|
||||
for (x = 1; x < im->xsize - 1; x++) {
|
||||
float ss = offset;
|
||||
ss += KERNEL1x3(in1, x, &kernel[0], 1);
|
||||
ss += KERNEL1x3(in0, x, &kernel[3], 1);
|
||||
ss += KERNEL1x3(in_1, x, &kernel[6], 1);
|
||||
out[x] = clip8(ss);
|
||||
}
|
||||
out[x] = in0[x];
|
||||
}
|
||||
out[x] = in0[x];
|
||||
}
|
||||
} else {
|
||||
// Add one time for rounding
|
||||
|
@ -195,10 +225,10 @@ ImagingFilter3x3(Imaging imOut, Imaging im, const float *kernel, float offset) {
|
|||
void
|
||||
ImagingFilter5x5(Imaging imOut, Imaging im, const float *kernel, float offset) {
|
||||
#define KERNEL1x5(in0, x, kernel, d) \
|
||||
(_i2f((UINT8)in0[x - d - d]) * (kernel)[0] + \
|
||||
_i2f((UINT8)in0[x - d]) * (kernel)[1] + _i2f((UINT8)in0[x]) * (kernel)[2] + \
|
||||
_i2f((UINT8)in0[x + d]) * (kernel)[3] + \
|
||||
_i2f((UINT8)in0[x + d + d]) * (kernel)[4])
|
||||
(_i2f(in0[x - d - d]) * (kernel)[0] + \
|
||||
_i2f(in0[x - d]) * (kernel)[1] + _i2f(in0[x]) * (kernel)[2] + \
|
||||
_i2f(in0[x + d]) * (kernel)[3] + \
|
||||
_i2f(in0[x + d + d]) * (kernel)[4])
|
||||
|
||||
int x = 0, y = 0;
|
||||
|
||||
|
@ -207,27 +237,52 @@ ImagingFilter5x5(Imaging imOut, Imaging im, const float *kernel, float offset) {
|
|||
if (im->bands == 1) {
|
||||
// Add one time for rounding
|
||||
offset += 0.5;
|
||||
for (y = 2; y < im->ysize - 2; y++) {
|
||||
UINT8 *in_2 = (UINT8 *)im->image[y - 2];
|
||||
UINT8 *in_1 = (UINT8 *)im->image[y - 1];
|
||||
UINT8 *in0 = (UINT8 *)im->image[y];
|
||||
UINT8 *in1 = (UINT8 *)im->image[y + 1];
|
||||
UINT8 *in2 = (UINT8 *)im->image[y + 2];
|
||||
UINT8 *out = (UINT8 *)imOut->image[y];
|
||||
if (im->type == IMAGING_TYPE_INT32) {
|
||||
for (y = 2; y < im->ysize - 2; y++) {
|
||||
INT32 *in_2 = (INT32 *)im->image[y - 2];
|
||||
INT32 *in_1 = (INT32 *)im->image[y - 1];
|
||||
INT32 *in0 = (INT32 *)im->image[y];
|
||||
INT32 *in1 = (INT32 *)im->image[y + 1];
|
||||
INT32 *in2 = (INT32 *)im->image[y + 2];
|
||||
INT32 *out = (INT32 *)imOut->image[y];
|
||||
|
||||
out[0] = in0[0];
|
||||
out[1] = in0[1];
|
||||
for (x = 2; x < im->xsize - 2; x++) {
|
||||
float ss = offset;
|
||||
ss += KERNEL1x5(in2, x, &kernel[0], 1);
|
||||
ss += KERNEL1x5(in1, x, &kernel[5], 1);
|
||||
ss += KERNEL1x5(in0, x, &kernel[10], 1);
|
||||
ss += KERNEL1x5(in_1, x, &kernel[15], 1);
|
||||
ss += KERNEL1x5(in_2, x, &kernel[20], 1);
|
||||
out[x] = clip8(ss);
|
||||
out[0] = in0[0];
|
||||
out[1] = in0[1];
|
||||
for (x = 2; x < im->xsize - 2; x++) {
|
||||
float ss = offset;
|
||||
ss += KERNEL1x5(in2, x, &kernel[0], 1);
|
||||
ss += KERNEL1x5(in1, x, &kernel[5], 1);
|
||||
ss += KERNEL1x5(in0, x, &kernel[10], 1);
|
||||
ss += KERNEL1x5(in_1, x, &kernel[15], 1);
|
||||
ss += KERNEL1x5(in_2, x, &kernel[20], 1);
|
||||
out[x] = clip32(ss);
|
||||
}
|
||||
out[x + 0] = in0[x + 0];
|
||||
out[x + 1] = in0[x + 1];
|
||||
}
|
||||
} else {
|
||||
for (y = 2; y < im->ysize - 2; y++) {
|
||||
UINT8 *in_2 = (UINT8 *)im->image[y - 2];
|
||||
UINT8 *in_1 = (UINT8 *)im->image[y - 1];
|
||||
UINT8 *in0 = (UINT8 *)im->image[y];
|
||||
UINT8 *in1 = (UINT8 *)im->image[y + 1];
|
||||
UINT8 *in2 = (UINT8 *)im->image[y + 2];
|
||||
UINT8 *out = (UINT8 *)imOut->image[y];
|
||||
|
||||
out[0] = in0[0];
|
||||
out[1] = in0[1];
|
||||
for (x = 2; x < im->xsize - 2; x++) {
|
||||
float ss = offset;
|
||||
ss += KERNEL1x5(in2, x, &kernel[0], 1);
|
||||
ss += KERNEL1x5(in1, x, &kernel[5], 1);
|
||||
ss += KERNEL1x5(in0, x, &kernel[10], 1);
|
||||
ss += KERNEL1x5(in_1, x, &kernel[15], 1);
|
||||
ss += KERNEL1x5(in_2, x, &kernel[20], 1);
|
||||
out[x] = clip8(ss);
|
||||
}
|
||||
out[x + 0] = in0[x + 0];
|
||||
out[x + 1] = in0[x + 1];
|
||||
}
|
||||
out[x + 0] = in0[x + 0];
|
||||
out[x + 1] = in0[x + 1];
|
||||
}
|
||||
} else {
|
||||
// Add one time for rounding
|
||||
|
@ -327,7 +382,7 @@ ImagingFilter(Imaging im, int xsize, int ysize, const FLOAT32 *kernel, FLOAT32 o
|
|||
Imaging imOut;
|
||||
ImagingSectionCookie cookie;
|
||||
|
||||
if (!im || im->type != IMAGING_TYPE_UINT8) {
|
||||
if (im->type != IMAGING_TYPE_UINT8 && im->type != IMAGING_TYPE_INT32) {
|
||||
return (Imaging)ImagingError_ModeError();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user