{"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":"code","source":"import pandas as pd\nimport numpy as np\nimport os\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport cv2 as cv\n\nimport PIL.Image as Image\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.preprocessing import LabelEncoder\n\nimport tensorflow as tf\nfrom tensorflow.keras.layers import Dense, MaxPooling2D, Dropout, Conv2D, Flatten\nfrom tensorflow.keras.callbacks import EarlyStopping\nfrom keras.models import Sequential\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-11-10T11:34:20.970016Z","iopub.execute_input":"2023-11-10T11:34:20.970288Z","iopub.status.idle":"2023-11-10T11:34:31.184213Z","shell.execute_reply.started":"2023-11-10T11:34:20.970262Z","shell.execute_reply":"2023-11-10T11:34:31.183211Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Loading the Dataset","metadata":{}},{"cell_type":"code","source":"train_csv = pd.read_csv('/kaggle/input/UBC-OCEAN/train.csv')\ntrain_csv.tail()","metadata":{"execution":{"iopub.status.busy":"2023-11-10T11:34:31.186182Z","iopub.execute_input":"2023-11-10T11:34:31.186984Z","iopub.status.idle":"2023-11-10T11:34:31.214933Z","shell.execute_reply.started":"2023-11-10T11:34:31.18694Z","shell.execute_reply":"2023-11-10T11:34:31.214082Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_csv[[\"image_width\", \"image_height\"]].describe()","metadata":{"execution":{"iopub.status.busy":"2023-11-10T11:34:31.215933Z","iopub.execute_input":"2023-11-10T11:34:31.216184Z","iopub.status.idle":"2023-11-10T11:34:31.240441Z","shell.execute_reply.started":"2023-11-10T11:34:31.216162Z","shell.execute_reply":"2023-11-10T11:34:31.239376Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"path_folder = \"/kaggle/input/UBC-OCEAN/train_images\"\nimg_files = [os.path.join(path_folder, \n                          f\"{str(f[1][0])}_thumbnail.png\") for f in train_csv.iterrows()]\n\ntrain_csv['path'] = pd.Series(img_files).astype(str)\ntrain_csv.tail()","metadata":{"execution":{"iopub.status.busy":"2023-11-10T11:34:31.242904Z","iopub.execute_input":"2023-11-10T11:34:31.243171Z","iopub.status.idle":"2023-11-10T11:34:31.289942Z","shell.execute_reply.started":"2023-11-10T11:34:31.243148Z","shell.execute_reply":"2023-11-10T11:34:31.288963Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"istma_false = train_csv[train_csv[\"is_tma\"]==False]\nprint(len(istma_false))\nistma_false.tail()","metadata":{"execution":{"iopub.status.busy":"2023-11-10T11:34:31.290968Z","iopub.execute_input":"2023-11-10T11:34:31.291302Z","iopub.status.idle":"2023-11-10T11:34:31.303703Z","shell.execute_reply.started":"2023-11-10T11:34:31.291273Z","shell.execute_reply":"2023-11-10T11:34:31.302818Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Preprocessing","metadata":{}},{"cell_type":"markdown","source":"## Cropping the Images","metadata":{}},{"cell_type":"markdown","source":"### Example of a cropped image (e.g crop (500,500))","metadata":{}},{"cell_type":"code","source":"# Sample\nex = \"/kaggle/input/UBC-OCEAN/train_thumbnails/4_thumbnail.png\"\nimg = Image.open(ex)\ngray = img.convert('L')\ngray1 = np.array(gray) # for plotting rectangle\n\nheigth, width = np.array(gray1).shape # height <- shape[0], width <- shape[1]\n\nlist_img = []\npatch_size = (500,500)\nfor y in range(0, heigth, patch_size[0]):\n    for x in range(0, width, patch_size[1]):\n        \n        # When cropping an image according to patch_size, \n        # it is possible that the cropped image is less than the size specified in \n        # patch_size. So the crop results are eliminated\n        if y+patch_size[1] <= heigth:\n            if x+patch_size[0] <= width:\n                cv.rectangle(gray1, (x,y), (x+patch_size[0], y+patch_size[1]), \n                              (255, 0, 0), thickness=10)\n                \n                # Crop the Image\n                crop_img = gray.crop((x,y, x+patch_size[0], y+patch_size[1]))\n                crop_img = np.array(crop_img)\n                \n                if empty_image(crop_img):\n                    pass\n                else:\n                    # CLAHE (Contrast Limited Adaptive Histogram Equalization)\n                    clahe = cv.createCLAHE(clipLimit=40.0, tileGridSize=(2, 2))\n                    clahe_img = clahe.apply(crop_img)\n                    \n                    list_img.append(clahe_img)\n    \n#list_img = np.array(list_img)\nprint(gray1.shape)\nprint(len(list_img))\nplt.imshow(gray1, cmap='gray')\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-11-10T11:57:11.238278Z","iopub.execute_input":"2023-11-10T11:57:11.238654Z","iopub.status.idle":"2023-11-10T11:57:12.218987Z","shell.execute_reply.started":"2023-11-10T11:57:11.238626Z","shell.execute_reply":"2023-11-10T11:57:12.218022Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(len(list_img))\nplt.figure(figsize=(6,6))\nfor i in range(len(list_img)):\n    try:\n        plt.subplot(6,6,i+1)\n        plt.imshow(list_img[i], cmap='gray')\n        plt.axis('off')\n    except:pass","metadata":{"execution":{"iopub.status.busy":"2023-11-10T11:57:14.597434Z","iopub.execute_input":"2023-11-10T11:57:14.598289Z","iopub.status.idle":"2023-11-10T11:57:15.996986Z","shell.execute_reply.started":"2023-11-10T11:57:14.598258Z","shell.execute_reply":"2023-11-10T11:57:15.996064Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Sample\nrandom_n = np.random.randint(0,len(list_img),3)\n\nfig, ax = plt.subplots(1,3, figsize=(12, 8))\nj=0\nfor i in random_n:\n    ax[j].imshow(list_img[i], cmap='gray')\n    j+=1\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-11-10T11:57:16.297677Z","iopub.execute_input":"2023-11-10T11:57:16.298652Z","iopub.status.idle":"2023-11-10T11:57:16.844172Z","shell.execute_reply.started":"2023-11-10T11:57:16.298615Z","shell.execute_reply":"2023-11-10T11:57:16.843235Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"After cropping, if you notice there are several images that are black (there are no objects in them), so we will eliminate these images by counting the total number of pixels (np.sum(image)).\n\nif (np.sum(image) = 0) then the image has no object and must be eliminated","metadata":{}},{"cell_type":"code","source":"def empty_image(images):\n    return np.sum(images) < 100 # threshold","metadata":{"execution":{"iopub.status.busy":"2023-11-10T11:57:05.748952Z","iopub.execute_input":"2023-11-10T11:57:05.749638Z","iopub.status.idle":"2023-11-10T11:57:05.754035Z","shell.execute_reply.started":"2023-11-10T11:57:05.749603Z","shell.execute_reply":"2023-11-10T11:57:05.752972Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Let's Cropping all the Images","metadata":{}},{"cell_type":"code","source":"def crop_img(path_img, size):\n    # Read Img\n    img = Image.open(path_img)\n    gray = img.convert('L')\n    heigth, width = np.array(gray).shape # height <- shape[0], width <- shape[1]\n\n    list_img = []\n    patch_size = (size, size)\n    for y in range(0, heigth, patch_size[0]):\n        for x in range(0, width, patch_size[1]):\n\n            # When cropping an image according to patch_size, \n            # it is possible that the cropped image is less than the size specified in \n            # patch_size. So the crop results are eliminated\n            if y+patch_size[1] <= heigth:\n                if x+patch_size[0] <= width:\n                    # Crop the Image\n                    crop_img = gray.crop((x,y, x+patch_size[0], y+patch_size[1]))\n                    crop_img = np.array(crop_img)\n                    \n                    if empty_image(crop_img):\n                        pass\n                    else:\n                        # CLAHE (Contrast Limited Adaptive Histogram Equalization)\n                        #clahe = cv.createCLAHE(clipLimit=40.0, tileGridSize=(2, 2))\n                        #clahe_img = clahe.apply(crop_img)\n\n                        list_img.append(crop_img)\n                    \n    return list_img","metadata":{"execution":{"iopub.status.busy":"2023-11-10T11:57:31.360502Z","iopub.execute_input":"2023-11-10T11:57:31.360899Z","iopub.status.idle":"2023-11-10T11:57:31.369715Z","shell.execute_reply.started":"2023-11-10T11:57:31.360865Z","shell.execute_reply":"2023-11-10T11:57:31.368644Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def preprocessing_img(dataframe, path):\n    classes = []\n    images = []\n    for data in dataframe.iterrows():\n        img_path = os.path.join(path,f\"{str(data[1][0])}_thumbnail.png\")\n        temp_crop_img = crop_img(img_path, 224)\n        \n        # Because the image has been converted to grayscale (channel=1) \n        # it is necessary to change from (none,none,1) -> (none,none,3) by \n        # duplicating the first channel on the second and third channels. \n        # How to make source data acceptable to Transfer Learning.\n        for lol in temp_crop_img:\n            w,h = lol.shape\n            rgb_img = np.zeros((w,h,3), dtype=np.uint8)\n            rgb_img[:,:,0] = lol\n            rgb_img[:,:,1] = lol\n            rgb_img[:,:,2] = lol\n\n            images.append(rgb_img)\n            classes.append(data[1][1])\n        \n    return images, classes","metadata":{"execution":{"iopub.status.busy":"2023-11-10T11:57:33.377329Z","iopub.execute_input":"2023-11-10T11:57:33.377708Z","iopub.status.idle":"2023-11-10T11:57:33.38494Z","shell.execute_reply.started":"2023-11-10T11:57:33.37768Z","shell.execute_reply":"2023-11-10T11:57:33.383973Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"path = \"/kaggle/input/UBC-OCEAN/train_thumbnails\"\nimages, classes = preprocessing_img(istma_false, path)\n\nimages = np.array(images)\nprint(images.shape)\nprint(len(classes))","metadata":{"execution":{"iopub.status.busy":"2023-11-10T11:57:35.467135Z","iopub.execute_input":"2023-11-10T11:57:35.467976Z","iopub.status.idle":"2023-11-10T11:59:49.111814Z","shell.execute_reply.started":"2023-11-10T11:57:35.467941Z","shell.execute_reply":"2023-11-10T11:59:49.110903Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Label Encoded","metadata":{}},{"cell_type":"code","source":"# Encode classes\nle = LabelEncoder()\nlabel = le.fit_transform(classes)\n\nlabel_list = list(le.classes_)\nprint(len(label))\nlabel_list","metadata":{"execution":{"iopub.status.busy":"2023-11-10T11:59:49.113444Z","iopub.execute_input":"2023-11-10T11:59:49.113731Z","iopub.status.idle":"2023-11-10T11:59:49.139115Z","shell.execute_reply.started":"2023-11-10T11:59:49.113708Z","shell.execute_reply":"2023-11-10T11:59:49.138226Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Sample\nrandom_n = np.random.randint(0,512,3)\n\nfig, ax = plt.subplots(1,3, figsize=(12, 8))\nj=0\nfor i in random_n:\n    ax[j].imshow(images[i], cmap='gray'), ax[j].set_title(str(label[i])+\" \"+classes[i])\n    j+=1\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-11-10T12:01:15.559677Z","iopub.execute_input":"2023-11-10T12:01:15.560691Z","iopub.status.idle":"2023-11-10T12:01:16.262191Z","shell.execute_reply.started":"2023-11-10T12:01:15.560647Z","shell.execute_reply":"2023-11-10T12:01:16.26112Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Modelling","metadata":{}},{"cell_type":"code","source":"from tensorflow.keras.applications.efficientnet import EfficientNetB0\nbase_model = EfficientNetB0(\n    include_top=False,\n    input_shape=(224, 224, 3),\n    weights='imagenet'\n)\n\nfor layer in base_model.layers:\n    layer.trainable = False\n    \nx = tf.keras.layers.Flatten()(base_model.output)\nx = tf.keras.layers.Dense(64, activation='relu')(x)\nx = tf.keras.layers.Dense(5, activation='softmax')(x)\n\nmodel = tf.keras.Model(inputs=base_model.input, outputs=x)\n#model.summary()","metadata":{"execution":{"iopub.status.busy":"2023-11-10T12:01:36.001089Z","iopub.execute_input":"2023-11-10T12:01:36.001487Z","iopub.status.idle":"2023-11-10T12:01:37.91859Z","shell.execute_reply.started":"2023-11-10T12:01:36.001454Z","shell.execute_reply":"2023-11-10T12:01:37.917585Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.compile(\n    optimizer=tf.keras.optimizers.Adam(learning_rate=0.001),\n    loss='sparse_categorical_crossentropy',\n    metrics= [\"accuracy\"]\n)","metadata":{"execution":{"iopub.status.busy":"2023-11-10T12:01:37.920203Z","iopub.execute_input":"2023-11-10T12:01:37.920533Z","iopub.status.idle":"2023-11-10T12:01:37.935313Z","shell.execute_reply.started":"2023-11-10T12:01:37.920508Z","shell.execute_reply":"2023-11-10T12:01:37.934354Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model_callback = EarlyStopping(\n    monitor = 'val_loss', mode = 'min',\n    patience = 3\n)\n\nhistory = model.fit(\n    images, label,\n    batch_size = 32,\n    validation_split = 0.2,\n    epochs = 100,\n    callbacks = [model_callback]\n)","metadata":{"execution":{"iopub.status.busy":"2023-11-10T12:01:41.316969Z","iopub.execute_input":"2023-11-10T12:01:41.317622Z","iopub.status.idle":"2023-11-10T12:06:33.183619Z","shell.execute_reply.started":"2023-11-10T12:01:41.317589Z","shell.execute_reply":"2023-11-10T12:06:33.182745Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\nplt.figure(figsize=(8, 3))\nplt.plot(history.epoch, history.history['loss'])\n#plt.plot(history.epoch, history.history['val_loss'])\nplt.legend(['train loss', 'val loss'])\nplt.title('Loss Diagram')\nplt.xlabel('Epoch(s)')\nplt.ylabel('Loss')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-11-10T12:07:05.797949Z","iopub.execute_input":"2023-11-10T12:07:05.798323Z","iopub.status.idle":"2023-11-10T12:07:06.084579Z","shell.execute_reply.started":"2023-11-10T12:07:05.798291Z","shell.execute_reply":"2023-11-10T12:07:06.083578Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Evaluation on Test and Train Data**","metadata":{}},{"cell_type":"code","source":"# Read the image\ntest_path = \"/kaggle/input/UBC-OCEAN/test_thumbnails/41_thumbnail.png\"\nimg = cv.imread(test_path, 0)\nplt.imshow(img,cmap='gray')\nimg.shape","metadata":{"execution":{"iopub.status.busy":"2023-11-10T12:25:25.991765Z","iopub.execute_input":"2023-11-10T12:25:25.992507Z","iopub.status.idle":"2023-11-10T12:25:26.906713Z","shell.execute_reply.started":"2023-11-10T12:25:25.992473Z","shell.execute_reply":"2023-11-10T12:25:26.905768Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Slicing the Images\nimg_test = []\ntemp_crop_img = crop_img(test_path, 224)\nfor lol in temp_crop_img:\n    img_resize = cv.resize(lol, (224, 224), interpolation=cv.INTER_AREA)\n    w,h = img_resize.shape\n    rgb_img = np.zeros((w,h,3), dtype=np.uint8)\n    rgb_img[:,:,0] = img_resize\n    rgb_img[:,:,1] = img_resize\n    rgb_img[:,:,2] = img_resize\n    \n    img_test.append(rgb_img)\n    \nimg_test = np.array(img_test)\nprint(img_test.shape)\n\nplt.figure(figsize=(32,32))\nfor i, n in enumerate(img_test):\n    try:\n        plt.subplot(4,4,i+1)\n        plt.grid(False)\n        plt.imshow(n)\n    except:pass","metadata":{"execution":{"iopub.status.busy":"2023-11-10T12:26:31.103764Z","iopub.execute_input":"2023-11-10T12:26:31.104113Z","iopub.status.idle":"2023-11-10T12:26:36.480743Z","shell.execute_reply.started":"2023-11-10T12:26:31.104086Z","shell.execute_reply":"2023-11-10T12:26:36.479728Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Model Predict\nclasses = model.predict(img_test)\n\n# Plotting the Result\nplt.figure(figsize=(10,10))\nfor i, n in enumerate(img_test):\n    try:\n        plt.subplot(4,4,i+1)\n        #plt.grid(False)\n        plt.imshow(n, cmap='gray')\n        plt.title(label_list[np.argmax(classes[i])])\n        plt.axis('off')\n    except:pass","metadata":{"execution":{"iopub.status.busy":"2023-11-10T12:27:00.11895Z","iopub.execute_input":"2023-11-10T12:27:00.119723Z","iopub.status.idle":"2023-11-10T12:27:03.873708Z","shell.execute_reply.started":"2023-11-10T12:27:00.119687Z","shell.execute_reply":"2023-11-10T12:27:03.872817Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"v_result = []\nfor i in classes:\n    v_result.append(np.argmax(i))\n\nprint(f\"The result: {v_result}\")\nprint(f\"Voting: {np.argmax(np.bincount(v_result))}\")","metadata":{"execution":{"iopub.status.busy":"2023-11-10T12:27:22.04348Z","iopub.execute_input":"2023-11-10T12:27:22.043828Z","iopub.status.idle":"2023-11-10T12:27:22.051868Z","shell.execute_reply.started":"2023-11-10T12:27:22.043803Z","shell.execute_reply":"2023-11-10T12:27:22.050789Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sample_submission = pd.read_csv(\"/kaggle/input/UBC-OCEAN/sample_submission.csv\")\nsample_submission['label'] = label_list[np.argmax(np.bincount(v_result))]\n\n# Save the updated DataFrame to a CSV file\nsample_submission.to_csv('submission.csv', index=False)","metadata":{"execution":{"iopub.status.busy":"2023-11-10T12:27:46.636875Z","iopub.execute_input":"2023-11-10T12:27:46.637644Z","iopub.status.idle":"2023-11-10T12:27:46.651962Z","shell.execute_reply.started":"2023-11-10T12:27:46.637615Z","shell.execute_reply":"2023-11-10T12:27:46.650568Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sample_submission.head()","metadata":{"execution":{"iopub.status.busy":"2023-11-10T12:27:47.878006Z","iopub.execute_input":"2023-11-10T12:27:47.878727Z","iopub.status.idle":"2023-11-10T12:27:47.887116Z","shell.execute_reply.started":"2023-11-10T12:27:47.878692Z","shell.execute_reply":"2023-11-10T12:27:47.886198Z"},"trusted":true},"execution_count":null,"outputs":[]}]}