[Python-modules-commits] [willow] 02/07: Import willow_1.0.orig.tar.gz

Christopher Stuart Hoskin mans0954 at moszumanska.debian.org
Thu Sep 28 08:01:20 UTC 2017


This is an automated email from the git hooks/post-receive script.

mans0954 pushed a commit to branch master
in repository willow.

commit 6940b39a35556bc17badf81131664862649e952d
Author: Christopher Hoskin <mans0954 at debian.org>
Date:   Fri Sep 22 20:17:33 2017 +0100

    Import willow_1.0.orig.tar.gz
---
 .travis.yml                |   1 +
 Dockerfile                 |   8 ---
 Dockerfile.py2             |   7 +++
 Dockerfile.py3             |  15 ++++++
 readme.rst => README.rst   |   6 +--
 docker-test.sh             |   7 ++-
 docs/changelog.rst         |  11 +++-
 docs/conf.py               |   2 +-
 docs/reference.rst         |   2 +-
 setup.py                   |   4 +-
 tests/images/cameraman.tif | Bin 0 -> 65240 bytes
 tests/images/sails.bmp     | Bin 0 -> 394294 bytes
 tests/test_image.py        |  29 ++++++++++-
 tests/test_opencv.py       |  11 ++++
 tests/test_wand.py         |   2 +-
 willow/__init__.py         |   4 +-
 willow/image.py            |   7 ++-
 willow/plugins/opencv.py   | 123 ++++++++++++++++++++++++++-------------------
 willow/plugins/pillow.py   |   2 +
 willow/plugins/wand.py     |   2 +
 20 files changed, 168 insertions(+), 75 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 8a815d0..8b01a93 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -6,6 +6,7 @@ python:
     - 3.3
     - 3.4
     - 3.5
+    - 3.6
 
 # Package installation
 install:
diff --git a/Dockerfile b/Dockerfile
deleted file mode 100644
index af6ff5e..0000000
--- a/Dockerfile
+++ /dev/null
@@ -1,8 +0,0 @@
-FROM debian:jessie
-MAINTAINER Karl Hobley <karlhobley10 at gmail.com>
-
-RUN apt-get update -y
-RUN apt-get install -y python python-opencv python-numpy python-pillow python-wand python-mock
-
-VOLUME ["/src"]
-WORKDIR /src
diff --git a/Dockerfile.py2 b/Dockerfile.py2
new file mode 100644
index 0000000..a87b749
--- /dev/null
+++ b/Dockerfile.py2
@@ -0,0 +1,7 @@
+FROM debian:jessie
+MAINTAINER Karl Hobley <karlhobley10 at gmail.com>
+
+RUN apt-get update && apt-get install -y python python-opencv python-numpy python-pillow python-wand python-mock
+
+VOLUME ["/src"]
+WORKDIR /src
diff --git a/Dockerfile.py3 b/Dockerfile.py3
new file mode 100644
index 0000000..6ee35c6
--- /dev/null
+++ b/Dockerfile.py3
@@ -0,0 +1,15 @@
+FROM debian:jessie
+MAINTAINER Karl Hobley <karlhobley10 at gmail.com>
+
+RUN apt-get update && apt-get install -y python3 python3-numpy python3-pillow python3-wand python3-mock
+
+RUN apt-get install -y libjpeg-dev libtiff5-dev libjasper-dev libpng12-dev build-essential cmake git pkg-config libavcodec-dev libavformat-dev libswscale-dev libv4l-dev libatlas-base-dev gfortran python3.4-dev python3-numpy python3-scipy python3-matplotlib ipython3 python3-pandas ipython3-notebook python3-tk libtbb-dev libeigen3-dev yasm libopencore-amrnb-dev libopencore-amrwb-dev libtheora-dev libvorbis-dev libxvidcore-dev libx264-dev libqt4-dev libqt4-opengl-dev sphinx-common texlive-l [...]
+
+ADD opencv-3.2.0.tar.gz /opencv
+
+WORKDIR /opencv/opencv-3.2.0
+RUN cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D PYTHON_EXECUTABLE=/usr/bin/python3 -D PYTHON_LIBRARY=/usr/lib/x86_64-linux-gnu/libpython3.4m.so -D PYTHON_INCLUDE_DIR=/usr/include/python3.4m/ -D PYTHON_INCLUDE_DIR2=/usr/include/x86_64-linux-gnu/python3.4m/ -D PYTHON_NUMPY_INCLUDE_DIRS=/usr/lib/python3/dist-packages/numpy/core/include/ -D BUILD_opencv_java=OFF .
+RUN make && make install
+
+VOLUME ["/src"]
+WORKDIR /src
diff --git a/readme.rst b/README.rst
similarity index 93%
rename from readme.rst
rename to README.rst
index d88ea7c..0a85a0d 100644
--- a/readme.rst
+++ b/README.rst
@@ -1,5 +1,5 @@
-.. image:: https://travis-ci.org/torchbox/Willow.svg?branch=master
-    :target: https://travis-ci.org/torchbox/Willow
+.. image:: https://travis-ci.org/wagtail/Willow.svg?branch=master
+    :target: https://travis-ci.org/wagtail/Willow
 
 .. image:: http://drone4.kaed.uk/api/badges/torchbox/Willow/status.svg
     :target: http://drone4.kaed.uk/torchbox/Willow
@@ -18,7 +18,7 @@ Willow is a simple image library that combines the APIs of Pillow, Wand and Open
 
 Willow currently has basic resize and crop operations, face and feature detection and animated GIF support. New operations and library integrations can also be `easily implemented <http://willow.readthedocs.org/en/latest/guide/extend.html>`_.
 
-It is written in pure-Python (versions 2.7, 3.3, 3.4 and 3.5 are supported)
+It is written in pure-Python (versions 2.7, 3.3, 3.4, 3.5 and 3.6 are supported)
 
 Examples
 --------
diff --git a/docker-test.sh b/docker-test.sh
index 06a4bbb..3380ba5 100755
--- a/docker-test.sh
+++ b/docker-test.sh
@@ -1,5 +1,8 @@
 # Runs the tests using the provided Dockerfile
 # Saves having to install OpenCV locally
 
-docker build -t willow .
-docker run --rm -ti -v $(pwd):/src willow python runtests.py --opencv
+docker build -f Dockerfile.py2 -t willow-py2 .
+docker run --rm -ti -v $(pwd):/src willow-py2 python runtests.py --opencv
+
+docker build -f Dockerfile.py3 -t willow-py3 .
+docker run --rm -ti -v $(pwd):/src willow-py3 python3 runtests.py --opencv
diff --git a/docs/changelog.rst b/docs/changelog.rst
index c6c7d92..507960e 100644
--- a/docs/changelog.rst
+++ b/docs/changelog.rst
@@ -1,8 +1,17 @@
 Changelog
 =========
 
+1.0 (04/08/2016)
+----------------
+
+ - OpenCV 3 support (Will Giddens)
+ - Removed Apple copyrighted ICC profile from orientation test images (Christopher Hoskin)
+ - Fix: Altered `detect_features` in OpenCV 3 to return a list instead of a numpy array (Trent Holliday)
+ - Support for TIFF files (Maik Hoepfel)
+ - Support for BMP files was made official (Maik Hoepfel)
+
 0.4 (05/10/2016)
---------------------
+----------------
 
  - Support for image optimisation and saving progressive JPEG files
  - Added documentation
diff --git a/docs/conf.py b/docs/conf.py
index 80b0740..7f997c8 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -62,7 +62,7 @@ master_doc = 'index'
 
 # General information about the project.
 project = 'Willow'
-copyright = '2015, Torchbox'
+copyright = '2017, Torchbox'
 
 # The version info for the project you're documenting, acts as replacement for
 # |version| and |release|, also used in various other places throughout the
diff --git a/docs/reference.rst b/docs/reference.rst
index b83ef7d..578ace7 100644
--- a/docs/reference.rst
+++ b/docs/reference.rst
@@ -261,7 +261,7 @@ Here's a full list of operations provided by Willow out of the box:
 
         do_thing(image.get_wand_image())
 
-    You can convert a ``Wand.Image` object back into a Willow :class:`Image`
+    You can convert a ``Wand.Image`` object back into a Willow :class:`Image`
     using the ``WandImage`` class:
 
     .. code-block:: python
diff --git a/setup.py b/setup.py
index ffd359d..5502393 100644
--- a/setup.py
+++ b/setup.py
@@ -20,10 +20,10 @@ except ImportError:
 
 setup(
     name='Willow',
-    version='0.4',
+    version='1.0',
     description='A Python image library that sits on top of Pillow, Wand and OpenCV',
     author='Karl Hobley',
-    author_email='karlhobley10 at gmail.com',
+    author_email='karl at kaed.uk',
     url='',
     packages=find_packages(exclude=['tests']),
     include_package_data=True,
diff --git a/tests/images/cameraman.tif b/tests/images/cameraman.tif
new file mode 100644
index 0000000..bf8495b
Binary files /dev/null and b/tests/images/cameraman.tif differ
diff --git a/tests/images/sails.bmp b/tests/images/sails.bmp
new file mode 100644
index 0000000..ef8dd0f
Binary files /dev/null and b/tests/images/sails.bmp differ
diff --git a/tests/test_image.py b/tests/test_image.py
index e4021ed..4937603 100644
--- a/tests/test_image.py
+++ b/tests/test_image.py
@@ -2,7 +2,10 @@ import io
 import unittest
 import mock
 
-from willow.image import Image, JPEGImageFile, PNGImageFile, GIFImageFile, UnrecognisedImageFormatError
+from willow.image import (
+    Image, JPEGImageFile, PNGImageFile, GIFImageFile, UnrecognisedImageFormatError,
+    BMPImageFile, TIFFImageFile
+)
 
 
 class TestOpenImage(unittest.TestCase):
@@ -59,6 +62,30 @@ class TestOpenImage(unittest.TestCase):
             Image.open(f)
 
 
+class TestImageFormats(unittest.TestCase):
+    """
+    Tests image formats that are not well covered by the remaining tests.
+    """
+
+    def test_bmp(self):
+        with open('tests/images/sails.bmp', 'rb') as f:
+            image = Image.open(f)
+            width, height = image.get_size()
+
+        self.assertIsInstance(image, BMPImageFile)
+        self.assertEqual(width, 768)
+        self.assertEqual(height, 512)
+
+    def test_tiff(self):
+        with open('tests/images/cameraman.tif', 'rb') as f:
+            image = Image.open(f)
+            width, height = image.get_size()
+
+        self.assertIsInstance(image, TIFFImageFile)
+        self.assertEqual(width, 256)
+        self.assertEqual(height, 256)
+
+
 class TestSaveImage(unittest.TestCase):
     """
     Image.save must work out the name of the underlying operation based on the
diff --git a/tests/test_opencv.py b/tests/test_opencv.py
index d2c561f..a52e124 100644
--- a/tests/test_opencv.py
+++ b/tests/test_opencv.py
@@ -16,6 +16,13 @@ class TestOpenCVOperations(unittest.TestCase):
             colour_image = OpenCVColorImage.from_buffer_rgb(buffer_rgb)
             self.image = OpenCVGrayscaleImage.from_color(colour_image)
 
+        self.expected_features = [
+            [41.0, 206.0], [16.0, 201.0], [243.0, 208.0], [79.0, 130.0], [120.0, 24.0], [43.0, 119.0], [40.0, 165.0],
+            [37.0, 14.0], [250.0, 59.0], [98.0, 6.0], [78.0, 61.0], [201.0, 93.0], [8.0, 114.0], [189.0, 142.0],
+            [292.0, 188.0], [201.0, 199.0], [7.0, 154.0], [198.0, 247.0], [235.0, 55.0], [22.0, 36.0]
+        ]
+        self.expected_faces = [(272, 89, 364, 181), (91, 165, 187, 261)]
+
     def test_get_size(self):
         width, height = self.image.get_size()
         self.assertEqual(width, 600)
@@ -32,11 +39,15 @@ class TestOpenCVOperations(unittest.TestCase):
     def test_detect_features(self):
         features = self.image.detect_features()
 
+        self.assertIsInstance(features, list)
         # There are 20 features in the image
         self.assertEqual(len(features), 20)
+        self.assertEqual(features, self.expected_features)
 
     def test_detect_faces(self):
         faces = self.image.detect_faces()
 
+        self.assertIsInstance(faces, list)
         # There are two faces in the image
         self.assertEqual(len(faces), 2)
+        self.assertEqual(faces, self.expected_faces)
diff --git a/tests/test_wand.py b/tests/test_wand.py
index adc7ed1..6bc4c74 100644
--- a/tests/test_wand.py
+++ b/tests/test_wand.py
@@ -134,7 +134,7 @@ class TestWandImageOrientation(unittest.TestCase):
         # Check that the red flower is in the bottom left
         # The JPEGs have compressed slightly differently so the colours won't be spot on
         colour = image.image[282][155]
-        self.assertAlmostEqual(colour.red * 255, 217, delta=10)
+        self.assertAlmostEqual(colour.red * 255, 217, delta=12)
         self.assertAlmostEqual(colour.green * 255, 38, delta=11)
         self.assertAlmostEqual(colour.blue * 255, 46, delta=13)
 
diff --git a/willow/__init__.py b/willow/__init__.py
index 10ed687..f487025 100644
--- a/willow/__init__.py
+++ b/willow/__init__.py
@@ -10,6 +10,7 @@ def setup():
         BMPImageFile,
         RGBImageBuffer,
         RGBAImageBuffer,
+        TIFFImageFile,
     )
     from willow.plugins import pillow, wand, opencv
 
@@ -17,6 +18,7 @@ def setup():
     registry.register_image_class(PNGImageFile)
     registry.register_image_class(GIFImageFile)
     registry.register_image_class(BMPImageFile)
+    registry.register_image_class(TIFFImageFile)
     registry.register_image_class(RGBImageBuffer)
     registry.register_image_class(RGBAImageBuffer)
 
@@ -27,4 +29,4 @@ def setup():
 setup()
 
 
-__version__ = '0.4'
+__version__ = '1.0'
diff --git a/willow/image.py b/willow/image.py
index 7ddd818..c4a51fe 100644
--- a/willow/image.py
+++ b/willow/image.py
@@ -82,7 +82,7 @@ class Image(object):
 
     def save(self, image_format, output):
         # Get operation name
-        if image_format not in ['jpeg', 'png', 'gif']:
+        if image_format not in ['jpeg', 'png', 'gif', 'bmp', 'tiff']:
             raise ValueError("Unknown image format: %s" % image_format)
 
         operation_name = 'save_as_' + image_format
@@ -154,12 +154,17 @@ class BMPImageFile(ImageFile):
     format_name = 'bmp'
 
 
+class TIFFImageFile(ImageFile):
+    format_name = 'tiff'
+
+
 INITIAL_IMAGE_CLASSES = {
     # A mapping of image formats to their initial class
     'jpeg': JPEGImageFile,
     'png': PNGImageFile,
     'gif': GIFImageFile,
     'bmp': BMPImageFile,
+    'tiff': TIFFImageFile,
 }
 
 
diff --git a/willow/plugins/opencv.py b/willow/plugins/opencv.py
index 920bd5d..9be847f 100644
--- a/willow/plugins/opencv.py
+++ b/willow/plugins/opencv.py
@@ -1,14 +1,21 @@
 from __future__ import absolute_import
 
-import io
 import os
 
 from willow.image import Image, RGBImageBuffer
 
 
-def _cv():
-    import cv
-    return cv
+def _cv2():
+    try:
+        import cv2
+    except ImportError:
+        from cv import cv2
+    return cv2
+
+
+def _numpy():
+    import numpy
+    return numpy
 
 
 class BaseOpenCVImage(Image):
@@ -18,7 +25,7 @@ class BaseOpenCVImage(Image):
 
     @classmethod
     def check(cls):
-        _cv()
+        _cv2()
 
     @Image.operation
     def get_size(self):
@@ -37,75 +44,85 @@ class BaseOpenCVImage(Image):
 
 class OpenCVColorImage(BaseOpenCVImage):
     @classmethod
+    def check(cls):
+        super(OpenCVColorImage, cls).check()
+        _numpy()
+
+    @classmethod
     @Image.converter_from(RGBImageBuffer)
     def from_buffer_rgb(cls, image_buffer):
-        cv = _cv()
-
-        image = cv.CreateImageHeader(image_buffer.size, cv.IPL_DEPTH_8U, 3)
-        cv.SetData(image, image_buffer.data)
+        """
+        Converts a Color Image buffer into a numpy array suitable for use with OpenCV
+        """
+        numpy = _numpy()
+        cv2 = _cv2()
+
+        image = numpy.frombuffer(image_buffer.data, dtype=numpy.uint8)
+        image = image.reshape(image_buffer.size[1], image_buffer.size[0], 3)
+        image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
         return cls(image, image_buffer.size)
 
-    # TODO: Converter back to RGBImageBuffer
-
 
 class OpenCVGrayscaleImage(BaseOpenCVImage):
+    face_haar_flags = 0
+    face_min_neighbors = 3
+    face_haar_scale = 1.1
+    face_min_size = (40, 40)
+
     @Image.operation
     def detect_features(self):
-        cv = _cv()
-        rows, cols = self.size
-
-        eig_image = cv.CreateMat(rows, cols, cv.CV_32FC1)
-        temp_image = cv.CreateMat(rows, cols, cv.CV_32FC1)
-        points = cv.GoodFeaturesToTrack(self.image, eig_image, temp_image, 20, 0.04, 1.0, useHarris=False)
-
-        return points
+        """
+        Find interesting features of an image suitable for cropping to.
+        """
+        numpy = _numpy()
+        cv2 = _cv2()
+        points = cv2.goodFeaturesToTrack(self.image, 20, 0.04, 1.0)
+        if points is None:
+            return []
+        else:
+            points = numpy.reshape(points, (-1, 2))  # Numpy returns it with an extra third dimension
+            return points.tolist()
 
     @Image.operation
     def detect_faces(self, cascade_filename='haarcascade_frontalface_alt2.xml'):
-        cv = _cv()
-
-        # If a relative path was provided, check local cascades directory
+        """
+        Run OpenCV face detection on the image. Returns a list of coordinates representing a box around each face.
+        """
+        cv2 = _cv2()
+        cascade_filename = self._find_cascade(cascade_filename)
+        cascade = cv2.CascadeClassifier(cascade_filename)
+        equalised_image = cv2.equalizeHist(self.image)
+        faces = cascade.detectMultiScale(equalised_image,
+                                         self.face_haar_scale,
+                                         self.face_min_neighbors,
+                                         self.face_haar_flags,
+                                         self.face_min_size)
+        return [(face[0],
+                 face[1],
+                 face[0] + face[2],
+                 face[1] + face[3],
+                 ) for face in faces]
+
+    def _find_cascade(self, cascade_filename):
+        """
+        Find the requested OpenCV cascade file.  If a relative path was provided, check local cascades directory.
+        """
         if not os.path.isabs(cascade_filename):
             cascade_filename = os.path.join(
                 os.path.dirname(os.path.dirname(__file__)),
                 'data/cascades',
                 cascade_filename,
             )
-
-        # Load cascade file
-        cascade = cv.Load(cascade_filename)
-
-        # Equalise the images histogram
-        equalised_image = cv.CloneImage(self.image)
-        cv.EqualizeHist(self.image, equalised_image)
-
-        # Detect faces
-        min_size = (40, 40)
-        haar_scale = 1.1
-        min_neighbors = 3
-        haar_flags = 0
-
-        faces = cv.HaarDetectObjects(
-            equalised_image, cascade, cv.CreateMemStorage(0),
-            haar_scale, min_neighbors, haar_flags, min_size
-        )
-
-        return [
-            (
-                face[0][0],
-                face[0][1],
-                face[0][0] + face[0][2],
-                face[0][1] + face[0][3],
-            ) for face in faces
-        ]
+        return cascade_filename
 
     @classmethod
     @Image.converter_from(OpenCVColorImage)
     def from_color(cls, colour_image):
-        cv = _cv()
-
-        image = cv.CreateImage(colour_image.size, 8, 1)
-        cv.CvtColor(colour_image.image, image, cv.CV_RGB2GRAY)
+        """
+        Convert OpenCVColorImage to an OpenCVGrayscaleImage.
+        """
+        cv2 = _cv2()
+        image = cv2.cvtColor(colour_image.image, cv2.COLOR_BGR2GRAY)
         return cls(image, colour_image.size)
 
 
diff --git a/willow/plugins/pillow.py b/willow/plugins/pillow.py
index 6bb0000..f8b635e 100644
--- a/willow/plugins/pillow.py
+++ b/willow/plugins/pillow.py
@@ -6,6 +6,7 @@ from willow.image import (
     PNGImageFile,
     GIFImageFile,
     BMPImageFile,
+    TIFFImageFile,
     RGBImageBuffer,
     RGBAImageBuffer,
 )
@@ -143,6 +144,7 @@ class PillowImage(Image):
     @Image.converter_from(PNGImageFile)
     @Image.converter_from(GIFImageFile, cost=200)
     @Image.converter_from(BMPImageFile)
+    @Image.converter_from(TIFFImageFile)
     def open(cls, image_file):
         image_file.f.seek(0)
         image = _PIL_Image().open(image_file.f)
diff --git a/willow/plugins/wand.py b/willow/plugins/wand.py
index 482bc74..6e4ae0b 100644
--- a/willow/plugins/wand.py
+++ b/willow/plugins/wand.py
@@ -10,6 +10,7 @@ from willow.image import (
     BMPImageFile,
     RGBImageBuffer,
     RGBAImageBuffer,
+    TIFFImageFile
 )
 
 
@@ -119,6 +120,7 @@ class WandImage(Image):
     @Image.converter_from(PNGImageFile, cost=150)
     @Image.converter_from(GIFImageFile, cost=150)
     @Image.converter_from(BMPImageFile, cost=150)
+    @Image.converter_from(TIFFImageFile, cost=150)
     def open(cls, image_file):
         image_file.f.seek(0)
         image = _wand_image().Image(file=image_file.f)

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/willow.git



More information about the Python-modules-commits mailing list