def test_write_image_OpenImageIO(self): # pragma: no cover """ Tests :func:`colour.io.image.write_image_OpenImageIO` definition. """ if not is_openimageio_installed(): return source_image_path = os.path.join(RESOURCES_DIRECTORY, 'CMS_Test_Pattern.exr') target_image_path = os.path.join(self._temporary_directory, 'CMS_Test_Pattern.exr') image = read_image_OpenImageIO(source_image_path) write_image_OpenImageIO(image, target_image_path) image = read_image_OpenImageIO(target_image_path) self.assertTupleEqual(image.shape, (1267, 1274, 3)) self.assertIs(image.dtype, np.dtype('float32')) write_image_OpenImageIO( image, target_image_path, attributes=[ImageAttribute_Specification('John', 'Doe')]) image, attributes = read_image_OpenImageIO( target_image_path, attributes=True) for attribute in attributes: if attribute.name == 'John': self.assertEqual(attribute.value, 'Doe')
def read_image(path, bit_depth='float32', attributes=False): """ Reads given image using *OpenImageIO*. Parameters ---------- path : unicode Image path. bit_depth : unicode, optional **{'float32', 'uint8', 'uint16', 'float16'}**, Image bit_depth. attributes : bool, optional Whether to return the image attributes. Returns ------- ndarray Image as a ndarray. Notes ----- - For convenience, single channel images are squeezed to 2d arrays. Examples -------- >>> import os >>> path = os.path.join('tests', 'resources', 'CMSTestPattern.exr') >>> image = read_image(path) # doctest: +SKIP """ if is_openimageio_installed(raise_exception=True): from OpenImageIO import ImageInput path = str(path) bit_depth = BIT_DEPTH_MAPPING[bit_depth].openimageio image = ImageInput.open(path) specification = image.spec() shape = (specification.height, specification.width, specification.nchannels) image_data = image.read_image(bit_depth) image.close() image = np.squeeze(np.array(image_data).reshape(shape)) if attributes: extra_attributes = [] for i in range(len(specification.extra_attribs)): attribute = specification.extra_attribs[i] extra_attributes.append( ImageAttribute_Specification(attribute.name, attribute.value, attribute.type)) return image, extra_attributes else: return image
def read_image(path, bit_depth='float32', attributes=False): """ Reads given image using *OpenImageIO*. Parameters ---------- path : unicode Image path. bit_depth : unicode, optional **{'float32', 'uint8', 'uint16', 'float16'}**, Image bit_depth. attributes : bool, optional Whether to return the image attributes. Returns ------- ndarray Image as a ndarray. Notes ----- - For convenience, single channel images are squeezed to 2d arrays. Examples -------- >>> import os >>> path = os.path.join('tests', 'resources', 'CMSTestPattern.exr') >>> image = read_image(path) # doctest: +SKIP """ if is_openimageio_installed(raise_exception=True): from OpenImageIO import ImageInput path = str(path) bit_depth = BIT_DEPTH_MAPPING[bit_depth].openimageio image = ImageInput.open(path) specification = image.spec() shape = (specification.height, specification.width, specification.nchannels) image_data = image.read_image(bit_depth) image.close() image = np.squeeze(np.array(image_data).reshape(shape)) if attributes: extra_attributes = [] for i in range(len(specification.extra_attribs)): attribute = specification.extra_attribs[i] extra_attributes.append( ImageAttribute_Specification( attribute.name, attribute.value, attribute.type)) return image, extra_attributes else: return image
def test_read_image_OpenImageIO(self): # pragma: no cover """Test :func:`colour.io.image.read_image_OpenImageIO` definition.""" if not is_openimageio_installed(): return image = read_image_OpenImageIO( os.path.join(RESOURCES_DIRECTORY, "CMS_Test_Pattern.exr")) self.assertTupleEqual(image.shape, (1267, 1274, 3)) self.assertIs(image.dtype, np.dtype("float32")) image = read_image_OpenImageIO( os.path.join(RESOURCES_DIRECTORY, "CMS_Test_Pattern.exr"), "float16", ) self.assertIs(image.dtype, np.dtype("float16")) image, attributes = read_image_OpenImageIO( os.path.join(RESOURCES_DIRECTORY, "CMS_Test_Pattern.exr"), attributes=True, ) self.assertTupleEqual(image.shape, (1267, 1274, 3)) self.assertEqual(attributes[0].name, "oiio:ColorSpace") self.assertEqual(attributes[0].value, "Linear") image = read_image_OpenImageIO( os.path.join(RESOURCES_DIRECTORY, "Single_Channel.exr")) self.assertTupleEqual(image.shape, (256, 256)) image = read_image_OpenImageIO( os.path.join(RESOURCES_DIRECTORY, "Colour_Logo.png"), "uint8") self.assertTupleEqual(image.shape, (128, 256, 4)) self.assertIs(image.dtype, np.dtype("uint8")) self.assertEqual(np.min(image), 0) self.assertEqual(np.max(image), 255) image = read_image_OpenImageIO( os.path.join(RESOURCES_DIRECTORY, "Colour_Logo.png"), "uint16") self.assertTupleEqual(image.shape, (128, 256, 4)) self.assertIs(image.dtype, np.dtype("uint16")) self.assertEqual(np.min(image), 0) self.assertEqual(np.max(image), 65535) # TODO: Investigate "OIIO" behaviour here: 1.0 != 15360.0 # image = read_image_OpenImageIO( # os.path.join(RESOURCES_DIRECTORY, 'Colour_Logo.png'), 'float16') # self.assertIs(image.dtype, np.dtype('float16')) # self.assertEqual(np.min(image), 0.0) # self.assertEqual(np.max(image), 1.0) image = read_image_OpenImageIO( os.path.join(RESOURCES_DIRECTORY, "Colour_Logo.png"), "float32") self.assertIs(image.dtype, np.dtype("float32")) self.assertEqual(np.min(image), 0.0) self.assertEqual(np.max(image), 1.0)
def write_image(image, path, bit_depth='float32'): """ Writes given image using *OpenImageIO*. Parameters ---------- image : array_like Image data. path : unicode Image path. bit_depth : unicode, optional **{'float32', 'uint8', 'uint16', 'float16'}**, Image bit_depth. Returns ------- bool Definition success. Examples -------- >>> import os >>> path = os.path.join('tests', 'resources', 'CMSTestPattern.exr') >>> image = read_image_as_array(path) # doctest: +SKIP >>> path = os.path.join('tests', 'resources', 'CMSTestPattern.png') >>> write_image(image, path, 'uint8') # doctest: +SKIP True """ if is_openimageio_installed(raise_exception=True): from OpenImageIO import ImageOutput, ImageOutputOpenMode, ImageSpec bit_depth_specification = BIT_DEPTH_MAPPING.get(bit_depth) bit_depth = bit_depth_specification.openimageio image = np.asarray(image) image *= bit_depth_specification.domain if bit_depth_specification.clip: image = np.clip(image, 0, bit_depth_specification.domain) image = image.astype(bit_depth_specification.numpy) if image.ndim == 2: height, width = image.shape channels = 1 else: height, width, channels = image.shape specification = ImageSpec(width, height, channels, bit_depth) image_output = ImageOutput.create(path) image_output.open(path, specification, ImageOutputOpenMode.Create) image_output.write_image(bit_depth, image.tostring()) image_output.close() return True
def write_image(image, path, bit_depth='float32'): """ Writes given image using *OpenImageIO*. Parameters ---------- image : array_like Image data. path : unicode Image path. bit_depth : unicode, optional {'float32', 'uint8', 'uint16', 'float16'} Image bit_depth. Returns ------- bool Definition success. Examples -------- >>> import os >>> path = os.path.join('tests', 'resources', 'CMSTestPattern.exr') >>> image = read_image_as_array(path) # doctest: +SKIP >>> path = os.path.join('tests', 'resources', 'CMSTestPattern.png') >>> write_image(image, path, 'uint8') # doctest: +SKIP True """ if image.ndim != 3: raise ValueError( 'Image must have exactly 3 dimensions!') if is_openimageio_installed(raise_exception=True): from OpenImageIO import ImageOutput, ImageOutputOpenMode, ImageSpec bit_depth_specification = BIT_DEPTH_MAPPING.get(bit_depth) bit_depth = bit_depth_specification.openimageio image = np.asarray(image) image *= bit_depth_specification.domain if bit_depth_specification.clip: image = np.clip(image, 0, bit_depth_specification.domain) image = image.astype(bit_depth_specification.numpy) height, width, channels = image.shape specification = ImageSpec(width, height, channels, bit_depth) image_output = ImageOutput.create(path) image_output.open(path, specification, ImageOutputOpenMode.Create) image_output.write_image(bit_depth, image.tostring()) image_output.close() return True
def read_image(path, bit_depth='float32'): """ Reads given image using *OpenImageIO*. Parameters ---------- path : unicode Image path. bit_depth : unicode, optional **{'float32', 'uint8', 'uint16', 'float16'}**, Image bit_depth. Returns ------- ndarray Image as a ndarray. Notes ----- - For convenience, single channel images are squeezed to 2d arrays. Examples -------- >>> import os >>> path = os.path.join('tests', 'resources', 'CMSTestPattern.exr') >>> image = read_image_as_array(path) # doctest: +SKIP """ if is_openimageio_installed(raise_exception=True): from OpenImageIO import ImageInput bit_depth = BIT_DEPTH_MAPPING.get(bit_depth).openimageio image = ImageInput.open(path) specification = image.spec() shape = (specification.height, specification.width, specification.nchannels) return np.squeeze(np.array(image.read_image(bit_depth)).reshape(shape))
def write_image_OpenImageIO(image, path, bit_depth='float32', attributes=None): """ Writes given image at given path using *OpenImageIO*. Parameters ---------- image : array_like Image data. path : unicode Image path. bit_depth : unicode, optional **{'float32', 'uint8', 'uint16', 'float16'}**, Bit depth to write the image at, the bit depth conversion behaviour is ruled directly by *OpenImageIO*. attributes : array_like, optional An array of :class:`colour.io.ImageAttribute_Specification` class instances used to set attributes of the image. Returns ------- bool Definition success. Examples -------- Basic image writing: >>> import os >>> import colour >>> path = os.path.join(colour.__path__[0], 'io', 'tests', 'resources', ... 'CMS_Test_Pattern.exr') >>> image = read_image(path) # doctest: +SKIP >>> path = os.path.join(colour.__path__[0], 'io', 'tests', 'resources', ... 'CMSTestPattern.tif') >>> write_image(image, path) # doctest: +SKIP True Advanced image writing while setting attributes: >>> compression = ImageAttribute_Specification('Compression', 'none') >>> write_image(image, path, 'uint8', [compression]) # doctest: +SKIP True """ if is_openimageio_installed(raise_exception=True): # pragma: no cover from OpenImageIO import VERSION_MAJOR, ImageOutput, ImageSpec path = str(path) if attributes is None: attributes = [] bit_depth_specification = BIT_DEPTH_MAPPING[bit_depth] bit_depth = bit_depth_specification.openimageio image = as_float_array(image) image = image * bit_depth_specification.domain if bit_depth_specification.clip: image = np.clip(image, 0, bit_depth_specification.domain) image = image.astype(bit_depth_specification.numpy) if image.ndim == 2: height, width = image.shape channels = 1 else: height, width, channels = image.shape specification = ImageSpec(width, height, channels, bit_depth) for attribute in attributes: name = str(attribute.name) value = (str(attribute.value) if isinstance( attribute.value, string_types) else attribute.value) type_ = attribute.type_ if attribute.type_ is None: specification.attribute(name, value) else: specification.attribute(name, type_, value) image_output = ImageOutput.create(path) if VERSION_MAJOR == 1: from OpenImageIO import ImageOutputOpenMode image_output.open(path, specification, ImageOutputOpenMode.Create) image_output.write_image(bit_depth, image.tostring()) else: image_output.open(path, specification) image_output.write_image(image) image_output.close() return True
def write_image(image, path, bit_depth='float32', attributes=None): """ Writes given image using *OpenImageIO*. Parameters ---------- image : array_like Image data. path : unicode Image path. bit_depth : unicode, optional **{'float32', 'uint8', 'uint16', 'float16'}**, Image bit_depth. attributes : array_like, optional An array of :class:`colour.io.ImageAttribute_Specification` class instances used to set attributes of the image. Returns ------- bool Definition success. Examples -------- Basic image writing: >>> import os >>> path = os.path.join('tests', 'resources', 'CMSTestPattern.exr') >>> image = read_image(path) # doctest: +SKIP >>> path = os.path.join('tests', 'resources', 'CMSTestPattern.tif') >>> write_image(image, path) # doctest: +SKIP True Advanced image writing while setting attributes: >>> compression = ImageAttribute_Specification('Compression', 'none') >>> write_image(image, path, 'uint8', [compression]) # doctest: +SKIP True """ if is_openimageio_installed(raise_exception=True): from OpenImageIO import ImageOutput, ImageOutputOpenMode, ImageSpec path = str(path) if attributes is None: attributes = [] bit_depth_specification = BIT_DEPTH_MAPPING[bit_depth] bit_depth = bit_depth_specification.openimageio image = as_float_array(image) image *= bit_depth_specification.domain if bit_depth_specification.clip: image = np.clip(image, 0, bit_depth_specification.domain) image = image.astype(bit_depth_specification.numpy) if image.ndim == 2: height, width = image.shape channels = 1 else: height, width, channels = image.shape specification = ImageSpec(width, height, channels, bit_depth) for attribute in attributes: name = str(attribute.name) value = (str(attribute.value) if isinstance( attribute.value, string_types) else attribute.value) type_ = attribute.type_ if attribute.type_ is None: specification.attribute(name, value) else: specification.attribute(name, type_, value) image_output = ImageOutput.create(path) image_output.open(path, specification, ImageOutputOpenMode.Create) image_output.write_image(bit_depth, image.tostring()) image_output.close() return True
Attribute value. type_ : TypeDesc, optional Attribute type as an *OpenImageIO* :class:`TypeDesc` class instance. """ def __new__(cls, name, value, type_=None): """ Returns a new instance of the :class:`colour.ImageAttribute_Specification` class. """ return super(ImageAttribute_Specification, cls).__new__( cls, name, value, type_) if is_openimageio_installed(): from OpenImageIO import UINT8, UINT16, HALF, FLOAT BIT_DEPTH_MAPPING = CaseInsensitiveMapping({ 'uint8': BitDepth_Specification('uint8', np.uint8, UINT8, 255, True), 'uint16': BitDepth_Specification('uint16', np.uint16, UINT16, 65535, True), 'float16': BitDepth_Specification('float16', np.float16, HALF, 1, False), 'float32': BitDepth_Specification('float32', np.float32, FLOAT, 1, False) }) else: BIT_DEPTH_MAPPING = CaseInsensitiveMapping({ 'uint8':
def read_image( path: str, bit_depth: Literal[ "uint8", "uint16", "float16", "float32", "float64", "float128" ] = "float32", method: Union[Literal["Imageio", "OpenImageIO"], str] = "OpenImageIO", **kwargs: Any, ) -> NDArray: # noqa: D405,D407,D410,D411,D414 """ Read the image at given path using given method. Parameters ---------- path Image path. bit_depth Returned image bit depth, for the *Imageio* method, the image data is converted with :func:`colour.io.convert_bit_depth` definition after reading the image, for the *OpenImageIO* method, the bit depth conversion behaviour is driven directly by the library, this definition only converts to the relevant data type after reading. method Read method, i.e. the image library used for reading images. Other Parameters ---------------- attributes {:func:`colour.io.read_image_OpenImageIO`}, Whether to return the image attributes. Returns ------- :class`numpy.ndarray` Image data. Notes ----- - If the given method is *OpenImageIO* but the library is not available writing will be performed by *Imageio*. - If the given method is *Imageio*, ``kwargs`` is passed directly to the wrapped definition. - For convenience, single channel images are squeezed to 2D arrays. Examples -------- >>> import os >>> import colour >>> path = os.path.join(colour.__path__[0], 'io', 'tests', 'resources', ... 'CMS_Test_Pattern.exr') >>> image = read_image(path) >>> image.shape # doctest: +SKIP (1267, 1274, 3) >>> image.dtype dtype('float32') """ method = validate_method(method, READ_IMAGE_METHODS) if method == "openimageio": # pragma: no cover if not is_openimageio_installed(): usage_warning( '"OpenImageIO" related API features are not available, ' 'switching to "Imageio"!' ) method = "Imageio" function = READ_IMAGE_METHODS[method] if method == "openimageio": # pragma: no cover kwargs = filter_kwargs(function, **kwargs) return function(path, bit_depth, **kwargs)
def test_write_image_OpenImageIO(self): # pragma: no cover """Test :func:`colour.io.image.write_image_OpenImageIO` definition.""" if not is_openimageio_installed(): return from OpenImageIO import TypeDesc source_image_path = os.path.join(RESOURCES_DIRECTORY, "Overflowing_Gradient.png") target_image_path = os.path.join(self._temporary_directory, "Overflowing_Gradient.png") RGB = np.arange(0, 256, 1, dtype=np.uint8)[np.newaxis] * 2 write_image_OpenImageIO(RGB, target_image_path, bit_depth="uint8") image = read_image_OpenImageIO(source_image_path, bit_depth="uint8") np.testing.assert_equal(np.squeeze(RGB), image) source_image_path = os.path.join(RESOURCES_DIRECTORY, "CMS_Test_Pattern.exr") target_image_path = os.path.join(self._temporary_directory, "CMS_Test_Pattern.exr") image = read_image_OpenImageIO(source_image_path) write_image_OpenImageIO(image, target_image_path) image = read_image_OpenImageIO(target_image_path) self.assertTupleEqual(image.shape, (1267, 1274, 3)) self.assertIs(image.dtype, np.dtype("float32")) chromaticities = ( 0.73470, 0.26530, 0.00000, 1.00000, 0.00010, -0.07700, 0.32168, 0.33767, ) write_attributes = [ ImageAttribute_Specification("acesImageContainerFlag", True), ImageAttribute_Specification("chromaticities", chromaticities, TypeDesc("float[8]")), ImageAttribute_Specification("compression", "none"), ] write_image_OpenImageIO(image, target_image_path, attributes=write_attributes) image, read_attributes = read_image_OpenImageIO(target_image_path, attributes=True) for write_attribute in write_attributes: attribute_exists = False for read_attribute in read_attributes: if write_attribute.name == read_attribute.name: attribute_exists = True if isinstance(write_attribute.value, tuple): np.testing.assert_almost_equal( write_attribute.value, read_attribute.value, decimal=5, ) else: self.assertEqual(write_attribute.value, read_attribute.value) attest( attribute_exists, f'"{write_attribute.name}" attribute was not found on image!', )
__author__ = 'Colour Developers' __copyright__ = 'Copyright (C) 2013-2016 - Colour Developers' __license__ = 'New BSD License - http://opensource.org/licenses/BSD-3-Clause' __maintainer__ = 'Colour Developers' __email__ = '*****@*****.**' __status__ = 'Production' __all__ = [ 'BitDepth_Specification', 'BIT_DEPTH_MAPPING', 'read_image', 'write_image' ] BitDepth_Specification = namedtuple( 'BitDepth_Specification', ('name', 'numpy', 'openimageio', 'domain', 'clip')) if is_openimageio_installed(): from OpenImageIO import UINT8, UINT16, HALF, FLOAT BIT_DEPTH_MAPPING = CaseInsensitiveMapping({ 'uint8': BitDepth_Specification('uint8', np.uint8, UINT8, 255, True), 'uint16': BitDepth_Specification('uint16', np.uint16, UINT16, 65535, True), 'float16': BitDepth_Specification('float16', np.float16, HALF, 1, False), 'float32': BitDepth_Specification('float32', np.float32, FLOAT, 1, False) }) else: BIT_DEPTH_MAPPING = CaseInsensitiveMapping({ 'uint8':
def write_image( image: ArrayLike, path: str, bit_depth: Literal[ "uint8", "uint16", "float16", "float32", "float64", "float128" ] = "float32", method: Union[Literal["Imageio", "OpenImageIO"], str] = "OpenImageIO", **kwargs: Any, ) -> Boolean: # noqa: D405,D407,D410,D411,D414 """ Write given image at given path using given method. Parameters ---------- image Image data. path Image path. bit_depth Bit depth to write the image at, for the *Imageio* method, the image data is converted with :func:`colour.io.convert_bit_depth` definition prior to writing the image. method Write method, i.e. the image library used for writing images. Other Parameters ---------------- attributes {:func:`colour.io.write_image_OpenImageIO`}, An array of :class:`colour.io.ImageAttribute_Specification` class instances used to set attributes of the image. Returns ------- :class:`bool` Definition success. Notes ----- - If the given method is *OpenImageIO* but the library is not available writing will be performed by *Imageio*. - If the given method is *Imageio*, ``kwargs`` is passed directly to the wrapped definition. Examples -------- Basic image writing: >>> import os >>> import colour >>> path = os.path.join(colour.__path__[0], 'io', 'tests', 'resources', ... 'CMS_Test_Pattern.exr') >>> image = read_image(path) # doctest: +SKIP >>> path = os.path.join(colour.__path__[0], 'io', 'tests', 'resources', ... 'CMSTestPattern.tif') >>> write_image(image, path) # doctest: +SKIP True Advanced image writing while setting attributes using *OpenImageIO*: >>> compression = ImageAttribute_Specification('Compression', 'none') >>> write_image(image, path, bit_depth='uint8', attributes=[compression]) ... # doctest: +SKIP True """ method = validate_method(method, WRITE_IMAGE_METHODS) if method == "openimageio": # pragma: no cover if not is_openimageio_installed(): usage_warning( '"OpenImageIO" related API features are not available, ' 'switching to "Imageio"!' ) method = "Imageio" function = WRITE_IMAGE_METHODS[method] if method == "openimageio": # pragma: no cover kwargs = filter_kwargs(function, **kwargs) return function(image, path, bit_depth, **kwargs)
def write_image(image, path, bit_depth='float32', method='OpenImageIO', **kwargs): """ Writes given image at given path using given method. Parameters ---------- image : array_like Image data. path : unicode Image path. bit_depth : unicode, optional **{'float32', 'uint8', 'uint16', 'float16'}**, Bit depth to write the image at, for the *Imageio* method, the image data is converted with :func:`colour.io.convert_bit_depth` definition prior to writing the image. method : unicode, optional **{'OpenImageIO', 'Imageio'}**, Write method, i.e. the image library used for writing images. Other Parameters ---------------- attributes : array_like, optional {:func:`colour.io.write_image_OpenImageIO`}, An array of :class:`colour.io.ImageAttribute_Specification` class instances used to set attributes of the image. Returns ------- bool Definition success. Notes ----- - If the given method is *OpenImageIO* but the library is not available writing will be performed by *Imageio*. - If the given method is *Imageio*, ``kwargs`` is passed directly to the wrapped definition. Examples -------- Basic image writing: >>> import os >>> import colour >>> path = os.path.join(colour.__path__[0], 'io', 'tests', 'resources', ... 'CMS_Test_Pattern.exr') >>> image = read_image(path) # doctest: +SKIP >>> path = os.path.join(colour.__path__[0], 'io', 'tests', 'resources', ... 'CMSTestPattern.tif') >>> write_image(image, path) # doctest: +SKIP True Advanced image writing while setting attributes using *OpenImageIO*: >>> compression = ImageAttribute_Specification('Compression', 'none') >>> write_image(image, path, bit_depth='uint8', attributes=[compression]) ... # doctest: +SKIP True """ if method.lower() == 'openimageio': # pragma: no cover if not is_openimageio_installed(): usage_warning( '"OpenImageIO" related API features are not available, ' 'switching to "Imageio"!') method = 'Imageio' function = WRITE_IMAGE_METHODS[method] if method.lower() == 'openimageio': # pragma: no cover kwargs = filter_kwargs(function, **kwargs) return function(image, path, bit_depth, **kwargs)
Attribute value. type_ : TypeDesc, optional Attribute type as an *OpenImageIO* :class:`TypeDesc` class instance. """ def __new__(cls, name, value, type_=None): """ Returns a new instance of the :class:`colour.ImageAttribute_Specification` class. """ return super(ImageAttribute_Specification, cls).__new__( cls, name, value, type_) if is_openimageio_installed(): # pragma: no cover from OpenImageIO import UINT8, UINT16, HALF, FLOAT BIT_DEPTH_MAPPING = CaseInsensitiveMapping({ 'uint8': BitDepth_Specification('uint8', np.uint8, UINT8, 255, True), 'uint16': BitDepth_Specification('uint16', np.uint16, UINT16, 65535, True), 'float16': BitDepth_Specification('float16', np.float16, HALF, 1, False), 'float32': BitDepth_Specification('float32', np.float32, FLOAT, 1, False), 'float64': BitDepth_Specification('float64', np.float64, FLOAT, 1, False), }) if platform.system() not in ('Windows', 'Microsoft'): # pragma: no cover
def read_image(path, bit_depth='float32', method='OpenImageIO', **kwargs): """ Reads the image at given path using given method. Parameters ---------- path : unicode Image path. bit_depth : unicode, optional **{'float32', 'uint8', 'uint16', 'float16'}**, Returned image bit depth, for the *Imageio* method, the image data is converted with :func:`colour.io.convert_bit_depth` definition after reading the image, for the *OpenImageIO* method, the bit depth conversion behaviour is driven directly by the library, this definition only converts to the relevant data type after reading. method : unicode, optional **{'OpenImageIO', 'Imageio'}**, Read method, i.e. the image library used for reading images. Other Parameters ---------------- attributes : bool, optional {:func:`colour.io.read_image_OpenImageIO`}, Whether to return the image attributes. Returns ------- ndarray Image as a ndarray. Notes ----- - If the given method is *OpenImageIO* but the library is not available writing will be performed by *Imageio*. - If the given method is *Imageio*, ``kwargs`` is passed directly to the wrapped definition. - For convenience, single channel images are squeezed to 2d arrays. Examples -------- >>> import os >>> import colour >>> path = os.path.join(colour.__path__[0], 'io', 'tests', 'resources', ... 'CMS_Test_Pattern.exr') >>> image = read_image(path) >>> image.shape # doctest: +SKIP (1267, 1274, 3) >>> image.dtype dtype('float32') """ if method.lower() == 'openimageio': # pragma: no cover if not is_openimageio_installed(): usage_warning( '"OpenImageIO" related API features are not available, ' 'switching to "Imageio"!') method = 'Imageio' function = READ_IMAGE_METHODS[method] if method.lower() == 'openimageio': # pragma: no cover kwargs = filter_kwargs(function, **kwargs) return function(path, bit_depth, **kwargs)
def read_image_OpenImageIO(path, bit_depth='float32', attributes=False): """ Reads the image at given path using *OpenImageIO*. Parameters ---------- path : unicode Image path. bit_depth : unicode, optional **{'float32', 'uint8', 'uint16', 'float16'}**, Returned image bit depth, the bit depth conversion behaviour is driven directly by *OpenImageIO*, this definition only converts to the relevant data type after reading. attributes : bool, optional Whether to return the image attributes. Returns ------- ndarray or tuple Image as a ndarray or tuple of image as ndarray and list of attributes Notes ----- - For convenience, single channel images are squeezed to 2d arrays. Examples -------- >>> import os >>> import colour >>> path = os.path.join(colour.__path__[0], 'io', 'tests', 'resources', ... 'CMS_Test_Pattern.exr') >>> image = read_image(path) # doctest: +SKIP """ if is_openimageio_installed(raise_exception=True): # pragma: no cover from OpenImageIO import ImageInput path = str(path) bit_depth = BIT_DEPTH_MAPPING[bit_depth] image = ImageInput.open(path) specification = image.spec() shape = (specification.height, specification.width, specification.nchannels) image_data = image.read_image(bit_depth.openimageio) image.close() image = np.squeeze( np.array(image_data, dtype=bit_depth.numpy).reshape(shape)) if attributes: extra_attributes = [] for i in range(len(specification.extra_attribs)): attribute = specification.extra_attribs[i] extra_attributes.append( ImageAttribute_Specification( attribute.name, attribute.value, attribute.type)) return image, extra_attributes else: return image