{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.7.9","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":25563,"databundleVersionId":2094376,"sourceType":"competition"}],"dockerImageVersionId":30085,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"## <a name=\"Wheat Detection\">Introduction : Plant Pathology 2021 FGVC8 </a>\n\n#### <a name=\"About_Competition\"> Introduction </a>\n\nApples are one of the most important temperate fruit crops in the world. Foliar (leaf) diseases pose a major threat to the overall productivity and quality of apple orchards. The current process for disease diagnosis in apple orchards is based on manual scouting by humans, which is time-consuming and expensive.\n\nAlthough computer vision-based models have shown promise for plant disease identification, there are some limitations that need to be addressed. Large variations in visual symptoms of a single disease across different apple cultivars, or new varieties that originated under cultivation, are major challenges for computer vision-based disease identification. These variations arise from differences in natural and image capturing environments, for example, leaf color and leaf morphology, the age of infected tissues, non-uniform image background, and different light illumination during imaging etc.\n\nPlant Pathology 2021-FGVC8 challenge competition had a pilot dataset of 3,651 RGB images of foliar disease of apples. For Plant Pathology 2021-FGVC8, we have significantly increased the number of foliar disease images and added additional disease categories. This year’s dataset contains approximately 23,000 high-quality RGB images of apple foliar diseases, including a large expert-annotated disease dataset. This dataset reflects real field scenarios by representing non-homogeneous backgrounds of leaf images taken at different maturity stages and at different times of day under different focal camera settings.\n                           \n\n#### <a name=\"Specific Objectives\">Specific Objectives</a>           \n\nThe main objective of the competition is to develop machine learning-based models to accurately classify a given leaf image from the test dataset to a particular disease category, and to identify an individual disease from multiple disease symptoms on a single leaf image.\n\n\n#### <a name=\"dataset_description\">Dataset Description</a>: \n\nThe data holds the images of apple - Plant leaf with healthy and infected conditions\n\nFiles\ntrain.csv - the training set metadata.\n\nimage - the image ID.\n\nlabels - the target classes, a space delimited list of all diseases found in the image. Unhealthy leaves with too many diseases to classify visually will have the complex class, and may also have a subset of the diseases identified.\n\nsample_submission.csv - A sample submission file in the correct format.\n\n    1. image\n    2. labels\n\ntrain_images - The training set images.\n\ntest_images - The test set images. This competition has a hidden test set: only three images are provided here as samples while the remaining 5,000 images will be available to your notebook once it is submitted.\n\n\n#### <a name=\"target_variable\">Target Variable</a>                                        \n* __Submission data__  \n    Image & labels \n\nCatagory of Labels :- \n*     healthy\n*     complex\n*     frog_eye_leaf_spot\n*     frog_eye_leaf_spot complex\n*     powdery_mildew\n*     powdery_mildew complex\n*     rust\n*     rust complex\n*     rust frog_eye_leaf_spot\n*     scab\n*     scab frog_eye_leaf_spot\n*     scab frog_eye_leaf_spot complex\n","metadata":{}},{"cell_type":"markdown","source":"# Contents\n\n* [<font size=4>EDA</font>](#1)\n    * [Preparing the ground](#1.1)\n    * [Visualize one leaf](#1.2)\n    * [Channel distributions](#1.3)\n    * [Visualize sample leaves](#1.4)\n    * [Visualize targets](#1.5)\n\n\n* [<font size=4>Image processing and augmentation</font>](#2)\n    * [Canny edge detection](#2.1)\n    * [Flipping](#2.2)\n    * [Convolution](#2.3)\n    * [Blurring](#2.4)\n","metadata":{}},{"cell_type":"markdown","source":"## Importing necessary libraries","metadata":{}},{"cell_type":"code","source":"import os\nfrom tqdm import tqdm\n\n# Data Processing Libraries \n\nimport pandas as pd \nimport numpy as np \n\n\n# Feature Engineering Libraries\n\nfrom sklearn.preprocessing import OneHotEncoder\n\n# Data Visualisation libraries \n%matplotlib inline\nimport seaborn as sns\nimport matplotlib.pyplot as plt\n\nimport cv2\nimport plotly.express as px\nimport plotly.graph_objects as go\nimport plotly.figure_factory as ff\nfrom plotly.subplots import make_subplots\nfrom plotly.offline import init_notebook_mode, iplot\ninit_notebook_mode(connected=True)\n\nimport warnings\nwarnings.filterwarnings(\"ignore\")\n\n## Image Augmentation \n\n# skimage\nfrom skimage.io import imshow, imread, imsave\nfrom skimage.transform import rotate, AffineTransform, warp,rescale, resize, downscale_local_mean\nfrom skimage import color,data\nfrom skimage.exposure import adjust_gamma\nfrom skimage.util import random_noise\n\n\n# 3D scatter plot\nfrom mpl_toolkits.mplot3d import Axes3D\nfrom matplotlib import cm\nfrom matplotlib import colors\n\n\n#OpenCV-Python\nimport cv2\n\n# imgaug\nimport imageio\nimport imgaug as ia\nimport imgaug.augmenters as iaa\n\n# Albumentations\nimport albumentations as A\n\nSAMPLE_LEN=100","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:03:56.355881Z","iopub.execute_input":"2025-06-13T15:03:56.356252Z","iopub.status.idle":"2025-06-13T15:04:07.926249Z","shell.execute_reply.started":"2025-06-13T15:03:56.356158Z","shell.execute_reply":"2025-06-13T15:04:07.925606Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Preparing the ground","metadata":{}},{"cell_type":"code","source":"train_image_path = '../input/plant-pathology-2021-fgvc8/train_images'\ntest_image_path = '../input/plant-pathology-2021-fgvc8/test_images'\ntrain_df_path = '../input/plant-pathology-2021-fgvc8/train.csv'\ntest_df_path = '../input/plant-pathology-2021-fgvc8/sample_submission.csv'","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:04:07.928197Z","iopub.execute_input":"2025-06-13T15:04:07.928453Z","iopub.status.idle":"2025-06-13T15:04:07.934674Z","shell.execute_reply.started":"2025-06-13T15:04:07.928428Z","shell.execute_reply":"2025-06-13T15:04:07.933932Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df_train = pd.read_csv(train_df_path)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:04:07.936507Z","iopub.execute_input":"2025-06-13T15:04:07.936731Z","iopub.status.idle":"2025-06-13T15:04:08.004054Z","shell.execute_reply.started":"2025-06-13T15:04:07.936711Z","shell.execute_reply":"2025-06-13T15:04:08.003397Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df_train.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:04:08.005217Z","iopub.execute_input":"2025-06-13T15:04:08.005546Z","iopub.status.idle":"2025-06-13T15:04:08.030444Z","shell.execute_reply.started":"2025-06-13T15:04:08.005514Z","shell.execute_reply":"2025-06-13T15:04:08.029699Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df_train['labels'].value_counts()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:04:08.031765Z","iopub.execute_input":"2025-06-13T15:04:08.032096Z","iopub.status.idle":"2025-06-13T15:04:08.046059Z","shell.execute_reply.started":"2025-06-13T15:04:08.032066Z","shell.execute_reply":"2025-06-13T15:04:08.045224Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sns.histplot(df_train['labels'].value_counts(sort=True))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:04:08.047116Z","iopub.execute_input":"2025-06-13T15:04:08.047436Z","iopub.status.idle":"2025-06-13T15:04:08.259354Z","shell.execute_reply.started":"2025-06-13T15:04:08.047403Z","shell.execute_reply":"2025-06-13T15:04:08.258645Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.figure(figsize=(15,12))\nlabels = sns.barplot(df_train.labels.value_counts().index,df_train.labels.value_counts())\nfor item in labels.get_xticklabels():\n    item.set_rotation(45)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:04:08.260229Z","iopub.execute_input":"2025-06-13T15:04:08.260471Z","iopub.status.idle":"2025-06-13T15:04:08.474616Z","shell.execute_reply.started":"2025-06-13T15:04:08.260448Z","shell.execute_reply":"2025-06-13T15:04:08.473994Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"source = df_train['labels'].value_counts()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:04:08.475496Z","iopub.execute_input":"2025-06-13T15:04:08.475720Z","iopub.status.idle":"2025-06-13T15:04:08.480882Z","shell.execute_reply.started":"2025-06-13T15:04:08.475698Z","shell.execute_reply":"2025-06-13T15:04:08.480223Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"fig = go.Figure(data=[go.Pie(labels=source.index,values=source.values)])\nfig.update_layout(title='Label distribution')\nfig.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:04:08.482026Z","iopub.execute_input":"2025-06-13T15:04:08.482335Z","iopub.status.idle":"2025-06-13T15:04:08.571047Z","shell.execute_reply.started":"2025-06-13T15:04:08.482304Z","shell.execute_reply":"2025-06-13T15:04:08.570249Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Observation \n\n- Dataset is pretty unbalanced as per above pie chart \n- Need to chose the appropirate sampling strategy to sortout this issue ","metadata":{}},{"cell_type":"markdown","source":"# Let see the Plant pathology Images","metadata":{}},{"cell_type":"code","source":"def visualize_batch(path,image_ids, labels):\n    plt.figure(figsize=(16, 12))\n    \n    for ind, (image_id, label) in enumerate(zip(image_ids, labels)):\n        plt.subplot(3, 3, ind + 1)\n        image = cv2.imread(os.path.join(path, image_id))\n        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n\n        plt.imshow(image)\n        plt.title(f\"Class: {label}\", fontsize=12)\n        plt.axis(\"off\")\n    plt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:04:08.571969Z","iopub.execute_input":"2025-06-13T15:04:08.572176Z","iopub.status.idle":"2025-06-13T15:04:08.577209Z","shell.execute_reply.started":"2025-06-13T15:04:08.572156Z","shell.execute_reply":"2025-06-13T15:04:08.576440Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"tmp_df = df_train.sample(9)\nimage_ids = tmp_df[\"image\"].values\nlabels = tmp_df[\"labels\"].values\nvisualize_batch(train_image_path,image_ids,labels)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:04:08.578122Z","iopub.execute_input":"2025-06-13T15:04:08.578330Z","iopub.status.idle":"2025-06-13T15:04:18.573741Z","shell.execute_reply.started":"2025-06-13T15:04:08.578310Z","shell.execute_reply":"2025-06-13T15:04:18.572843Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":" I have plotted the few images in the training data above (the RGB values can be seen by hovering over the image). The green parts of the image have very low blue values, but by contrast, the brown parts have high blue values. This suggests that green (healthy) parts of the image have low blue values, whereas unhealthy parts are more likely to have high blue values. **This might suggest that the blue channel may be the key to detecting diseases in plants.**","metadata":{}},{"cell_type":"code","source":"df_train","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:04:18.575017Z","iopub.execute_input":"2025-06-13T15:04:18.575260Z","iopub.status.idle":"2025-06-13T15:04:18.584994Z","shell.execute_reply.started":"2025-06-13T15:04:18.575235Z","shell.execute_reply":"2025-06-13T15:04:18.584277Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_image_path","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:04:18.586159Z","iopub.execute_input":"2025-06-13T15:04:18.586393Z","iopub.status.idle":"2025-06-13T15:04:18.599873Z","shell.execute_reply.started":"2025-06-13T15:04:18.586361Z","shell.execute_reply":"2025-06-13T15:04:18.598852Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def load_image(image_id):\n    file_path = image_id\n    image = cv2.imread(train_image_path+'/'+ file_path)\n    return cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n\n# Just take 100 sample images with SAMPLE_LEN=100 for RBG Channel Analysis\n\ntrain_images = df_train[\"image\"][:SAMPLE_LEN].apply(load_image)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:04:18.601406Z","iopub.execute_input":"2025-06-13T15:04:18.601732Z","iopub.status.idle":"2025-06-13T15:04:31.938186Z","shell.execute_reply.started":"2025-06-13T15:04:18.601692Z","shell.execute_reply":"2025-06-13T15:04:31.937472Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"red_values = [np.mean(train_images[idx][:, :, 0]) for idx in range(len(train_images))]\ngreen_values = [np.mean(train_images[idx][:, :, 1]) for idx in range(len(train_images))]\nblue_values = [np.mean(train_images[idx][:, :, 2]) for idx in range(len(train_images))]\nvalues = [np.mean(train_images[idx]) for idx in range(len(train_images))]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:04:31.939460Z","iopub.execute_input":"2025-06-13T15:04:31.939711Z","iopub.status.idle":"2025-06-13T15:04:37.371413Z","shell.execute_reply.started":"2025-06-13T15:04:31.939688Z","shell.execute_reply":"2025-06-13T15:04:37.370768Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Distribution of RBG ( All Channel Values )","metadata":{}},{"cell_type":"markdown","source":"Histograms are a graphical representation showing how frequently various color values occur in the image i.e frequency of pixels intensity values. In a RGB color space, pixel values range from 0 to 255 where 0 stands for black and 255 stands for white. Analysis of a histogram can help us understand thee brightness, contrast and intensity distribution of an image. Now let's look at the histogram of a random selected sample from each category.","metadata":{}},{"cell_type":"code","source":"fig = ff.create_distplot([values], group_labels=[\"Channels\"], colors=[\"purple\"])\nfig.update_layout(showlegend=False, template=\"simple_white\")\nfig.update_layout(title_text=\"Distribution of channel values\")\nfig.data[0].marker.line.color = 'rgb(0, 0, 0)'\nfig.data[0].marker.line.width = 0.5\nfig","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:04:37.372559Z","iopub.execute_input":"2025-06-13T15:04:37.372887Z","iopub.status.idle":"2025-06-13T15:04:38.754828Z","shell.execute_reply.started":"2025-06-13T15:04:37.372838Z","shell.execute_reply":"2025-06-13T15:04:38.754117Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Distribution of Red Channel ","metadata":{}},{"cell_type":"code","source":"fig = ff.create_distplot([red_values], group_labels=[\"R\"], colors=[\"red\"])\nfig.update_layout(showlegend=False, template=\"simple_white\")\nfig.update_layout(title_text=\"Distribution of red channel values\")\nfig.data[0].marker.line.color = 'rgb(0, 0, 0)'\nfig.data[0].marker.line.width = 0.5\nfig","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:04:38.758820Z","iopub.execute_input":"2025-06-13T15:04:38.759078Z","iopub.status.idle":"2025-06-13T15:04:38.943309Z","shell.execute_reply.started":"2025-06-13T15:04:38.759054Z","shell.execute_reply":"2025-06-13T15:04:38.942426Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Observation :- \nThe red channel values seem to roughly normal distribution, but with a slight leftward (Negative skew). This indicates that the red channel tends to be more concentrated at higher values, at around 100. There is large variation in average red values across images.","metadata":{}},{"cell_type":"markdown","source":"","metadata":{}},{"cell_type":"code","source":"fig = ff.create_distplot([green_values], group_labels=[\"G\"], colors=[\"green\"])\nfig.update_layout(showlegend=False, template=\"simple_white\")\nfig.update_layout(title_text=\"Distribution of green channel values\")\nfig.data[0].marker.line.color = 'rgb(0, 0, 0)'\nfig.data[0].marker.line.width = 0.5\nfig","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:04:38.944786Z","iopub.execute_input":"2025-06-13T15:04:38.945145Z","iopub.status.idle":"2025-06-13T15:04:38.993342Z","shell.execute_reply.started":"2025-06-13T15:04:38.945114Z","shell.execute_reply":"2025-06-13T15:04:38.992618Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Observation :- \nThe green channel values have a more uniform distribution than the red channel values but its right skewed, with a smaller peak. \nThe distribution also has a right skew (in contrast to red) and a larger mode of around 160.\nThis indicates that green is more pronounced in these images than red,\nwhich makes sense, because these are images of leaves!","metadata":{}},{"cell_type":"markdown","source":"# Distribution of Blue Channel Values","metadata":{}},{"cell_type":"code","source":"fig = ff.create_distplot([blue_values], group_labels=[\"B\"], colors=[\"blue\"])\nfig.update_layout(showlegend=False, template=\"simple_white\")\nfig.update_layout(title_text=\"Distribution of blue channel values\")\nfig.data[0].marker.line.color = 'rgb(0, 0, 0)'\nfig.data[0].marker.line.width = 0.5\nfig","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:04:38.994311Z","iopub.execute_input":"2025-06-13T15:04:38.994605Z","iopub.status.idle":"2025-06-13T15:04:39.044347Z","shell.execute_reply.started":"2025-06-13T15:04:38.994573Z","shell.execute_reply":"2025-06-13T15:04:39.043595Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Observation :- \n\nThe blue channel has the most uniform distribution out of the three color channels, with minimal skew (slight leftward skew). The blue channel shows great variation across images in the dataset.","metadata":{}},{"cell_type":"markdown","source":"# All Channels (RBG) togather","metadata":{}},{"cell_type":"code","source":"fig = go.Figure()\n\nfor idx, values in enumerate([red_values, green_values, blue_values]):\n    if idx == 0:\n        color = \"Red\"\n    if idx == 1:\n        color = \"Green\"\n    if idx == 2:\n        color = \"Blue\"\n    fig.add_trace(go.Box(x=[color]*len(values), y=values, name=color, marker=dict(color=color.lower())))\n    \nfig.update_layout(yaxis_title=\"Mean value\", xaxis_title=\"Color channel\",\n                  title=\"Mean value vs. Color channel\", template=\"plotly_white\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:04:39.045218Z","iopub.execute_input":"2025-06-13T15:04:39.045457Z","iopub.status.idle":"2025-06-13T15:04:39.122009Z","shell.execute_reply.started":"2025-06-13T15:04:39.045434Z","shell.execute_reply":"2025-06-13T15:04:39.121209Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"fig = ff.create_distplot([red_values, green_values, blue_values],\n                         group_labels=[\"R\", \"G\", \"B\"],\n                         colors=[\"red\", \"green\", \"blue\"])\nfig.update_layout(title_text=\"Distribution of red channel values\", template=\"simple_white\")\nfig.data[0].marker.line.color = 'rgb(0, 0, 0)'\nfig.data[0].marker.line.width = 0.5\nfig.data[1].marker.line.color = 'rgb(0, 0, 0)'\nfig.data[1].marker.line.width = 0.5\nfig.data[2].marker.line.color = 'rgb(0, 0, 0)'\nfig.data[2].marker.line.width = 0.5\nfig","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:04:39.123316Z","iopub.execute_input":"2025-06-13T15:04:39.123628Z","iopub.status.idle":"2025-06-13T15:04:39.204288Z","shell.execute_reply.started":"2025-06-13T15:04:39.123597Z","shell.execute_reply":"2025-06-13T15:04:39.203609Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"image = train_images[10]\nimshow(image)\nprint(image.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:04:39.205288Z","iopub.execute_input":"2025-06-13T15:04:39.205546Z","iopub.status.idle":"2025-06-13T15:04:40.175739Z","shell.execute_reply.started":"2025-06-13T15:04:39.205522Z","shell.execute_reply":"2025-06-13T15:04:40.174833Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 3D scatter plot for the image in RGB\n","metadata":{}},{"cell_type":"code","source":"r, g, b = cv2.split(image)\nfig = plt.figure()\naxis = fig.add_subplot(1, 1, 1, projection=\"3d\")\n\npixel_colors = image.reshape((np.shape(image)[0]*np.shape(image)[1], 3))\nnorm = colors.Normalize(vmin=-1.,vmax=1.)\nnorm.autoscale(pixel_colors)\npixel_colors = norm(pixel_colors).tolist()\n\naxis.scatter(r.flatten(), g.flatten(), b.flatten(), facecolors=pixel_colors, marker=\".\")\naxis.set_xlabel(\"Red\")\naxis.set_ylabel(\"Green\")\naxis.set_zlabel(\"Blue\")\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:04:40.177450Z","iopub.execute_input":"2025-06-13T15:04:40.177905Z","iopub.status.idle":"2025-06-13T15:07:05.182519Z","shell.execute_reply.started":"2025-06-13T15:04:40.177838Z","shell.execute_reply":"2025-06-13T15:07:05.181629Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 3D scatter plot for the image in HSV","metadata":{}},{"cell_type":"code","source":"hsv_image = cv2.cvtColor(image, cv2.COLOR_RGB2HSV)\nh, s, v = cv2.split(hsv_image)\nfig = plt.figure()\naxis = fig.add_subplot(1, 1, 1, projection=\"3d\")\n\naxis.scatter(h.flatten(), s.flatten(), v.flatten(), facecolors=pixel_colors, marker=\".\")\naxis.set_xlabel(\"Hue\")\naxis.set_ylabel(\"Saturation\")\naxis.set_zlabel(\"Value\")\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:07:05.183651Z","iopub.execute_input":"2025-06-13T15:07:05.183908Z","iopub.status.idle":"2025-06-13T15:09:19.794414Z","shell.execute_reply.started":"2025-06-13T15:07:05.183873Z","shell.execute_reply":"2025-06-13T15:09:19.793527Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Parallel categories plot of targets","metadata":{}},{"cell_type":"code","source":"df_train['label_list'] = df_train['labels'].str.split(' ')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:09:19.795680Z","iopub.execute_input":"2025-06-13T15:09:19.796010Z","iopub.status.idle":"2025-06-13T15:09:19.811111Z","shell.execute_reply.started":"2025-06-13T15:09:19.795973Z","shell.execute_reply":"2025-06-13T15:09:19.810352Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Distinct List of labels \n\n\n\n*     healthy\n*     complex\n*     rust\n*     frog_eye_leaf_spot\n*     powdery_mildew\n*     scab","metadata":{}},{"cell_type":"code","source":"lbls = ['healthy','complex','rust','frog_eye_leaf_spot','powdery_mildew','scab']\nfor x in lbls:\n    df_train[x]=0","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:09:19.812041Z","iopub.execute_input":"2025-06-13T15:09:19.812271Z","iopub.status.idle":"2025-06-13T15:09:19.826531Z","shell.execute_reply.started":"2025-06-13T15:09:19.812242Z","shell.execute_reply":"2025-06-13T15:09:19.826006Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"","metadata":{}},{"cell_type":"code","source":"def lbl_lgc(col,lbl_list):\n    if col in lbl_list:\n        res = 1 \n    else:\n        res = 0\n    return res","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:09:19.827605Z","iopub.execute_input":"2025-06-13T15:09:19.827798Z","iopub.status.idle":"2025-06-13T15:09:19.842492Z","shell.execute_reply.started":"2025-06-13T15:09:19.827779Z","shell.execute_reply":"2025-06-13T15:09:19.841920Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"lbls = ['healthy','complex','rust','frog_eye_leaf_spot','powdery_mildew','scab']\n\nfor x in lbls:\n    df_train[x] = np.vectorize(lbl_lgc)(x,df_train['label_list'])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:09:19.843318Z","iopub.execute_input":"2025-06-13T15:09:19.843522Z","iopub.status.idle":"2025-06-13T15:09:19.874404Z","shell.execute_reply.started":"2025-06-13T15:09:19.843497Z","shell.execute_reply":"2025-06-13T15:09:19.873781Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df_train","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:09:19.875375Z","iopub.execute_input":"2025-06-13T15:09:19.875607Z","iopub.status.idle":"2025-06-13T15:09:19.894321Z","shell.execute_reply.started":"2025-06-13T15:09:19.875572Z","shell.execute_reply":"2025-06-13T15:09:19.893598Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"","metadata":{}},{"cell_type":"code","source":"df_train_lbl_onehot = pd.get_dummies(df_train, columns=[\"labels\"], prefix=[\"LBL\"])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:09:19.895361Z","iopub.execute_input":"2025-06-13T15:09:19.895685Z","iopub.status.idle":"2025-06-13T15:09:19.911446Z","shell.execute_reply.started":"2025-06-13T15:09:19.895652Z","shell.execute_reply":"2025-06-13T15:09:19.910828Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df_train_lbl_onehot.columns","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:09:19.912409Z","iopub.execute_input":"2025-06-13T15:09:19.912724Z","iopub.status.idle":"2025-06-13T15:09:19.923087Z","shell.execute_reply.started":"2025-06-13T15:09:19.912692Z","shell.execute_reply":"2025-06-13T15:09:19.922449Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.figure(figsize=(35,20))\nfig = px.parallel_categories(df_train[['healthy','complex','rust','frog_eye_leaf_spot','powdery_mildew','scab']], color=\"healthy\", color_continuous_scale=\"sunset\",\\\n                             title=\"Parallel categories plot of targets\")\nfig","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:09:19.924203Z","iopub.execute_input":"2025-06-13T15:09:19.924517Z","iopub.status.idle":"2025-06-13T15:09:20.390788Z","shell.execute_reply.started":"2025-06-13T15:09:19.924484Z","shell.execute_reply":"2025-06-13T15:09:20.390117Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Observation :- \n\nIn the above plot, we can see the relationship between all 6 categories. As expected, it is impossible for a healthy leaf  to have scab, rust, or multiple diseases. Also, every unhealthy leaf has one of either scab, rust, or multiple diseases. The frequency of each combination can be seen by hovering over the plot.","metadata":{}},{"cell_type":"markdown","source":"## Canny edge detection <a id=\"2.1\"></a>\n\nCanny is a popular edge detection algorithm, and as the name suggests, it detects the edges of objects present in an image. It was developed by John F. Canny in 1986. The algorithm involves several steps.\n\n1. **Noise reduction:** Since edge detection is susceptible to noise in an image, we remove the noise in the image using a 5x5 Gaussian filter.\n\n\n2. **Finding Intensity Gradient of the Image**: The smoothened image is then filtered with a Sobel kernel in both horizontal and vertical directions to get the first derivative in the horizontal (*G<sub>x</sub>*) and vertical (*G<sub>y</sub>*) directions. From these two images, one can find the edge gradient and direction for each pixel:\n\n<center><img src=\"https://i.imgur.com/ntyjTep.png\" width=\"300px\"></center>\n<center><img src=\"https://i.imgur.com/75qDjv6.png\" width=\"260px\"></center>\n\n<br>\n\n3. **Rounding:** The gradient is always perpendicular to edges. So, it is rounded to one of the four angles representing vertical, horizontal and two diagonal directions.\n\n4. **Non-maximum suppression:** After getting the gradient magnitude and direction, a full scan of the image is done to remove any unwanted pixels which may not constitute the edge. For this, we check every pixel for being a local maximum in its neighborhood in the direction of the gradient.\n\n5. **Hysteresis Thresholding:** This stage decides which parts are edges and which are not. For this, we need two threshold values, *minVal* and *maxVal*. Any edges with intensity gradient greater than *maxVal* are considered edges and those lesser than *minVal* are considered non-edges, and discarded. Those who lie between these two thresholds are classified edges or non-edges based on their neighborhood. If they are near “sure-edge” pixels, they are considered edges, and otherwise, they are discarded.\n\nThe result of these five steps is a two-dimensional binary map (0 or 255) indicating the location of edges on the image. Canny edge is demonstrated below with a few leaf images:","metadata":{}},{"cell_type":"code","source":"def edge_and_cut(img):\n    emb_img = img.copy()\n    edges = cv2.Canny(img, 100, 200)\n    edge_coors = []\n    for i in range(edges.shape[0]):\n        for j in range(edges.shape[1]):\n            if edges[i][j] != 0:\n                edge_coors.append((i, j))\n    \n    row_min = edge_coors[np.argsort([coor[0] for coor in edge_coors])[0]][0]\n    row_max = edge_coors[np.argsort([coor[0] for coor in edge_coors])[-1]][0]\n    col_min = edge_coors[np.argsort([coor[1] for coor in edge_coors])[0]][1]\n    col_max = edge_coors[np.argsort([coor[1] for coor in edge_coors])[-1]][1]\n    new_img = img[row_min:row_max, col_min:col_max]\n    \n    emb_img[row_min-10:row_min+10, col_min:col_max] = [255, 0, 0]\n    emb_img[row_max-10:row_max+10, col_min:col_max] = [255, 0, 0]\n    emb_img[row_min:row_max, col_min-10:col_min+10] = [255, 0, 0]\n    emb_img[row_min:row_max, col_max-10:col_max+10] = [255, 0, 0]\n    \n    fig, ax = plt.subplots(nrows=1, ncols=3, figsize=(30, 20))\n    ax[0].imshow(img, cmap='gray')\n    ax[0].set_title('Original Image', fontsize=24)\n    ax[1].imshow(edges, cmap='gray')\n    ax[1].set_title('Canny Edges', fontsize=24)\n    ax[2].imshow(emb_img, cmap='gray')\n    ax[2].set_title('Bounding Box', fontsize=24)\n    plt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:09:20.392140Z","iopub.execute_input":"2025-06-13T15:09:20.392385Z","iopub.status.idle":"2025-06-13T15:09:20.400688Z","shell.execute_reply.started":"2025-06-13T15:09:20.392361Z","shell.execute_reply":"2025-06-13T15:09:20.400041Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"edge_and_cut(train_images[3])\nedge_and_cut(train_images[4])\nedge_and_cut(train_images[5])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:09:20.401572Z","iopub.execute_input":"2025-06-13T15:09:20.401762Z","iopub.status.idle":"2025-06-13T15:10:27.074112Z","shell.execute_reply.started":"2025-06-13T15:09:20.401743Z","shell.execute_reply":"2025-06-13T15:10:27.073325Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Observation :-\n\nThe second column of images above contains the Canny edges and the third column contains cropped images. I have taken the Canny edges and used it to predict a bounding box in which the actual leaf is contained. The most extreme edges at the four corners of the image are the vertices of the bounding box. This red box is likely to contain most of if not all of the leaf. These edges and bounding boxes can be used to build more accurate models.","metadata":{}},{"cell_type":"markdown","source":"## Flipping <a id=\"2.2\"></a>\n\nFlipping is a simple transformation that involves index-switching on the image channels. In vertical flipping, the order of rows is exchanged, whereas in vertical flipping, the order of rows is exchanged. Let us assume that *A<sub>ijk</sub>* (of size *(m, n, 3)*) is the image we want to flip. Horizontal and vertical flipping can be represented by the transformations below:\n\n<center><img src=\"https://i.imgur.com/B9y5apl.png\" width=\"135px\"></center>\n<center><img src=\"https://i.imgur.com/eQ1dyvN.png\" width=\"305px\"></center>\n<center><img src=\"https://i.imgur.com/i30LQgq.png\" width=\"305px\"></center>\n<br>\n\nWe can see that the order of columns is exchanged in horizontal flipping. While the *i* and *k* indices remain the same, the *j* index reverses. Whereas, in vertical flipping, the order of rows is exchanged in horizontal flipping. While the *j* and *k* indices remain the same, the *i* index reverses.\n\n","metadata":{}},{"cell_type":"code","source":"def invert(img):\n    fig, ax = plt.subplots(nrows=1, ncols=3, figsize=(30, 20))\n    ax[0].imshow(img)\n    ax[0].set_title('Original Image', fontsize=24)\n    ax[1].imshow(cv2.flip(img, 0))\n    ax[1].set_title('Vertical Flip', fontsize=24)\n    ax[2].imshow(cv2.flip(img, 1))\n    ax[2].set_title('Horizontal Flip', fontsize=24)\n    plt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:10:27.075138Z","iopub.execute_input":"2025-06-13T15:10:27.075407Z","iopub.status.idle":"2025-06-13T15:10:27.080495Z","shell.execute_reply.started":"2025-06-13T15:10:27.075384Z","shell.execute_reply":"2025-06-13T15:10:27.079842Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"invert(train_images[3])\ninvert(train_images[4])\ninvert(train_images[5])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:10:27.081404Z","iopub.execute_input":"2025-06-13T15:10:27.081602Z","iopub.status.idle":"2025-06-13T15:10:38.582953Z","shell.execute_reply.started":"2025-06-13T15:10:27.081583Z","shell.execute_reply":"2025-06-13T15:10:38.582052Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Convolution <a id=\"2.3\"></a>\n\nConvolution is a rather simple algorithm which involves a kernel (a 2D matrix) which moves over the entire image, calculating dot products with each window along the way. The GIF below demonstrates convolution in action.\n\n<center><img src=\"https://i.imgur.com/wYUaqR3.gif\" width=\"450px\"></center>\n\nThe above process can be summarized with an equation, where *f* is the image and *h* is the kernel. The dimensions of *f* are *(m, n)* and the kernel is a square matrix with dimensions smaller than *f*:\n\n<center><img src=\"https://i.imgur.com/9scTOGv.png\" width=\"350px\"></center>\n<br>\n\nIn the above equation, the kernel *h* is moving across the length and breadth of the image. The dot product of *h* with a sub-matrix or window of matrix *f* is taken at each step, hence the double summation (rows and columns). Below I demonstrate the effect of convolution on leaf images.","metadata":{}},{"cell_type":"code","source":"def conv(img):\n    fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(20, 20))\n    kernel = np.ones((7, 7), np.float32)/25\n    conv = cv2.filter2D(img, -1, kernel)\n    ax[0].imshow(img)\n    ax[0].set_title('Original Image', fontsize=24)\n    ax[1].imshow(conv)\n    ax[1].set_title('Convolved Image', fontsize=24)\n    plt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:10:38.584051Z","iopub.execute_input":"2025-06-13T15:10:38.584360Z","iopub.status.idle":"2025-06-13T15:10:38.590584Z","shell.execute_reply.started":"2025-06-13T15:10:38.584329Z","shell.execute_reply":"2025-06-13T15:10:38.589949Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"conv(train_images[3])\nconv(train_images[4])\nconv(train_images[5])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:10:38.591581Z","iopub.execute_input":"2025-06-13T15:10:38.591898Z","iopub.status.idle":"2025-06-13T15:10:46.660300Z","shell.execute_reply.started":"2025-06-13T15:10:38.591861Z","shell.execute_reply":"2025-06-13T15:10:46.659378Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Observation :- \n\nThe convolution operator seems to have an apparent \"sunshine\" effect of the images. This may also serve the purpose of augmenting the data, thus helping to build more robust and accurate models. ","metadata":{}},{"cell_type":"markdown","source":"## Blurring <a id=\"2.4\"></a>\n\nBlurring is simply the addition of noise to the image, resulting in a less-clear image. The noise can be sampled from any distribution of choice, as long as the main content in the image does not become invisible. Only the minor details get obfuscated due to blurring. The blurring transformation can be represented using the equation below. \n\n<center><img src=\"https://i.imgur.com/zVM8HCU.png\" width=\"220px\"></center>\n<br>\n\nThe example uses a Gaussian distribution with mean 0 and variance 0.1. Below I demonstrate the effect of blurring on a few leaf images:","metadata":{}},{"cell_type":"code","source":"def blur(img):\n    fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(20, 20))\n    ax[0].imshow(img)\n    ax[0].set_title('Original Image', fontsize=24)\n    ax[1].imshow(cv2.blur(img, (100, 100)))\n    ax[1].set_title('Blurred Image', fontsize=24)\n    plt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:10:46.661434Z","iopub.execute_input":"2025-06-13T15:10:46.661764Z","iopub.status.idle":"2025-06-13T15:10:46.667994Z","shell.execute_reply.started":"2025-06-13T15:10:46.661734Z","shell.execute_reply":"2025-06-13T15:10:46.667165Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"blur(train_images[3])\nblur(train_images[4])\nblur(train_images[5])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:10:46.669414Z","iopub.execute_input":"2025-06-13T15:10:46.669765Z","iopub.status.idle":"2025-06-13T15:10:54.351258Z","shell.execute_reply.started":"2025-06-13T15:10:46.669731Z","shell.execute_reply":"2025-06-13T15:10:54.350603Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"##  2.5 Rotation with skimage <a id=\"2.5\"></a>","metadata":{}},{"cell_type":"code","source":"image = train_images[10]\nimshow(image)\nprint(image.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:10:54.352382Z","iopub.execute_input":"2025-06-13T15:10:54.352600Z","iopub.status.idle":"2025-06-13T15:10:55.507147Z","shell.execute_reply.started":"2025-06-13T15:10:54.352579Z","shell.execute_reply":"2025-06-13T15:10:55.506429Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# clockwise rotation\nrot_clockwise_image = rotate(image, angle=45) \n# Anticlockwise rotation\nrot_anticlockwise_image = rotate(image, angle=-45)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:10:55.508092Z","iopub.execute_input":"2025-06-13T15:10:55.508327Z","iopub.status.idle":"2025-06-13T15:10:58.181877Z","shell.execute_reply.started":"2025-06-13T15:10:55.508304Z","shell.execute_reply":"2025-06-13T15:10:58.181175Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"fig,ax = plt.subplots(nrows=1,ncols=3,figsize=(30,16))\nax[0].imshow(image)\nax[0].set_title(\"Original Image\", size=30)\nax[1].imshow(rot_clockwise_image)\nax[1].set_title(\"+45 degree Rotation\", size=30)\nax[2].imshow(rot_anticlockwise_image)\nax[2].set_title(\"-45 degree rotation\", size=30);","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:10:58.183278Z","iopub.execute_input":"2025-06-13T15:10:58.183566Z","iopub.status.idle":"2025-06-13T15:11:04.260261Z","shell.execute_reply.started":"2025-06-13T15:10:58.183539Z","shell.execute_reply":"2025-06-13T15:11:04.259351Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"##  2.6 Cropping with skimage <a id=\"2.6\"></a>","metadata":{}},{"cell_type":"code","source":"# source: https://www.kaggle.com/safavieh/image-augmentation-using-skimage\nimport random\nimport pylab as pl \ndef randRange(a, b):\n    '''\n    a utility function to generate random float values in desired range\n    '''\n    return pl.rand() * (b - a) + a\ndef randomCrop(im):\n    '''\n    croping the image in the center from a random margin from the borders\n    '''\n    margin = 1/3.5\n    start = [int(randRange(0, im.shape[0] * margin)),\n             int(randRange(0, im.shape[1] * margin))]\n    end = [int(randRange(im.shape[0] * (1-margin), im.shape[0])), \n           int(randRange(im.shape[1] * (1-margin), im.shape[1]))]\n    cropped_image = (im[start[0]:end[0], start[1]:end[1]])\n    return cropped_image","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:11:04.261382Z","iopub.execute_input":"2025-06-13T15:11:04.261633Z","iopub.status.idle":"2025-06-13T15:11:04.274109Z","shell.execute_reply.started":"2025-06-13T15:11:04.261607Z","shell.execute_reply":"2025-06-13T15:11:04.272937Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"fig,ax = plt.subplots(nrows=1,ncols=2,figsize=(20,12))\nax[0].imshow(image)\nax[0].set_title(\"Original Image\", size=20)\nax[1].imshow(randomCrop(image))\nax[1].set_title(\"Cropped\", size=20)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:11:04.275017Z","iopub.execute_input":"2025-06-13T15:11:04.275268Z","iopub.status.idle":"2025-06-13T15:11:06.273524Z","shell.execute_reply.started":"2025-06-13T15:11:04.275232Z","shell.execute_reply":"2025-06-13T15:11:06.272791Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"##  2.7 Brightness Manipulation <a id=\"2.7\"></a>","metadata":{}},{"cell_type":"code","source":"image_bright = adjust_gamma(image, gamma=0.5,gain=1)\nimage_dark = adjust_gamma(image, gamma=2,gain=1)\n\n\nfig,ax = plt.subplots(nrows=1,ncols=3,figsize=(20,12))\nax[0].imshow(image)\nax[0].set_title(\"Original Image\", size=20)\nax[1].imshow(image_bright)\nax[1].set_title(\"Brightened Image\", size=20)\nax[2].imshow(image_dark)\nax[2].set_title(\"Darkened Image\", size=20)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:11:06.274882Z","iopub.execute_input":"2025-06-13T15:11:06.275132Z","iopub.status.idle":"2025-06-13T15:11:09.762133Z","shell.execute_reply.started":"2025-06-13T15:11:06.275108Z","shell.execute_reply":"2025-06-13T15:11:09.761349Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"torch.save(model.state_dict(), 'model.pth')\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:19:13.179885Z","iopub.execute_input":"2025-06-13T15:19:13.180208Z","iopub.status.idle":"2025-06-13T15:19:13.254880Z","shell.execute_reply.started":"2025-06-13T15:19:13.180177Z","shell.execute_reply":"2025-06-13T15:19:13.254102Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nfrom torchvision import transforms\nfrom torchvision.models import resnet18  # or your actual model\nfrom PIL import Image\nimport pandas as pd\nimport os\n\n# Load CSV\ndf = pd.read_csv('../input/plant-pathology-2021-fgvc8/train.csv')\ndf_sample = df.sample(20).reset_index(drop=True)\n\n# Image folder\nimage_dir = '../input/plant-pathology-2021-fgvc8/train_images'\n\n# Model Setup (must match training)\nmodel = resnet18(pretrained=False)\nmodel.fc = torch.nn.Linear(model.fc.in_features, 12)  # change to correct class count\nmodel.load_state_dict(torch.load('/kaggle/working/model.pth'))\nmodel.eval()\n\n# Device\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nmodel.to(device)\n\n# Transform\ntransform = transforms.Compose([\n    transforms.Resize((224, 224)),\n    transforms.ToTensor(),\n    transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])\n])\n\n# Predict\npredictions = []\nwith torch.no_grad():\n    for _, row in df_sample.iterrows():\n        img_path = os.path.join(image_dir, row['image'])\n        image = Image.open(img_path).convert(\"RGB\")\n        input_tensor = transform(image).unsqueeze(0).to(device)\n\n        output = model(input_tensor)\n        pred = torch.argmax(output, dim=1).item()\n        predictions.append(pred)\n\n# Display predictions\nfor idx, row in df_sample.iterrows():\n    print(f\"Image: {row['image']}, True Label: {row['labels']}, Predicted Index: {predictions[idx]}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-13T15:19:33.789289Z","iopub.execute_input":"2025-06-13T15:19:33.789564Z","iopub.status.idle":"2025-06-13T15:19:49.041297Z","shell.execute_reply.started":"2025-06-13T15:19:33.789540Z","shell.execute_reply":"2025-06-13T15:19:49.040418Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Ending note <a id=\"5\"></a>\n\n<font color=\"red\" size=4>This concludes my kernel. Please upvote if you like it. It motivates me to produce more quality content :)</font>","metadata":{}},{"cell_type":"markdown","source":"","metadata":{}}]}