Source code for pycimg.pycimg

import functools
import numbers
import numpy as np

from .cimg_bindings import CImg_uint8, CImg_uint16, CImg_uint32, CImg_float32, CImg_float64

# Supported numeric pixel type
uint8 = np.uint8
uint16 = np.uint16
uint32 = np.uint32
float32 = np.float32
float64 = np.float64

# Interpolation type
NONE_RAW = -1
NONE = 0
NEAREST = 1
MOVING_AVERAGE = 2
LINEAR = 3
GRID = 4
CUBIC = 5
LANCZOS = 6

# Boundary condition type
DIRICHLET = 0
NEUMANN = 1
PERIODIC = 2
MIRROR = 3

# Variance method
SECOND_MOMENT = 0
BEST_UNBIASED = 1
LEAST_MEDIAN_SQ = 2
LEAST_TRIMMED_SQ = 3

# Norm type
LINF_NORM = -1
L0_NORM = 0
L1_NORM = 1
L2_NORM = 2

# Rounding type
R_BACKWARD = -1
R_NEAREST = 0
R_FORWARD = 1

# Noise type
GAUSSIAN = 0
UNIFORM = 1
SALT_AND_PEPPER = 2
POISSON = 3
RICIAN = 4

# Compression type
C_NONE = 0
C_LZW = 1
C_JPEG = 2

# Filter order
SMOOTH_FILTER = 0
FIRST_DERIV = 1
SECOND_DERIV = 2
THIRD_DERIV = 3

# Plot type
POINTS = 0
SEGMENTS = 1
SPLINES = 2
BARS = 3


[docs]class CImg: """ CImg is a wrapper class for the CImg library: """
[docs] def __init__(self, *args, **kwargs): """ Create CImg with given data type. Supported datatypes are int8, int16, int32, uint8, uint16, uint32, float32, and float64. Examples: 1. Create empty image with default type float32 im = CImg() 2. Create image from file. im = CImg("filename.png") 3. Create image from numpy array arr = np.zeros((100,2)) im = CImg(arr) 4. Create image of size 100x200 with data type uint8 im = CImg((100, 200), dtype=uint8) Args: Either image filename, numpy array, or image size. Keyword arguments: dtype: Data type of CImg. Raises: RuntimeError: For unsupported data types. """ self.dtype = kwargs.get('dtype', float32) if self.dtype == np.uint8: self._cimg = CImg_uint8() elif self.dtype == np.uint16: self._cimg = CImg_uint16() elif self.dtype == np.uint32: self._cimg = CImg_uint32() elif self.dtype == np.float32: self._cimg = CImg_float32() elif self.dtype == np.float64: self._cimg = CImg_float64() else: raise RuntimeError("Unknown data type '{}'".format(self.dtype)) if len(args) == 1: if isinstance(args[0], str): self.load(args[0]) elif isinstance(args[0], np.ndarray): self.fromarray(args[0]) elif isinstance(args[0], CImg): self.fromarray(args[0].asarray()) elif isinstance(args[0], tuple): shape = [max(1, sz) for sz in args[0]] self.resize(*shape, interpolation_type=NONE_RAW) elif isinstance(args[0], int): sz = max(1, args[0]) self.resize(sz, interpolation_type=NONE_RAW) elif isinstance(args[0], list) and all(map(lambda t: isinstance(t, numbers.Number), args[0])): self.fromarray(np.array(args[0])) else: raise RuntimeError("Type of first argument not supported") elif len(args) > 1: raise RuntimeError("More than one argument not supported")
[docs] def asarray(self, copy=False): """ Returns image data as a numpy array. Args: copy (bool) - If true copy image data. Default: False. """ return np.array(self._cimg, copy=copy)
@property def width(self): """ Return width of image. """ return self._cimg.width() @property def height(self): """ Return height of image. """ return self._cimg.height() @property def depth(self): """ Return depth of image. """ return self._cimg.depth() @property def spectrum(self): """ Return spectrum (number of channels) of image. """ return self._cimg.spectrum() @property def shape(self): """ Return shape of image data. """ return (self.spectrum, self.depth, self.height, self.width) @property def size(self): """ Return the total number of pixel values in the image. """ return self._cimg.size()
[docs] def isempty(self): """ Return true if image is empty. """ return self.width == 0 and \ self.height == 0 and \ self.depth == 0 and \ self.spectrum == 0
[docs] def __eq__(self, img): return self._cimg == img._cimg
def __neq__(self, img): return self._cimg != img._cimg def __add__(self, other): return CImg(self.asarray() + (other.asarray() if isinstance(other, CImg) else other)) def __sub__(self, other): return CImg(self.asarray() - (other.asarray() if isinstance(other, CImg) else other)) def __mul__(self, other): return CImg(self.asarray() * (other.asarray() if isinstance(other, CImg) else other)) def __truediv__(self, other): return CImg(self.asarray() / (other.asarray() if isinstance(other, CImg) else other)) def __floordiv__(self, other): return CImg(self.asarray() // (other.asarray() if isinstance(other, CImg) else other)) def __iadd__(self, other): a = self.asarray() a += (other.asarray() if isinstance(other, CImg) else other) return self def __isub__(self, other): a = self.asarray() a -= (other.asarray() if isinstance(other, CImg) else other) return self def __imul__(self, other): a = self.asarray() a *= (other.asarray() if isinstance(other, CImg) else other) return self def __itruediv__(self, other): a = self.asarray() a /= (other.asarray() if isinstance(other, CImg) else other) return self def __ifloordiv__(self, other): a = self.asarray() a //= (other.asarray() if isinstance(other, CImg) else other) return self
[docs] def __repr__(self): if self.isempty(): return 'CImg()' return 'CImg(' + repr(self.asarray()) + ')'
[docs] def __str__(self): if self.isempty(): arr = None else: arr = self.asarray() return "%s %5d\n%s %5d\n%s %5d\n%s %5d\n%s\n%s" % \ ("height: ", self.height, "width: ", self.width, "depth: ", self.depth, "spectrum:", self.spectrum, "data: ", arr)
def __getattr__(self, attr): if hasattr(self._cimg, attr): func = getattr(self._cimg, attr) @functools.wraps(func) def wrapper(*args, **kwargs): # Unwrap CImg arguments cargs = [arg._cimg if isinstance(arg, CImg) else arg for arg in args] cargs = [] for arg in args: if isinstance(arg, CImg): cargs.append(arg._cimg) else: cargs.append(arg) r = func(*cargs, **kwargs) if isinstance(r, CImg_uint8) or \ isinstance(r, CImg_uint16) or \ isinstance(r, CImg_uint32) or \ isinstance(r, CImg_float32) or \ isinstance(r, CImg_float64): self._cimg = r return self else: return r return wrapper raise AttributeError(attr) def _check_index(self, index): cls = type(self) def raiseError(): msg = 'only integers and slices (`:`) are valid indices' raise IndexError(msg.format(cls=cls)) # Handle special case of single index if isinstance(index, numbers.Integral): index = tuple([index]) if isinstance(index, tuple): # Check number of indices if len(index) > 4: raise IndexError('Image has < 5 dimensions.') index = list(index) # Case 1: indices are a mix of integers and slices if any(map(lambda t: isinstance(t, slice), index)): # Expand integers to slices slice_index = [] for idx in index: if isinstance(idx, numbers.Integral): slice_index.append(slice(idx, idx+1, None)) elif isinstance(idx, slice): slice_index.append(idx) else: raiseError() index = slice_index # Expand slices to cover all dimensions while len(index) < 4: index.append(slice(None, None, None)) index = list(reversed(index)) return (index, True) # Case 2: all indices are integers elif all(map(lambda t: isinstance(t, numbers.Integral), index)): # Expand indices to cover all dimensions while len(index) < 4: index.append(0) index = tuple(reversed(index)) return (index, False) else: raiseError() else: raiseError() def __getitem__(self, index): index, is_slice = self._check_index(index) if is_slice: cls = type(self) return cls(self.asarray()[tuple(index)]) else: return self.asarray()[index] def __setitem__(self, index, value): index, is_slice = self._check_index(index) self.asarray()[tuple(index)] = value