{"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":"# **What is this about?**\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 2020-FGVC7 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\n","metadata":{}},{"cell_type":"markdown","source":"# Let Us See an Image","metadata":{}},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport matplotlib.image as img\n  \ntestImage = img.imread('../input/plant-pathology-2021-fgvc8/train_images/8002cb321f8bfcdf.jpg')\n  \n# displaying the image\nplt.imshow(testImage)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Let Us Perform Some Image Operations that We Can Perform on This Image**","metadata":{}},{"cell_type":"code","source":"from matplotlib import pyplot as plt\n\ndef show_image(image, title='Image', cmap_type='gray'): \n  plt.imshow(image, cmap=cmap_type)\n  plt.title(title)\n  plt.axis('off')\n  plt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"leaf_image = img.imread('../input/plant-pathology-2021-fgvc8/train_images/8002cb321f8bfcdf.jpg')\nshow_image(leaf_image, 'Original Image')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Grayscale Image","metadata":{}},{"cell_type":"code","source":"from skimage import color\nleaf_image_gray = color.rgb2gray(leaf_image)\nshow_image(leaf_image_gray)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Let Us See The Histogram Of An Image","metadata":{}},{"cell_type":"code","source":"red = leaf_image[:, :, 0] # using the red channel of the rocket image.\n\nplt.hist(red.ravel(), bins=256) # plot its histogram with 256 bins, the number of possible values of a pixel.\nplt.title('Red Histogram')\nplt.show","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We notice that the frequency of the pixels varies between 25 to 250 , with most of it being in the region between 100 to 175 approximately","metadata":{}},{"cell_type":"markdown","source":"# Applying Thresholding Algorithms ","metadata":{}},{"cell_type":"code","source":"import cv2\nleaf_img= cv2.imread('../input/plant-pathology-2021-fgvc8/train_images/8002cb321f8bfcdf.jpg')\ngrayimg = cv2.cvtColor(leaf_img,cv2.COLOR_BGR2GRAY)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Grayscale Image**","metadata":{}},{"cell_type":"code","source":"plt.imshow(grayimg,cmap='gray') #cmap has been used as matplotlib uses some default colormap to plot grayscale images\nplt.xticks([]) #To get rid of the x-ticks and y-ticks on the image axis\nplt.yticks([])\nprint('New Image Shape',grayimg.shape)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Finding optimal threshold\nfrom skimage.filters import threshold_otsu\nthresh_val = threshold_otsu(grayimg)\nprint('The optimal seperation value is',thresh_val)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"thresh = 120 # set a random thresh value\n\nbinary_high = grayimg > thresh_val\nbinary_low = grayimg <= thresh_val\n\nshow_image(binary_high, 'Tresholded high values')\nshow_image(binary_low, 'Tresholded low values')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Trying All Thresholded Values**","metadata":{}},{"cell_type":"code","source":"from skimage.filters import try_all_threshold\n\nfig, ax = try_all_threshold(grayimg, verbose=False)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**We see that Iso data , Mean and Otsu , dives better results than the others so let us look at Otsu Thresholding**","metadata":{}},{"cell_type":"code","source":"from skimage.filters import threshold_otsu\n\nthresh = threshold_otsu(grayimg)\n\ntext_binary_otsu = grayimg > thresh\n\nshow_image(text_binary_otsu, 'Otsu algorithm')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Applying Edge Detection Techniques on The Image","metadata":{}},{"cell_type":"code","source":"def plot_comparison(original, filtered, title_filtered):\n  fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(8, 6), sharex=True, sharey=True)\n  ax1.imshow(original, cmap=plt.cm.gray) \n  ax1.set_title('original') \n  ax1.axis('off')\n  ax2.imshow(filtered, cmap=plt.cm.gray) \n  ax2.set_title(title_filtered) \n  ax2.axis('off')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Sobel Operator**","metadata":{}},{"cell_type":"code","source":"from skimage.filters import sobel\n\nedge_image = sobel(grayimg) # apply the filter\n\nplot_comparison(grayimg, edge_image, 'Edge image')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**We Can Now safely say , Sobel Operator , doesn't work on the image**","metadata":{}},{"cell_type":"markdown","source":"# Let Us Look at the Smoothening Features ","metadata":{}},{"cell_type":"code","source":"from skimage.filters import gaussian\nsmooth_leaf_image = gaussian(leaf_img, multichannel=True) # you have to specify the multichannel\n\nplot_comparison(leaf_img, smooth_leaf_image, 'Smooth leaf')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Contrast Enhancement Techniques","metadata":{}},{"cell_type":"code","source":"from skimage import exposure\nequalized_leaf_image = exposure.equalize_hist(leaf_img)\n\nplot_comparison(leaf_img, equalized_leaf_image, 'Histogram equalization')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Note the leaves become more prominent by Histogram Equalization Techniques**","metadata":{}},{"cell_type":"markdown","source":"**ADAPTIVE HISTOGRAM EQUALISATION**","metadata":{}},{"cell_type":"code","source":"from skimage import exposure\n\nadapthits_leag_image = exposure.equalize_adapthist(leaf_img)\n\nplot_comparison(leaf_img, adapthits_leag_image, 'Adaptive Histogram equalization')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"It seems to have a better representation of the image","metadata":{}},{"cell_type":"markdown","source":"# Now Let Us Finally Look at the Contour Methods","metadata":{}},{"cell_type":"code","source":"def show_image_contour(image, contours):\n    plt.figure()\n    for n, contour in enumerate(contours):\n        plt.plot(contour[:, 1], contour[:, 0], linewidth=3)\n    plt.imshow(image, interpolation='nearest', cmap='gray_r')\n    plt.title('Contours')\n    plt.axis('off')\n    plt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from skimage import measure\n\n\n\ncontours_gray_image = measure.find_contours(grayimg, 0.8)\n\nshow_image_contour(grayimg, contours_gray_image)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Edge Detection","metadata":{}},{"cell_type":"code","source":"from skimage.feature import canny\ncanny_leaf_image = canny(grayimg)\n\nshow_image(canny_leaf_image)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Interestingly it shows The Focused Leaf Properly**","metadata":{}},{"cell_type":"markdown","source":"# **Specific Objectives**\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.","metadata":{}},{"cell_type":"markdown","source":"# **Resources**\nI thank Kaggle for providing the dataset and [Data](http://https://bsapubs.onlinelibrary.wiley.com/doi/10.1002/aps3.11390)\nwithout whom this wouldn't have been Possible. \nAlso I would like to thank [Ankur Singh](http://https://www.kaggle.com/ankursingh12/resized-plant2021) for this amazing dataset as without it , it would have taken hours and hours to train the below mentioned model. ","metadata":{}},{"cell_type":"markdown","source":"# Import the necessary libraries","metadata":{}},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport tensorflow as tf\nimport tensorflow.keras as keras\nimport PIL\nimport cv2\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport os\nimport random\nfrom tqdm import tqdm\nimport tensorflow_addons as tfa\nimport random\nfrom sklearn.preprocessing import MultiLabelBinarizer\nimport tensorflow as tf\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport keras\nfrom keras.preprocessing import image\nfrom keras.models import Sequential\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator, load_img, img_to_array, smart_resize\nfrom keras.layers import Dense, Dropout, Flatten, BatchNormalization, Activation\nfrom keras.constraints import maxnorm\nfrom keras.layers.convolutional import Conv2D, MaxPooling2D\nfrom tensorflow.keras.optimizers import Adam\nimport cv2\nfrom PIL import Image\nfrom keras.preprocessing.image import load_img, img_to_array\nfrom keras.models import load_model\nfrom keras.metrics import AUC\n\npd.set_option(\"display.max_columns\", None)","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Let's Now Have a look at the Dataset and Study it better**\n\nI would like to thank [Praveen](http://https://www.kaggle.com/praveengovi/plant-pathology-detail-eda-pytorch) for this amazing EDA and analysis and also [Arnab](http://https://www.kaggle.com/arnabs007/apple-leaf-diseases-with-inceptionresnetv2-keras) from whom I have taken reference from . I have implemented various EDA and studied from their models and approached it with Transfer Learning Model of ResNet 50v2 base.\n ","metadata":{}},{"cell_type":"code","source":"train_dir= '../input/plant-pathology-2021-fgvc8/train_images'\ntest_dir =  '../input/plant-pathology-2021-fgvc8/test_images'\ntrain = pd.read_csv('../input/plant-pathology-2021-fgvc8/train.csv')\n#print(len(train))\n#print(train.columns)\n# print(train['labels'].value_counts())\n#print(train['labels'].value_counts().plot.bar())","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Let's Study the dataset in a better way and try to find some interesting stuff!!! ","metadata":{}},{"cell_type":"code","source":"train.head","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**We get to know that we have \"many\" images with mostly 12 types of labels (but there is a twist) which we will comeback to later.**","metadata":{}},{"cell_type":"markdown","source":"Let's look at the number of images for various of 12 categories present","metadata":{}},{"cell_type":"code","source":"train['labels'].value_counts()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(20,12))\nlabels = sns.barplot(train.labels.value_counts().index,train.labels.value_counts())\nfor item in labels.get_xticklabels():\n    item.set_rotation(45)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Note**\n\nNotice that there is a huge imbalance in dataset with \"scab\" having the highest number of frequency and \"powdery_mildew complex\" , the least","metadata":{}},{"cell_type":"markdown","source":"# Important Observation\n\n**Look at the labels, doesn't it strike you ??** \n\n**Some of the labels are mixture of one or more types !!! And thus the problem becomes Multilabel Problem**\n","metadata":{}},{"cell_type":"markdown","source":"So there are not 12 labels, its actually just 6 labels.\n5 diseases: \n1. rust\n2. scab \n3. complex \n4. frog eye leaf spot\n5. powdery mildew \n\nand another label is \n\n6. healthy (healthy leaves) \n\nNow the most important thing is, as one image can have multiple diseases, that means this problem is **Multi label classification** problem. Many get confused betweeen multilabel and multiclass classification. if you are new to multilabel classification I would suggest going over this [An introduction to MultiLabel classification](https://www.geeksforgeeks.org/an-introduction-to-multilabel-classification/) . \n\nSo now we gotta process the labels. And then lets find out the actual frequencies of the labels. \n","metadata":{}},{"cell_type":"markdown","source":"We divide it based on \" \" or space character , in order to get the labels for each of the image","metadata":{}},{"cell_type":"code","source":"train['labels'] = train['labels'].apply(lambda string: string.split(' '))\ntrain","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Converting the labels representation into **one hot encoded format** using MultilabelBinarizer from Scikit learn. Now we can see and plot the frequencies of each label. ","metadata":{}},{"cell_type":"code","source":"s = list(train['labels'])\nmlb = MultiLabelBinarizer()\ntrainx = pd.DataFrame(mlb.fit_transform(s), columns=mlb.classes_, index=train.index)\nprint(trainx.columns)\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"These are the 6 different labels ","metadata":{}},{"cell_type":"code","source":"print(trainx.sum())","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"labels = list(trainx.sum().keys())\n#print(labels)\nlabel_counts = trainx.sum().values.tolist()\n\nfig, ax = plt.subplots(1,1, figsize=(20,6))\n\nsns.barplot(x= labels, y= label_counts, ax=ax)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**NOW WE CAN SEE THE DATASET BECOMES MORE OR LESS BALANCED , AT LEAST BETTER THAN WHAT IT WAS PREVIOUSLY!**","metadata":{}},{"cell_type":"markdown","source":"# Let's See the Plant Pathology Images","metadata":{}},{"cell_type":"code","source":"labels = pd.concat([train['image'], trainx], axis=1)\nlabels.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig1 = plt.figure(figsize=(20,10))\n\nfor i in range(1, 10):\n    \n    rand =  random.randrange(1, 18000)\n    sample = os.path.join('../input/plant-pathology-2021-fgvc8/train_images/', train['image'][rand])\n    \n    img = PIL.Image.open(sample)\n    \n    ax = fig1.add_subplot(4,3,i)\n    ax.imshow(img)\n    \n    title = f\"{train['labels'][rand]}{img.size}\"\n    plt.title(title)\n    \n    fig1.tight_layout()\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Imaze Size & Processing\nfrom the titles we can see some random image sizes - (4000, 2672). Larger images are harder to process hence takes much longer to train the CNN. Downsampling all these 18632 images is also a time consuming task. This is I am going to use the resized imaged for this dataset [resized-plant2021](https://www.kaggle.com/ankursingh12/resized-plant2021) by Ankur Singh. He has already downsampled the images into size of 256, 384, 512 & 640px.\nNow for Pre Processing I take help of the [Keras Image Data Generator](http://https://keras.io/api/preprocessing/image/). We transform it to size of (256,256,3) .","metadata":{}},{"cell_type":"code","source":"%%time\ndatagen = keras.preprocessing.image.ImageDataGenerator(rescale=1/255.0,\n                                                        preprocessing_function=None,\n                                                        data_format=None,\n                                                    )\n\ntrain_data = datagen.flow_from_dataframe(\n    train,\n    directory= '../input/resized-plant2021/img_sz_512',\n    x_col=\"image\",\n    y_col= 'labels',\n    color_mode=\"rgb\",\n    target_size = (256,256),\n    class_mode=\"categorical\",\n    batch_size=32,\n    shuffle=False,\n    seed=40,\n)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# If you liked the Notebook Please Upvote It ! ","metadata":{}},{"cell_type":"markdown","source":"# Thank You","metadata":{}},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}