From 295b18585a5e7be8723acad4b6534f1995adbad0 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Sat, 7 Nov 2015 20:34:56 +0000 Subject: [PATCH] python uses bandjoin_const when possible added a test case, speedup seems worthwhile --- TODO | 4 +--- python/Vips.py | 33 +++++++++++++++++++++++---------- test/test_conversion.py | 10 ++++++++++ 3 files changed, 34 insertions(+), 13 deletions(-) diff --git a/TODO b/TODO index 17144f20..7faf4de2 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,4 @@ -- pyvips should use bandjoin_const when possible - - benchmark, maybe not worthwhile +- need to update docs, c++ binding - test suite is broken, float->int mask I guess diff --git a/python/Vips.py b/python/Vips.py index cfe757ea..babda542 100644 --- a/python/Vips.py +++ b/python/Vips.py @@ -35,6 +35,7 @@ from __future__ import division import sys import re import logging +import numbers logger = logging.getLogger(__name__) @@ -110,12 +111,7 @@ def unpack(value): return value def array_image_new(array): - match_image = None - for i in range(0, len(array)): - if isinstance(array[i], Vips.Image): - match_image = array[i] - break - + match_image = next((x for x in array if isinstance(x, Vips.Image)), None) if match_image is None: raise Error('Unable to make image array argument.', 'Array must contain at least one image.') @@ -757,16 +753,25 @@ class Image(Vips.Image): return self.relational_const(other, Vips.OperationRelational.LESSEQ) def __eq__(self, other): + # for == and != we need to allow comparison to None if isinstance(other, Vips.Image): return self.relational(other, Vips.OperationRelational.EQUAL) - else: + elif isinstance(other, list): return self.relational_const(other, Vips.OperationRelational.EQUAL) + elif isinstance(other, numbers.Number): + return self.relational_const(other, Vips.OperationRelational.EQUAL) + else: + return False def __ne__(self, other): if isinstance(other, Vips.Image): return self.relational(other, Vips.OperationRelational.NOTEQ) - else: + elif isinstance(other, list): return self.relational_const(other, Vips.OperationRelational.NOTEQ) + elif isinstance(other, numbers.Number): + return self.relational_const(other, Vips.OperationRelational.NOTEQ) + else: + return False def __getitem__(self, arg): if isinstance(arg, slice): @@ -868,11 +873,19 @@ class Image(Vips.Image): return [x for x in self] def bandjoin(self, other): - """Join a set of images bandwise.""" + """Append a set of images or constants bandwise.""" if not isinstance(other, list): other = [other] - return Vips.Image.bandjoin([self] + other) + # if [other] is all numbers, we can use bandjoin_const + non_number = next((x for x in other + if not isinstance(x, numbers.Number)), + None) + + if non_number == None: + return self.bandjoin_const(other) + else: + return Vips.Image.bandjoin([self] + other) def maxpos(self): """Return the coordinates of the image maximum.""" diff --git a/test/test_conversion.py b/test/test_conversion.py index 91e4b419..bcaa7cca 100755 --- a/test/test_conversion.py +++ b/test/test_conversion.py @@ -179,6 +179,16 @@ class TestConversion(unittest.TestCase): self.run_binary(self.all_images, bandjoin) + def test_bandjoin_const(self): + x = self.colour.bandjoin(1) + self.assertEqual(x.bands, 4) + self.assertEqual(x[3].avg(), 1) + + x = self.colour.bandjoin([1,2]) + self.assertEqual(x.bands, 5) + self.assertEqual(x[3].avg(), 1) + self.assertEqual(x[4].avg(), 2) + def test_bandmean(self): def bandmean(x): if isinstance(x, Vips.Image):