add [] overload to python

index and slice image bands
This commit is contained in:
John Cupitt 2015-02-28 16:53:06 +00:00
parent a49e6772fd
commit 5d912fdbbb
7 changed files with 108 additions and 2 deletions

View File

@ -10,6 +10,7 @@
- added test_foreign.py, plus more test images
- rewritten tiff writer is about 3 - 4x faster at making pyramids
- jpg, magick, png, tiff readers now use only 1 fd per input image
- python: use [] to index and slice image bands
6/2/15 started 7.42.3
- bump version for back-compat ABI change

8
TODO
View File

@ -3,6 +3,14 @@
python people are not going to want to use the glib arg parser, for example
- need to add [] overload to Ruby bindings
- overload (x, y) to be getpoint()?
- support orientation tag in tiff images

View File

@ -1263,6 +1263,12 @@ public:
return( a * -1 );
}
friend VImage operator[]( VImage a, int index )
throw( VError )
{
return( a.extract_band( index ) );
}
};
VIPS_NAMESPACE_END

View File

@ -347,6 +347,26 @@ help(image.add)
result_image = ((image * [1, 2, 3]).abs() < 128) | 4
</programlisting>
</para>
<para>
The wrapper overloads <code>[]</code> to be band indexing. You can write:
<programlisting language="Python">
result_image = image[2]
</programlisting>
to extract the third band of the image. It implements the usual
slicing and negative indexes, so you can write:
<programlisting language="Python">
result_image = image[1:]
result_image = image[:3]
result_image = image[-2:]
result_image = [x.avg() for x in image]
</programlisting>
and so on.
</para>
</refsect3>
<refsect3 id="python-expansions">

View File

@ -757,6 +757,32 @@ class Image(Vips.Image):
else:
return self.relational_const(other, Vips.OperationRelational.NOTEQ)
def __getitem__(self, arg):
if isinstance(arg, slice):
i = 0
if arg.start != None:
i = arg.start
n = self.bands - i
if arg.stop != None:
if arg.stop < 0:
n = self.bands + arg.stop - i
else:
n = arg.stop - i
elif isinstance(arg, int):
i = arg
n = 1
else:
raise TypeError
if i < 0:
i = self.bands + i
if i < 0 or i >= self.bands:
raise IndexError
return self.extract_band(i, n = n)
# the cast operators int(), long() and float() must return numeric types,
# so we can't define them for images
@ -813,7 +839,7 @@ class Image(Vips.Image):
def bandsplit(self):
"""Split an n-band image into n separate images."""
return [self.extract_band(i) for i in range(0, self.bands)]
return [x for x in self]
def bandjoin(self, other):
"""Join a set of images bandwise."""

18
python/example/try17.py Executable file
View File

@ -0,0 +1,18 @@
#!/usr/bin/python3
import sys
import logging
#logging.basicConfig(level = logging.DEBUG)
from gi.repository import Vips
#Vips.cache_set_trace(True)
a = Vips.Image.new_from_file(sys.argv[1])
a = a[1:]
a.write_to_file(sys.argv[2])

View File

@ -80,6 +80,8 @@ rot_angle_bonds = [Vips.Angle.D0,
# the other
def zip_expand(x, y):
if isinstance(x, list) and isinstance(y, list):
if len(x) != len(y):
raise Vips.Error("zip_expand list args not equal length")
return list(zip(x, y))
elif isinstance(x, list):
return [[i, y] for i in x]
@ -138,7 +140,7 @@ class TestConversion(unittest.TestCase):
def setUp(self):
im = Vips.Image.mask_ideal(100, 100, 0.5, reject = True, optical = True)
self.colour = im * [1, 2, 3] + [2, 3, 4]
self.mono = self.colour.extract_band(1)
self.mono = self.colour[1]
self.all_images = [self.mono, self.colour]
def test_band_and(self):
@ -295,6 +297,31 @@ class TestConversion(unittest.TestCase):
pixel = sub.getpoint(30, 30)
self.assertAlmostEqualObjects(pixel, [3, 4])
def test_slice(self):
test = self.colour
bands = [x.avg() for x in test]
x = test[0].avg()
self.assertEqual(x, bands[0])
x = test[-1].avg()
self.assertAlmostEqualObjects(x, bands[2])
x = [i.avg() for i in test[1:3]]
self.assertAlmostEqualObjects(x, bands[1:3])
x = [i.avg() for i in test[1:-1]]
self.assertAlmostEqualObjects(x, bands[1:-1])
x = [i.avg() for i in test[:2]]
self.assertAlmostEqualObjects(x, bands[:2])
x = [i.avg() for i in test[1:]]
self.assertAlmostEqualObjects(x, bands[1:])
x = [i.avg() for i in test[-1]]
self.assertAlmostEqualObjects(x, bands[-1])
def test_crop(self):
for fmt in all_formats:
test = self.colour.cast(fmt)