Source code for openalea.phenomenal.object.imageView
# -*- python -*-
#
# Copyright INRIA - CIRAD - INRA
#
# Distributed under the Cecill-C License.
# See accompanying file LICENSE.txt or copy at
# http://www.cecill.info/licences/Licence_CeCILL-C_V1-en.html
#
# ==============================================================================
# ==============================================================================
[docs]
class ImageView:
"""Container associating an image with its geometric projection.
Attributes:
image:
Image array associated with a camera/view configuration.
projection:
Projection object/function returned by the calibration model for
the corresponding camera and angle.
integral:
Optional cached integral image representation. Initialized to
``None`` and can be computed later for performance purposes.
"""
[docs]
def __init__(self, image, projection):
"""Initialize an ImageView instance.
Args:
image:
Input image array.
projection:
Projection object/function describing the mapping associated
with the image acquisition setup.
"""
self.image = image
self.projection = projection
self.integral = None
[docs]
def iter_image_paths(image_paths, imread, cameras=None, angles=None):
"""Iterate over images stored as file paths.
Args:
image_paths:
Nested dictionary mapping camera identifiers and angles to image
file paths::
{
camera_id: {
angle: image_path,
...
},
...
}
imread:
Callable used to read an image from a file path.
cameras:
Optional iterable of camera identifiers to filter.
If ``None``, all cameras are used.
angles:
Optional iterable of view angles to filter.
If ``None``, all angles are used.
Yields:
Tuples ``(camera_id, angle, image_array)`` for each selected image.
"""
if cameras is not None:
cameras = set(cameras)
if angles is not None:
angles = set(angles)
for id_camera in image_paths:
if cameras is not None and id_camera not in cameras:
continue
for angle in image_paths[id_camera]:
if angles is not None and angle not in angles:
continue
yield id_camera, angle, imread(image_paths[id_camera][angle])
[docs]
def iter_images(images, cameras=None, angles=None):
"""Iterate over an in-memory image dictionary.
Args:
images:
Nested dictionary mapping camera identifiers and angles to image
arrays::
{
camera_id: {
angle: image_array,
...
},
...
}
cameras:
Optional iterable of camera identifiers to filter.
If ``None``, all cameras are used.
angles:
Optional iterable of view angles to filter.
If ``None``, all angles are used.
Yields:
Tuples ``(camera_id, angle, image_array)`` for each selected image.
"""
if cameras is not None:
cameras = set(cameras)
if angles is not None:
angles = set(angles)
for id_camera in images:
if cameras is not None and id_camera not in cameras:
continue
for angle in images[id_camera]:
if angles is not None and angle not in angles:
continue
yield id_camera, angle, images[id_camera][angle]
[docs]
def as_image_views(images_iterator, calibration):
"""Convert an image iterator into a dictionary of ImageView objects.
Args:
images_iterator:
Iterator yielding ``(camera_id, angle, image_array)`` tuples.
Typically created with :func:`iter_images` or
:func:`iter_image_paths`.
calibration:
Calibration object providing the method
``get_projection(camera_id, angle)``.
Returns:
Dictionary mapping ``"{camera_id}_{angle}"`` keys to
:class:`ImageView` instances.
Example:
>>> iterator = iter_images(images)
>>> image_views = as_image_views(iterator, calibration)
>>> image_views["side_0"]
"""
im_views = dict()
for id_camera, angle, image in images_iterator:
name = f'{id_camera}_{angle}'
projection = calibration.get_projection(id_camera, angle)
im_views[name] = ImageView(
image,
projection
)
return im_views