conda env create -f eden_transfer_learning.yml
Note: If you find any issues while executing the notebook, don't hesitate to open an issue on Github. We will reply you as soon as possible.
In order to improve the performance of a deep-learning-based system, many times a pre-processing step known as background removal is applied. This technique is supposed to remove as much noise/background from the image, making the object of study appearing as the main part of the picture. Additionally, background removal is not only useful for improving the performance of the deep neural network, but also for reducing overfitting.
In agriculture, several works have made use of background removal techniques for achieving a better performance (Mohanty et al., 2016; McCool et al., 2017; Milioto et al., 2017; Espejo-Garcia et al., 2020).
In this notebook, we are gonna cover one of the most important pre-processing steps when implementing an AI-based solution in weeds identification: Background removal. Specifically, the GrabCut algorithm is gonna be used. Designed in Rother et al., 2004, this is an algorithm for foreground extraction with minimal user interaction. The algorithm works like this:
UPDATES
import numpy as np
import cv2
from tqdm import tqdm
from glob import glob
from pathlib import Path
import random
import matplotlib.pyplot as plt
%matplotlib inline
# Reads data from the specified paths in path_list
def read_data(path_list, im_size=(128,128)):
X = []
for path in path_list :
for im_file in tqdm(glob(path + '*/*')):
if im_file.lower().endswith("jpg"): # Avoid reading metadata .txt files.
try:
im = cv2.imread(im_file)
# Resize to appropriate dimensions.You can try different interpolation methods.
im = cv2.resize(im, im_size,interpolation=cv2.INTER_LINEAR)
# By default OpenCV read with BGR format, return back to RGB.
im = cv2.cvtColor(im, cv2.COLOR_BGR2RGB)
X.append(im)
except Exception as e:
# In case annotations or metadata are found
print("Not a picture")
X = np.array(X)# Convert list to numpy array.
return X
def plot_sample(images):
nb_rows = 3
nb_cols = 3
fig, axs = plt.subplots(nb_rows, nb_cols, figsize=(10, 10))
for i in range(0, nb_rows):
for j in range(0, nb_cols):
axs[i, j].xaxis.set_ticklabels([])
axs[i, j].yaxis.set_ticklabels([])
axs[i, j].imshow(images[random.randint(0, images.shape[0]-1)])
NUM_ITERS = 5
IM_SIZE = (256, 256)
# Datasets' paths we want to work on.
PATH_LIST = ['eden_data/Broccoli-080919-Healthy-zz-V1-20210225102111']
i=0
for path in PATH_LIST:
#Define paths in an OS agnostic way.
PATH_LIST[i] = str(Path(Path.cwd()).parents[0].joinpath(path))
i+=1
X = read_data(PATH_LIST, IM_SIZE)
100%|██████████| 93/93 [00:12<00:00, 7.54it/s]
plot_sample(X)
def add_contours(image, mask):
contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
if len(contours) != 0:
cv2.drawContours(image, contours, -1, (255, 0, 0), 2)
c = max(contours, key = cv2.contourArea)
x,y,w,h = cv2.boundingRect(c)
cv2.rectangle(image, (x, y), (x+w, y+h), (0, 255, 0) ,2)
def remove_background(image):
h, w = image.shape[:2]
mask = init_grabcut_mask(h, w)
bgm = np.zeros((1, 65), np.float64)
fgm = np.zeros((1, 65), np.float64)
# We give the rectangle parameters and let the algorithm run for NUM_ITERS iterations.
# The parameter mode should be cv.GC_INIT_WITH_RECT since we are using rectangle.
cv2.grabCut(image, mask, None, bgm, fgm, NUM_ITERS, cv2.GC_INIT_WITH_MASK)
mask_binary = np.where((mask == 2) | (mask == 0), 0, 1).astype('uint8')
result = cv2.bitwise_and(image, image, mask = mask_binary)
add_contours(result, mask_binary) # optional, adds visualizations
return result
def init_grabcut_mask(h, w):
mask = np.ones((h, w), np.uint8) * cv2.GC_BGD # A trivial background pixel
mask[h//10:9*h//10, w//10:9*w//10] = cv2.GC_PR_BGD # A possible backgroung pixel
mask[h//4:3*h//4, w//4:3*w//4] = cv2.GC_PR_FGD # A possible foreground pixel
mask[2*h//5:3*h//5, 2*w//5:3*w//5] = cv2.GC_FGD # A trivial foreground pixel
return mask
plt.imshow(init_grabcut_mask(128, 128), cmap="RdYlGn")
<matplotlib.image.AxesImage at 0x255e6ba1250>
%%time
filtered_images = []
for im in X:
filtered_images.append(remove_background(im))
Wall time: 19.3 s
plot_sample(np.array(filtered_images))
Rother, C., Kolmogorov, V., & Blake, A. (2004). "GrabCut": interactive foreground extraction using iterated graph cuts. ACM SIGGRAPH 2004 Papers.
McCool, C., Perez, T., Upcroft, B., 2017. Mixtures of lightweight deep convolutional neural networks: applied to agricultural robotics. IEEE Rob. Autom. Lett. 2 (3), 1344–1351.
Milioto, A., Lottes, P., Stachniss, C., 2017. Real-time blob-wise sugar beets vs weeds classification for monitoring fields using convolutional neural networks. Proceedings of the International Conference on Unmanned Aerial Vehicles in Geomatics. Bonn, Germany.
Mohanty, S.P., Hughes, D.P., Salathé, M., 2016. Using deep learning for image-based plant disease detection. Front. Plant. Sci. 7.
Espejo-García, B., Mylonas, N., Athanasakos, L., Fountas, S., & Vasilakoglou, I. (2020). Towards weeds identification assistance through transfer learning. Comput. Electron. Agric., 171, 105306.
OpenCV details: https://docs.opencv.org/3.4/d8/d83/tutorial_py_grabcut.html
This notebook was highly inspired by Victor-Louis De Gusseme (https://www.kaggle.com/victorlouisdg/plant-pathology-opencv-background-removal)