Source code for cv_depot.ops.channel

from typing import Union  # noqa F401

import re

from lunchbox.enforce import Enforce
import cv2
import numpy as np

from cv_depot.core.channel_map import ChannelMap
from cv_depot.core.color import BasicColor
from cv_depot.core.enum import BitDepth
from cv_depot.core.image import Image
import cv_depot.core.image as cvimg
import cv_depot.ops.draw as cvdraw
# ------------------------------------------------------------------------------


[docs] def has_super_brights(image): # type: (Image) -> bool ''' Determines if given image has values above 1.0. Args: image (Image): Image instance. Raises: EnforceError: If image is not an Image instance. Returns: bool: Presence of super brights. ''' return cvimg._has_super_brights(image)
[docs] def has_super_darks(image): # type: (Image) -> bool ''' Determines if given image has values below 0.0. Args: image (Image): Image instance. Raises: EnforceError: If image is not an Image instance. Returns: bool: Presence of super darks. ''' return cvimg._has_super_darks(image)
[docs] def to_hsv(image): # type: (Image) -> Image ''' Convert image to hue, saturation, value colorspace. Args: Image: Image to be converted. Raises: AttributeError: If given image does not have RGB channels. Returns: Image: Image converted to HSV. ''' rgb = list('rgb') channels = set(image.channels).intersection(rgb) if channels != set(rgb): msg = 'Image does not contain RGB channels. ' msg += f'Channels found: {image.channels}.' raise AttributeError(msg) img_ = image.to_bit_depth(BitDepth.FLOAT32) img = img_[:, :, rgb].data img = cv2.cvtColor(img, cv2.COLOR_RGB2HSV) img[:, :, 0] = np.divide(img[:, :, 0], 360) output = Image\ .from_array(img)\ .set_channels(list('hsv'))\ .to_bit_depth(image.bit_depth) return output
[docs] def to_rgb(image): # type: (Image) -> Image ''' Convert image from HSV to RGB. Args: Image: Image to be converted. Raises: AttributeError: If given image does not have RGB channels. Returns: Image: Image converted to RGB. ''' hsv = list('hsv') channels = set(image.channels).intersection(hsv) if channels != set(hsv): msg = 'Image does not contain HSV channels. ' msg += f'Channels found: {image.channels}.' raise AttributeError(msg) img_ = image.to_bit_depth(BitDepth.FLOAT32) img = img_[:, :, hsv].data img = cv2.cvtColor(img, cv2.COLOR_HSV2RGB) img[:, :, 0] = np.divide(img[:, :, 0], 360) output = Image\ .from_array(img)\ .set_channels(list('rgb'))\ .to_bit_depth(image.bit_depth) return output
[docs] def invert(image): # type: (Image) -> Image ''' Inverts the values of the given image. Black becomes white, white becomes black. Args: image (Image): Image to be inverted. Raises: EnforeError: If image is not an instance of Image. Returns: image: Image ''' Enforce(image, 'instance of', Image) # -------------------------------------------------------------------------- bit_depth = image.bit_depth data = image.to_bit_depth(BitDepth.FLOAT32).data data = data * -1 + 1 output = Image.from_array(data).to_bit_depth(bit_depth) return output
[docs] def mix(a, b, amount=0.5): # type: (Image, Image, float) -> Image ''' Mix images A and B by a given amount. An amount of 1.0 means 100% of image A. An amount of 0.0 means 100% of image B. Args: a (Image): Image A. b (Image): Image B. amount (float, optional): Amount of image A. Default: 0.5 Raises: EnforceError: If a is not an Image instance. EnforceError: If b is not an Image instance. EnforceError: If amount is not between 0 and 1. Returns: Image: Mixture of A and B. ''' Enforce(a, 'instance of', Image) Enforce(b, 'instance of', Image) Enforce(amount, '<=', 1) Enforce(amount, '>=', 0) # -------------------------------------------------------------------------- amount = float(amount) bit_depth = a.bit_depth x = a.to_bit_depth(BitDepth.FLOAT32).data y = b.to_bit_depth(BitDepth.FLOAT32).data img = x * amount + y * (1 - amount) output = Image.from_array(img).to_bit_depth(bit_depth) return output
[docs] def remap_single_channel(image, channels): # type: (Image, list) -> Image ''' Maps an image with a single channel to an image of a given number of channels. Args: image (Image): Image to be mapped. channels (list): List of channel names to map image to. Raises: EnforceError: If image is not an Image with only one channel. EnforceError: If channels is not a list. Returns: Image: Image with given channels. ''' Enforce(image, 'instance of', Image) msg = 'Image must be an Image with only 1 channel. ' msg += 'Channels found: {a}.' Enforce(image.num_channels, '==', 1, message=msg) Enforce(channels, 'instance of', list) # -------------------------------------------------------------------------- data = np.squeeze(image.data)[..., np.newaxis] output = np.concatenate([data] * len(channels), axis=2) output = Image.from_array(output).set_channels(channels) return output
[docs] def remap(images, channel_map): # type: (Union[Image, list[Image]], ChannelMap) -> Image ''' Maps many images into a single image according to a given channel map. Args: images (Image, list[Image]): Images. channel_map (ChannelMap): Mapping of image channels into output image. Raises: EnforceError: If images is not an instance of Image or list of Images. EnforceError: If images are not of all the same width and height. EnforceError: If channel_map is not an instance of ChannelMap. Returns: Image: Combined image. ''' if isinstance(images, Image): images = [images] msg = 'Images must be an Image or list of Images of uniform width and height.' msg += f' Given type: {images.__class__.__name__}' [Enforce(x, 'instance of', Image) for x in images] shapes = {x.width_and_height for x in images} Enforce(len(shapes), '==', 1, message=msg) Enforce(channel_map, 'instance of', ChannelMap) # -------------------------------------------------------------------- w, h = images[0].width_and_height bit_depth = images[0].bit_depth images = [x.to_bit_depth(bit_depth) for x in images] shape = (w, h, 1) black = cvdraw.swatch(shape, BasicColor.BLACK, bit_depth=bit_depth) white = cvdraw.swatch(shape, BasicColor.WHITE, bit_depth=bit_depth) channels = [] for chan in channel_map.source: chan_l = chan.lower() img = None if chan_l in ['b', 'black']: img = black elif chan_l in ['w', 'white']: img = white else: frame, tgt_chan = re.split(r'\.', chan, maxsplit=1) img = images[int(frame)][:, :, tgt_chan] array = np.squeeze(img.data)[..., np.newaxis] channels.append(array) img = np.concatenate(channels, axis=2).astype(bit_depth.dtype) output = Image.from_array(img).set_channels(channel_map.target) # type: ignore return output