mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-25 17:36:18 +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),
|
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):
|
def test_sanity(filter_to_apply, mode):
|
||||||
im = hopper(mode)
|
im = hopper(mode)
|
||||||
out = im.filter(filter_to_apply)
|
if mode != "I" or isinstance(filter_to_apply, ImageFilter.BuiltinFilter):
|
||||||
assert out.mode == im.mode
|
out = im.filter(filter_to_apply)
|
||||||
assert out.size == im.size
|
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):
|
def test_sanity_error(mode):
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
im = hopper(mode)
|
im = hopper(mode)
|
||||||
|
@ -130,10 +131,12 @@ def test_kernel_not_enough_coefficients():
|
||||||
ImageFilter.Kernel((3, 3), (0, 0))
|
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):
|
def test_consistency_3x3(mode):
|
||||||
with Image.open("Tests/images/hopper.bmp") as source:
|
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(
|
kernel = ImageFilter.Kernel(
|
||||||
(3, 3),
|
(3, 3),
|
||||||
# fmt: off
|
# fmt: off
|
||||||
|
@ -146,16 +149,20 @@ def test_consistency_3x3(mode):
|
||||||
source = source.split() * 2
|
source = source.split() * 2
|
||||||
reference = reference.split() * 2
|
reference = reference.split() * 2
|
||||||
|
|
||||||
assert_image_equal(
|
if mode == "I":
|
||||||
Image.merge(mode, source[: len(mode)]).filter(kernel),
|
source = source[0].convert(mode)
|
||||||
Image.merge(mode, reference[: len(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):
|
def test_consistency_5x5(mode):
|
||||||
with Image.open("Tests/images/hopper.bmp") as source:
|
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(
|
kernel = ImageFilter.Kernel(
|
||||||
(5, 5),
|
(5, 5),
|
||||||
# fmt: off
|
# fmt: off
|
||||||
|
@ -170,10 +177,12 @@ def test_consistency_5x5(mode):
|
||||||
source = source.split() * 2
|
source = source.split() * 2
|
||||||
reference = reference.split() * 2
|
reference = reference.split() * 2
|
||||||
|
|
||||||
assert_image_equal(
|
if mode == "I":
|
||||||
Image.merge(mode, source[: len(mode)]).filter(kernel),
|
source = source[0].convert(mode)
|
||||||
Image.merge(mode, reference[: len(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():
|
def test_invalid_box_blur_filter():
|
||||||
|
|
|
@ -37,6 +37,17 @@ clip8(float in) {
|
||||||
return (UINT8)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
|
Imaging
|
||||||
ImagingExpand(Imaging imIn, int xmargin, int ymargin, int mode) {
|
ImagingExpand(Imaging imIn, int xmargin, int ymargin, int mode) {
|
||||||
Imaging imOut;
|
Imaging imOut;
|
||||||
|
@ -96,8 +107,8 @@ ImagingExpand(Imaging imIn, int xmargin, int ymargin, int mode) {
|
||||||
void
|
void
|
||||||
ImagingFilter3x3(Imaging imOut, Imaging im, const float *kernel, float offset) {
|
ImagingFilter3x3(Imaging imOut, Imaging im, const float *kernel, float offset) {
|
||||||
#define KERNEL1x3(in0, x, kernel, d) \
|
#define KERNEL1x3(in0, x, kernel, d) \
|
||||||
(_i2f((UINT8)in0[x - d]) * (kernel)[0] + _i2f((UINT8)in0[x]) * (kernel)[1] + \
|
(_i2f(in0[x - d]) * (kernel)[0] + _i2f(in0[x]) * (kernel)[1] + \
|
||||||
_i2f((UINT8)in0[x + d]) * (kernel)[2])
|
_i2f(in0[x + d]) * (kernel)[2])
|
||||||
|
|
||||||
int x = 0, y = 0;
|
int x = 0, y = 0;
|
||||||
|
|
||||||
|
@ -105,21 +116,40 @@ ImagingFilter3x3(Imaging imOut, Imaging im, const float *kernel, float offset) {
|
||||||
if (im->bands == 1) {
|
if (im->bands == 1) {
|
||||||
// Add one time for rounding
|
// Add one time for rounding
|
||||||
offset += 0.5;
|
offset += 0.5;
|
||||||
for (y = 1; y < im->ysize - 1; y++) {
|
if (im->type == IMAGING_TYPE_INT32) {
|
||||||
UINT8 *in_1 = (UINT8 *)im->image[y - 1];
|
for (y = 1; y < im->ysize - 1; y++) {
|
||||||
UINT8 *in0 = (UINT8 *)im->image[y];
|
INT32 *in_1 = (INT32 *)im->image[y - 1];
|
||||||
UINT8 *in1 = (UINT8 *)im->image[y + 1];
|
INT32 *in0 = (INT32 *)im->image[y];
|
||||||
UINT8 *out = (UINT8 *)imOut->image[y];
|
INT32 *in1 = (INT32 *)im->image[y + 1];
|
||||||
|
INT32 *out = (INT32 *)imOut->image[y];
|
||||||
|
|
||||||
out[0] = in0[0];
|
out[0] = in0[0];
|
||||||
for (x = 1; x < im->xsize - 1; x++) {
|
for (x = 1; x < im->xsize - 1; x++) {
|
||||||
float ss = offset;
|
float ss = offset;
|
||||||
ss += KERNEL1x3(in1, x, &kernel[0], 1);
|
ss += KERNEL1x3(in1, x, &kernel[0], 1);
|
||||||
ss += KERNEL1x3(in0, x, &kernel[3], 1);
|
ss += KERNEL1x3(in0, x, &kernel[3], 1);
|
||||||
ss += KERNEL1x3(in_1, x, &kernel[6], 1);
|
ss += KERNEL1x3(in_1, x, &kernel[6], 1);
|
||||||
out[x] = clip8(ss);
|
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 {
|
} else {
|
||||||
// Add one time for rounding
|
// Add one time for rounding
|
||||||
|
@ -195,10 +225,10 @@ ImagingFilter3x3(Imaging imOut, Imaging im, const float *kernel, float offset) {
|
||||||
void
|
void
|
||||||
ImagingFilter5x5(Imaging imOut, Imaging im, const float *kernel, float offset) {
|
ImagingFilter5x5(Imaging imOut, Imaging im, const float *kernel, float offset) {
|
||||||
#define KERNEL1x5(in0, x, kernel, d) \
|
#define KERNEL1x5(in0, x, kernel, d) \
|
||||||
(_i2f((UINT8)in0[x - d - d]) * (kernel)[0] + \
|
(_i2f(in0[x - d - d]) * (kernel)[0] + \
|
||||||
_i2f((UINT8)in0[x - d]) * (kernel)[1] + _i2f((UINT8)in0[x]) * (kernel)[2] + \
|
_i2f(in0[x - d]) * (kernel)[1] + _i2f(in0[x]) * (kernel)[2] + \
|
||||||
_i2f((UINT8)in0[x + d]) * (kernel)[3] + \
|
_i2f(in0[x + d]) * (kernel)[3] + \
|
||||||
_i2f((UINT8)in0[x + d + d]) * (kernel)[4])
|
_i2f(in0[x + d + d]) * (kernel)[4])
|
||||||
|
|
||||||
int x = 0, y = 0;
|
int x = 0, y = 0;
|
||||||
|
|
||||||
|
@ -207,27 +237,52 @@ ImagingFilter5x5(Imaging imOut, Imaging im, const float *kernel, float offset) {
|
||||||
if (im->bands == 1) {
|
if (im->bands == 1) {
|
||||||
// Add one time for rounding
|
// Add one time for rounding
|
||||||
offset += 0.5;
|
offset += 0.5;
|
||||||
for (y = 2; y < im->ysize - 2; y++) {
|
if (im->type == IMAGING_TYPE_INT32) {
|
||||||
UINT8 *in_2 = (UINT8 *)im->image[y - 2];
|
for (y = 2; y < im->ysize - 2; y++) {
|
||||||
UINT8 *in_1 = (UINT8 *)im->image[y - 1];
|
INT32 *in_2 = (INT32 *)im->image[y - 2];
|
||||||
UINT8 *in0 = (UINT8 *)im->image[y];
|
INT32 *in_1 = (INT32 *)im->image[y - 1];
|
||||||
UINT8 *in1 = (UINT8 *)im->image[y + 1];
|
INT32 *in0 = (INT32 *)im->image[y];
|
||||||
UINT8 *in2 = (UINT8 *)im->image[y + 2];
|
INT32 *in1 = (INT32 *)im->image[y + 1];
|
||||||
UINT8 *out = (UINT8 *)imOut->image[y];
|
INT32 *in2 = (INT32 *)im->image[y + 2];
|
||||||
|
INT32 *out = (INT32 *)imOut->image[y];
|
||||||
|
|
||||||
out[0] = in0[0];
|
out[0] = in0[0];
|
||||||
out[1] = in0[1];
|
out[1] = in0[1];
|
||||||
for (x = 2; x < im->xsize - 2; x++) {
|
for (x = 2; x < im->xsize - 2; x++) {
|
||||||
float ss = offset;
|
float ss = offset;
|
||||||
ss += KERNEL1x5(in2, x, &kernel[0], 1);
|
ss += KERNEL1x5(in2, x, &kernel[0], 1);
|
||||||
ss += KERNEL1x5(in1, x, &kernel[5], 1);
|
ss += KERNEL1x5(in1, x, &kernel[5], 1);
|
||||||
ss += KERNEL1x5(in0, x, &kernel[10], 1);
|
ss += KERNEL1x5(in0, x, &kernel[10], 1);
|
||||||
ss += KERNEL1x5(in_1, x, &kernel[15], 1);
|
ss += KERNEL1x5(in_1, x, &kernel[15], 1);
|
||||||
ss += KERNEL1x5(in_2, x, &kernel[20], 1);
|
ss += KERNEL1x5(in_2, x, &kernel[20], 1);
|
||||||
out[x] = clip8(ss);
|
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 {
|
} else {
|
||||||
// Add one time for rounding
|
// Add one time for rounding
|
||||||
|
@ -327,7 +382,7 @@ ImagingFilter(Imaging im, int xsize, int ysize, const FLOAT32 *kernel, FLOAT32 o
|
||||||
Imaging imOut;
|
Imaging imOut;
|
||||||
ImagingSectionCookie cookie;
|
ImagingSectionCookie cookie;
|
||||||
|
|
||||||
if (!im || im->type != IMAGING_TYPE_UINT8) {
|
if (im->type != IMAGING_TYPE_UINT8 && im->type != IMAGING_TYPE_INT32) {
|
||||||
return (Imaging)ImagingError_ModeError();
|
return (Imaging)ImagingError_ModeError();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user