def get_demosaiced(img: ndarray, pattern: str = 'GRBG', method: str = 'bilinear') -> ndarray: """Get a demosaiced RGB image from a raw image. This function is a wrapper of the demosaicing functions supplied by the ``color_demosaicing`` package. Args: img: Input image, greyscale, of shape (x,y). pattern: Bayer filter pattern that the input image is modulated with. Patterns are: 'RGGB', 'BGGR', 'GRBG', 'GBRG'. Default: 'GRBG' method: Algorithm used to calculate the demosaiced image.\n * 'bilinear': Simple bilinear interpolation of color values * 'malvar2004': Algorithm introduced by Malvar et. al. [R3]_ * 'menon2007': Algorithm introduced by Menon et. al. [R4]_, Returns: Demosaiced RGB-color image of shape (x,y,3) of dtype :class:`numpy.float64`. References: .. [R3] H.S. Malvar, Li-wei He, and R. Cutler (2004). High-quality linear interpolation for demosaicing of Bayer-patterned color images. IEEE International Conference on Acoustics, Speech, and Signal Processing, Proceedings. (ICASSP '04). DOI: 10.1109/ICASSP.2004.1326587 .. [R4] D. Menon, S. Andriani, G. Calvagno (2007). Demosaicing With Directional Filtering and a posteriori Decision. IEEE Transactions on Image Processing (Volume: 16, Issue: 1) DOI: 10.1109/TIP.2006.884928 """ param_list = ["bilinear", "malvar2004", "menon2007"] # Do demosaicing with specified method if method not in param_list: raise ValueError( f"The specified method {method} is none of the supported " f"methods: {param_list}.") elif method == "bilinear": return demosaicing_CFA_Bayer_bilinear(img.astype(np.float64), pattern=pattern) elif method == "malvar2004": return demosaicing_CFA_Bayer_Malvar2004(img.astype(np.float64), pattern=pattern) elif method == "menon2007": return demosaicing_CFA_Bayer_Menon2007(img.astype(np.float64), pattern=pattern)
def compute(img: ndarray, k_size: int = 3) -> ndarray: im = img.astype(np.float) width, height, c = im.shape if c > 1: img = 0.2126 * im[:, :, 0] + 0.7152 * im[:, :, 1] + 0.0722 * im[:, :, 2] else: img = im assert k_size == 3 or k_size == 5 if k_size == 3: kh = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]], dtype=np.float) kv = np.array([[1, 2, 1], [0, 0, 0], [-1, -2, -1]], dtype=np.float) else: kh = np.array( [ [-1, -2, 0, 2, 1], [-4, -8, 0, 8, 4], [-6, -12, 0, 12, 6], [-4, -8, 0, 8, 4], [-1, -2, 0, 2, 1], ], dtype=np.float, ) kv = np.array( [ [1, 4, 6, 4, 1], [2, 8, 12, 8, 2], [0, 0, 0, 0, 0], [-2, -8, -12, -8, -2], [-1, -4, -6, -4, -1], ], dtype=np.float, ) gx = convolve2d(img, kh, mode="same", boundary="symm") gy = convolve2d(img, kv, mode="same", boundary="symm") g = np.sqrt(gx * gx + gy * gy) g *= 255.0 / np.max(g) return g
def conv2d(data_in: ndarray, kernel: ndarray, stride: int = 1): """ Perform a 2D convolution over a batch of tensors. This is equivalent to output[b, i, j, k] = sum_{di, dj, q} input[b, strides[1] * i + di, strides[2] * j + dj, q] * filter[di, dj, q, k] :param data_in: Input data tensor with shape [batch, height, width, channels_in] :param kernel: Convolution kernel tensor with shape [kernel_height, kernel_width, channels_in, channels_out] :param stride: Integer for the step width :return: Tensor with shape [batch, height/stride, width/stride, channels_out] """ # Obtain shapes fh, fw, kin_ch, kout_ch = kernel.shape batch, in_h, in_w, in_ch = data_in.shape if kin_ch != in_ch: raise ValueError("Input channel mismatch") # Check if the filter has an uneven width assert (1 == fh % 2) assert (1 == fw % 2) # Find the midpoint of the filter. This only works for odd filter sizes fh2 = int((fh - 1) / 2) fw2 = int((fw - 1) / 2) # Given an input tensor of shape [batch, in_height, in_width, in_channels] and a filter / kernel tensor of # shape [filter_height, filter_width, in_channels, out_channels], this op performs the following: # # 1) Flattens the filter to a 2-D matrix with shape [filter_height * filter_width * in_channels, # output_channels]. # # 2) Extracts image patches from the input tensor to form a virtual tensor of shape [batch, # out_height, out_width, filter_height * filter_width * in_channels]. # # 3) For each patch, right-multiplies the # filter matrix and the image patch vector if kernel.dtype.kind in 'ui': # check if datatype is unsigned or integer out = np.zeros(shape=[batch, in_h, in_w, kout_ch], dtype=np.int32) else: out = np.zeros(shape=[batch, in_h, in_w, kout_ch], dtype=data_in.dtype) # pad input in_padded = np.pad(data_in, ((0, 0), (fh2, fh2), (fw2, fw2), (0, 0)), 'constant', constant_values=(0, 0)) # in_padded = np.pad(data_in, ((0, 0), (30, 30), (30, 30), (0, 0)), 'constant', constant_values=(0, 0)) # img = np.squeeze(in_padded) # fig, ax = plt.subplots() # _im = ax.imshow(img, cmap='gray') # fig.colorbar(_im) # plt.show() # kflat = np.reshape(kernel, newshape=(-1, kout_ch)) # vout = np.zeros(shape=(batch, in_h, in_w, fh * fw * in_ch)) # create virtual out # # for b in range(batch): # for i in range(in_h): # for j in range(in_w): # vout[b, i, j, :] = np.reshape(in_padded[b, i:i+fh, j:j+fw, :], newshape=(-1)) # # out = np.dot(vout, kflat) # output[b, i, j, k] = # sum_{di, dj, q} input[b, strides[1] * i + di, strides[2] * j + dj, q] * # filter[di, dj, q, k] for b in range(batch): for k in range(kout_ch): # k = kernel[:, :, q, k] # 2d kernel # Perform convolution i_out, j_out = 0, 0 for i in range(0, in_h, stride): for j in range(0, in_w, stride): patch = in_padded[b, i:i + fh, j:j + fw, :] # 3d tensor 3x3x16 if kernel.dtype.kind in 'ui': # check if datatype is unsigned or integer patch16 = patch.astype(np.int16) kernel16 = kernel.astype(np.int16) temp = patch16 * kernel16[:, :, :, k] temp = temp.flatten().astype(np.int64) # patch_sum = np.sum(patch * kernel[:, :, :, k], axis=(0, 1, 2)) # sum along all axis # min_value = np.iinfo(kernel.dtype).min # max_value = np.iinfo(kernel.dtype).max patch_sum = np.sum(temp) out[b, i_out, j_out, k] = patch_sum else: # patch_sum is always int64 patch_sum = np.sum(patch * kernel[:, :, :, k], axis=(0, 1, 2)) # sum along all axis out[b, i_out, j_out, k] = patch_sum j_out += 1 j_out = 0 i_out += 1 return out