Blood Face Detector in Python(Part 2) — Building a Web Application using Streamlit in Python
By: Mrinal Walia
Tags: TensorFlow, Keras, Data Science, Python, Artificial Intelligence

Note: You can download the source code for the project on my Github page. The code for today's article can be found in the app.py file.

Now, coming back to the topic:

Step-1: Installing Streamlit using Pypi

Simply open your terminal and write:

pip install streamlit

Step-2: Importing the required libraries

from sklearn.metrics import classification_report, accuracy_score, confusion_matrix

from tensorflow.keras.applications.mobilenet_v2 import preprocess_input

from tensorflow.keras.preprocessing.image import img_to_array

from tensorflow.keras.models import load_model

from imutils.video import VideoStream

from PIL import Image,ImageEnhance

import matplotlib.pyplot as plt

import pandas as pd

import numpy as np

import argparse

import imutils

import time

import glob

import random

import cv2

import os import streamlit as st st.set_option('deprecation.showfileUploaderEncoding', False)

@st.cache(suppress_st_warning=True)

@st.cache(persist=True)

I have imported streamlit as st on the last import line and all the other TensorFlow and utility libraries are also imported.

Last three line of code is to avoid any warnings you may get while using OpenCV with streamlit.

Step-3: helper function to predict images

# helper function to predict images

def imagepreds(image):



# load our serialized face detector model from disk

prototxtPath = os.path.sep.join(['Model', "deploy.prototxt"])

weightsPath = os.path.sep.join(['Model', "res10_300x300_ssd_iter_140000.caffemodel"])

net = cv2.dnn.readNet(prototxtPath, weightsPath) # load the face mask detector model from disk

model = load_model('blood_noblood_classifier.model')



orig = image.copy()

(h, w) = image.shape[:2] # construct a blob from the image

blob = cv2.dnn.blobFromImage(image, 1.0, (300, 300), (104.0, 177.0, 123.0)) # pass the blob through the network and obtain the face detections

net.setInput(blob)

detections = net.forward() # loop over the detections

for i in range(0, detections.shape[2]):



# extract the confidence (i.e., probability) associated with

# the detection

confidence = detections[0, 0, i, 2]



# filter out weak detections by ensuring the confidence is

# greater than the minimum confidence



if confidence > 0.6:



# compute the (x, y)-coordinates of the bounding box for

# the object

box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])

(startX, startY, endX, endY) = box.astype("int")



# ensure the bounding boxes fall within the dimensions of

# the frame

(startX, startY) = (max(0, startX), max(0, startY))

(endX, endY) = (min(w - 1, endX), min(h - 1, endY)) # extract the face ROI, convert it from BGR to RGB channel

# ordering, resize it to 224x224, and preprocess it

face = image[startY:endY, startX:endX]

#face = cv2.cvtColor(face, 1)

face = cv2.cvtColor(face, cv2.COLOR_BGR2RGB)

face = cv2.resize(face, (224, 224))

face = img_to_array(face)

face = preprocess_input(face)

face = np.expand_dims(face, axis=0)



# pass the face through the model to determine if the face

# has a mask or not

(blood, noblood) = model.predict(face)[0] # determine the class label and color we'll use to draw

# the bounding box and text

label = "Blood" if blood > noblood else "No Blood"

color = (0, 0, 255) if label == "Blood" else (0, 255, 0)



# include the probability in the label

label = "{}: {:.2f}%".format(label, max(blood, noblood) * 100)



# display the label and bounding box rectangle on the output

# frame

cv2.putText(image, label, (startX, startY - 10),

cv2.FONT_HERSHEY_SIMPLEX, 0.45, color, 2)

cv2.rectangle(image, (startX, startY), (endX, endY), color, 2)



# show the output image

st.image(image, caption='Predictions', width=720)

If you have read my previous article (part-1 of this blog post) there is nothing new for you in this function to understand except the last line where we are using st.image(image, caption='Predictions', width=720) to show the output instead of the OpenCV utility method imshow() .

Step-4: helper function to predict in real-time

# helper function to predict in real-time

def videopreds():



# define a helper function to detected face and bounding box for each image

# in a live video frame

def detect_and_predict_blood(frame, faceNet, bloodNet):



# grab the dimensions of the frame and then construct a blob

# from it

(h, w) = frame.shape[:2]

blob = cv2.dnn.blobFromImage(frame, 1.0, (300, 300), (104.0, 177.0, 123.0))



# pass the blob through the network and obtain the face detections

faceNet.setInput(blob)

detections = faceNet.forward()



# initialize our list of faces, their corresponding locations,

# and the list of predictions from our face mask network

faces = []

locs = []

preds = [] # loop over the detections

for i in range(0, detections.shape[2]):



# extract the confidence (i.e., probability) associated with

# the detection

confidence = detections[0, 0, i, 2]



# filter out weak detections by ensuring the confidence is

# greater than the minimum confidence

if confidence > 0.5:



# compute the (x, y)-coordinates of the bounding box for

# the object

box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])

(startX, startY, endX, endY) = box.astype("int")



# ensure the bounding boxes fall within the dimensions of

# the frame

(startX, startY) = (max(0, startX), max(0, startY))

(endX, endY) = (min(w - 1, endX), min(h - 1, endY)) # extract the face ROI, convert it from BGR to RGB channel

# ordering, resize it to 224x224, and preprocess it

face = frame[startY:endY, startX:endX]

face = cv2.cvtColor(face, cv2.COLOR_BGR2RGB)

face = cv2.resize(face, (224, 224))

face = img_to_array(face)

face = preprocess_input(face)



# add the face and bounding boxes to their respective

# lists

faces.append(face)

locs.append((startX, startY, endX, endY)) # only make a predictions if at least one face was detected

if len(faces) > 0:



# for faster inference we'll make batch predictions on *all*

# faces at the same time rather than one-by-one predictions

# in the above `for` loop

faces = np.array(faces, dtype="float32")

preds = bloodNet.predict(faces, batch_size=32)



# return a 2-tuple of the face locations and their corresponding

# locations

return (locs, preds) # load our serialized face detector model from disk

prototxtPath = os.path.sep.join(['Model', "deploy.prototxt"])

weightsPath = os.path.sep.join(['Model', "res10_300x300_ssd_iter_140000.caffemodel"])

faceNet = cv2.dnn.readNet(prototxtPath, weightsPath) # load the face mask detector model from disk

bloodNet = load_model('blood_noblood_classifier.model')



# time.sleep(2.0)

@st.cache(allow_output_mutation=True)

def get_cap():

return cv2.VideoCapture(0) cap = get_cap() frameST = st.empty() # loop over the frames from the video stream

while True:



# grab the frame from the threaded video stream and resize it

# to have a maximum width of 400 pixels

# frame = vs.read()

# frame = imutils.resize(frame, width=400)

ret, frame = cap.read()

# detect faces in the frame and determine if they are wearing a

# face mask or not

(locs, preds) = detect_and_predict_blood(frame, faceNet, bloodNet) # loop over the detected face locations and their corresponding

# locations

for (box, pred) in zip(locs, preds):



# unpack the bounding box and predictions

(startX, startY, endX, endY) = box

(blood, noblood) = pred



# determine the class label and color we'll use to draw

# the bounding box and text

label = "Blood" if blood > noblood else "No Blood"

color = (0, 0, 255) if label == "Blood" else (0, 255, 0)



# include the probability in the label

label = "{}: {:.2f}%".format(label, max(blood, noblood) * 100)



# display the label and bounding box rectangle on the output

# frame

cv2.putText(frame, label, (startX, startY - 10),

cv2.FONT_HERSHEY_SIMPLEX, 0.45, color, 2)

cv2.rectangle(frame, (startX, startY), (endX, endY), color, 2) # show the output frame

frameST.image(frame, channels="BGR")



# do a bit of cleanup

cv2.destroyAllWindows()

Again if you have read part-1 of this blog post, this part would be pretty clear to you as there are not many changes in this part. Here we are using frameST = st.empty() to get a frame after starting the VideoCapture() method and using frameST.image(frame, channels="BGR") to show the output frame.

Step-5: Designing the Front Page for your application

ig = Image.open('sample.jpg')

st.image(ig, width=920) st.title('Blood Detection Classifier')

st.text('Build with Streamlit,Tensorflow, Keras and OpenCV By Mrinal Walia')

st.header("Select the options from sidebar: ")

st.subheader("Image Detection: For uploading an Image")

st.subheader("Video Detection: For opening the webcam and checking the results")

st.subheader("Performance Metrics: To check various performance metrices")

st.markdown("THANKS FOLKS!!")

st.subheader("Happy Learning")

st.subheader("Creator: @MRINAL WALIA")

st.markdown('Source Code Link: https://github.com/abhiwalia15/Face-Classification-into-Blood-No-Blood')

There are various methods that can be used to design the front page for your application. I always encourage you to write some useful information regarding your project and/or give links to your code or social profiles so if anyone wants to reach out to you, he/she can easily connect with you.

Note: Refer to the streamlit documentation.

Step-6: Writing the main function

def main(): menu = ['Image Detection', 'Video Detection', 'Perofrmance Metrics']

choice = st.sidebar.selectbox('Menu',menu) if choice == 'Image Detection':

st.subheader('**Blood Detection**')

img_file_buffer = st.file_uploader("Upload an image")



if img_file_buffer is not None:

image = Image.open(img_file_buffer)

img_array = np.array(image)

imagepreds(img_array) elif choice == 'Video Detection':

st.subheader('**Blood Detection**')

videopreds() elif choice == 'Perofrmance Metrics': st.subheader('About Performance Metrics') st.info("CLASSIFICATION REPORT")

cr = Image.open('Results/classification_report.png')

st.image(cr, width=320) st.info("CONFUSION MATRIX")

cm = Image.open('Results/confusion_matrix.png')

st.image(cm, width=320) st.info("ACCURACY SCORE")

acs = Image.open('Results/accuracy_score.png')

st.image(acs, width=320)

I have used a sidebar to prompt the user with various options. Use can also use a dropdown or checkbox.

If the user selects the 'Image Detection' from the sidebar, firstly the file_uploader built-in function in streamlit is used to upload the file and then the image is converted to an array and is passed to the imagepreds() function.

from the sidebar, firstly the built-in function in streamlit is used to upload the file and then the image is converted to an array and is passed to the function. This will return the predictions on the uploaded image.

If the user selects 'Video Detection' choice then the videopreds() function is called.

choice then the function is called. At last 'Performance Metrics' is an extra part but I found this useful for the project to upload the performance metrics for everyone to understand how well the model is performing.

Step-7: Call the main function

# driver code

if __name__ == '__main__':

main()

It's time now to wrap up the code and call the main function.

Step-8: Save the python script and run the file

Now, everything is done, save the file and open up the terminal and type the following command for the streamlit application to run on the local host machine.

$ streamlit run app.py

Results: