diff --git a/src/methods/TheoLafond/Image analysis report.pdf b/src/methods/TheoLafond/Image analysis report.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..8a940fef84bc9758e54616af1c175af3a1b98c41
Binary files /dev/null and b/src/methods/TheoLafond/Image analysis report.pdf differ
diff --git a/reconstruct.py b/src/methods/TheoLafond/reconstruct.py
similarity index 69%
rename from reconstruct.py
rename to src/methods/TheoLafond/reconstruct.py
index f2d99e31008448a850e27c7dcf6fe110d179cac5..4d831a1e0f67437b2e0d9f73a5861b47bd822022 100644
--- a/reconstruct.py
+++ b/src/methods/TheoLafond/reconstruct.py
@@ -13,10 +13,15 @@ from src.forward_model import CFA
 
 
 def regression_filter_func(chans):
-    """_summary_
+    """computes the linear regression coefficients between channel :
+    red and green
+    blue and green
+    green and red
+    green and blue
 
 
     Returns:
+        a is high order coef and b is 0 order.
         _type_: a_red, b_red, a_blue, b_blue, a_green_red, b_green_red, a_green_blue, b_green_blue
     """
     red = chans[:,:,0].flatten()
@@ -27,7 +32,7 @@ def regression_filter_func(chans):
     return np.concatenate((np.polyfit(red[nonzeros_red], green[nonzeros_red], deg=1), np.polyfit(blue[nonzeros_blue], green[nonzeros_blue], deg=1), np.polyfit(green[nonzeros_red], red[nonzeros_red], deg=1), np.polyfit(green[nonzeros_blue], blue[nonzeros_blue], deg=1)), axis=0)
 
 def personal_generic_filter(a, func, footprint, output, msg=""):
-    """Computes the regression filter on the input channel between the red with the green as a guide and the blue with the green as a guide.
+    """Apply func on each footprint of a.
     """
 
     # Suppress RankWarning
@@ -51,6 +56,36 @@ def personal_generic_filter(a, func, footprint, output, msg=""):
                 fen[:i_end-i_start, :j_end-j_start] = a[i_start:i_end, j_start:j_end]
                 output[i, j, :] = func(a[i_start:i_end, j_start:j_end])
 
+def combine_directions(bh,bv):
+    combo = np.zeros(bh.shape)
+    combo[:,:,0] = bh[:,:,0] + bv[:,:,0]
+    combo[:,:,0][(bh[:,:,0]!=0) * (bv[:,:,0]!=0)] = (bh[:,:,0][(bh[:,:,0]!=0) * (bv[:,:,0]!=0)] + bv[:,:,0][(bh[:,:,0]!=0) * (bv[:,:,0]!=0)])/2
+    combo[:,:,0][(bh[:,:,0]==0) * (bv[:,:,0]==0)] = 0
+
+    combo[:,:,1] = bh[:,:,1]/2 + bv[:,:,1]/2
+    combo[:,:,2] = bh[:,:,2] + bv[:,:,2]
+    combo[:,:,2][(bh[:,:,2]!=0) * (bv[:,:,2]!=0)] = (bh[:,:,2][(bh[:,:,2]!=0) * (bv[:,:,2]!=0)] + bv[:,:,2][(bh[:,:,2]!=0) * (bv[:,:,2]!=0)])/2
+    combo[:,:,2][(bh[:,:,2]==0) * (bv[:,:,2]==0)] = 0
+    
+
+    for i in range(combo.shape[0]):
+        for j in range(combo.shape[1]):
+            moy = []
+            if i != 0 :
+                moy.append(combo[i-1,j,:])
+            if i != combo.shape[0]-1 :
+                moy.append(combo[i+1,j,:])
+            if j != 0 :
+                moy.append(combo[i,j-1,:])
+            if j != combo.shape[1]-1 :
+                moy.append(combo[i,j+1,:])
+            moy = np.stack(moy).mean(axis=0)
+            if combo[i,j,0] == 0:
+                combo[i,j,0] = moy[0]
+            if combo[i,j,2] == 0:
+                combo[i,j,2] = moy[2]
+    return combo
+
 
 def run_reconstruction(y: np.ndarray, cfa: str) -> np.ndarray:
     """Performs demosaicking on y.
@@ -63,7 +98,7 @@ def run_reconstruction(y: np.ndarray, cfa: str) -> np.ndarray:
         np.ndarray: Demosaicked image.
     """
     # Performing the reconstruction.
-    # TODO
+
     input_shape = (y.shape[0], y.shape[1], 3)
     op = CFA(cfa, input_shape)
     adjoint = op.adjoint(y)
@@ -86,85 +121,57 @@ def run_reconstruction(y: np.ndarray, cfa: str) -> np.ndarray:
                 continue
             bv[:, j, i] = np.interp(np.arange(adjoint.shape[0]), non_zero, adjoint[:, j, i][non_zero])
 
-    
-
     # Residuals interpolation
-    K = 1
-    for k in range(K):
-        M = 3
-        N = 5
-        kernel_hor = np.ones((M, N))/(M*N)
-        kernel_ver = np.ones((N, M))/(M*N)
-
-        # Horizontal Regression filtering
-        regh = np.zeros((bh.shape[0], bh.shape[1], 8))
-        personal_generic_filter(bh, regression_filter_func, kernel_hor, regh,msg="Regression filtering horizontal #"+str(k+1)+"/"+str(K))
-        ch = np.zeros(bh.shape)
-        for i in range(regh.shape[-1]):
-            regh[:, :, i] = convolve(regh[:, :, i], kernel_hor)
-        ch[:,:,0] = regh[:,:,0]*bh[:,:,0] + regh[:,:,1]
-        ch[:,:,1] = regh[:,:,2]*bh[:,:,1] + regh[:,:,3]
-        ch[:,:,2] = regh[:,:,4]*bh[:,:,2] + regh[:,:,5] + regh[:,:,6]*bh[:,:,2] + regh[:,:,7]
-        dh = adjoint - ch
-        dh[adjoint==0] = 0
-        # interpolation
-        for i in range(3):
-            for j in range(adjoint.shape[0]):
-                non_zero = np.nonzero(adjoint[j, :, i])[0]
-                if len(non_zero) == 0:
-                    continue
-                ch[j, :, i] += np.interp(np.arange(adjoint.shape[1]), non_zero, adjoint[j, :, i][non_zero])
-        bh = ch.copy()
-
-        # Vertical Regression filtering
-        regv = np.zeros((bv.shape[0], bv.shape[1], 8))
-        personal_generic_filter(bv, regression_filter_func, kernel_ver, regv,msg="Regression filtering vertical #"+str(k+1))
-        cv = np.zeros(bv.shape)
-        for i in range(regv.shape[-1]):
-            regv[:, :, i] = convolve(regv[:, :, i], kernel_ver)
-        cv[:,:,0] = regv[:,:,0]*bv[:,:,0] + regv[:,:,1]
-        cv[:,:,1] = regv[:,:,2]*bv[:,:,1] + regv[:,:,3]
-        cv[:,:,2] = regv[:,:,4]*bv[:,:,2] + regv[:,:,5] + regv[:,:,6]*bv[:,:,2] + regv[:,:,7]
-        dv = adjoint - cv
-        dv[adjoint==0] = 0
-        # interpolation
-        for i in range(3):
-            for j in range(adjoint.shape[1]):
-                non_zero = np.nonzero(adjoint[:, j, i])[0]
-                if len(non_zero) == 0:
-                    continue
-                cv[:, j, i] += np.interp(np.arange(adjoint.shape[0]), non_zero, adjoint[:, j, i][non_zero])
-        bv = cv.copy()
-
-    combo = np.zeros(adjoint.shape)
-    combo[:,:,0] = bh[:,:,0] + bv[:,:,0]
-    combo[:,:,0][(bh[:,:,0]!=0) * (bv[:,:,0]!=0)] = (bh[:,:,0][(bh[:,:,0]!=0) * (bv[:,:,0]!=0)] + bv[:,:,0][(bh[:,:,0]!=0) * (bv[:,:,0]!=0)])/2
-    combo[:,:,0][(bh[:,:,0]==0) * (bv[:,:,0]==0)] = 0
-
-    combo[:,:,1] = bh[:,:,1]/2 + bv[:,:,1]/2
-    combo[:,:,2] = bh[:,:,2] + bv[:,:,2]
-    combo[:,:,2][(bh[:,:,2]!=0) * (bv[:,:,2]!=0)] = (bh[:,:,2][(bh[:,:,2]!=0) * (bv[:,:,2]!=0)] + bv[:,:,2][(bh[:,:,2]!=0) * (bv[:,:,2]!=0)])/2
-    combo[:,:,2][(bh[:,:,2]==0) * (bv[:,:,2]==0)] = 0
-    
+    M = 3
+    N = 5
+    kernel_hor = np.ones((M, N))/(M*N)
+    kernel_ver = np.ones((N, M))/(M*N)
+
+    # Horizontal Regression filtering
+    regh = np.zeros((bh.shape[0], bh.shape[1], 8))
+    personal_generic_filter(bh, regression_filter_func, kernel_hor, regh,msg="Regression filtering horizontal")
+    ch = np.zeros(bh.shape)
+    for i in range(regh.shape[-1]):
+        regh[:, :, i] = convolve(regh[:, :, i], kernel_hor)
+    ch[:,:,0] = regh[:,:,0]*bh[:,:,0] + regh[:,:,1]
+    ch[:,:,1] = (regh[:,:,4]*bh[:,:,1] + regh[:,:,5] + regh[:,:,6]*bh[:,:,1] + regh[:,:,7])/2
+    ch[:,:,2] = regh[:,:,2]*bh[:,:,2] + regh[:,:,3]
+    # return ch[:,:,1]
+    dh = ch - adjoint
+    dh[adjoint==0] = 0
+    # interpolation
+    for i in range(3):
+        for j in range(adjoint.shape[0]):
+            non_zero = np.nonzero(dh[j, :, i])[0]
+            if len(non_zero) == 0:
+                continue
+            ch[j, :, i] -= np.interp(np.arange(adjoint.shape[1]), non_zero, dh[j, :, i][non_zero])
+    ch[bh == 0] = 0
+    bh = ch.copy()
+    # return bh[:,:,0]
+
+    # Vertical Regression filtering
+    regv = np.zeros((bv.shape[0], bv.shape[1], 8))
+    personal_generic_filter(bv, regression_filter_func, kernel_ver, regv,msg="Regression filtering vertical")
+    cv = np.zeros(bv.shape)
+    for i in range(regv.shape[-1]):
+        regv[:, :, i] = convolve(regv[:, :, i], kernel_ver)
+    cv[:,:,0] = regv[:,:,0]*bv[:,:,0] + regv[:,:,1]
+    cv[:,:,1] = (regv[:,:,4]*bv[:,:,1] + regv[:,:,5] + regv[:,:,6]*bv[:,:,1] + regv[:,:,7])/2
+    cv[:,:,2] = regv[:,:,2]*bv[:,:,2] + regv[:,:,3]
+    dv = cv - adjoint
+    dv[adjoint==0] = 0
+    # interpolation
+    for i in range(3):
+        for j in range(adjoint.shape[1]):
+            non_zero = np.nonzero(dv[:, j, i])[0]
+            if len(non_zero) == 0:
+                continue
+            cv[:, j, i] -= np.interp(np.arange(adjoint.shape[0]), non_zero, dv[:, j, i][non_zero])
+    cv[bv == 0] = 0
+    bv = cv.copy()
 
-    for i in range(combo.shape[0]):
-        for j in range(combo.shape[1]):
-            moy = []
-            if i != 0 :
-                moy.append(combo[i-1,j,:])
-            if i != combo.shape[0]-1 :
-                moy.append(combo[i+1,j,:])
-            if j != 0 :
-                moy.append(combo[i,j-1,:])
-            if j != combo.shape[1]-1 :
-                moy.append(combo[i,j+1,:])
-            moy = np.stack(moy).mean(axis=0)
-            if combo[i,j,0] == 0:
-                combo[i,j,0] = moy[0]
-            if combo[i,j,2] == 0:
-                combo[i,j,2] = moy[2]
-    
-    return combo
+    return combine_directions(bh,bv)
 
     
 
@@ -172,16 +179,16 @@ def run_reconstruction(y: np.ndarray, cfa: str) -> np.ndarray:
 if __name__ == "__main__":
     from src.utils import load_image, save_image, psnr, ssim
     from src.forward_model import CFA
-    image_path = 'images/img_1.png'
+    image_path = 'images/img_4.png'
 
-    img = load_image(image_path)[:256,:256,:]
+    img = load_image(image_path)
 
     cfa_name = 'bayer' # bayer or quad_bayer
     op = CFA(cfa_name, img.shape)
     y = op.direct(img)
     res = run_reconstruction(y, cfa_name)
-    # print('PSNR:', psnr(img, res))
-    # print('SSIM:', ssim(img, res))
+    print('PSNR:', psnr(img, res))
+    print('SSIM:', ssim(img, res))
     save_image('output/bh.png', res)