Mask Prediction
[ Baseline ] Mask Prediction
The baseline with a naive approach of mask detection using Canny Edge Detection, Sklearn Models etc.
Getting Started with Mask Recognition Challenge
In this puzzle, we have detect mask type and bounding box of the mask from the image of human face.
In this notebook, we'll use the naive approach to prepare the baseline for this puzzle.
Naive Approach¶
- We will create bounding box that will detect the face and crop the image as per the co-ordinates of bounding box from image.
- Once we've the cropped image(It'll have the image of mask), we'll feed the data to train classifier which will classify the mask.
Setting up Environment¶
Downloading Dataset¶
So we will first need to download the python library by AIcrowd that will allow us to download the dataset by just inputting the API key.
%%capture
!pip install aicrowd-cli
%load_ext aicrowd.magic
Login to AIcrowd ㊗¶¶
%aicrowd login
Download Dataset¶¶
We will create a folder name data and download the files there.
!rm -rf data
!mkdir data
%aicrowd ds dl -c mask-prediction -o data
!unzip data/train.zip -d data/ > /dev/null
!unzip data/val.zip -d data/ > /dev/null
!unzip data/test.zip -d data/ > /dev/null
Importing Libraries¶
#Reading the file
import pandas as pd
import numpy as np
import os
# Image Reading & Preprocessing
from PIL import Image, ImageDraw
import cv2
import matplotlib.pyplot as plt
import numpy as np
# Misc.
from tqdm.notebook import tqdm
from sklearn.ensemble import RandomForestClassifier
Diving in the dataset 🕵️♂️¶
train_images = 'data/train'
val_images = 'data/val'
test_images = 'data/test'
train_df = pd.read_csv("data/train.csv")
val_df = pd.read_csv("data/val.csv")
train_df.head()
train_df.loc[train_df.masktype == "cloth"][:2]
train_img = os.listdir(train_images)
train_img[:5]
From the above, we can see that ImageId is image_name without extensions(.jpg).
img = Image.open(os.path.join(train_images, '7a0l9.jpg'))
img
Image Preprocessing¶
In this section we are going to learn some opencv functions which can help us detecting the mask from the image!
# Converting the image to numpy array
np_img= np.array(img)
np_img.shape
# Converting the Image to RGB to Grayscale ( black/white )
gray= cv2.cvtColor(np_img, cv2.COLOR_BGR2GRAY)
plt.imshow(gray)
cv2.Canny
¶
Now cv2.Canny
is Canny Edge Detection which helps us to detect edges in the image. Let's try it our on the image
canny= cv2.Canny(gray, 120,250)
plt.imshow(canny)
So as you can see the function detected edges including the mask and some noise too, there are many ways to reduce that noise, however you can try changing the parameters in the function and see where that leads.
Countours¶
Contours are lines joining along the bounding of a intensity or color in an image. In the canny image or the original image, we see that the image has much different color as compared to the sky.
# Finding contours in the image
contours, hierarchy = cv2.findContours(canny,
cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
# Sorting the contours in ascending order
contours = sorted(contours, key=cv2.contourArea)
# Getting the bounding boxes of the biggest contours
x,y,w,h = list(cv2.boundingRect(contours[-1]))
x,y,w,h
# Showing the contour
draw_img = img.copy()
draw = ImageDraw.Draw(draw_img)
draw.rectangle([x,y,x+w,y+h ], outline ="red")
draw_img
So as you can see, fnding contours did a pretty great job in finfing the mask.
left,top,right, bottom = x,y,x+w,y+h
mask = img.crop((left,top,right, bottom))
mask
mask = mask.convert('L')
mask1 = np.asarray(mask)
mask1.shape
mask
Now, we will create a function which will perform the all things which we've done previous cells.
def gen_bounding_boxes_and_mask(img):
# Converting the image to numpy array
np_img = np.array(img)
gray = cv2.cvtColor(np_img, cv2.COLOR_BGR2GRAY)
# Getting the edges
canny = cv2.Canny(gray, 100, 200)
# Getting the contours
contours, hierarchy = cv2.findContours(canny,
cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
# Sorting the contours
contours = sorted(contours, key=cv2.contourArea)
try:
# Return the boundong boxes of the biggest contour
x,y,w,h = list(cv2.boundingRect(contours[-1]))
# Incase no countous found
except:
x,y,w,h = [1, 1, 1, 1]
left,top,right, bottom = x,y,x+w,y+h
mask = img.crop((left,top,right, bottom))
return x,y,w,h, mask
Preprocessor¶
Prepare data for feeding the model by using function gen_bounding_boxes_and_mask
.
def preprocessor(image_path,dataframe):
bboxes = []
image_ids = []
mask_type = []
# Ground through each test image
# for i in range(len(df_list)):
for i in tqdm(range(dataframe.shape[0])):
# Reading the test image
img = Image.open(os.path.join(image_path, list(dataframe['ImageID'])[i]+'.jpg'))
# Generating the bounding boxes
x,y,w,h,mask = gen_bounding_boxes_and_mask(img)
#Convert to grayscale
mask = mask.convert('L')
#Reshapes the image to a fix sahpe -> 190×190(You can choose any shape)
mask = mask.resize((190,190))
mask = np.asarray(mask)
#Squeezes the matrix for feeding the value to model
mask = np.squeeze(mask[10,:])
mask_type.append(mask)
# Adding the boundong boxes and image id
bboxes.append([x,y,x+w,y+h])
# image_ids.append(test_imgs[i].split(".")[0])
if image_path == test_images:
dataframe['bbox'] = bboxes
else:
dataframe['pred_bbox'] = bboxes
dataframe['imgData'] = mask_type
return dataframe
train_final_df = preprocessor(train_images,train_df)
train_final_df.head()
Model¶
train_final_df['imgData'][12].shape
X = train_final_df.imgData
y = train_final_df.masktype
X.shape,y.shape
from sklearn.ensemble import RandomForestClassifier
mask_type_predictor = RandomForestClassifier(max_features=0.15, random_state=2)
mask_type_predictor.fit(list(X),y)
print(mask_type_predictor.score(list(X),y))
val_final_df = preprocessor(val_images,val_df)
val_x = val_final_df.imgData
val_y = val_final_df.masktype
val_predict = mask_type_predictor.predict(list(val_x))
from sklearn.metrics import f1_score
print(f1_score(val_predict,val_y,average='weighted'))
Submitting Results 📄¶
test_df = pd.DataFrame()
n_test_image = os.listdir(test_images)
test_df['ImageID'] = [img_name.split(".")[0] for img_name in n_test_image]
test_df.head()
test_df = preprocessor(test_images,test_df)
test_df.head()
pred = mask_type_predictor.predict(list(test_df.imgData))
Adding prediction to test dataframe in a separate column named masktype.
test_df['masktype'] = pred
For submission, we've to drop imgData
column.
test_df.drop(['imgData'], axis=1, inplace = True)
test_df.head()
test_df
!rm -rf assets
!mkdir assets
test_df.to_csv(os.path.join("assets", "submission.csv"), index=False)
Note : Please make sure that there should be filename submission.csv
in assets
folder before submitting it
Uploading the Results¶
%aicrowd notebook submit -c mask-prediction -a assets --no-verify
Content
Comments
You must login before you can post a comment.