mirror of
https://github.com/wassname/scikit-image.git
synced 2026-07-20 12:40:31 +08:00
Added a MultiImg class similar to the ImageCollection one, to function as the data structure for multi-image files.
This commit is contained in:
+172
-40
@@ -2,33 +2,39 @@
|
||||
|
||||
from __future__ import with_statement
|
||||
|
||||
__all__ = ['Image','ImageCollection','imread']
|
||||
__all__ = ['Img', 'ImgCollection', 'imread']
|
||||
|
||||
from glob import glob
|
||||
import os.path
|
||||
|
||||
import numpy as N
|
||||
from numpy.testing import set_local_path, restore_path
|
||||
from scipy.misc.pilutil import imread
|
||||
import numpy as np
|
||||
from pil_imread import imread
|
||||
|
||||
set_local_path('../..')
|
||||
import supreme
|
||||
from supreme.lib import EXIF
|
||||
restore_path()
|
||||
try:
|
||||
from PIL import Image
|
||||
except ImportError:
|
||||
raise ImportError("Could not import the Python Imaging Library (PIL)"
|
||||
" required to load image files. Please refer to"
|
||||
" http://pypi.python.org/pypi/PIL/ for installation"
|
||||
" instructions.")
|
||||
|
||||
class Image(N.ndarray):
|
||||
#import supreme
|
||||
#from supreme.lib import EXIF
|
||||
|
||||
|
||||
class Img(np.ndarray):
|
||||
"""Image data with tags."""
|
||||
|
||||
tags = {'filename' : '',
|
||||
'EXIF' : {},
|
||||
'info' : {}}
|
||||
|
||||
def __new__(image_cls,arr,**kwargs):
|
||||
def __new__(image_cls, arr, **kwargs):
|
||||
"""Set the image data and tags according to given parameters.
|
||||
|
||||
Input:
|
||||
------
|
||||
`image_cls` : Image class specification
|
||||
`image_cls` : Img class specification
|
||||
This is not normally specified by the user.
|
||||
`arr` : ndarray
|
||||
Image data.
|
||||
@@ -36,42 +42,168 @@ class Image(N.ndarray):
|
||||
Specified in the form ``tag0=value``, ``tag1=value``.
|
||||
|
||||
"""
|
||||
x = N.asarray(arr).view(image_cls)
|
||||
for tag,value in Image.tags.items():
|
||||
setattr(x,tag,kwargs.get(tag,getattr(arr,tag,value)))
|
||||
x = np.asarray(arr).view(image_cls)
|
||||
for tag, value in Img.tags.items():
|
||||
setattr(x, tag, kwargs.get(tag, getattr(arr, tag, value)))
|
||||
return x
|
||||
|
||||
def __array_finalize__(self, obj):
|
||||
"""Copy object tags."""
|
||||
for tag,value in Image.tags.items():
|
||||
setattr(self,tag,getattr(obj,tag,value))
|
||||
for tag, value in Img.tags.items():
|
||||
setattr(self, tag, getattr(obj, tag, value))
|
||||
return
|
||||
|
||||
def __reduce__(self):
|
||||
object_state = list(N.ndarray.__reduce__(self))
|
||||
object_state = list(np.ndarray.__reduce__(self))
|
||||
subclass_state = {}
|
||||
for tag in self.tags:
|
||||
subclass_state[tag] = getattr(self,tag)
|
||||
object_state[2] = (object_state[2],subclass_state)
|
||||
subclass_state[tag] = getattr(self, tag)
|
||||
object_state[2] = (object_state[2], subclass_state)
|
||||
return tuple(object_state)
|
||||
|
||||
def __setstate__(self,state):
|
||||
nd_state,subclass_state = state
|
||||
N.ndarray.__setstate__(self,nd_state)
|
||||
def __setstate__(self, state):
|
||||
nd_state, subclass_state = state
|
||||
np.ndarray.__setstate__(self, nd_state)
|
||||
|
||||
for tag in subclass_state:
|
||||
setattr(self,tag,subclass_state[tag])
|
||||
setattr(self, tag, subclass_state[tag])
|
||||
|
||||
@property
|
||||
def exposure(self):
|
||||
"""Return exposure time based on EXIF tag."""
|
||||
exposure = self.EXIF['EXIF ExposureTime'].values[0]
|
||||
return exposure.num / float(exposure.den)
|
||||
#@property
|
||||
#def exposure(self):
|
||||
# """Return exposure time based on EXIF tag."""
|
||||
# exposure = self.EXIF['EXIF ExposureTime'].values[0]
|
||||
# return exposure.num / float(exposure.den)
|
||||
|
||||
class ImageCollection(object):
|
||||
|
||||
class MultiImg(object):
|
||||
"""A class containing a single multi-image.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
filename : str
|
||||
The complete path to the image file.
|
||||
conserve_memory : bool, optional
|
||||
Whether to conserve memory by only caching a single frame. Default is
|
||||
True.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
filename : str
|
||||
The complete path to the image file.
|
||||
conserve_memory : bool
|
||||
Whether memory is conserved by only caching a single frame.
|
||||
numframes : int
|
||||
The number of frames in the image.
|
||||
|
||||
Notes
|
||||
-----
|
||||
If ``conserve_memory=True`` the memory footprint can be reduced, however
|
||||
the performance can be affected because frames have to be read from file
|
||||
more often.
|
||||
|
||||
The last accessed frame is cached, all other frames will have to be read
|
||||
from file.
|
||||
|
||||
Examples
|
||||
--------
|
||||
::
|
||||
>>> img = MultiImg(fname)
|
||||
>>> img.numframes
|
||||
3
|
||||
>>> for frame in img:
|
||||
... frame.shape
|
||||
(576, 384)
|
||||
(576, 384)
|
||||
(576, 384)
|
||||
"""
|
||||
|
||||
def __init__(self, filename, conserve_memory=True):
|
||||
"""Load a multi-img"""
|
||||
self.filename = filename
|
||||
self.conserve_memory = conserve_memory
|
||||
self._cached = None
|
||||
|
||||
img = Image.open(self.filename)
|
||||
if self.conserve_memory:
|
||||
self.numframes = self._find_numframes(img)
|
||||
else:
|
||||
self._frames = self._getallframes(img)
|
||||
self.numframes = len(self._frames)
|
||||
|
||||
def _find_numframes(self, img):
|
||||
"""Find the number of frames in the multi-img."""
|
||||
try:
|
||||
i = 0
|
||||
while True:
|
||||
i += 1
|
||||
img.seek(i)
|
||||
except EOFError:
|
||||
return i
|
||||
|
||||
def _getframe(self, framenum):
|
||||
"""Open the image and extract the frame."""
|
||||
img = Image.open(self.filename)
|
||||
img.seek(framenum)
|
||||
return np.asarray(img)
|
||||
|
||||
|
||||
def _getallframes(self, img):
|
||||
"""Extract all frames from the multi-img."""
|
||||
frames = []
|
||||
try:
|
||||
i = 0
|
||||
while True:
|
||||
frames.append(np.asarray(img))
|
||||
i += 1
|
||||
img.seek(i)
|
||||
except EOFError:
|
||||
return frames
|
||||
|
||||
def __getitem__(self, n):
|
||||
"""Return the n-th frame as an array.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
n : int
|
||||
Number of the required frame.
|
||||
|
||||
Returns
|
||||
-------
|
||||
frame : ndarray
|
||||
The n-th frame.
|
||||
"""
|
||||
numframes = self.numframes
|
||||
if -numframes <= n < numframes:
|
||||
n = n% numframes
|
||||
else:
|
||||
raise IndexError, "There are only %s frames in the image"%numframes
|
||||
|
||||
if self.conserve_memory:
|
||||
if not self._cached == n:
|
||||
frame = self._getframe(n)
|
||||
self._cached = n
|
||||
self._cachedframe = frame
|
||||
return self._cachedframe
|
||||
else:
|
||||
return self._frames[n]
|
||||
|
||||
def __iter__(self):
|
||||
"""Iterate over the frames."""
|
||||
for i in range(len(self)):
|
||||
yield self[i]
|
||||
|
||||
def __len__(self):
|
||||
"""Number of images in collection."""
|
||||
return self.numframes
|
||||
|
||||
def __str__(self):
|
||||
return str(self.filename)
|
||||
|
||||
|
||||
class ImgCollection(object):
|
||||
"""Load and manage a collection of images."""
|
||||
|
||||
def __init__(self,file_pattern,conserve_memory=True,grey=False):
|
||||
def __init__(self, file_pattern, conserve_memory=True, grey=False):
|
||||
"""Load image files.
|
||||
|
||||
Note that files are always stored in alphabetical order.
|
||||
@@ -89,9 +221,9 @@ class ImageCollection(object):
|
||||
Example:
|
||||
--------
|
||||
>>> from os.path import dirname, join
|
||||
>>> data_dir = join(dirname(__file__),'tests')
|
||||
>>> data_dir = join(dirname(__file__), 'tests')
|
||||
|
||||
>>> c = ImageCollection(data_dir + '/*.png')
|
||||
>>> c = ImgCollection(data_dir + '/*.png')
|
||||
>>> len(c)
|
||||
3
|
||||
>>> c[2].shape
|
||||
@@ -107,9 +239,9 @@ class ImageCollection(object):
|
||||
|
||||
self.conserve_memory = conserve_memory
|
||||
self.grey = grey
|
||||
self.data = N.empty(memory_slots,dtype=object)
|
||||
self.data = np.empty(memory_slots, dtype=object)
|
||||
|
||||
def __getitem__(self,n,_cached=N.array(-1)):
|
||||
def __getitem__(self, n, _cached=np.array(-1)):
|
||||
"""Return image n in the queue.
|
||||
|
||||
Loading is done on demand.
|
||||
@@ -127,14 +259,14 @@ class ImageCollection(object):
|
||||
"""
|
||||
idx = n % len(self.data)
|
||||
if (_cached != n and self.conserve_memory) or (self.data[idx] is None):
|
||||
image_data = imread(self.files[n],self.grey)
|
||||
image_data = imread(self.files[n], self.grey)
|
||||
|
||||
with file(self.files[n]) as f:
|
||||
exif = EXIF.process_file(f)
|
||||
#with file(self.files[n]) as f:
|
||||
#exif = EXIF.process_file(f)
|
||||
|
||||
self.data[idx] = Image(image_data,
|
||||
filename=os.path.basename(self.files[n]),
|
||||
EXIF=exif,info={})
|
||||
#self.data[idx] = Img(image_data,
|
||||
#filename=os.path.basename(self.files[n]),
|
||||
#EXIF=exif, info={})
|
||||
|
||||
_cached.flat = n
|
||||
|
||||
|
||||
Reference in New Issue
Block a user