diff --git a/Deblur_Algorithm.py b/Deblur_Algorithm.py
new file mode 100644
index 0000000000000000000000000000000000000000..adef6d9e0f3f2cb84925889357a42f7d0bb2348b
--- /dev/null
+++ b/Deblur_Algorithm.py
@@ -0,0 +1,151 @@
+"""
+Deblur Algorithm
+
+input image : F16.tiff
+filters : Mean Filter, Gaussian Filter
+paddings : zero, replicate, mirror
+"""
+
+import cv2
+import numpy as np
+import matplotlib.pyplot as plt
+from scipy.sparse import csr_matrix
+from scipy.sparse.linalg import spsolve
+from datetime import datetime
+from pytz import timezone
+
+# calculate global matrix M in CSR format
+def M(input_data, filter_data, stride):
+    num_elements= n*m*filter_data.size
+    # allocate memory for data, row indices, column indices
+    data=np.zeros(num_elements)
+    row_indices= np.zeros(num_elements, dtype=int)
+    col_indices= np.zeros(num_elements, dtype=int)
+    # initialize counters for data storage
+    count_i = 0 # for row indices
+    count_data=0 # for the current position
+    # operation for convolution 
+    for i in range(0, input_data.shape[0] - filter_data.shape[0] + 1, stride):
+        for j in range(0, input_data.shape[1] - filter_data.shape[1] + 1, stride):
+            tmp = np.array(input_data[i:i + filter_data.shape[0], j:j + filter_data.shape[1]]).ravel()
+            tmp2 = np.nonzero(tmp)[0]
+            for k in range(len(tmp2)):
+                data[count_data]= filter_data.ravel()[tmp2[k]]
+                row_indices[count_data]= count_i
+                col_indices[count_data]= tmp[tmp2[k]] - 1
+                count_data +=1
+            count_i += 1
+    data= data[:count_data]
+    row_indices=row_indices[:count_data]
+    col_indices=col_indices[:count_data]
+    result_sparse = csr_matrix((data, (row_indices, col_indices)), shape=(n * m, n * m)) #store in CSR format
+    return result_sparse
+
+# solve MX=Y using spsolve 
+def solve(M_sparse, img_blur):
+    try:
+        Y = np.array(img_blur)
+        img_deblur = spsolve(M_sparse, Y.ravel())
+        img_deblur = np.reshape(img_deblur, (n, m))
+    # if inverse matrix doesn't exists, exit the program
+    except (np.linalg.LinAlgError, RuntimeError): 
+        img_deblur = np.zeros((n, m))
+        print("Inverse of M does not exist.")
+        exit()
+    return img_deblur
+
+# calculate errors 
+def InfNorm(A, B):
+    if A.shape != B.shape:
+        raise ValueError("The shapes of two matrixes must be the same")
+    diff = np.abs(A - B)
+    infnorm = np.max((diff))
+    return infnorm
+
+def apply_filter_and_deblur(img, K):
+    # blur using openCV
+    if border == 0:
+        img_blur = cv2.filter2D(img, -1, K, borderType=cv2.BORDER_CONSTANT)
+    elif border == 1:
+        img_blur = cv2.filter2D(img, -1, K, borderType=cv2.BORDER_REPLICATE)
+    elif border == 2:
+        img_blur = cv2.filter2D(img, -1, K, borderType=cv2.BORDER_REFLECT_101)
+    # calculate M
+    M_sparse = M(border_X, K, 1)
+    # solve MX=Y using spsolve
+    img_deblur = solve(M_sparse, img_blur)
+    # calculate errors between original image and deblurred image
+    error = InfNorm(img128, img_deblur)
+    return img_blur, img_deblur, error
+
+# input image
+img = cv2.imread("images/F16.tiff", cv2.IMREAD_GRAYSCALE)
+img128 = cv2.resize(img, (128, 128))
+img128 = img128.astype(np.float64)/255.0 # image normalization
+
+# show results using matplotlib
+fig = plt.figure()
+rows = 1
+cols = 3
+
+# result 1. original image
+ax1 = fig.add_subplot(rows, cols, 1)
+ax1.imshow(img128, cmap='gray')
+ax1.set_title('F16')
+ax1.axis("off")
+
+n, m = 128, 128
+X = (np.arange(1, n * m + 1)).reshape(n, m) 
+
+# choose the padding type
+border_type = ['zero', 'replicate', 'mirror']
+border = int(input(f"{border_type[:]}(Choose from 0-2) : " ))
+if border == 0: # zero padding
+    border_X = np.pad(X, ((1, 1), (1, 1)), mode='constant', constant_values=0) 
+elif border == 1: # replicate padding
+    border_X = np.pad(X, ((1, 1), (1, 1)), mode='edge')
+elif border == 2: # mirror padding
+    border_X = np.pad(X, ((1, 1), (1, 1)), mode='reflect')
+
+# choose the filter type 
+filter_type = ['Mean', 'Gaussian']
+kernel_size = 3
+kernel = int(input(f"{filter_type[:]}(Choose from 0-1) : " ))
+if kernel == 0: # Mean filter
+    K = np.ones((kernel_size,kernel_size),np.float64)/(kernel_size*kernel_size)
+    img_blur, img_deblur, min_error = apply_filter_and_deblur(img128, K)
+elif kernel == 1: # Gaussian filter
+    min_error = float('inf')
+    best_sigma = None
+    sigma_values = np.arange(1, 101, 1)
+    # find best sigma values
+    for sigma in sigma_values:
+        tmp3 = cv2.getGaussianKernel(kernel_size, sigma)
+        K = np.outer(tmp3, tmp3.T)
+        img_blur, img_deblur, error = apply_filter_and_deblur(img128, K)
+        if error < min_error:
+            min_error = error
+            best_sigma = sigma
+            best_deblur = img_deblur
+    img_deblur = best_deblur
+    print("Best sigma value: ", best_sigma)
+
+# result 2. blurred image using openCV
+ax2 = fig.add_subplot(rows, cols, 2)
+ax2.imshow(img_blur, cmap='gray')
+ax2.set_title(f'{filter_type[kernel]}')
+ax2.axis("off")
+
+#result 3. deblurred image using M()
+ax3 = fig.add_subplot(rows, cols, 3)
+ax3.imshow(img_deblur, cmap='gray')
+ax3.set_title('Deblur')
+ax3.axis("off")
+
+# print error
+print("Error:", min_error)
+
+# save results
+date_today = datetime.now(timezone('Asia/Seoul')).strftime("%Y%m%d_%H%M")
+plt.savefig('Results/{}.jpg'.format(date_today), format='jpg')
+plt.close()
\ No newline at end of file
diff --git a/F16.tiff b/F16.tiff
new file mode 100644
index 0000000000000000000000000000000000000000..8d0769987d66cc7c66d8e157d26403eca57b4b62
Binary files /dev/null and b/F16.tiff differ