Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • samanost/sicom_image_analysis_project
  • gerayelk/sicom_image_analysis_project
  • jelassiy/sicom_image_analysis_project
  • chardoto/sicom_image_analysis_project
  • chaarim/sicom_image_analysis_project
  • domers/sicom_image_analysis_project
  • elmurrt/sicom_image_analysis_project
  • sadonest/sicom_image_analysis_project
  • kouddann/sicom_image_analysis_project
  • mirabitj/sicom-image-analysis-project-mirabito
  • plotj/sicom_image_analysis_project
  • torrem/sicom-image-analysis-project-maxime-torre
  • dzike/sicom_image_analysis_project
  • daip/sicom_image_analysis_project
  • casanovv/sicom_image_analysis_project
  • girmarti/sicom_image_analysis_project
  • lioretn/sicom_image_analysis_project
  • lemoinje/sicom_image_analysis_project
  • ouahmanf/sicom_image_analysis_project
  • vouilloa/sicom_image_analysis_project
  • diopb/sicom_image_analysis_project
  • davidale/sicom_image_analysis_project
  • enza/sicom_image_analysis_project
  • conversb/sicom_image_analysis_project
  • mullemat/sicom_image_analysis_project
25 results
Show changes
Showing
with 1338 additions and 0 deletions
import os
import cv2
def folderExists(path):
CHECK_FOLDER = os.path.isdir(path)
# If folder doesn't exist, it creates it.
if not CHECK_FOLDER:
os.makedirs(path)
print("[DATA] You created a new folder : " + str(path))
import numpy as np
def quad_bayer_to_bayer(quad_bayer_pattern):
# We test that thee quad bayer size fit with a multiple of 2 for width and height). If not, we pad it.
if quad_bayer_pattern.shape[0] % 2 != 0 or quad_bayer_pattern.shape[1] % 2 != 0:
print("[INFO] The quad bayer pattern size is not valid. We need to pad it.")
pad_schema = []
if quad_bayer_pattern.shape[0] % 2 != 0:
pad_schema.append([0, 1])
if quad_bayer_pattern.shape[1] % 2 != 0:
pad_schema.append([0, 1])
else:
pad_schema.append([0, 0])
quad_bayer_pattern = np.pad(quad_bayer_pattern, pad_schema, mode="reflect")[:, 2:]
# we create a new bayer pattern with the good size
bayer_pattern = np.zeros((quad_bayer_pattern.shape[0] // 2, quad_bayer_pattern.shape[1] // 2))
# We combine adjacent pixels to create the Bayer pattern
for i in range(0, quad_bayer_pattern.shape[0], 2):
for j in range(0, quad_bayer_pattern.shape[1], 2):
bayer_pattern[i // 2, j // 2] = (
quad_bayer_pattern[i, j] +
quad_bayer_pattern[i, j + 1] +
quad_bayer_pattern[i + 1, j] +
quad_bayer_pattern[i + 1, j + 1]
) / 4
# We resize bayer iamge to the original image size
#return cv2.resize(bayer_pattern, quad_bayer_pattern.shape, interpolation=cv2.INTER_CUBIC)
return bayer_pattern
import numpy as np
from scipy.signal import convolve2d
from src.forward_model import CFA
def bilinear_demosaicing(op: CFA, y: np.ndarray) -> np.ndarray:
"""
Bilinear demosaicing method.
Args:
op (CFA): CFA operator.
y (np.ndarray): Mosaicked image.
Returns:
np.ndarray: Demosaicked image.
"""
# Copie des valeurs directement connues pour chaque canal
red = y[:, :, 0]
green = y[:, :, 1]
blue = y[:, :, 2]
# Création des masques pour chaque couleur selon le motif CFA
mask_red = (op.mask == 0) # Supposons que 0 correspond au rouge dans le masque
mask_green = (op.mask == 1) # Supposons que 1 correspond au vert
mask_blue = (op.mask == 2) # Supposons que 2 correspond au bleu
# Interpolation bilinéaire pour le rouge et le bleu
# Note: np.multiply multiplie les éléments correspondants des tableaux, c'est pourquoi nous utilisons np.multiply au lieu de *
red_interp = convolve2d(np.multiply(red, mask_red), [[1/4, 1/2, 1/4], [1/2, 1, 1/2], [1/4, 1/2, 1/4]], mode='same')
blue_interp = convolve2d(np.multiply(blue, mask_blue), [[1/4, 1/2, 1/4], [1/2, 1, 1/2], [1/4, 1/2, 1/4]], mode='same')
# Interpolation bilinéaire pour le vert
# Pour le vert, nous utilisons un autre noyau car il y a plus de pixels verts
green_interp = convolve2d(np.multiply(green, mask_green), [[0, 1/4, 0], [1/4, 1, 1/4], [0, 1/4, 0]], mode='same')
# Création de l'image interpolée
demosaicked_image = np.stack((red_interp, green_interp, blue_interp), axis=-1)
# Correction des valeurs interpolées: on réapplique les valeurs connues pour éviter le flou
demosaicked_image[:, :, 0][mask_red] = red[mask_red]
demosaicked_image[:, :, 1][mask_green] = green[mask_green]
demosaicked_image[:, :, 2][mask_blue] = blue[mask_blue]
# Clip pour s'assurer que toutes les valeurs sont dans la plage [0, 1]
demosaicked_image = np.clip(demosaicked_image, 0, 1)
return demosaicked_image
def quad_bayer_demosaicing(op: CFA, y: np.ndarray) -> np.ndarray:
"""
Demosaicing method for Quad Bayer CFA pattern.
Args:
op (CFA): CFA operator.
y (np.ndarray): Mosaicked image.
Returns:
np.ndarray: Demosaicked image.
"""
# Interpolation bilinéaire pour chaque canal
red_interp = convolve2d(np.multiply(y[:, :, 0], op.mask == 0), [[1/4, 1/2, 1/4], [1/2, 1, 1/2], [1/4, 1/2, 1/4]], mode='same')
green_interp = convolve2d(np.multiply(y[:, :, 1], op.mask == 1), [[0, 1/4, 0], [1/4, 1, 1/4], [0, 1/4, 0]], mode='same')
blue_interp = convolve2d(np.multiply(y[:, :, 2], op.mask == 2), [[1/4, 1/2, 1/4], [1/2, 1, 1/2], [1/4, 1/2, 1/4]], mode='same')
# Assemblage de l'image interpolée
demosaicked_image = np.stack((red_interp, green_interp, blue_interp), axis=-1)
# Réapplication des valeurs connues
demosaicked_image[:, :, 0][op.mask == 0] = y[:, :, 0][op.mask == 0]
demosaicked_image[:, :, 1][op.mask == 1] = y[:, :, 1][op.mask == 1]
demosaicked_image[:, :, 2][op.mask == 2] = y[:, :, 2][op.mask == 2]
# Clip des valeurs pour les maintenir dans la plage appropriée
demosaicked_image = np.clip(demosaicked_image, 0, 1)
return demosaicked_image
"""The main file for the reconstruction.
This file should NOT be modified except the body of the 'run_reconstruction' function.
Students can call their functions (declared in others files of src/methods/your_name).
"""
import numpy as np
from src.forward_model import CFA
from src.methods.chaari_mohamed.fonctions import bilinear_demosaicing,quad_bayer_demosaicing
def run_reconstruction(y: np.ndarray, cfa: str) -> np.ndarray:
"""
Performs demosaicking on y based on the CFA pattern.
Args:
y (np.ndarray): Mosaicked image to be reconstructed.
cfa (str): Name of the CFA pattern. Can be 'bayer' or 'quad_bayer'.
Returns:
np.ndarray: Demosaicked image.
"""
input_shape = (y.shape[0], y.shape[1], 3)
op = CFA(cfa, input_shape)
if cfa == 'bayer':
res = bilinear_demosaicing(op, y)
elif cfa == 'quad_bayer':
res = quad_bayer_demosaicing(op, y)
else:
raise ValueError("Unsupported CFA pattern. Supported patterns are 'bayer' and 'quad_bayer'.")
return res
####
####
####
#### #### #### #############
#### ###### #### ##################
#### ######## #### ####################
#### ########## #### #### ########
#### ############ #### #### ####
#### #### ######## #### #### ####
#### #### ######## #### #### ####
#### #### ######## #### #### ####
#### #### ## ###### #### #### ######
#### #### #### ## #### #### ############
#### #### ###### #### #### ##########
#### #### ########## #### #### ########
#### #### ######## #### ####
#### #### ############ ####
#### #### ########## ####
#### #### ######## ####
#### #### ###### ####
# 2023
# Authors: Mauro Dalla Mura and Matthieu Muller
File added
File added
import numpy as np
import cv2
from scipy.signal import convolve2d
from src.forward_model import CFA
def superpixel(op: CFA, y: np.ndarray) -> np.ndarray:
"""Performs the method of variable number of gradients
Args:
op (CFA): CFA operator.
y (np.ndarray): Mosaicked image.
Returns:
np.ndarray: Demosaicked image.
"""
z = op.adjoint(y)
if op.cfa == 'bayer':
res = np.empty((op.input_shape[0]//2, op.input_shape[1]//2, op.input_shape[2]))
for i in range(1,op.input_shape[0],2):
for j in range(1, op.input_shape[1],2):
res[i//2,j//2,0] = z[ i-1,j ,0]
res[i//2,j//2,1] = (z[i,j,1] + z[i-1,j-1,1]) / 2
res[i//2,j//2,2] = z[ i,j-1 ,2]
else:
res = np.empty((op.input_shape[0]//2, op.input_shape[1]//2, op.input_shape[2]))
print()
for i in range(2,op.input_shape[0]-5,4):
for j in range(2, op.input_shape[1]-5,4):
res[i//2,j//2,0] = z[ i-2,j ,0]
res[i//2,j//2,1] = (z[i,j,1] + z[i-2,j-2,1]) / 2
res[i//2,j//2,2] = z[ i,j-2 ,2]
res[i//2+1,j//2,0] = z[ i-2+1,j ,0]
res[i//2+1,j//2,1] = (z[i+1,j,1] + z[i-2+1,j-2,1]) / 2
res[i//2+1,j//2,2] = z[ i+1,j-2 ,2]
res[i//2+1,j//2+1,0] = z[ i-2+1,j+1 ,0]
res[i//2+1,j//2+1,1] = (z[i+1,j+1,1] + z[i-2+1,j-2+1,1]) / 2
res[i//2+1,j//2+1,2] = z[ i+1,j-2+1 ,2]
res[i//2,j//2+1,0] = z[ i-2,j+1 ,0]
res[i//2,j//2+1,1] = (z[i,j+1,1] + z[i-2,j-2+1,1]) / 2
res[i//2,j//2+1,2] = z[ i,j-2+1 ,2]
return cv2.resize(res, (op.input_shape[0], op.input_shape[1]))
####
####
####
#### #### #### #############
#### ###### #### ##################
#### ######## #### ####################
#### ########## #### #### ########
#### ############ #### #### ####
#### #### ######## #### #### ####
#### #### ######## #### #### ####
#### #### ######## #### #### ####
#### #### ## ###### #### #### ######
#### #### #### ## #### #### ############
#### #### ###### #### #### ##########
#### #### ########## #### #### ########
#### #### ######## #### ####
#### #### ############ ####
#### #### ########## ####
#### #### ######## ####
#### #### ###### ####
# 2023
# Authors: Mauro Dalla Mura and Matthieu Muller
"""The main file for the reconstruction.
This file should NOT be modified except the body of the 'run_reconstruction' function.
Students can call their functions (declared in others files of src/methods/your_name).
"""
import numpy as np
from src.forward_model import CFA
from src.methods.charpentier_laurine.functions import superpixel
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.
"""
input_shape = (y.shape[0], y.shape[1], 3)
op = CFA(cfa, input_shape)
res = superpixel(op, y)
return res
####
####
####
#### #### #### #############
#### ###### #### ##################
#### ######## #### ####################
#### ########## #### #### ########
#### ############ #### #### ####
#### #### ######## #### #### ####
#### #### ######## #### #### ####
#### #### ######## #### #### ####
#### #### ## ###### #### #### ######
#### #### #### ## #### #### ############
#### #### ###### #### #### ##########
#### #### ########## #### #### ########
#### #### ######## #### ####
#### #### ############ ####
#### #### ########## ####
#### #### ######## ####
#### #### ###### ####
# 2023
# Authors: Mauro Dalla Mura and Matthieu Muller
File added
import numpy as np
from scipy.signal import convolve2d
from src.forward_model import CFA
def naive_interpolation(op: CFA, y: np.ndarray) -> np.ndarray:
"""Performs a simple interpolation of the lost pixels.
Args:
op (CFA): CFA operator.
y (np.ndarray): Mosaicked image.
Returns:
np.ndarray: Demosaicked image.
"""
res = np.empty(op.input_shape)
z = op.adjoint(y)
res[:, :, 0] = convolve2d(z[:, :, 0], ker_bayer_red_blue, mode='same')
res[:, :, 1] = convolve2d(z[:, :, 1], ker_bayer_green, mode='same')
res[:, :, 2] = convolve2d(z[:, :, 2], ker_bayer_red_blue, mode='same')
return res
def Spectral_difference(op,y):
z = op.adjoint(y)
y_hat = naive_interpolation(op,y)
res = np.empty(op.input_shape)
for l in range(3):
res[:,:,0]+=z[:,:,l]+convolve2d(z[:,:,0]-y_hat[:,:,l]*op.mask[:,:,0], ker_bayer_red_blue, mode='same')*op.mask[:,:,l]
res[:,:,1]+=z[:,:,l]+convolve2d(z[:,:,1]-y_hat[:,:,l]*op.mask[:,:,1], ker_bayer_green, mode='same')*op.mask[:,:,l]
res[:,:,2]+=z[:,:,l]+convolve2d(z[:,:,2]-y_hat[:,:,l]*op.mask[:,:,2], ker_bayer_red_blue, mode='same')*op.mask[:,:,l]
return res
def quad_bayer_to_bayer(y_quad):
y_bayer=np.copy(y_quad)
for i in range(1,y_quad.shape[0],4):
temp = np.copy(y_bayer[i,:])
y_bayer[i,:]=y_bayer[i+1,:]
y_bayer[i+1,:]=temp
for j in range(1,y_quad.shape[1],4):
temp = np.copy(y_bayer[:,j])
y_bayer[:,j]=y_bayer[:,j+1]
y_bayer[:,j+1]=temp
return y_bayer
ker_bayer_red_blue = np.array([[1, 2, 1], [2, 4, 2], [1, 2, 1]]) / 4
ker_bayer_green = np.array([[0, 1, 0], [1, 4, 1], [0, 1, 0]]) / 4
\ No newline at end of file
"""The main file for the baseline reconstruction.
This file should NOT be modified.
"""
import numpy as np
from src.forward_model import CFA
from src.methods.dai.function import Spectral_difference, quad_bayer_to_bayer
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.
"""
input_shape = (y.shape[0], y.shape[1], 3)
op = CFA(cfa, input_shape)
if op.cfa == 'bayer':
res = Spectral_difference(op, y)
else:
op.mask = quad_bayer_to_bayer(op.mask)
res = Spectral_difference(CFA('bayer',input_shape),quad_bayer_to_bayer(y))
return res
####a
####
####
#### #### #### #############
#### ###### #### ##################
#### ######## #### ####################
#### ########## #### #### ########
#### ############ #### #### ####
#### #### ######## #### #### ####
#### #### ######## #### #### ####
#### #### ######## #### #### ####
#### #### ## ###### #### #### ######
#### #### #### ## #### #### ############
#### #### ###### #### #### ##########
#### #### ########## #### #### ########
#### #### ######## #### ####
#### #### ############ ####
#### #### ########## ####
#### #### ######## ####
#### #### ###### ####
# 2023
# Authors: Mauro Dalla Mura and Matthieu Muller
File added
import numpy as np
# interpolation kernels
w1 = np.array([[0,0,-1,0,0], [0,0,2,0,0], [-1,2,4,2,-1], [0,0,2,0,0], [0,0,-1,0,0]])/8 # G at R location
w2 = w1 #G at B location
w3 = np.array([[0,0,0.5,0,0], [0,-1,0,-1,0], [-1,4,5,4,-1], [0,-1,0,-1,0], [0,0,0.5,0,0]])/8 # R at G location (Brow, Rcol)
w4 = np.array([[0,0,-1,0,0], [0,-1,4,-1,0], [0.5,0,5,0,0.5], [0,-1,4,-1,0], [0,0,-1,0,0]])/8 # R at G location (Rrow, Bcol)
w5 = np.array([[0,0,-3/2,0,0], [0,2,0,2,0], [-3/2,0,6,0,-1], [0,2,0,2,0], [0,0,-3/2,0,0]])/8 # R at B location (Brow, Bcol)
w6 = w3 #R at G location (Brow, Rcol)
w7 = w4 #B at G location (Rrow, Bcol)
w8 = w5 #B at R location (Rrow, Rcol)
w_s = [w1, w2, w3, w4, w5, w6, w7, w8]
def conv(A,B):
return np.sum(A*B)
def bayer_gradient_interpolation(y, op, w=w_s):
"""
Second interpolation method: convolution with a 2D kernels (5x5) using multi-channel interpolations
y: input image
w: interpolation kernels
"""
y_padded = np.pad(y, ((2,2),(2,2)), 'constant', constant_values=0)
size_padded = y_padded.shape
#separate channels
y_0 = y*op.mask[:, :, 0]
y_1 = y*op.mask[:, :, 1]
y_2 = y*op.mask[:, :, 2]
for i in range(2,size_padded[0]-2):
for j in range(2,size_padded[1]-2):
# determine the location of the pixel
if op.mask[i-2,j-2,1] == 1: # at G
if op.mask[i-2,j-3,0] == 1: #R row
y_0[i-2,j-2] = conv(y_padded[i-2:i+3, j-2:j+3],w3)
y_2[i-2,j-2] = conv(y_padded[i-2:i+3, j-2:j+3],w7)
else: #B row
y_0[i-2,j-2] = conv(y_padded[i-2:i+3, j-2:j+3],w4)
y_2[i-2,j-2] = conv(y_padded[i-2:i+3, j-2:j+3],w6)
elif op.mask[i-2,j-2,0] == 1: # at R
y_1[i-2,j-2] = conv(y_padded[i-2:i+3, j-2:j+3],w1)
y_2[i-2,j-2] = conv(y_padded[i-2:i+3, j-2:j+3],w8)
else: # at B
y_1[i-2,j-2] = conv(y_padded[i-2:i+3, j-2:j+3],w2)
y_0[i-2,j-2] = conv(y_padded[i-2:i+3, j-2:j+3],w5)
y_res = np.zeros((y.shape[0], y.shape[1], 3))
y_res[:, :, 0] = y_0
y_res[:, :, 1] = y_1
y_res[:, :, 2] = y_2
return y_res
import numpy as np
def conv(A,B):
return np.sum(A*B)
def quad_gradient_interpolation(y, op):
"""
Second interpolation method: convolution with a 2D kernels (5x5) using multi-channel interpolations
y: input image
w: interpolation kernels
"""
y_padded = np.pad(y, ((2,2),(2,2)), 'constant', constant_values=0)
size_padded = y_padded.shape
mask_padded = np.pad(op.mask, ((2,2),(2,2),(0,0)), 'constant', constant_values=-1)
#separate channels
y_0 = y*op.mask[:, :, 0]
y_1 = y*op.mask[:, :, 1]
y_2 = y*op.mask[:, :, 2]
#interpolation kernels
# green quad kernels
wg11 = np.zeros((5,5))
wg11[0,2] = -3
wg11[1,2] = 13
wg11[2,4] = 2
wg11 += wg11.T
wg11 = wg11/24
# rotate the kernel
wg12 = np.rot90(wg11,3)
wg22 = np.rot90(wg11,2)
wg21 = np.rot90(wg11,1)
#red/blue quad kernels
# center part
w_c11 = np.zeros((5,5))
w_c11[0:2,0:2] = np.array([[-1,-1],[-1,9]])/6
w_c21 = np.rot90(w_c11,1)
w_c22 = np.rot90(w_c11,2)
w_c12 = np.rot90(w_c11,3)
# left part
w_l11 = np.zeros((5,5))
w_l11[0:2, 2] = np.array([-3,13])
w_l11[4,2] = 2
w_l11 = w_l11/12
w_l22 = np.rot90(w_l11,2)
# top part
w_t11 = np.rot90(w_l11,1)
w_t22 = np.rot90(w_t11,2)
for i in range(2,size_padded[0]-2):
for j in range(2,size_padded[1]-2):
# determine the location of the pixel
if mask_padded[i,j,1] == 1: # at G
if mask_padded[i-1,j,0] + mask_padded[i+1,j,0] == 1: # at R column
if mask_padded[i,j-1,2] == 1:
y_2[i-2,j-2] = conv(y_padded[i-2:i+3, j-2:j+3],w_t11)
elif mask_padded[i,j+1,2] == 1:
y_2[i-2,j-2] = conv(y_padded[i-2:i+3, j-2:j+3],w_t22)
if mask_padded[i-1,j,0] == 1:
y_0[i-2,j-2] = conv(y_padded[i-2:i+3, j-2:j+3],w_l11)
elif mask_padded[i+1,j,0] == 1:
y_0[i-2,j-2] = conv(y_padded[i-2:i+3, j-2:j+3],w_l22)
else:
if mask_padded[i,j-1,0] == 1:
y_0[i-2,j-2] = conv(y_padded[i-2:i+3, j-2:j+3],w_t11)
elif mask_padded[i,j+1,0] == 1:
y_0[i-2,j-2] = conv(y_padded[i-2:i+3, j-2:j+3],w_t22)
if mask_padded[i-1,j,2] == 1:
y_2[i-2,j-2] = conv(y_padded[i-2:i+3, j-2:j+3],w_l11)
elif mask_padded[i+1,j,2] == 1:
y_2[i-2,j-2] = conv(y_padded[i-2:i+3, j-2:j+3],w_l22)
elif mask_padded[i,j,1] == 0: # at R or B
if mask_padded[i-1,j,1] ==1:
if mask_padded[i,j-1,1] ==1:
y_1[i-2,j-2] = conv(y_padded[i-2:i+3, j-2:j+3],wg11)
else:
y_1[i-2,j-2] = conv(y_padded[i-2:i+3, j-2:j+3],wg12)
else:
if mask_padded[i,j-1,1] ==1:
y_1[i-2,j-2] = conv(y_padded[i-2:i+3, j-2:j+3],wg21)
else:
y_1[i-2,j-2] = conv(y_padded[i-2:i+3, j-2:j+3],wg22)
if mask_padded[i,j,0] == 1: #at R
if mask_padded[i-1,j-1,2] ==1: #center (1,1)
y_2[i-2,j-2] = conv(y_padded[i-2:i+3, j-2:j+3],w_c11)
elif mask_padded[i-1,j+1,2] ==1: #center (1,2)
y_2[i-2,j-2] = conv(y_padded[i-2:i+3, j-2:j+3],w_c12)
elif mask_padded[i+1,j-1,2] ==1: #center (2,1)
y_2[i-2,j-2] = conv(y_padded[i-2:i+3, j-2:j+3],w_c21)
elif mask_padded[i+1,j+1,2] ==1: #center (2,2)
y_2[i-2,j-2] = conv(y_padded[i-2:i+3, j-2:j+3],w_c22)
elif mask_padded[i,j,2] == 1: #at B
if mask_padded[i-1,j-1,0] ==1: #center (1,1)
y_0[i-2,j-2] = conv(y_padded[i-2:i+3, j-2:j+3],w_c11)
elif mask_padded[i-1,j+1,0] ==1: #center (1,2)
y_0[i-2,j-2] = conv(y_padded[i-2:i+3, j-2:j+3],w_c12)
elif mask_padded[i+1,j-1,0] ==1: #center (2,1)
y_0[i-2,j-2] = conv(y_padded[i-2:i+3, j-2:j+3],w_c21)
elif mask_padded[i+1,j+1,0] ==1: #center (2,2)
y_0[i-2,j-2] = conv(y_padded[i-2:i+3, j-2:j+3],w_c22)
y_res = np.zeros((y.shape[0], y.shape[1], 3))
y_res[:, :, 0] = y_0
y_res[:, :, 1] = y_1
y_res[:, :, 2] = y_2
return y_res
from scipy import signal
def interpolate(y, op, mode = 'bayer'):
"""
First interpolation method: convolution with a 2D kernel
y: input image
op: object of class CFA
"""
#separate channels
y_0 = y*op.mask[:, :, 0]
y_1 = y*op.mask[:, :, 1]
y_2 = y*op.mask[:, :, 2]
#convolution 2D
if mode == 'bayer':
a = np.array([1,2,1])
elif mode == 'quad_bayer':
a = np.array([1,2,3,2,1])
else:
raise Exception('Mode not supported')
# create the 2D kernel
w = a[:, None] * a[None, :]
w = w / np.sum(w)
#interpolate green
y_1_interpolated = signal.convolve2d(y_1, w, mode='same', boundary='fill', fillvalue=0)
#interpolate red
y_0_interpolated = signal.convolve2d(y_0, w, mode='same', boundary='fill', fillvalue=0)
# interpolate blue
y_2_interpolated = signal.convolve2d(y_2, w, mode='same', boundary='fill', fillvalue=0)
y_res = np.zeros((y.shape[0], y.shape[1], 3))
y_res[:,:,0] = y_0_interpolated*4
y_res[:,:,1] = y_1_interpolated*2
y_res[:,:,2] = y_2_interpolated*4
return y_res
Source diff could not be displayed: it is too large. Options to address this: view the blob.
"""The main file for the reconstruction.
"""
import numpy as np
from src.forward_model import CFA
from src.methods.david_alexis.functions import bayer_gradient_interpolation, quad_gradient_interpolation
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.
"""
input_shape = (y.shape[0], y.shape[1], 3)
op = CFA(cfa, input_shape)
if cfa == "bayer":
res = bayer_gradient_interpolation(y, op)
else:
res = quad_gradient_interpolation(y, op)
return res
# Author: Alexis DAVID
"""The main file for the reconstruction.
This file should NOT be modified except the body of the 'run_reconstruction' function.
Students can call their functions (declared in others files of src/methods/your_name).
"""
import numpy as np
from src.forward_model import CFA
from src.methods.digeronimo.somefunc import spectral_difference, normalization, quad_bayer_to_bayer_pattern, quad_bayer_to_bayer_image, bilinear_interpolation
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 != 'bayer' and op.cfa != 'quad_bayer':
raise ValueError("CFA must be bayer or quad_bayer")
if op.cfa == 'quad_bayer':
quad_bayer_to_bayer_pattern(op)
quad_bayer_to_bayer_image(y)
# Apply adjoint operation on raw aquisition
z = op.adjoint(y)
# Demosaicing process
res_bi = bilinear_interpolation(op, z)
res_sd = spectral_difference(op, z, res_bi)
res = normalization(res_sd) # min-max normalization
return res
####
####
####
#### #### #### #############
#### ###### #### ##################
#### ######## #### ####################
#### ########## #### #### ########
#### ############ #### #### ####
#### #### ######## #### #### ####
#### #### ######## #### #### ####
#### #### ######## #### #### ####
#### #### ## ###### #### #### ######
#### #### #### ## #### #### ############
#### #### ###### #### #### ##########
#### #### ########## #### #### ########
#### #### ######## #### ####
#### #### ############ ####
#### #### ########## ####
#### #### ######## ####
#### #### ###### ####
# 2023
# Authors: Mauro Dalla Mura and Matthieu Muller
File added
import numpy as np
from scipy.signal import convolve2d
from src.forward_model import CFA
def bilinear_interpolation(op: CFA, z: np.ndarray) -> np.ndarray:
"""Perform bilinear interpolation for demosaicing
Args:
op (CFA): CFA operator.
z (np.ndarray): Adjoint image.
Returns:
np.ndarray: Interpolated image.
"""
# Bi-linear interpolation
ker_bayer_red_blue = np.array([[1, 2, 1], [2, 4, 2], [1, 2, 1]]) / 4
ker_bayer_green = np.array([[0, 1, 0], [1, 4, 1], [0, 1, 0]]) / 4
res = np.empty(op.input_shape)
res[:, :, 0] = convolve2d(z[:, :, 0], ker_bayer_red_blue, mode='same')
res[:, :, 1] = convolve2d(z[:, :, 1], ker_bayer_green, mode='same')
res[:, :, 2] = convolve2d(z[:, :, 2], ker_bayer_red_blue, mode='same')
return res
def spectral_difference(op: CFA, z: np.ndarray, res: np.ndarray) -> np.ndarray:
"""Perform spectral difference method for demosaicing
Args:
op (CFA): CFA operator.
z (np.ndarray): Adjoint image.
res (np.ndarray): Interpolated image.
Returns:
np.ndarray: Demosaicked image.
"""
ker_bayer_red_blue = np.array([[1, 2, 1], [2, 4, 2], [1, 2, 1]]) / 4
ker_bayer_green = np.array([[0, 1, 0], [1, 4, 1], [0, 1, 0]]) / 4
# Computation of spectral differences
delta_red_green_quad = z[:, :, 0] - np.multiply(res[:, :, 1],op.mask[:,:,0])
delta_red_blue_quad = z[:, :, 0] - np.multiply(res[:, :, 2],op.mask[:,:,0])
delta_blue_green_quad = z[:, :, 2] - np.multiply(res[:, :, 1],op.mask[:,:,2])
delta_blue_red_quad = z[:, :, 2] - np.multiply(res[:, :, 0],op.mask[:,:,2])
delta_green_red_quad = z[:, :, 1] - np.multiply(res[:, :, 0],op.mask[:,:,1])
delta_green_blue_quad = z[:, :, 1] - np.multiply(res[:, :, 2],op.mask[:,:,1])
# Estimation
res_sd = np.empty(op.input_shape)
res_sd[:,:,0] = res[:, :, 1] + convolve2d(delta_red_green_quad,ker_bayer_red_blue,mode='same') + res[:, :, 2] + convolve2d(delta_red_blue_quad,ker_bayer_red_blue,mode='same')
res_sd[:,:,2] = res[:, :, 1] + convolve2d(delta_blue_green_quad,ker_bayer_red_blue,mode='same') + res[:, :, 0] + convolve2d(delta_blue_red_quad,ker_bayer_red_blue,mode='same')
res_sd[:,:,1] = res[:, :, 0] + convolve2d(delta_green_red_quad,ker_bayer_green,mode='same') + res[:, :, 2] + convolve2d(delta_green_blue_quad,ker_bayer_green,mode='same')
return res_sd
def normalization(res_sd:np.ndarray)-> np.ndarray:
"""Perform a min-max normalization
Args:
res_sd (np.ndarray): Demosaicked image.
Returns:
np.ndarray: Normalized image.
"""
res = (res_sd - np.min(res_sd)) / (np.max(res_sd) - np.min(res_sd))
return res
def quad_bayer_to_bayer_pattern(op: CFA):
"""Quad to Bayer pattern conversion by swapping method
Args:
op (CFA): CFA operator.
Returns:
CFA: Bayer pettern.
"""
if op.cfa == 'quad_bayer':
for j in range(1, op.mask.shape[1], 4):
op.mask[:,j], op.mask[:,j+1] = op.mask[:,j+1].copy(), op.mask[:,j].copy()
for i in range(1, op.mask.shape[0], 4):
op.mask[i, :], op.mask[i+1,:] = op.mask[i+1,:].copy(), op.mask[i,:].copy()
for i in range(1, op.mask.shape[0], 4):
for j in range(1, op.mask.shape[1], 4):
op.mask[i,j], op.mask[i+1,j+1] = op.mask[i+1,j+1].copy(), op.mask[i,j].copy()
return 0
def quad_bayer_to_bayer_image(y:np.array):
"""Quad to Bayer conversion of a mosaicked image by swapping method
Args:
y (np.array): Mosaicked image.
"""
for j in range(1, y.shape[1], 4):
y[:,j], y[:,j+1] = y[:,j+1].copy(), y[:,j].copy()
for i in range(1, y.shape[0], 4):
y[i, :], y[i+1,:] = y[i+1,:].copy(), y[i,:].copy()
for i in range(1, y.shape[0], 4):
for j in range(1, y.shape[1], 4):
y[i,j], y[i+1,j+1] = y[i+1,j+1].copy(), y[i,j].copy()
return 0
\ No newline at end of file
File added
"""A file containing the forward operator.
This file should NOT be modified.
"""
import numpy as np
from src.checks import check_cfa, check_rgb
class CFA():
def __init__(self, cfa: str, input_shape: tuple) -> None:
"""Constructor of the forward operator's class.
Args:
cfa (str): Name of the pattern. Either bayer or quad_bayer.
input_shape (tuple): Shape of the input images of the operator.
"""
check_cfa(cfa)
self.cfa = cfa
self.input_shape = input_shape
self.output_shape = input_shape[:-1]
if self.cfa == 'bayer':
self.mask = get_bayer_mask(input_shape)
elif self.cfa == 'quad_bayer':
self.mask = get_quad_bayer_mask(input_shape)
def direct(self, x: np.ndarray) -> np.ndarray:
"""Applies the CFA operation to the image x.
Args:
x (np.ndarray): Input image.
Returns:
np.ndarray: Output image.
"""
check_rgb(x)
return np.sum(x * self.mask, axis=2)
def adjoint(self, y: np.ndarray) -> np.ndarray:
"""Applies the adjoint of the CFA operation.
Args:
y (np.ndarray): Input image.
Returns:
np.ndarray: Output image.
"""
return self.mask * y[..., np.newaxis]
def get_bayer_mask(input_shape: tuple) -> np.ndarray:
"""Return the mask of the Bayer CFA.
Args:
input_shape (tuple): Shape of the mask.
Returns:
np.ndarray: Mask.
"""
res = np.kron(np.ones((input_shape[0], input_shape[1], 1)), [0, 1, 0])
res[::2, 1::2] = [1, 0, 0]
res[1::2, ::2] = [0, 0, 1]
return res
def get_quad_bayer_mask(input_shape: tuple) -> np.ndarray:
"""Return the mask of the quad_bayer CFA.
Args:
input_shape (tuple): Shape of the mask.
Returns:
np.ndarray: Mask.
"""
res = np.kron(np.ones((input_shape[0], input_shape[1], 1)), [0, 1, 0])
res[::4, 2::4] = [1, 0, 0]
res[::4, 3::4] = [1, 0, 0]
res[1::4, 2::4] = [1, 0, 0]
res[1::4, 3::4] = [1, 0, 0]
res[2::4, ::4] = [0, 0, 1]
res[2::4, 1::4] = [0, 0, 1]
res[3::4, ::4] = [0, 0, 1]
res[3::4, 1::4] = [0, 0, 1]
return res
####
####
####
#### #### #### #############
#### ###### #### ##################
#### ######## #### ####################
#### ########## #### #### ########
#### ############ #### #### ####
#### #### ######## #### #### ####
#### #### ######## #### #### ####
#### #### ######## #### #### ####
#### #### ## ###### #### #### ######
#### #### #### ## #### #### ############
#### #### ###### #### #### ##########
#### #### ########## #### #### ########
#### #### ######## #### ####
#### #### ############ ####
#### #### ########## ####
#### #### ######## ####
#### #### ###### ####
# 2023
# Authors: Mauro Dalla Mura and Matthieu Muller