mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-27 09:44:31 +03:00
Merge pull request #716 from hugovk/morph_flake8
Flake8 on morphology changes
This commit is contained in:
commit
ca148208f0
|
@ -10,8 +10,10 @@ from PIL import _imagingmorph
|
|||
import re
|
||||
|
||||
LUT_SIZE = 1 << 9
|
||||
|
||||
|
||||
class LutBuilder:
|
||||
"""A class for building MorphLut's from a descriptive language
|
||||
"""A class for building a MorphLut from a descriptive language
|
||||
|
||||
The input patterns is a list of a strings sequences like these:
|
||||
|
||||
|
@ -20,8 +22,8 @@ class LutBuilder:
|
|||
111)->1
|
||||
|
||||
(whitespaces including linebreaks are ignored). The option 4
|
||||
descibes a series of symmetry operations (in this case a
|
||||
4-rotation), the pattern is decribed by:
|
||||
describes a series of symmetry operations (in this case a
|
||||
4-rotation), the pattern is described by:
|
||||
|
||||
. or X - Ignore
|
||||
1 - Pixel is on
|
||||
|
@ -64,7 +66,7 @@ class LutBuilder:
|
|||
'4:(.0. .1. ...)->1',
|
||||
'4:(01. .1. ...)->1']
|
||||
}
|
||||
if not op_name in known_patterns:
|
||||
if op_name not in known_patterns:
|
||||
raise Exception('Unknown pattern '+op_name+'!')
|
||||
|
||||
self.patterns = known_patterns[op_name]
|
||||
|
@ -82,14 +84,14 @@ class LutBuilder:
|
|||
|
||||
def _string_permute(self, pattern, permutation):
|
||||
"""string_permute takes a pattern and a permutation and returns the
|
||||
string permuted accordinging to the permutation list.
|
||||
string permuted according to the permutation list.
|
||||
"""
|
||||
assert(len(permutation) == 9)
|
||||
return ''.join([pattern[p] for p in permutation])
|
||||
|
||||
def _pattern_permute(self, basic_pattern, options, basic_result):
|
||||
"""pattern_permute takes a basic pattern and its result and clones
|
||||
the mattern according to the modifications described in the $options
|
||||
the pattern according to the modifications described in the $options
|
||||
parameter. It returns a list of all cloned patterns."""
|
||||
patterns = [(basic_pattern, basic_result)]
|
||||
|
||||
|
@ -98,8 +100,7 @@ class LutBuilder:
|
|||
res = patterns[-1][1]
|
||||
for i in range(4):
|
||||
patterns.append(
|
||||
(self._string_permute(patterns[-1][0],
|
||||
[6,3,0,
|
||||
(self._string_permute(patterns[-1][0], [6, 3, 0,
|
||||
7, 4, 1,
|
||||
8, 5, 2]), res))
|
||||
# mirror
|
||||
|
@ -135,7 +136,8 @@ class LutBuilder:
|
|||
|
||||
# Parse and create symmetries of the patterns strings
|
||||
for p in self.patterns:
|
||||
m = re.search(r'(\w*):?\s*\((.+?)\)\s*->\s*(\d)', p.replace('\n',''))
|
||||
m = re.search(
|
||||
r'(\w*):?\s*\((.+?)\)\s*->\s*(\d)', p.replace('\n', ''))
|
||||
if not m:
|
||||
raise Exception('Syntax error in pattern "'+p+'"')
|
||||
options = m.group(1)
|
||||
|
@ -172,6 +174,7 @@ class LutBuilder:
|
|||
|
||||
return self.lut
|
||||
|
||||
|
||||
class MorphOp:
|
||||
"""A class for binary morphological operators"""
|
||||
|
||||
|
@ -195,13 +198,16 @@ class MorphOp:
|
|||
raise Exception('No operator loaded')
|
||||
|
||||
outimage = Image.new(image.mode, image.size, None)
|
||||
count = _imagingmorph.apply(bytes(self.lut), image.im.id, outimage.im.id)
|
||||
count = _imagingmorph.apply(
|
||||
bytes(self.lut), image.im.id, outimage.im.id)
|
||||
return count, outimage
|
||||
|
||||
def match(self, image):
|
||||
"""Get a list of coordinates matching the morphological operation on an image
|
||||
"""Get a list of coordinates matching the morphological operation on
|
||||
an image.
|
||||
|
||||
Returns a list of tuples of (x,y) coordinates of all matching pixels."""
|
||||
Returns a list of tuples of (x,y) coordinates
|
||||
of all matching pixels."""
|
||||
if self.lut is None:
|
||||
raise Exception('No operator loaded')
|
||||
|
||||
|
@ -209,7 +215,9 @@ class MorphOp:
|
|||
|
||||
def get_on_pixels(self, image):
|
||||
"""Get a list of all turned on pixels in a binary image
|
||||
Returns a list of tuples of (x,y) coordinates of all matching pixels."""
|
||||
|
||||
Returns a list of tuples of (x,y) coordinates
|
||||
of all matching pixels."""
|
||||
|
||||
return _imagingmorph.get_on_pixels(image.im.id)
|
||||
|
||||
|
@ -223,7 +231,7 @@ class MorphOp:
|
|||
raise Exception('Wrong size operator file!')
|
||||
|
||||
def save_lut(self, filename):
|
||||
"""Load an operator save mrl file"""
|
||||
"""Save an operator to an mrl file"""
|
||||
if self.lut is None:
|
||||
raise Exception('No operator loaded')
|
||||
with open(filename, 'wb') as f:
|
||||
|
@ -233,4 +241,4 @@ class MorphOp:
|
|||
"""Set the lut from an external source"""
|
||||
self.lut = lut
|
||||
|
||||
|
||||
# End of file
|
||||
|
|
|
@ -20,7 +20,6 @@ class MorphTests(PillowTestCase):
|
|||
"""
|
||||
)
|
||||
|
||||
|
||||
def img_to_string(self, im):
|
||||
"""Turn a (small) binary image into a string representation"""
|
||||
chars = '.1'
|
||||
|
@ -51,14 +50,18 @@ class MorphTests(PillowTestCase):
|
|||
self.assertEqual(self.img_to_string(A), self.img_to_string(B))
|
||||
|
||||
def assert_img_equal_img_string(self, A, Bstring):
|
||||
self.assertEqual(self.img_to_string(A), self.img_string_normalize(Bstring))
|
||||
self.assertEqual(
|
||||
self.img_to_string(A),
|
||||
self.img_string_normalize(Bstring))
|
||||
|
||||
def test_str_to_img(self):
|
||||
im = Image.open('Tests/images/morph_a.png')
|
||||
self.assert_image_equal(self.A, im)
|
||||
|
||||
def create_lut(self):
|
||||
for op in ('corner', 'dilation4', 'dilation8', 'erosion4', 'erosion8', 'edge'):
|
||||
for op in (
|
||||
'corner', 'dilation4', 'dilation8',
|
||||
'erosion4', 'erosion8', 'edge'):
|
||||
lb = ImageMorph.LutBuilder(op_name=op)
|
||||
lut = lb.build_lut(self)
|
||||
with open('Tests/images/%s.lut' % op, 'wb') as f:
|
||||
|
@ -66,13 +69,14 @@ class MorphTests(PillowTestCase):
|
|||
|
||||
# create_lut()
|
||||
def test_lut(self):
|
||||
for op in ('corner', 'dilation4', 'dilation8', 'erosion4', 'erosion8', 'edge'):
|
||||
for op in (
|
||||
'corner', 'dilation4', 'dilation8',
|
||||
'erosion4', 'erosion8', 'edge'):
|
||||
lb = ImageMorph.LutBuilder(op_name=op)
|
||||
lut = lb.build_lut()
|
||||
with open('Tests/images/%s.lut' % op, 'rb') as f:
|
||||
self.assertEqual(lut, bytearray(f.read()))
|
||||
|
||||
|
||||
# Test the named patterns
|
||||
def test_erosion8(self):
|
||||
# erosion8
|
||||
|
@ -138,7 +142,6 @@ class MorphTests(PillowTestCase):
|
|||
.......
|
||||
""")
|
||||
|
||||
|
||||
def test_corner(self):
|
||||
# Create a corner detector pattern
|
||||
mop = ImageMorph.MorphOp(patterns=['1:(... ... ...)->0',
|
||||
|
@ -156,14 +159,17 @@ class MorphTests(PillowTestCase):
|
|||
.......
|
||||
""")
|
||||
|
||||
|
||||
# Test the coordinate counting with the same operator
|
||||
coords = mop.match(self.A)
|
||||
self.assertEqual(len(coords), 4)
|
||||
self.assertEqual(tuple(coords),
|
||||
((2,2),(4,2),(2,4),(4,4)))
|
||||
self.assertEqual(tuple(coords), ((2, 2), (4, 2), (2, 4), (4, 4)))
|
||||
|
||||
coords = mop.get_on_pixels(Aout)
|
||||
self.assertEqual(len(coords), 4)
|
||||
self.assertEqual(tuple(coords),
|
||||
((2,2),(4,2),(2,4),(4,4)))
|
||||
self.assertEqual(tuple(coords), ((2, 2), (4, 2), (2, 4), (4, 4)))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
# End of file
|
||||
|
|
57
setup.py
57
setup.py
|
@ -106,6 +106,7 @@ class pil_build_ext(build_ext):
|
|||
|
||||
def require(self, feat):
|
||||
return feat in self.required
|
||||
|
||||
def want(self, feat):
|
||||
return getattr(self, feat) is None
|
||||
|
||||
|
@ -225,9 +226,11 @@ class pil_build_ext(build_ext):
|
|||
if ft_prefix and os.path.isdir(ft_prefix):
|
||||
# freetype might not be linked into Homebrew's prefix
|
||||
_add_directory(library_dirs, os.path.join(ft_prefix, 'lib'))
|
||||
_add_directory(include_dirs, os.path.join(ft_prefix, 'include'))
|
||||
_add_directory(
|
||||
include_dirs, os.path.join(ft_prefix, 'include'))
|
||||
else:
|
||||
# fall back to freetype from XQuartz if Homebrew's freetype is missing
|
||||
# fall back to freetype from XQuartz if
|
||||
# Homebrew's freetype is missing
|
||||
_add_directory(library_dirs, "/usr/X11/lib")
|
||||
_add_directory(include_dirs, "/usr/X11/include")
|
||||
|
||||
|
@ -245,30 +248,38 @@ class pil_build_ext(build_ext):
|
|||
if platform_ in ["x86_64", "64bit"]:
|
||||
_add_directory(library_dirs, "/lib64")
|
||||
_add_directory(library_dirs, "/usr/lib64")
|
||||
_add_directory(library_dirs, "/usr/lib/x86_64-linux-gnu")
|
||||
_add_directory(
|
||||
library_dirs, "/usr/lib/x86_64-linux-gnu")
|
||||
break
|
||||
elif platform_ in ["i386", "i686", "32bit"]:
|
||||
_add_directory(library_dirs, "/usr/lib/i386-linux-gnu")
|
||||
_add_directory(
|
||||
library_dirs, "/usr/lib/i386-linux-gnu")
|
||||
break
|
||||
elif platform_ in ["aarch64"]:
|
||||
_add_directory(library_dirs, "/usr/lib64")
|
||||
_add_directory(library_dirs, "/usr/lib/aarch64-linux-gnu")
|
||||
_add_directory(
|
||||
library_dirs, "/usr/lib/aarch64-linux-gnu")
|
||||
break
|
||||
elif platform_ in ["arm", "armv7l"]:
|
||||
_add_directory(library_dirs, "/usr/lib/arm-linux-gnueabi")
|
||||
_add_directory(
|
||||
library_dirs, "/usr/lib/arm-linux-gnueabi")
|
||||
break
|
||||
elif platform_ in ["ppc64"]:
|
||||
_add_directory(library_dirs, "/usr/lib64")
|
||||
_add_directory(library_dirs, "/usr/lib/ppc64-linux-gnu")
|
||||
_add_directory(library_dirs, "/usr/lib/powerpc64-linux-gnu")
|
||||
_add_directory(
|
||||
library_dirs, "/usr/lib/ppc64-linux-gnu")
|
||||
_add_directory(
|
||||
library_dirs, "/usr/lib/powerpc64-linux-gnu")
|
||||
break
|
||||
elif platform_ in ["ppc"]:
|
||||
_add_directory(library_dirs, "/usr/lib/ppc-linux-gnu")
|
||||
_add_directory(library_dirs, "/usr/lib/powerpc-linux-gnu")
|
||||
_add_directory(
|
||||
library_dirs, "/usr/lib/powerpc-linux-gnu")
|
||||
break
|
||||
elif platform_ in ["s390x"]:
|
||||
_add_directory(library_dirs, "/usr/lib64")
|
||||
_add_directory(library_dirs, "/usr/lib/s390x-linux-gnu")
|
||||
_add_directory(
|
||||
library_dirs, "/usr/lib/s390x-linux-gnu")
|
||||
break
|
||||
elif platform_ in ["s390"]:
|
||||
_add_directory(library_dirs, "/usr/lib/s390-linux-gnu")
|
||||
|
@ -344,7 +355,8 @@ class pil_build_ext(build_ext):
|
|||
best_path = None
|
||||
for name in os.listdir(program_files):
|
||||
if name.startswith('OpenJPEG '):
|
||||
version = tuple([int(x) for x in name[9:].strip().split('.')])
|
||||
version = tuple(
|
||||
[int(x) for x in name[9:].strip().split('.')])
|
||||
if version > best_version:
|
||||
best_version = version
|
||||
best_path = os.path.join(program_files, name)
|
||||
|
@ -371,7 +383,8 @@ class pil_build_ext(build_ext):
|
|||
if _find_include_file(self, "zlib.h"):
|
||||
if _find_library_file(self, "z"):
|
||||
feature.zlib = "z"
|
||||
elif sys.platform == "win32" and _find_library_file(self, "zlib"):
|
||||
elif (sys.platform == "win32" and
|
||||
_find_library_file(self, "zlib")):
|
||||
feature.zlib = "zlib" # alternative name
|
||||
|
||||
if feature.want('jpeg'):
|
||||
|
@ -405,14 +418,16 @@ class pil_build_ext(build_ext):
|
|||
# include path
|
||||
_add_directory(self.compiler.include_dirs, best_path, 0)
|
||||
feature.jpeg2000 = 'openjp2'
|
||||
feature.openjpeg_version = '.'.join([str(x) for x in best_version])
|
||||
feature.openjpeg_version = '.'.join(
|
||||
[str(x) for x in best_version])
|
||||
|
||||
if feature.want('tiff'):
|
||||
if _find_library_file(self, "tiff"):
|
||||
feature.tiff = "tiff"
|
||||
if sys.platform == "win32" and _find_library_file(self, "libtiff"):
|
||||
feature.tiff = "libtiff"
|
||||
if sys.platform == "darwin" and _find_library_file(self, "libtiff"):
|
||||
if (sys.platform == "darwin" and
|
||||
_find_library_file(self, "libtiff")):
|
||||
feature.tiff = "libtiff"
|
||||
|
||||
if feature.want('freetype'):
|
||||
|
@ -459,13 +474,15 @@ class pil_build_ext(build_ext):
|
|||
if feature.want('webp'):
|
||||
if (_find_include_file(self, "webp/encode.h") and
|
||||
_find_include_file(self, "webp/decode.h")):
|
||||
if _find_library_file(self, "webp"): # in googles precompiled zip it is call "libwebp"
|
||||
# In Google's precompiled zip it is call "libwebp":
|
||||
if _find_library_file(self, "webp"):
|
||||
feature.webp = "webp"
|
||||
|
||||
if feature.want('webpmux'):
|
||||
if (_find_include_file(self, "webp/mux.h") and
|
||||
_find_include_file(self, "webp/demux.h")):
|
||||
if _find_library_file(self, "webpmux") and _find_library_file(self, "webpdemux"):
|
||||
if (_find_library_file(self, "webpmux") and
|
||||
_find_library_file(self, "webpdemux")):
|
||||
feature.webpmux = "webpmux"
|
||||
|
||||
for f in feature:
|
||||
|
@ -527,7 +544,9 @@ class pil_build_ext(build_ext):
|
|||
if sys.platform == "win32":
|
||||
extra.extend(["user32", "gdi32"])
|
||||
exts.append(Extension(
|
||||
"PIL._imagingcms", ["_imagingcms.c"], libraries=["lcms2"] + extra))
|
||||
"PIL._imagingcms",
|
||||
["_imagingcms.c"],
|
||||
libraries=["lcms2"] + extra))
|
||||
|
||||
if os.path.isfile("_webp.c") and feature.webp:
|
||||
libs = ["webp"]
|
||||
|
@ -603,7 +622,8 @@ class pil_build_ext(build_ext):
|
|||
options = [
|
||||
(feature.tcl and feature.tk, "TKINTER"),
|
||||
(feature.jpeg, "JPEG"),
|
||||
(feature.jpeg2000, "OPENJPEG (JPEG2000)", feature.openjpeg_version),
|
||||
(feature.jpeg2000, "OPENJPEG (JPEG2000)",
|
||||
feature.openjpeg_version),
|
||||
(feature.zlib, "ZLIB (PNG/ZIP)"),
|
||||
(feature.tiff, "LIBTIFF"),
|
||||
(feature.freetype, "FREETYPE2"),
|
||||
|
@ -720,3 +740,4 @@ setup(
|
|||
zip_safe=True,
|
||||
)
|
||||
|
||||
# End of file
|
||||
|
|
Loading…
Reference in New Issue
Block a user