def signal_unpack_data(data=None, domain=None): domain_upk, range_upk = None, None if isinstance(data, Signal): domain_upk = data.domain range_upk = data.range elif (issubclass(type(data), Sequence) or isinstance(data, (tuple, list, np.ndarray, Iterator))): data = tsplit(list(data) if isinstance(data, Iterator) else data) assert data.ndim in (1, 2), ( 'User "data" must be a 1d or 2d array-like variable!') if data.ndim == 1: # TODO: Swap for np.arange(0, data.size + 1) domain_upk, range_upk = np.linspace(0, 1, data.size), data else: domain_upk, range_upk = data elif (issubclass(type(data), Mapping) or isinstance(data, (dict, OrderedDict))): domain_upk, range_upk = tsplit(sorted(data.items())) elif is_pandas_installed(): if isinstance(data, Series): domain_upk = data.index.values range_upk = data.values if domain is not None and range_upk is not None: assert len(domain) == len(range_upk), ( 'User "domain" is not compatible with unpacked range!') domain_upk = domain return domain_upk, range_upk
def multi_signal_unpack_data(data=None, domain=None, labels=None): domain_upk, range_upk, signals = None, None, None signals = OrderedDict() if isinstance(data, MultiSignal): signals = data.signals elif (issubclass(type(data), Sequence) or isinstance(data, (tuple, list, np.ndarray, Iterator))): data = tsplit(list(data) if isinstance(data, Iterator) else data) assert data.ndim in (1, 2), ( 'User "data" must be a 1d or 2d array-like variable!') if data.ndim == 1: # TODO: Swap for np.arange(0, data.size + 1) signals[0] = Signal(data, np.linspace(0, 1, data.size)) else: domain_upk, range_upk = ((data[0], data[1:]) if domain is None else (domain, data)) for i, range_upk_c in enumerate(range_upk): signals[i] = Signal(range_upk_c, domain_upk) elif (issubclass(type(data), Mapping) or isinstance(data, (dict, OrderedDict))): domain_upk, range_upk = tsplit(sorted(data.items())) for i, range_upk in enumerate(tsplit(range_upk)): signals[i] = Signal(range_upk, domain_upk) elif is_pandas_installed(): if isinstance(data, Series): signals[0] = Signal(data) elif isinstance(data, DataFrame): # Check order consistency. domain_upk = data.index.values signals = OrderedDict( ((label, Signal(data[label], domain_upk, name=label)) for label in data)) if domain is not None and signals is not None: for signal in signals.values(): assert len(domain) == len(signal.domain), ( 'User "domain" is not compatible with unpacked signals!') signal.domain = domain if labels is not None and signals is not None: assert len(labels) == len(signals), ( 'User "labels" is not compatible with unpacked signals!') signals = OrderedDict([ (labels[i], signal) for i, (_key, signal) in enumerate(signals.items()) ]) if len(signals) == 0: signals[0] = Signal() return signals
def multi_signal_unpack_data(data=None, domain=None, labels=None): domain_upk, range_upk, signals = None, None, None signals = OrderedDict() if isinstance(data, MultiSignal): signals = data.signals elif (issubclass(type(data), Sequence) or isinstance(data, (tuple, list, np.ndarray, Iterator))): data = tsplit(list(data) if isinstance(data, Iterator) else data) assert data.ndim in (1, 2), ( 'User "data" must be a 1d or 2d array-like variable!') if data.ndim == 1: # TODO: Swap for np.arange(0, data.size + 1) signals[0] = Signal(data, np.linspace(0, 1, data.size)) else: domain_upk, range_upk = ((data[0], data[1:]) if domain is None else (domain, data)) for i, range_upk_c in enumerate(range_upk): signals[i] = Signal(range_upk_c, domain_upk) elif (issubclass(type(data), Mapping) or isinstance(data, (dict, OrderedDict))): domain_upk, range_upk = tsplit(sorted(data.items())) for i, range_upk in enumerate(tsplit(range_upk)): signals[i] = Signal(range_upk, domain_upk) elif is_pandas_installed(): if isinstance(data, Series): signals[0] = Signal(data) elif isinstance(data, DataFrame): # Check order consistency. domain_upk = data.index.values signals = OrderedDict(((label, Signal( data[label], domain_upk, name=label)) for label in data)) if domain is not None and signals is not None: for signal in signals.values(): assert len(domain) == len(signal.domain), ( 'User "domain" is not compatible with unpacked signals!') signal.domain = domain if labels is not None and signals is not None: assert len(labels) == len(signals), ( 'User "labels" is not compatible with unpacked signals!') signals = OrderedDict( [(labels[i], signal) for i, (_key, signal) in enumerate(signals.items())]) if len(signals) == 0: signals[0] = Signal() return signals
def __setattr__(self, attribute, value): """ Reimplements the :meth:`MutableSequence.__getattr__` method. Parameters ---------- attribute : unicode Attribute to set the value. value : object Value to set. """ if hasattr(Image, attribute): if attribute == 'data': data = tsplit(value) for i, image in enumerate(self): image.data = data[i] else: for i, image in enumerate(self): setattr(image, attribute, value[i]) elif hasattr(Metadata, attribute): for i, image in enumerate(self): setattr(image.metadata, attribute, value[i]) else: super(ImageStack, self).__setattr__(attribute, value)
def spectral2XYZ_img_vectorized(cmfs, R): """ Parameters ---------- cmfs R: np.ndarray (nb_pixels, 3) in [0., 1.] Returns ------- """ x_bar, y_bar, z_bar = colour.tsplit(cmfs) # tested: OK. x_bar is the double one, the rightmost one (red). z_bar is the leftmost one (blue) plt.close('all') plt.plot(np.array([z_bar, y_bar, x_bar]).transpose()) plt.savefig('cmf_cie1964_10.png') plt.close('all') # illuminant. We assume that the captured R is reflectance with illuminant E (although it really is not, it is reflected radiance with an unknown illuminant, but the result is the same) S = colour.ILLUMINANTS_RELATIVE_SPDS['E'].values[20:81:2] / 100. # Equal-energy radiator (ones) sample_spectra_from_hsimg 300 to xxx with delta=5nm # print S # dw = cmfs.shape.interval dw = 10 k = 100 / (np.sum(y_bar * S) * dw) X_p = R * x_bar * S * dw # R(N,31) * x_bar(31,) * S(31,) * dw(1,) Y_p = R * y_bar * S * dw Z_p = R * z_bar * S * dw XYZ = k * np.sum(np.array([X_p, Y_p, Z_p]), axis=-1) XYZ = np.rollaxis(XYZ, 1, 0) # th2tf() but for 2D input return XYZ
def get_cmfs(cmf_name='cie1964_10', nm_range=(400., 701.), nm_step=10, split=True): if cmf_name == 'cie1931_2': cmf_full_name = 'CIE 1931 2 Degree Standard Observer' elif cmf_name == 'cie2012_2': cmf_full_name = 'CIE 2012 2 Degree Standard Observer' elif cmf_name == 'cie2012_10': cmf_full_name = 'CIE 2012 10 Degree Standard Observer' elif cmf_name == 'cie1964_10': cmf_full_name = 'CIE 1964 10 Degree Standard Observer' else: raise AttributeError('Wrong cmf name') cmfs = colour.STANDARD_OBSERVERS_CMFS[cmf_full_name] # subsample and trim range ix_wl_first = np.where(cmfs.wavelengths == nm_range[0])[0][0] ix_wl_last = np.where(cmfs.wavelengths == nm_range[1] + 1.)[0][0] cmfs = cmfs.values[ix_wl_first:ix_wl_last:int(nm_step), :] if split: x_bar, y_bar, z_bar = colour.tsplit(cmfs) return x_bar, y_bar, z_bar else: return cmfs
def spectral2XYZ_img_vectorized(cmfs, R): x_bar, y_bar, z_bar = colour.tsplit(cmfs) # plt.close('all') plt.plot(np.array([z_bar, y_bar, x_bar]).transpose()) plt.savefig('cmf_cie1964_10.png') plt.close('all') # illuminant. S = colour.ILLUMINANTS_RELATIVE_SPDS['E'].values[0:31] / 100. dw = 10 k = 100 / (np.sum(y_bar * S) * dw) X_p = R * x_bar * S * dw Y_p = R * y_bar * S * dw Z_p = R * z_bar * S * dw XYZ = k * np.sum(np.array([X_p, Y_p, Z_p]), axis=-1) XYZ = np.rollaxis(XYZ, 1, 0) return XYZ
def samples_Grossberg2003(image_stack, samples=1000, n=256): """ Returns the samples for given image stack intensity histograms using Grossberg (2003) method. Parameters ---------- image_stack : array_like Stack of single channel or multi-channel floating point images. samples : int, optional Samples count. n : int, optional Histograms bins count. Returns ------- ndarray Intensity histograms samples. """ image_stack = np.asarray(image_stack) if image_stack.ndim == 3: channels_c = 1 else: channels_c = image_stack.shape[-2] cdf_i = [] for image in tsplit(image_stack): histograms = tstack( [np.histogram(image[..., c], n, range=(0, 1))[0] for c in np.arange(channels_c)]) cdf = np.cumsum(histograms, axis=0) cdf_i.append(cdf.astype(np.float_) / np.max(cdf, axis=0)) samples_cdf_i = np.zeros((samples, len(cdf_i), channels_c)) samples_u = np.linspace(0, 1, samples) for i in np.arange(samples): for j in np.arange(channels_c): for k, cdf in enumerate(cdf_i): samples_cdf_i[i, k, j] = np.argmin(np.abs(cdf[:, j] - samples_u[i])) return samples_cdf_i
def mosaicing_CFA_Bayer(RGB, pattern='RGGB'): """ Returns the *Bayer* CFA mosaic for a given *RGB* colourspace array. Parameters ---------- RGB : array_like *RGB* colourspace array. pattern : unicode, optional **{'RGGB', 'BGGR', 'GRBG', 'GBRG'}**, Arrangement of the colour filters on the pixel array. Returns ------- ndarray *Bayer* CFA mosaic. Examples -------- >>> RGB = np.array([[[0, 1, 2], ... [0, 1, 2]], ... [[0, 1, 2], ... [0, 1, 2]]]) >>> mosaicing_CFA_Bayer(RGB) array([[0, 1], [1, 2]]) >>> mosaicing_CFA_Bayer(RGB, pattern='BGGR') array([[2, 1], [1, 0]]) """ RGB = np.asarray(RGB) R, G, B = tsplit(RGB) R_m, G_m, B_m = masks_CFA_Bayer(RGB.shape[0:2], pattern) CFA = R * R_m + G * G_m + B * B_m return CFA
def get_cmfs(cmf_name='cie1964_10', nm_range=(400., 700.), nm_step=10, split=True): if cmf_name == 'cie1931_2': cmf_full_name = 'CIE 1931 2 Degree Standard Observer' elif cmf_name == 'cie1931_10': cmf_full_name = 'CIE 1931 10 Degree Standard Observer' elif cmf_name == 'cie1964_2': cmf_full_name = 'CIE 1964 2 Degree Standard Observer' elif cmf_name == 'cie1964_10': cmf_full_name = 'CIE 1964 10 Degree Standard Observer' else: raise AttributeError('Wrong cmf name') cmfs = colour.STANDARD_OBSERVERS_CMFS[cmf_full_name] # subsample and trim range ix_wl_first = np.where(cmfs.wavelengths == nm_range[0])[0][0] ix_wl_last = np.where(cmfs.wavelengths == nm_range[1] + 1.)[0][0] cmfs = cmfs.values[ix_wl_first:ix_wl_last:int(nm_step), :] # make sure the nm_step is an int if split: x_bar, y_bar, z_bar = colour.tsplit(cmfs) #tested: OK. x_bar is the double one, the rightmost one (red). z_bar is the leftmost one (blue) return x_bar, y_bar, z_bar else: return cmfs
def lut_interpolation(im, im_type, lut_file, lut_size, interp_type): inPixels = read_image(im) # print(np.amax(inPixels)) max_cv = np.amax(inPixels) lut = np.loadtxt(lut_file, skiprows=7) lattice = np.reshape(lut, (lut_size, lut_size, lut_size, 3), order='F') if interp_type == 'trilinear': n = lattice.shape[0] - 1 inPixels = np.asarray(inPixels) / np.amax(inPixels) theShape = inPixels.shape inPixels = np.ravel(inPixels) pixels = inPixels.size / 3 inPixels = np.reshape(inPixels, (pixels, 3)) R, G, B = tsplit(inPixels) rLow = np.floor(R * n).astype(np.int_) rHigh = np.clip(rLow + 1, 0, n) gLow = np.floor(G * n).astype(np.int_) gHigh = np.clip(gLow + 1, 0, n) bLow = np.floor(B * n).astype(np.int_) bHigh = np.clip(bLow + 1, 0, n) V000 = lattice[rLow, gLow, bLow] V001 = lattice[rLow, gLow, bHigh] V010 = lattice[rLow, gHigh, bLow] V011 = lattice[rLow, gHigh, bHigh] V100 = lattice[rHigh, gLow, bLow] V101 = lattice[rHigh, gLow, bHigh] V110 = lattice[rHigh, gHigh, bLow] V111 = lattice[rHigh, gHigh, bHigh] fR = n * R - rLow fG = n * G - gLow fB = n * B - bLow fR = np.reshape(fR, (pixels, 1)) fG = np.reshape(fG, (pixels, 1)) fB = np.reshape(fB, (pixels, 1)) fR = np.tile(fR, 3) fG = np.tile(fG, 3) fB = np.tile(fB, 3) W000 = (1 - fR) * (1 - fG) * (1 - fB) W001 = (1 - fR) * (1 - fG) * fB W010 = (1 - fR) * fG * (1 - fB) W011 = (1 - fR) * fG * fB W100 = fR * (1 - fG) * (1 - fB) W101 = fR * (1 - fG) * fB W110 = fR * fG * (1 - fB) W111 = fR * fG * fB outPixels = V000 * W000 + V001 * W001 + V010 * W010 + V011 * W011 + V100 * W100 + V101 * W101 + V110 * W110 + V111 * W111 outPixels = np.reshape(outPixels, theShape) * 255 * max_cv if interp_type == 'tetrahedral': n = lattice.shape[0] - 1 inPixels = np.asarray(inPixels) / max_cv theShape = inPixels.shape inPixels = np.ravel(inPixels) pixels = inPixels.size / 3 inPixels = np.reshape(inPixels, (pixels, 3)) R, G, B = tsplit(inPixels) rLow = np.floor(R * n).astype(np.int_) rHigh = np.clip(rLow + 1, 0, n) gLow = np.floor(G * n).astype(np.int_) gHigh = np.clip(gLow + 1, 0, n) bLow = np.floor(B * n).astype(np.int_) bHigh = np.clip(bLow + 1, 0, n) V000 = lattice[rLow, gLow, bLow] V001 = lattice[rLow, gLow, bHigh] V010 = lattice[rLow, gHigh, bLow] V011 = lattice[rLow, gHigh, bHigh] V100 = lattice[rHigh, gLow, bLow] V101 = lattice[rHigh, gLow, bHigh] V110 = lattice[rHigh, gHigh, bLow] V111 = lattice[rHigh, gHigh, bHigh] fR = n * R - rLow fG = n * G - gLow fB = n * B - bLow fR = np.reshape(fR, (pixels, 1)) fG = np.reshape(fG, (pixels, 1)) fB = np.reshape(fB, (pixels, 1)) outPixels = (1 - fG) * V000 + (fG - fR) * V010 + ( fR - fB) * V110 + fB * V111 outPixels = np.where(np.logical_and(fR > fG, fG > fB), (1 - fR) * V000 + (fR - fG) * V100 + (fG - fB) * V110 + fB * V111, outPixels) outPixels = np.where(np.logical_and(fR > fG, fR > fB), (1 - fR) * V000 + (fR - fB) * V100 + (fB - fG) * V101 + fG * V111, outPixels) outPixels = np.where(np.logical_and(fR > fG, fB >= fR), (1 - fB) * V000 + (fB - fR) * V001 + (fR - fG) * V101 + fG * V111, outPixels) outPixels = np.where(np.logical_and(fG >= fR, fB > fG), (1 - fB) * V000 + (fB - fG) * V001 + (fG - fR) * V011 + fR * V111, outPixels) outPixels = np.where(np.logical_and(fG >= fR, fB > fR), (1 - fG) * V000 + (fG - fB) * V010 + (fB - fR) * V011 + fR * V111, outPixels) outPixels = np.clip(outPixels, 0., np.inf) outPixels = np.reshape(outPixels, theShape) * 255 * max_cv # return outPixels # print(outPixels) cv2.imwrite('test_tetrahedral.tiff', outPixels.astype(np.uint8)) return outPixels
def image_stack_to_radiance_image( image_stack, weighting_function=weighting_function_Debevec1997, weighting_average=False, camera_response_functions=None): """ Generates a HDRI / radiance image from given image stack. Parameters ---------- image_stack : ImageStack Stack of single channel or multi-channel floating point images. The stack is assumed to be representing linear values except if ``camera_response_functions`` argument is provided. weighting_function : callable, optional Weighting function :math:`w`. weighting_average : bool, optional Enables weighting function :math:`w` computation on channels average instead of on a per channel basis. camera_response_functions : array_like, optional Camera response functions :math:`g(z)` of the imaging system / camera if the stack is representing non linear values. Returns ------- ndarray Radiance image. """ image_c = None weight_c = None for image in image_stack: if image_c is None: image_c = np.zeros(image.data.shape) weight_c = np.zeros(image.data.shape) L = average_luminance( image.metadata.f_number, image.metadata.exposure_time, image.metadata.iso) if weighting_average and image.data.ndim == 3: weight = weighting_function(np.average(image.data, axis=-1)) weight = np.rollaxis(weight[np.newaxis], 0, 3) else: weight = weighting_function(image.data) image_data = image.data if camera_response_functions is not None: samples = np.linspace(0, 1, camera_response_functions.shape[0]) R, G, B = tsplit(image.data) R = np.interp(R, samples, camera_response_functions[..., 0]) G = np.interp(G, samples, camera_response_functions[..., 1]) B = np.interp(B, samples, camera_response_functions[..., 2]) image_data = tstack((R, G, B)) image_c += weight * image_data / L weight_c += weight if image_c is not None: image_c /= weight_c image_c[np.isnan(image_c)] = 0 return image_c
def refining_step_Menon2007(RGB, RGB_m, M): """ Performs the refining step on given *RGB* colourspace array. Parameters ---------- RGB : array_like *RGB* colourspace array. RGB_m : array_like *Bayer* CFA red, green and blue masks. M : array_like Estimation for the best directional reconstruction. Returns ------- ndarray Refined *RGB* colourspace array. Examples -------- >>> RGB = np.array([[[0.30588236, 0.35686275, 0.3764706], ... [0.30980393, 0.36078432, 0.39411766], ... [0.29607844, 0.36078432, 0.40784314], ... [0.29803923, 0.37647060, 0.42352942]], ... [[0.30588236, 0.35686275, 0.3764706], ... [0.30980393, 0.36078432, 0.39411766], ... [0.29607844, 0.36078432, 0.40784314], ... [0.29803923, 0.37647060, 0.42352942]]]) >>> RGB_m = np.array([[[0, 0, 1], ... [0, 1, 0], ... [0, 0, 1], ... [0, 1, 0]], ... [[0, 1, 0], ... [1, 0, 0], ... [0, 1, 0], ... [1, 0, 0]]]) >>> M = np.array([[0, 1, 0, 1], ... [1, 0, 1, 0]]) >>> refining_step_Menon2007(RGB, RGB_m, M) array([[[ 0.30588236, 0.35686275, 0.3764706 ], [ 0.30980393, 0.36078432, 0.39411765], [ 0.29607844, 0.36078432, 0.40784314], [ 0.29803923, 0.3764706 , 0.42352942]], <BLANKLINE> [[ 0.30588236, 0.35686275, 0.3764706 ], [ 0.30980393, 0.36078432, 0.39411766], [ 0.29607844, 0.36078432, 0.40784314], [ 0.29803923, 0.3764706 , 0.42352942]]]) """ R, G, B = tsplit(RGB) R_m, G_m, B_m = tsplit(RGB_m) M = np.asarray(M) # Updating of the green component. R_G = R - G B_G = B - G FIR = np.ones(3) / 3 B_G_m = np.where(B_m == 1, np.where(M == 1, _cnv_h(B_G, FIR), _cnv_v(B_G, FIR)), 0) R_G_m = np.where(R_m == 1, np.where(M == 1, _cnv_h(R_G, FIR), _cnv_v(R_G, FIR)), 0) G = np.where(R_m == 1, R - R_G_m, G) G = np.where(B_m == 1, B - B_G_m, G) # Updating of the red and blue components in the green locations. # Red rows. R_r = np.transpose(np.any(R_m == 1, axis=1)[np.newaxis]) * np.ones(R.shape) # Red columns. R_c = np.any(R_m == 1, axis=0)[np.newaxis] * np.ones(R.shape) # Blue rows. B_r = np.transpose(np.any(B_m == 1, axis=1)[np.newaxis]) * np.ones(B.shape) # Blue columns B_c = np.any(B_m == 1, axis=0)[np.newaxis] * np.ones(B.shape) R_G = R - G B_G = B - G k_b = np.array([0.5, 0, 0.5]) R_G_m = np.where(np.logical_and(G_m == 1, B_r == 1), _cnv_v(R_G, k_b), R_G_m) R = np.where(np.logical_and(G_m == 1, B_r == 1), G + R_G_m, R) R_G_m = np.where(np.logical_and(G_m == 1, B_c == 1), _cnv_h(R_G, k_b), R_G_m) R = np.where(np.logical_and(G_m == 1, B_c == 1), G + R_G_m, R) B_G_m = np.where(np.logical_and(G_m == 1, R_r == 1), _cnv_v(B_G, k_b), B_G_m) B = np.where(np.logical_and(G_m == 1, R_r == 1), G + B_G_m, B) B_G_m = np.where(np.logical_and(G_m == 1, R_c == 1), _cnv_h(B_G, k_b), B_G_m) B = np.where(np.logical_and(G_m == 1, R_c == 1), G + B_G_m, B) # Updating of the red (blue) component in the blue (red) locations. R_B = R - B R_B_m = np.where(B_m == 1, np.where(M == 1, _cnv_h(R_B, FIR), _cnv_v(R_B, FIR)), 0) R = np.where(B_m == 1, B + R_B_m, R) R_B_m = np.where(R_m == 1, np.where(M == 1, _cnv_h(R_B, FIR), _cnv_v(R_B, FIR)), 0) B = np.where(R_m == 1, R - R_B_m, B) return tstack((R, G, B))