diff --git a/src/methods/inssaf_cherki/cherki_inssaf_projectreport.pdf b/src/methods/inssaf_cherki/cherki_inssaf_projectreport.pdf new file mode 100644 index 0000000000000000000000000000000000000000..e81933ea4b7805a30b8b60eb88d8cab7f4aa5c9d Binary files /dev/null and b/src/methods/inssaf_cherki/cherki_inssaf_projectreport.pdf differ diff --git a/src/methods/inssaf_cherki/other_functions.py b/src/methods/inssaf_cherki/other_functions.py new file mode 100644 index 0000000000000000000000000000000000000000..63d0823248b566dd343408d088310c3ad4ac8493 --- /dev/null +++ b/src/methods/inssaf_cherki/other_functions.py @@ -0,0 +1,86 @@ +import numpy as np +from scipy import signal +from src.forward_model import CFA + +def compute_gradient(channel, points): + """ Compute the gradient for the channel based on the specified points. """ + gradient = np.zeros_like(channel) + for point in points: + gradient += np.roll(channel, shift=point, axis=(0, 1)) + gradient /= len(points) + gradient -= channel + return gradient + +def gradient_correction_interpolation(op: CFA, z: np.ndarray,alpha=0.5, beta=0.5, gamma=0.5) -> np.ndarray: + # defining bilinear interpolation filters for the different channels (bayer pattern case) + bilinear_filter_red = np.array([[1, 2, 1], [2, 4, 2], [1, 2, 1]]) / 4 + bilinear_filter_green = np.array([[0, 1, 0], [1, 4, 1], [0, 1, 0]]) / 4 + bilinear_filter_blue = np.array([[1, 2, 1], [2, 4, 2], [1, 2, 1]]) / 4 + + interpolated_img = np.empty(op.input_shape) + + # applying the convolution product with the bilinear filters + interpolated_img[:, :, 0] = signal.convolve2d(z[:, :, 0], bilinear_filter_red, boundary='symm',mode='same') + interpolated_img[:, :, 1] = signal.convolve2d(z[:, :, 1], bilinear_filter_green, boundary='symm',mode='same') + interpolated_img[:, :, 2] = signal.convolve2d(z[:, :, 2], bilinear_filter_blue, boundary='symm', mode='same') + + """ Applying gradient correction to the bilinearly interpolated image. """ + + + R = interpolated_img[:, :, 0] + G = interpolated_img[:, :, 1] + B = interpolated_img[:, :, 2] + + # computing gradients for R and B channels + points_R = [(0, -2), (0, 2), (-2, 0), (2, 0)] + points_B = [(-1, -1), (-1, 1), (1, -1), (1, 1), (0, 0)] + grad_R = compute_gradient(R, points_R) + grad_B = compute_gradient(B, points_B) + + G_corrected = np.copy(G) + G_corrected[0::2, 0::2] = G[0::2, 0::2] + alpha * grad_R[0::2, 0::2] + + G_corrected[1::2, 1::2] = G[1::2, 1::2] + gamma * grad_B[1::2, 1::2] + + # correction of R at G locations and B at G locations + R_corrected = np.copy(R) + B_corrected = np.copy(B) + R_corrected[1::2, 0::2] = R[1::2, 0::2] + beta * grad_R[1::2, 0::2] + R_corrected[0::2, 1::2] = R[0::2, 1::2] + beta * grad_R[0::2, 1::2] + B_corrected[1::2, 0::2] = B[1::2, 0::2] + beta * grad_B[1::2, 0::2] + B_corrected[0::2, 1::2] = B[0::2, 1::2] + beta * grad_B[0::2, 1::2] + + + corrected_image = np.stack((R_corrected, G_corrected, B_corrected), axis=-1) + + return corrected_image + +def swapping(op, y): + """ + Convert both the CFA operator's mask and an image from Quad Bayer to Bayer by swapping method. + + Args: + op: CFA operator. + y (np.ndarray): Mosaicked image. + + Returns: + tuple: A tuple containing the updated CFA operator and the converted image. + """ + + if op.cfa == 'quad_bayer': + # swapping 2 columns every 2 columns + op.mask[:, 1::4], op.mask[:, 2::4] = op.mask[:, 2::4].copy(), op.mask[:, 1::4].copy() + # swapping 2 lines every 2 lines + op.mask[1::4, :], op.mask[2::4, :] = op.mask[2::4, :].copy(), op.mask[1::4, :].copy() + # swapping the diagonal pairs + op.mask[1::4, 1::4], op.mask[2::4, 2::4] = op.mask[2::4, 2::4].copy(), op.mask[1::4, 1::4].copy() + + converted_image = y.copy() + converted_image[:, 1::4], converted_image[:, 2::4] = converted_image[:, 2::4].copy(), converted_image[:, 1::4].copy() + converted_image[1::4, :], converted_image[2::4, :] = converted_image[2::4, :].copy(), converted_image[1::4, :].copy() + converted_image[1::4, 1::4], converted_image[2::4, 2::4] = converted_image[2::4, 2::4].copy(), converted_image[1::4, 1::4].copy() + + # updating to bayer pattern + op.cfa = 'bayer' + + return op, converted_image \ No newline at end of file diff --git a/src/methods/inssaf_cherki/reconstruct.py b/src/methods/inssaf_cherki/reconstruct.py new file mode 100644 index 0000000000000000000000000000000000000000..8b3c46b040a4eb2ec49d20617db555f27d6c5c9d --- /dev/null +++ b/src/methods/inssaf_cherki/reconstruct.py @@ -0,0 +1,53 @@ +import numpy as np +from src.methods.inssaf_cherki.other_functions import gradient_correction_interpolation, swapping, compute_gradient +from src.forward_model import CFA + + +def run_reconstruction(y: np.ndarray, cfa: str) -> np.ndarray: + """Performs demosaicking on y. + + Args: + y (np.ndarray): Mosaicked image to be reconstructed. + cfa (str): Name of the CFA. Can be bayer or quad_bayer. + + Returns: + np.ndarray: Demosaicked image. + """ + # Performing the reconstruction. + + input_shape = (y.shape[0], y.shape[1], 3) + op = CFA(cfa, input_shape) + + if op.cfa == 'quad_bayer': + op, y = swapping(op, y) + + z = op.adjoint(y) + reconstructed_image = gradient_correction_interpolation(op,z,alpha=0.5, beta=0.5, gamma=0.5) + + return reconstructed_image + + +#### +#### +#### + +#### #### #### ############# +#### ###### #### ################## +#### ######## #### #################### +#### ########## #### #### ######## +#### ############ #### #### #### +#### #### ######## #### #### #### +#### #### ######## #### #### #### +#### #### ######## #### #### #### +#### #### ## ###### #### #### ###### +#### #### #### ## #### #### ############ +#### #### ###### #### #### ########## +#### #### ########## #### #### ######## +#### #### ######## #### #### +#### #### ############ #### +#### #### ########## #### +#### #### ######## #### +#### #### ###### #### + +# 2023 +# Authors: Mauro Dalla Mura and Matthieu Muller