Merge pull request #6531 from Yay295/parametrize

This commit is contained in:
Hugo van Kemenade 2022-09-06 17:50:41 +03:00 committed by GitHub
commit 7cff8227d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 267 additions and 239 deletions

View File

@ -5,90 +5,109 @@ from PIL import Image, ImageFilter
from .helper import assert_image_equal, hopper from .helper import assert_image_equal, hopper
def test_sanity(): @pytest.mark.parametrize(
def apply_filter(filter_to_apply): "filter_to_apply",
for mode in ["L", "RGB", "CMYK"]: (
im = hopper(mode) ImageFilter.BLUR,
out = im.filter(filter_to_apply) ImageFilter.CONTOUR,
assert out.mode == im.mode ImageFilter.DETAIL,
assert out.size == im.size ImageFilter.EDGE_ENHANCE,
ImageFilter.EDGE_ENHANCE_MORE,
ImageFilter.EMBOSS,
ImageFilter.FIND_EDGES,
ImageFilter.SMOOTH,
ImageFilter.SMOOTH_MORE,
ImageFilter.SHARPEN,
ImageFilter.MaxFilter,
ImageFilter.MedianFilter,
ImageFilter.MinFilter,
ImageFilter.ModeFilter,
ImageFilter.GaussianBlur,
ImageFilter.GaussianBlur(5),
ImageFilter.BoxBlur(5),
ImageFilter.UnsharpMask,
ImageFilter.UnsharpMask(10),
),
)
@pytest.mark.parametrize("mode", ("L", "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
apply_filter(ImageFilter.BLUR)
apply_filter(ImageFilter.CONTOUR)
apply_filter(ImageFilter.DETAIL)
apply_filter(ImageFilter.EDGE_ENHANCE)
apply_filter(ImageFilter.EDGE_ENHANCE_MORE)
apply_filter(ImageFilter.EMBOSS)
apply_filter(ImageFilter.FIND_EDGES)
apply_filter(ImageFilter.SMOOTH)
apply_filter(ImageFilter.SMOOTH_MORE)
apply_filter(ImageFilter.SHARPEN)
apply_filter(ImageFilter.MaxFilter)
apply_filter(ImageFilter.MedianFilter)
apply_filter(ImageFilter.MinFilter)
apply_filter(ImageFilter.ModeFilter)
apply_filter(ImageFilter.GaussianBlur)
apply_filter(ImageFilter.GaussianBlur(5))
apply_filter(ImageFilter.BoxBlur(5))
apply_filter(ImageFilter.UnsharpMask)
apply_filter(ImageFilter.UnsharpMask(10))
@pytest.mark.parametrize("mode", ("L", "RGB", "CMYK"))
def test_sanity_error(mode):
with pytest.raises(TypeError): with pytest.raises(TypeError):
apply_filter("hello") im = hopper(mode)
im.filter("hello")
def test_crash(): # crashes on small images
@pytest.mark.parametrize("size", ((1, 1), (2, 2), (3, 3)))
# crashes on small images def test_crash(size):
im = Image.new("RGB", (1, 1)) im = Image.new("RGB", size)
im.filter(ImageFilter.SMOOTH)
im = Image.new("RGB", (2, 2))
im.filter(ImageFilter.SMOOTH)
im = Image.new("RGB", (3, 3))
im.filter(ImageFilter.SMOOTH) im.filter(ImageFilter.SMOOTH)
def test_modefilter(): @pytest.mark.parametrize(
def modefilter(mode): "mode, expected",
im = Image.new(mode, (3, 3), None) (
im.putdata(list(range(9))) ("1", (4, 0)),
# image is: ("L", (4, 0)),
# 0 1 2 ("P", (4, 0)),
# 3 4 5 ("RGB", ((4, 0, 0), (0, 0, 0))),
# 6 7 8 ),
mod = im.filter(ImageFilter.ModeFilter).getpixel((1, 1)) )
im.putdata([0, 0, 1, 2, 5, 1, 5, 2, 0]) # mode=0 def test_modefilter(mode, expected):
mod2 = im.filter(ImageFilter.ModeFilter).getpixel((1, 1)) im = Image.new(mode, (3, 3), None)
return mod, mod2 im.putdata(list(range(9)))
# image is:
assert modefilter("1") == (4, 0) # 0 1 2
assert modefilter("L") == (4, 0) # 3 4 5
assert modefilter("P") == (4, 0) # 6 7 8
assert modefilter("RGB") == ((4, 0, 0), (0, 0, 0)) mod = im.filter(ImageFilter.ModeFilter).getpixel((1, 1))
im.putdata([0, 0, 1, 2, 5, 1, 5, 2, 0]) # mode=0
mod2 = im.filter(ImageFilter.ModeFilter).getpixel((1, 1))
assert (mod, mod2) == expected
def test_rankfilter(): @pytest.mark.parametrize(
def rankfilter(mode): "mode, expected",
im = Image.new(mode, (3, 3), None) (
im.putdata(list(range(9))) ("1", (0, 4, 8)),
# image is: ("L", (0, 4, 8)),
# 0 1 2 ("RGB", ((0, 0, 0), (4, 0, 0), (8, 0, 0))),
# 3 4 5 ("I", (0, 4, 8)),
# 6 7 8 ("F", (0.0, 4.0, 8.0)),
minimum = im.filter(ImageFilter.MinFilter).getpixel((1, 1)) ),
med = im.filter(ImageFilter.MedianFilter).getpixel((1, 1)) )
maximum = im.filter(ImageFilter.MaxFilter).getpixel((1, 1)) def test_rankfilter(mode, expected):
return minimum, med, maximum im = Image.new(mode, (3, 3), None)
im.putdata(list(range(9)))
# image is:
# 0 1 2
# 3 4 5
# 6 7 8
minimum = im.filter(ImageFilter.MinFilter).getpixel((1, 1))
med = im.filter(ImageFilter.MedianFilter).getpixel((1, 1))
maximum = im.filter(ImageFilter.MaxFilter).getpixel((1, 1))
assert (minimum, med, maximum) == expected
assert rankfilter("1") == (0, 4, 8)
assert rankfilter("L") == (0, 4, 8) @pytest.mark.parametrize(
"filter", (ImageFilter.MinFilter, ImageFilter.MedianFilter, ImageFilter.MaxFilter)
)
def test_rankfilter_error(filter):
with pytest.raises(ValueError): with pytest.raises(ValueError):
rankfilter("P") im = Image.new("P", (3, 3), None)
assert rankfilter("RGB") == ((0, 0, 0), (4, 0, 0), (8, 0, 0)) im.putdata(list(range(9)))
assert rankfilter("I") == (0, 4, 8) # image is:
assert rankfilter("F") == (0.0, 4.0, 8.0) # 0 1 2
# 3 4 5
# 6 7 8
im.filter(filter).getpixel((1, 1))
def test_rankfilter_properties(): def test_rankfilter_properties():
@ -110,7 +129,8 @@ def test_kernel_not_enough_coefficients():
ImageFilter.Kernel((3, 3), (0, 0)) ImageFilter.Kernel((3, 3), (0, 0))
def test_consistency_3x3(): @pytest.mark.parametrize("mode", ("L", "LA", "RGB", "CMYK"))
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: with Image.open("Tests/images/hopper_emboss.bmp") as reference:
kernel = ImageFilter.Kernel( kernel = ImageFilter.Kernel(
@ -125,14 +145,14 @@ def test_consistency_3x3():
source = source.split() * 2 source = source.split() * 2
reference = reference.split() * 2 reference = reference.split() * 2
for mode in ["L", "LA", "RGB", "CMYK"]: assert_image_equal(
assert_image_equal( Image.merge(mode, source[: len(mode)]).filter(kernel),
Image.merge(mode, source[: len(mode)]).filter(kernel), Image.merge(mode, reference[: len(mode)]),
Image.merge(mode, reference[: len(mode)]), )
)
def test_consistency_5x5(): @pytest.mark.parametrize("mode", ("L", "LA", "RGB", "CMYK"))
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: with Image.open("Tests/images/hopper_emboss_more.bmp") as reference:
kernel = ImageFilter.Kernel( kernel = ImageFilter.Kernel(
@ -149,8 +169,7 @@ def test_consistency_5x5():
source = source.split() * 2 source = source.split() * 2
reference = reference.split() * 2 reference = reference.split() * 2
for mode in ["L", "LA", "RGB", "CMYK"]: assert_image_equal(
assert_image_equal( Image.merge(mode, source[: len(mode)]).filter(kernel),
Image.merge(mode, source[: len(mode)]).filter(kernel), Image.merge(mode, reference[: len(mode)]),
Image.merge(mode, reference[: len(mode)]), )
)

View File

@ -38,58 +38,64 @@ gradients_image = Image.open("Tests/images/radial_gradients.png")
gradients_image.load() gradients_image.load()
def test_args_factor(): @pytest.mark.parametrize(
"size, expected",
(
(3, (4, 4)),
((3, 1), (4, 10)),
((1, 3), (10, 4)),
),
)
def test_args_factor(size, expected):
im = Image.new("L", (10, 10)) im = Image.new("L", (10, 10))
assert expected == im.reduce(size).size
assert (4, 4) == im.reduce(3).size
assert (4, 10) == im.reduce((3, 1)).size
assert (10, 4) == im.reduce((1, 3)).size
with pytest.raises(ValueError):
im.reduce(0)
with pytest.raises(TypeError):
im.reduce(2.0)
with pytest.raises(ValueError):
im.reduce((0, 10))
def test_args_box(): @pytest.mark.parametrize(
"size, expected_error", ((0, ValueError), (2.0, TypeError), ((0, 10), ValueError))
)
def test_args_factor_error(size, expected_error):
im = Image.new("L", (10, 10)) im = Image.new("L", (10, 10))
with pytest.raises(expected_error):
assert (5, 5) == im.reduce(2, (0, 0, 10, 10)).size im.reduce(size)
assert (1, 1) == im.reduce(2, (5, 5, 6, 6)).size
with pytest.raises(TypeError):
im.reduce(2, "stri")
with pytest.raises(TypeError):
im.reduce(2, 2)
with pytest.raises(ValueError):
im.reduce(2, (0, 0, 11, 10))
with pytest.raises(ValueError):
im.reduce(2, (0, 0, 10, 11))
with pytest.raises(ValueError):
im.reduce(2, (-1, 0, 10, 10))
with pytest.raises(ValueError):
im.reduce(2, (0, -1, 10, 10))
with pytest.raises(ValueError):
im.reduce(2, (0, 5, 10, 5))
with pytest.raises(ValueError):
im.reduce(2, (5, 0, 5, 10))
def test_unsupported_modes(): @pytest.mark.parametrize(
"size, expected",
(
((0, 0, 10, 10), (5, 5)),
((5, 5, 6, 6), (1, 1)),
),
)
def test_args_box(size, expected):
im = Image.new("L", (10, 10))
assert expected == im.reduce(2, size).size
@pytest.mark.parametrize(
"size, expected_error",
(
("stri", TypeError),
((0, 0, 11, 10), ValueError),
((0, 0, 10, 11), ValueError),
((-1, 0, 10, 10), ValueError),
((0, -1, 10, 10), ValueError),
((0, 5, 10, 5), ValueError),
((5, 0, 5, 10), ValueError),
),
)
def test_args_box_error(size, expected_error):
im = Image.new("L", (10, 10))
with pytest.raises(expected_error):
im.reduce(2, size).size
@pytest.mark.parametrize("mode", ("P", "1", "I;16"))
def test_unsupported_modes(mode):
im = Image.new("P", (10, 10)) im = Image.new("P", (10, 10))
with pytest.raises(ValueError): with pytest.raises(ValueError):
im.reduce(3) im.reduce(3)
im = Image.new("1", (10, 10))
with pytest.raises(ValueError):
im.reduce(3)
im = Image.new("I;16", (10, 10))
with pytest.raises(ValueError):
im.reduce(3)
def get_image(mode): def get_image(mode):
mode_info = ImageMode.getmode(mode) mode_info = ImageMode.getmode(mode)
@ -197,63 +203,69 @@ def test_mode_L():
compare_reduce_with_box(im, factor) compare_reduce_with_box(im, factor)
def test_mode_LA(): @pytest.mark.parametrize("factor", remarkable_factors)
def test_mode_LA(factor):
im = get_image("LA") im = get_image("LA")
for factor in remarkable_factors: compare_reduce_with_reference(im, factor, 0.8, 5)
compare_reduce_with_reference(im, factor, 0.8, 5)
@pytest.mark.parametrize("factor", remarkable_factors)
def test_mode_LA_opaque(factor):
im = get_image("LA")
# With opaque alpha, an error should be way smaller. # With opaque alpha, an error should be way smaller.
im.putalpha(Image.new("L", im.size, 255)) im.putalpha(Image.new("L", im.size, 255))
for factor in remarkable_factors: compare_reduce_with_reference(im, factor)
compare_reduce_with_reference(im, factor) compare_reduce_with_box(im, factor)
compare_reduce_with_box(im, factor)
def test_mode_La(): @pytest.mark.parametrize("factor", remarkable_factors)
def test_mode_La(factor):
im = get_image("La") im = get_image("La")
for factor in remarkable_factors: compare_reduce_with_reference(im, factor)
compare_reduce_with_reference(im, factor) compare_reduce_with_box(im, factor)
compare_reduce_with_box(im, factor)
def test_mode_RGB(): @pytest.mark.parametrize("factor", remarkable_factors)
def test_mode_RGB(factor):
im = get_image("RGB") im = get_image("RGB")
for factor in remarkable_factors: compare_reduce_with_reference(im, factor)
compare_reduce_with_reference(im, factor) compare_reduce_with_box(im, factor)
compare_reduce_with_box(im, factor)
def test_mode_RGBA(): @pytest.mark.parametrize("factor", remarkable_factors)
def test_mode_RGBA(factor):
im = get_image("RGBA") im = get_image("RGBA")
for factor in remarkable_factors: compare_reduce_with_reference(im, factor, 0.8, 5)
compare_reduce_with_reference(im, factor, 0.8, 5)
@pytest.mark.parametrize("factor", remarkable_factors)
def test_mode_RGBA_opaque(factor):
im = get_image("RGBA")
# With opaque alpha, an error should be way smaller. # With opaque alpha, an error should be way smaller.
im.putalpha(Image.new("L", im.size, 255)) im.putalpha(Image.new("L", im.size, 255))
for factor in remarkable_factors: compare_reduce_with_reference(im, factor)
compare_reduce_with_reference(im, factor) compare_reduce_with_box(im, factor)
compare_reduce_with_box(im, factor)
def test_mode_RGBa(): @pytest.mark.parametrize("factor", remarkable_factors)
def test_mode_RGBa(factor):
im = get_image("RGBa") im = get_image("RGBa")
for factor in remarkable_factors: compare_reduce_with_reference(im, factor)
compare_reduce_with_reference(im, factor) compare_reduce_with_box(im, factor)
compare_reduce_with_box(im, factor)
def test_mode_I(): @pytest.mark.parametrize("factor", remarkable_factors)
def test_mode_I(factor):
im = get_image("I") im = get_image("I")
for factor in remarkable_factors: compare_reduce_with_reference(im, factor)
compare_reduce_with_reference(im, factor) compare_reduce_with_box(im, factor)
compare_reduce_with_box(im, factor)
def test_mode_F(): @pytest.mark.parametrize("factor", remarkable_factors)
def test_mode_F(factor):
im = get_image("F") im = get_image("F")
for factor in remarkable_factors: compare_reduce_with_reference(im, factor, 0, 0)
compare_reduce_with_reference(im, factor, 0, 0) compare_reduce_with_box(im, factor)
compare_reduce_with_box(im, factor)
@skip_unless_feature("jpg_2000") @skip_unless_feature("jpg_2000")

View File

@ -75,23 +75,25 @@ class TestImageTransform:
assert_image_equal(transformed, scaled) assert_image_equal(transformed, scaled)
def test_fill(self): @pytest.mark.parametrize(
for mode, pixel in [ "mode, expected_pixel",
["RGB", (255, 0, 0)], (
["RGBA", (255, 0, 0, 255)], ("RGB", (255, 0, 0)),
["LA", (76, 0)], ("RGBA", (255, 0, 0, 255)),
]: ("LA", (76, 0)),
im = hopper(mode) ),
(w, h) = im.size )
transformed = im.transform( def test_fill(self, mode, expected_pixel):
im.size, im = hopper(mode)
Image.Transform.EXTENT, (w, h) = im.size
(0, 0, w * 2, h * 2), transformed = im.transform(
Image.Resampling.BILINEAR, im.size,
fillcolor="red", Image.Transform.EXTENT,
) (0, 0, w * 2, h * 2),
Image.Resampling.BILINEAR,
assert transformed.getpixel((w - 1, h - 1)) == pixel fillcolor="red",
)
assert transformed.getpixel((w - 1, h - 1)) == expected_pixel
def test_mesh(self): def test_mesh(self):
# this should be a checkerboard of halfsized hoppers in ul, lr # this should be a checkerboard of halfsized hoppers in ul, lr
@ -222,14 +224,12 @@ class TestImageTransform:
with pytest.raises(ValueError): with pytest.raises(ValueError):
im.transform((100, 100), None) im.transform((100, 100), None)
def test_unknown_resampling_filter(self): @pytest.mark.parametrize("resample", (Image.Resampling.BOX, "unknown"))
def test_unknown_resampling_filter(self, resample):
with hopper() as im: with hopper() as im:
(w, h) = im.size (w, h) = im.size
for resample in (Image.Resampling.BOX, "unknown"): with pytest.raises(ValueError):
with pytest.raises(ValueError): im.transform((100, 100), Image.Transform.EXTENT, (0, 0, w, h), resample)
im.transform(
(100, 100), Image.Transform.EXTENT, (0, 0, w, h), resample
)
class TestImageTransformAffine: class TestImageTransformAffine:
@ -239,7 +239,16 @@ class TestImageTransformAffine:
im = hopper("RGB") im = hopper("RGB")
return im.crop((10, 20, im.width - 10, im.height - 20)) return im.crop((10, 20, im.width - 10, im.height - 20))
def _test_rotate(self, deg, transpose): @pytest.mark.parametrize(
"deg, transpose",
(
(0, None),
(90, Image.Transpose.ROTATE_90),
(180, Image.Transpose.ROTATE_180),
(270, Image.Transpose.ROTATE_270),
),
)
def test_rotate(self, deg, transpose):
im = self._test_image() im = self._test_image()
angle = -math.radians(deg) angle = -math.radians(deg)
@ -271,77 +280,65 @@ class TestImageTransformAffine:
) )
assert_image_equal(transposed, transformed) assert_image_equal(transposed, transformed)
def test_rotate_0_deg(self): @pytest.mark.parametrize(
self._test_rotate(0, None) "scale, epsilon_scale",
(
def test_rotate_90_deg(self): (1.1, 6.9),
self._test_rotate(90, Image.Transpose.ROTATE_90) (1.5, 5.5),
(2.0, 5.5),
def test_rotate_180_deg(self): (2.3, 3.7),
self._test_rotate(180, Image.Transpose.ROTATE_180) (2.5, 3.7),
),
def test_rotate_270_deg(self): )
self._test_rotate(270, Image.Transpose.ROTATE_270) @pytest.mark.parametrize(
"resample,epsilon",
def _test_resize(self, scale, epsilonscale): (
(Image.Resampling.NEAREST, 0),
(Image.Resampling.BILINEAR, 2),
(Image.Resampling.BICUBIC, 1),
),
)
def test_resize(self, scale, epsilon_scale, resample, epsilon):
im = self._test_image() im = self._test_image()
size_up = int(round(im.width * scale)), int(round(im.height * scale)) size_up = int(round(im.width * scale)), int(round(im.height * scale))
matrix_up = [1 / scale, 0, 0, 0, 1 / scale, 0, 0, 0] matrix_up = [1 / scale, 0, 0, 0, 1 / scale, 0, 0, 0]
matrix_down = [scale, 0, 0, 0, scale, 0, 0, 0] matrix_down = [scale, 0, 0, 0, scale, 0, 0, 0]
for resample, epsilon in [ transformed = im.transform(size_up, self.transform, matrix_up, resample)
transformed = transformed.transform(
im.size, self.transform, matrix_down, resample
)
assert_image_similar(transformed, im, epsilon * epsilon_scale)
@pytest.mark.parametrize(
"x, y, epsilon_scale",
(
(0.1, 0, 3.7),
(0.6, 0, 9.1),
(50, 50, 0),
),
)
@pytest.mark.parametrize(
"resample, epsilon",
(
(Image.Resampling.NEAREST, 0), (Image.Resampling.NEAREST, 0),
(Image.Resampling.BILINEAR, 2), (Image.Resampling.BILINEAR, 1.5),
(Image.Resampling.BICUBIC, 1), (Image.Resampling.BICUBIC, 1),
]: ),
transformed = im.transform(size_up, self.transform, matrix_up, resample) )
transformed = transformed.transform( def test_translate(self, x, y, epsilon_scale, resample, epsilon):
im.size, self.transform, matrix_down, resample
)
assert_image_similar(transformed, im, epsilon * epsilonscale)
def test_resize_1_1x(self):
self._test_resize(1.1, 6.9)
def test_resize_1_5x(self):
self._test_resize(1.5, 5.5)
def test_resize_2_0x(self):
self._test_resize(2.0, 5.5)
def test_resize_2_3x(self):
self._test_resize(2.3, 3.7)
def test_resize_2_5x(self):
self._test_resize(2.5, 3.7)
def _test_translate(self, x, y, epsilonscale):
im = self._test_image() im = self._test_image()
size_up = int(round(im.width + x)), int(round(im.height + y)) size_up = int(round(im.width + x)), int(round(im.height + y))
matrix_up = [1, 0, -x, 0, 1, -y, 0, 0] matrix_up = [1, 0, -x, 0, 1, -y, 0, 0]
matrix_down = [1, 0, x, 0, 1, y, 0, 0] matrix_down = [1, 0, x, 0, 1, y, 0, 0]
for resample, epsilon in [ transformed = im.transform(size_up, self.transform, matrix_up, resample)
(Image.Resampling.NEAREST, 0), transformed = transformed.transform(
(Image.Resampling.BILINEAR, 1.5), im.size, self.transform, matrix_down, resample
(Image.Resampling.BICUBIC, 1), )
]: assert_image_similar(transformed, im, epsilon * epsilon_scale)
transformed = im.transform(size_up, self.transform, matrix_up, resample)
transformed = transformed.transform(
im.size, self.transform, matrix_down, resample
)
assert_image_similar(transformed, im, epsilon * epsilonscale)
def test_translate_0_1(self):
self._test_translate(0.1, 0, 3.7)
def test_translate_0_6(self):
self._test_translate(0.6, 0, 9.1)
def test_translate_50(self):
self._test_translate(50, 50, 0)
class TestImageTransformPerspective(TestImageTransformAffine): class TestImageTransformPerspective(TestImageTransformAffine):