{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Kelompok 1\nChaesa Adella Rahma      (2107411003)\n\nMarwah Nur Shafira       (2107411008)\n\nCut Azimah Noor Hanifah  (2107411014)\n\nAnnisa Marfadilla        (2107411019)\n\nSarah Humaira            (2107411023)\n\n# COVID 19 - Image Enhancement","metadata":{}},{"cell_type":"code","source":"# !conda install '/kaggle/input/pydicom-conda-helper/libjpeg-turbo-2.1.0-h7f98852_0.tar.bz2' -c conda-forge -y\n# !conda install '/kaggle/input/pydicom-conda-helper/libgcc-ng-9.3.0-h2828fa1_19.tar.bz2' -c conda-forge -y\n# !conda install '/kaggle/input/pydicom-conda-helper/gdcm-2.8.9-py37h500ead1_1.tar.bz2' -c conda-forge -y\n# !conda install '/kaggle/input/pydicom-conda-helper/conda-4.10.1-py37h89c1867_0.tar.bz2' -c conda-forge -y\n# !conda install '/kaggle/input/pydicom-conda-helper/certifi-2020.12.5-py37h89c1867_1.tar.bz2' -c conda-forge -y\n# !conda install '/kaggle/input/pydicom-conda-helper/openssl-1.1.1k-h7f98852_0.tar.bz2' -c conda-forge -y","metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# untuk komputasi numerik. seperti konversi list menjadi array, menghitung statistik, dan memanipulasi array\nimport numpy as np \n\n# untuk melakukan analisis dan manipulasi data terstruktur, terutama dalam bentuk DataFrame.\nimport pandas as pd\n\n# untuk berinteraksi dengan sistem operasi. Untuk mengakses variabel lingkungan, mengubah direktori kerja, membuat direktori, menghapus berkas, dsb\nimport os\n\n# visualisasi data statistik yang lebih menarik dan informatif, dengan fitur tambahan di atas matplotlib\nimport seaborn as sns\n\n# membuat plot dan visualisasi data\nimport matplotlib.pyplot as plt\n\n# menggambar berbagai bentuk dan objek geometris pada plot\nimport matplotlib.patches as patches\n\n# menampilkan plot secara langsung di dalam notebook\n%matplotlib inline\n\n# mencocokkan dan mengambil file atau direktori dengan pola tertentu\nimport glob\n\n# membaca dan memanipulasi file-format DICOM, yang umumnya digunakan dalam bidang medis untuk menyimpan gambar dan data medis\nimport pydicom\n\n# menerapkan Lookup Table (LUT) untuk meningkatkan visualisasi gambar DICOM\nfrom pydicom.pixel_data_handlers.util import apply_voi_lut\n\n# memanipulasi gambar, seperti membuka, mengubah ukuran, dan menyimpan gambar\nfrom PIL import Image\n\n# menggunakannya untuk membaca, menulis, dan memanipulasi gambar, mengaplikasikan filter dan efek, melakukan deteksi objek, dsb\nimport cv2 as cv\n\n# menghasilkan angka acak\nimport random \n\n# manipulasi gambar, seperti membaca, menyimpan, dan memanipulasi gambar dalam berbagai format\nimport scipy.misc\n\nrandom.seed(42)","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2023-07-12T15:51:02.741304Z","iopub.execute_input":"2023-07-12T15:51:02.741819Z","iopub.status.idle":"2023-07-12T15:51:02.753930Z","shell.execute_reply.started":"2023-07-12T15:51:02.741777Z","shell.execute_reply":"2023-07-12T15:51:02.753069Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"TARGET_SIZE = 512\n\n# 'dicom2array' mengonversi file DICOM menjadi array yang merepresentasikan gambar\ndef dicom2array(path, voi_lut = True, fix_monochrome = True):\n    \"\"\"\n    Transform a dicom file to an array.\n    \n    - path : path of the dicom file\n    - voi_lut : Apply VOI LUT transformation\n    - fix_monochrome : Indicate if we fix the pixel value for specific files.\n    \n    VOI LUT (Value of Interest - Look Up Table) : The idea is to have a larger representation of the data.\n    Since, dicom files have larger pixel display range than usuall pictures. The idea is to keep a larger representation in order ot better see the subtle differences.\n    \n    Fix Monochrome : Some images have MONOCHROME1 interpretation. Which means that higher pixel values corresponding to the dark instead of the white.\n    \"\"\"\n    dicom = pydicom.read_file(path)\n    \n    # Apply the VOI LUT\n    if voi_lut:\n        data = apply_voi_lut(dicom.pixel_array, dicom)\n    else:\n        data = dicom.pixel_array\n        \n    # Fix the representation\n    if fix_monochrome and dicom.PhotometricInterpretation == \"MONOCHROME1\":\n        data = np.amax(data) - data\n    \n    data = data - np.min(data)\n    data = data / np.max(data)\n    \n    data = data * 255\n    \n    data = data.astype(np.uint8)\n    \n    return data\n\ndef img_vizualisation(imgs, nb_samples = 5):\n    \n    fig, axes = plt.subplots(nrows=nb_samples // 5, ncols=min(5, nb_samples), figsize=(min(5, nb_samples) * 4, 4 * (nb_samples // 5)))\n    i = 0\n    for img in imgs:\n        axes[i // 5, i % 5].imshow(np.array(img), cmap=plt.cm.gray, aspect='auto')\n        axes[i // 5, i % 5].axis('off')\n        i += 1\n    fig.show()    \n","metadata":{"execution":{"iopub.status.busy":"2023-07-12T15:51:07.118808Z","iopub.execute_input":"2023-07-12T15:51:07.119443Z","iopub.status.idle":"2023-07-12T15:51:07.130161Z","shell.execute_reply.started":"2023-07-12T15:51:07.119385Z","shell.execute_reply":"2023-07-12T15:51:07.129330Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Sample visualization\n\nTo see the different techniques, we will have a sample set that will serve as a reference.","metadata":{}},{"cell_type":"code","source":"TRAIN_PATH = \"../input/siim-covid19-detection/train/\"\n\n# `glob.glob()` digunakan untuk mencari file dengan ekstensi .dcm dalam direktori yang ditentukan oleh `TRAIN_PATH`.\npaths = glob.glob(TRAIN_PATH + \"*/*/*.dcm\")","metadata":{"execution":{"iopub.status.busy":"2023-07-12T15:51:10.371640Z","iopub.execute_input":"2023-07-12T15:51:10.372404Z","iopub.status.idle":"2023-07-12T15:52:01.247937Z","shell.execute_reply.started":"2023-07-12T15:51:10.372362Z","shell.execute_reply":"2023-07-12T15:52:01.246626Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sampled_path = random.sample(paths, 10)\n\nsamples = []\nfor path in sampled_path:\n    img = dicom2array(path)\n    samples.append(img)","metadata":{"execution":{"iopub.status.busy":"2023-07-12T15:52:04.474884Z","iopub.execute_input":"2023-07-12T15:52:04.475558Z","iopub.status.idle":"2023-07-12T15:52:07.226146Z","shell.execute_reply.started":"2023-07-12T15:52:04.475511Z","shell.execute_reply":"2023-07-12T15:52:07.224758Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Fuzzification of Pixel Intensity","metadata":{}},{"cell_type":"code","source":"# Gaussian Function:\ndef G(x, mean, std):\n    return np.exp(-0.5*np.square((x-mean)/std))\n\n# Membership Functions:\ndef ExtremelyDark(x, M):\n    return G(x, -50, M/6)\n\ndef VeryDark(x, M):\n    return G(x, 0, M/6)\n\ndef Dark(x, M):\n    return G(x, M/2, M/6)\n\ndef SlightlyDark(x, M):\n    return G(x, 5*M/6, M/6)\n\ndef SlightlyBright(x, M):\n    return G(x, M+(255-M)/6, (255-M)/6)\n\ndef Bright(x, M):\n    return G(x, M+(255-M)/2, (255-M)/6)\n\ndef VeryBright(x, M):\n    return G(x, 255, (255-M)/6)\n\ndef ExtremelyBright(x, M):\n    return G(x, 305, (255-M)/6)","metadata":{"execution":{"iopub.status.busy":"2023-07-12T15:52:09.687633Z","iopub.execute_input":"2023-07-12T15:52:09.688251Z","iopub.status.idle":"2023-07-12T15:52:09.701096Z","shell.execute_reply.started":"2023-07-12T15:52:09.688196Z","shell.execute_reply":"2023-07-12T15:52:09.699293Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Rule SET\n\n* IF input is VeryDark THEN output is ExtremelyDark\n* IF input is Dark THEN output is VeryDark\n* IF input is SlightlyDark THEN output is Dark\n* IF input is SlightlyBright THEN output is Bright\n* IF input is Bright THEN output is VeryBright\n* IF input is VeryBright THEN output is ExtremelyBright","metadata":{}},{"cell_type":"markdown","source":"# Inference and Defuzzication (Tsukamoto's method)","metadata":{}},{"cell_type":"code","source":"def TsukamotoOutputFuzzySet(x, f, M):\n    x = np.array(x)\n    result = f(x, M)\n    return result\n\ndef TsukamotoInfer(i, M, get_fuzzy_set=False):\n    # Calculate degree of membership for each class\n    VD = VeryDark(i, M)\n    Da = Dark(i, M)\n    SD = SlightlyDark(i, M)\n    SB = SlightlyBright(i, M)\n    Br = Bright(i, M)\n    VB = VeryBright(i, M)\n    \n    # Fuzzy Inference:\n    x = np.arange(-50, 306)\n    Inferences = (\n        TsukamotoOutputFuzzySet(x, ExtremelyDark, M),\n        TsukamotoOutputFuzzySet(x, VeryDark, M),\n        TsukamotoOutputFuzzySet(x, Dark, M),\n        TsukamotoOutputFuzzySet(x, Bright, M),\n        TsukamotoOutputFuzzySet(x, VeryBright, M),\n        TsukamotoOutputFuzzySet(x, ExtremelyBright, M)\n    )\n    \n    # Calculate aggregated fuzzy set\n    fuzzy_output = np.zeros_like(x)\n    weights = [VD, Da, SD, SB, Br, VB]  # Define the weights for each fuzzy set\n    for i in range(len(Inferences)):\n        fuzzy_output = np.maximum(fuzzy_output, np.minimum(Inferences[i], weights[i]))\n    \n    # Calculate crisp value of centroid\n    if get_fuzzy_set:\n        return np.average(x, weights=fuzzy_output), fuzzy_output\n    return np.average(x, weights=fuzzy_output)","metadata":{"execution":{"iopub.status.busy":"2023-07-12T15:52:12.389085Z","iopub.execute_input":"2023-07-12T15:52:12.389493Z","iopub.status.idle":"2023-07-12T15:52:12.401601Z","shell.execute_reply.started":"2023-07-12T15:52:12.389444Z","shell.execute_reply":"2023-07-12T15:52:12.400226Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def FuzzyContrastEnhance(gray):\n    # Precompute the fuzzy transform\n    x = np.arange(-50, 306)\n    FuzzyTransform = TsukamotoInfer(x, 127, get_fuzzy_set=True)\n\n    # Resize the fuzzy sets to match the size of the grayscale image\n    resized_fuzzy_sets = np.array([cv.resize(fuzzy_set, gray.shape[::-1]) for fuzzy_set in FuzzyTransform[1]])\n\n    # Apply the transform to the grayscale image\n    enhanced = np.array([TsukamotoDefuzzification(fuzzy) for fuzzy in resized_fuzzy_sets])\n\n    # Reshape the enhanced array to match the shape of the gray image\n    enhanced = enhanced.reshape(gray.shape)\n\n    # Min-max scale the output image to fit (0, 255)\n    Min = np.min(enhanced)\n    Max = np.max(enhanced)\n    enhanced = (enhanced - Min) / (Max - Min) * 255\n\n    # Convert the enhanced image to uint8 type\n    enhanced = enhanced.astype(np.uint8)\n\n    return enhanced\n\ndef TsukamotoDefuzzification(fuzzy_set):\n    crisp_value = np.argmax(fuzzy_set)\n    return crisp_value","metadata":{"execution":{"iopub.status.busy":"2023-07-12T15:52:19.078859Z","iopub.execute_input":"2023-07-12T15:52:19.079705Z","iopub.status.idle":"2023-07-12T15:52:19.090224Z","shell.execute_reply.started":"2023-07-12T15:52:19.079632Z","shell.execute_reply":"2023-07-12T15:52:19.089217Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Implementation","metadata":{}},{"cell_type":"code","source":"img_example = samples[2]\n\n# Fungsi `cv.equalizeHist()` digunakan untuk menerapkan teknik Histogram Equalization pada gambar `img_example`.\n# Histogram Equalization adalah teknik pengolahan citra yang digunakan untuk meningkatkan kontras dan distribusi nilai piksel dalam gambar.\nimg_example_hist = cv.equalizeHist(img_example)\nimg_fuzzy = FuzzyContrastEnhance(img_example)\n\nfig, (ax1, ax2) = plt.subplots(1, 2, figsize=(20, 10))\n\nax1.imshow(img_example, cmap=plt.cm.gray)\nax1.axis('off')\nax1.set_title(\"Original image\")\n\nax2.imshow(img_fuzzy, cmap=plt.cm.gray)\nax2.axis('off')\nax2.set_title(\"Fuzzy applied on the original image\")\n\nfig.show()","metadata":{"execution":{"iopub.status.busy":"2023-07-12T15:52:23.863778Z","iopub.execute_input":"2023-07-12T15:52:23.864596Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## References \n\n- https://en.wikipedia.org/wiki/Histogram_equalization\n- https://docs.opencv.org/master/d5/daf/tutorial_py_histogram_equalization.html\n- https://www.ndt.net/article/icem2004/papers/64/64.htm\n- https://medium.com/@florestony5454/median-filtering-with-python-and-opencv-2bce390be0d1\n","metadata":{}}]}