Merge pull request #2735 from uploadcare/deprecate-some-ops

Deprecate ImageOps undocumented functions
This commit is contained in:
wiredfool 2017-09-19 10:46:22 +01:00 committed by GitHub
commit 9f787f6e3d
7 changed files with 114 additions and 47 deletions

View File

@ -160,6 +160,26 @@ class GaussianBlur(MultibandFilter):
return image.gaussian_blur(self.radius)
class BoxBlur(MultibandFilter):
"""Blurs the image by setting each pixel to the average value of the pixels
in a square box extending radius pixels in each direction.
Supports float radius of arbitrary size. Uses an optimized implementation
which runs in linear time relative to the size of the image
for any radius value.
:param radius: Size of the box in one direction. Radius 0 does not blur,
returns an identical image. Radius 1 takes 1 pixel
in each direction, i.e. 9 pixels in total.
"""
name = "BoxBlur"
def __init__(self, radius):
self.radius = radius
def filter(self, image):
return image.box_blur(self.radius)
class UnsharpMask(MultibandFilter):
"""Unsharp mask filter.

View File

@ -21,6 +21,7 @@ from . import Image
from ._util import isStringType
import operator
import functools
import warnings
#
@ -437,6 +438,13 @@ def solarize(image, threshold=128):
def gaussian_blur(im, radius=None):
""" PIL_usm.gblur(im, [radius])"""
warnings.warn(
'PIL.ImageOps.gaussian_blur is deprecated. '
'Use PIL.ImageFilter.GaussianBlur instead. '
'This function will be removed in a future version.',
DeprecationWarning
)
if radius is None:
radius = 5.0
@ -444,12 +452,30 @@ def gaussian_blur(im, radius=None):
return im.im.gaussian_blur(radius)
gblur = gaussian_blur
def gblur(im, radius=None):
""" PIL_usm.gblur(im, [radius])"""
warnings.warn(
'PIL.ImageOps.gblur is deprecated. '
'Use PIL.ImageFilter.GaussianBlur instead. '
'This function will be removed in a future version.',
DeprecationWarning
)
return gaussian_blur(im, radius)
def unsharp_mask(im, radius=None, percent=None, threshold=None):
""" PIL_usm.usm(im, [radius, percent, threshold])"""
warnings.warn(
'PIL.ImageOps.unsharp_mask is deprecated. '
'Use PIL.ImageFilter.UnsharpMask instead. '
'This function will be removed in a future version.',
DeprecationWarning
)
if radius is None:
radius = 5.0
if percent is None:
@ -461,7 +487,18 @@ def unsharp_mask(im, radius=None, percent=None, threshold=None):
return im.im.unsharp_mask(radius, percent, threshold)
usm = unsharp_mask
def usm(im, radius=None, percent=None, threshold=None):
""" PIL_usm.usm(im, [radius, percent, threshold])"""
warnings.warn(
'PIL.ImageOps.usm is deprecated. '
'Use PIL.ImageFilter.UnsharpMask instead. '
'This function will be removed in a future version.',
DeprecationWarning
)
return unsharp_mask(im, radius, percent, threshold)
def box_blur(image, radius):
@ -478,6 +515,13 @@ def box_blur(image, radius):
in each direction, i.e. 9 pixels in total.
:return: An image.
"""
warnings.warn(
'PIL.ImageOps.box_blur is deprecated. '
'Use PIL.ImageFilter.BoxBlur instead. '
'This function will be removed in a future version.',
DeprecationWarning
)
image.load()
return image._new(image.im.box_blur(radius))

View File

@ -13,20 +13,6 @@ sample.putdata(sum([
], []))
class ImageMock(object):
def __init__(self):
self.im = self
def load(self):
pass
def _new(self, im):
return im
def box_blur(self, radius, n):
return radius, n
class TestBoxBlurApi(PillowTestCase):
def test_imageops_box_blur(self):

View File

@ -1,7 +1,6 @@
from helper import unittest, PillowTestCase, hopper
from PIL import Image
from PIL import ImageFilter
from PIL import Image, ImageFilter
class TestImageFilter(PillowTestCase):
@ -9,10 +8,11 @@ class TestImageFilter(PillowTestCase):
def test_sanity(self):
def filter(filter):
im = hopper("L")
out = im.filter(filter)
self.assertEqual(out.mode, im.mode)
self.assertEqual(out.size, im.size)
for mode in ["L", "RGB", "CMYK"]:
im = hopper(mode)
out = im.filter(filter)
self.assertEqual(out.mode, im.mode)
self.assertEqual(out.size, im.size)
filter(ImageFilter.BLUR)
filter(ImageFilter.CONTOUR)
@ -28,9 +28,9 @@ class TestImageFilter(PillowTestCase):
filter(ImageFilter.MedianFilter)
filter(ImageFilter.MinFilter)
filter(ImageFilter.ModeFilter)
filter(ImageFilter.Kernel((3, 3), list(range(9))))
filter(ImageFilter.GaussianBlur)
filter(ImageFilter.GaussianBlur(5))
filter(ImageFilter.BoxBlur(5))
filter(ImageFilter.UnsharpMask)
filter(ImageFilter.UnsharpMask(10))

View File

@ -12,15 +12,25 @@ class TestImageOpsUsm(PillowTestCase):
def test_ops_api(self):
i = ImageOps.gaussian_blur(im, 2.0)
i = self.assert_warning(DeprecationWarning,
ImageOps.gaussian_blur, im, 2.0)
self.assertEqual(i.mode, "RGB")
self.assertEqual(i.size, (128, 128))
# i.save("blur.bmp")
i = ImageOps.unsharp_mask(im, 2.0, 125, 8)
i = self.assert_warning(DeprecationWarning,
ImageOps.gblur, im, 2.0)
self.assertEqual(i.mode, "RGB")
self.assertEqual(i.size, (128, 128))
i = self.assert_warning(DeprecationWarning,
ImageOps.unsharp_mask, im, 2.0, 125, 8)
self.assertEqual(i.mode, "RGB")
self.assertEqual(i.size, (128, 128))
i = self.assert_warning(DeprecationWarning,
ImageOps.usm, im, 2.0, 125, 8)
self.assertEqual(i.mode, "RGB")
self.assertEqual(i.size, (128, 128))
# i.save("usm.bmp")
def test_filter_api(self):
@ -36,38 +46,38 @@ class TestImageOpsUsm(PillowTestCase):
def test_usm_formats(self):
usm = ImageOps.unsharp_mask
self.assertRaises(ValueError, usm, im.convert("1"))
usm(im.convert("L"))
self.assertRaises(ValueError, usm, im.convert("I"))
self.assertRaises(ValueError, usm, im.convert("F"))
usm(im.convert("RGB"))
usm(im.convert("RGBA"))
usm(im.convert("CMYK"))
self.assertRaises(ValueError, usm, im.convert("YCbCr"))
usm = ImageFilter.UnsharpMask
self.assertRaises(ValueError, im.convert("1").filter, usm)
im.convert("L").filter(usm)
self.assertRaises(ValueError, im.convert("I").filter, usm)
self.assertRaises(ValueError, im.convert("F").filter, usm)
im.convert("RGB").filter(usm)
im.convert("RGBA").filter(usm)
im.convert("CMYK").filter(usm)
self.assertRaises(ValueError, im.convert("YCbCr").filter, usm)
def test_blur_formats(self):
blur = ImageOps.gaussian_blur
self.assertRaises(ValueError, blur, im.convert("1"))
blur = ImageFilter.GaussianBlur
self.assertRaises(ValueError, im.convert("1").filter, blur)
blur(im.convert("L"))
self.assertRaises(ValueError, blur, im.convert("I"))
self.assertRaises(ValueError, blur, im.convert("F"))
blur(im.convert("RGB"))
blur(im.convert("RGBA"))
blur(im.convert("CMYK"))
self.assertRaises(ValueError, blur, im.convert("YCbCr"))
self.assertRaises(ValueError, im.convert("I").filter, blur)
self.assertRaises(ValueError, im.convert("F").filter, blur)
im.convert("RGB").filter(blur)
im.convert("RGBA").filter(blur)
im.convert("CMYK").filter(blur)
self.assertRaises(ValueError, im.convert("YCbCr").filter, blur)
def test_usm_accuracy(self):
src = snakes.convert('RGB')
i = src._new(ImageOps.unsharp_mask(src, 5, 1024, 0))
i = src.filter(ImageFilter.UnsharpMask(5, 1024, 0))
# Image should not be changed because it have only 0 and 255 levels.
self.assertEqual(i.tobytes(), src.tobytes())
def test_blur_accuracy(self):
i = snakes._new(ImageOps.gaussian_blur(snakes, .4))
i = snakes.filter(ImageFilter.GaussianBlur(.4))
# These pixels surrounded with pixels with 255 intensity.
# 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),

View File

@ -38,6 +38,7 @@ image enhancement filters:
* **SHARPEN**
.. autoclass:: PIL.ImageFilter.GaussianBlur
.. autoclass:: PIL.ImageFilter.BoxBlur
.. autoclass:: PIL.ImageFilter.UnsharpMask
.. autoclass:: PIL.ImageFilter.Kernel
.. autoclass:: PIL.ImageFilter.RankFilter

View File

@ -4,13 +4,19 @@
Get One Channel From Image
==========================
New method :py:meth:`PIL.Image.Image.getchannel` added.
New method :py:meth:`PIL.Image.Image.getchannel` is added.
It returns single channel by index or name. For example,
``image.getchannel("A")`` will return alpha channel as separate image.
``getchannel`` should work up to 6 times faster than ``image.split()[0]``
in previous Pillow versions.
Box Blur
========
New filter :py:class:`PIL.ImageFilter.BoxBlur` is added.
Partial Resampling
==================