Dog Breed Classification: Part 3 (Simple App Development)

Shrinand Kadekodi
6 min readAug 6, 2022

In the last post using Transfer Learning, I showed how to train an EfficientNet model using tensorflow in Google Colab. You can revisit the post here —
https://shrinandkadekodi.medium.com/dog-breed-classification-part-2-deep-learning-model-93cb5cdf555e
In this post I will create a basic web application using a Python library called Streamlit with minimum coding. Let’s start!

Installation

To install Streamlit on PyCharm, search in the python interpreter and install the latest version. Other libraries which I have used for this exercise are — opencv, tensorflow, pillow, and numpy. After installing all these libraries we can start creating our web application. Earlier I had written a post for creating a basic web application using Flask and Swagger (flasger). You can check it here:
https://shrinandkadekodi.medium.com/simple-machine-learning-flask-api-using-flasgger-de1d19a79507
For me personally, I felt using Streamlit is much more easier and has a lot of additional functionality than Swagger (I could be wrong!).

Implementation

First, input image has to be taken from the from user after which the image has to be scaled to the required value (224,224) for our model. This is done using opencv. The below function shows how the image is scaled and the probability of each class is determined. The class showing probability greater than 0.5 is chosen as the correct one. If any class does not have greater than 0.5 probability, then it returns an unrecognized image string.

# import all required dependencies
import tensorflow as tf
import cv2
import streamlit as st
from PIL import Image
import numpy as np

# function to run model on user provided image
def analyseImage(efficientnetModel,imgPath,classNames):
# converting the image uploaded by user to numpy array for
# opencv to read properly
readImage = np.array(imgPath.convert('RGB'))
# resizing and expanding dimension for model to predict image
resizedImg = cv2.resize(readImage,(224,224))
expandImage = tf.expand_dims(resizedImg,axis=0)
index = efficientnetModel.predict(expandImage)
# finding the probability having more than 50%
findProb = index > 0.5
# flattening and conversion to list for finding the dog breed
tempData = findProb.flatten()
probList = tempData.tolist()
try:
return 'The image is a ' + classNames[probList.index(True)]
except ValueError:
return 'Sorry Could not recognise image. Please give only the images as displayed above'

The rest of the part is setting up how to display the web page. I am by no means a Streamlit expert but their documentation is very easy to understand and you have help available on their community pages as well. You can find the documentation link here
The layout is simple. It has a heading and some reference images of the dog breeds. These images are divided into columns. I have added some caption which shows where the images are taken from.

# drawing image in columns of streamlit
def drawCols(col,pathString,headerString,capString):
with col:
st.header(headerString)
st.image(pathString,caption = capString)
# loading model and classes
efficientnetModel = tf.keras.models.load_model('effModel')
# class names are in the order as defined when training the model
classNames = ['French Bulldog', 'Husky', 'Malamute', 'Boston Terrier']
# setting some simple streamlit messages
st.set_page_config(layout="wide")
st.title('Dog Breed Detection')
st.subheader('This Web App detects one of the below dog breeds:')
# setting some column
colLength = 4
col0,col1,col2,col3 = st.columns(colLength)
# setting image paths for app
allDogPath = {'Boston Terrier':'Images/For_app/BT129.jpg',
'French Bulldog':'Images/For_app/FB1.jpg',
'Husky':'Images/For_app/HD151.jpg',
'Malamute':'Images/For_app/MD6.jpg'}
# setting column for each breed
allDogColumns = {'Boston Terrier':col0,
'French Bulldog':col1,
'Husky':col2,
'Malamute':col3}
# copyright to their owner
allDogCaptions = {'Boston Terrier': 'Copyright: https://www.thegoodypet.com/how-much-does-a-boston-terrier-cost',
'French Bulldog':'Copyright: https://thichthucung.com/',
'Husky':'Copyright: https://siberiianblog.tumblr.com/post/188834198272/officialhuskylovers',
'Malamute':'Copyright: ©liliya kulianionak - stock.adobe.com'}
# assigning each column data
for key in allDogPath.keys():
drawCols(allDogColumns[key],allDogPath[key],key,allDogCaptions[key])

The next part is taking the image from the user. I had an issue in this where the image was not getting deleted after the classification was done. The images were getting saved and was getting added to the list. After searching the Streamlit community help pages I was able to get a workaround. I have used it with some changes for my need. So once the image is uploaded by the user, it then sends the image to the model to recognize the image and send back the answer

# user upload image
# taken from Streamlit community pages after going through the comments
with st.form("my-form", clear_on_submit=True):
uploadedFile = st.file_uploader("Choose a file", type=['jpg','png','jpeg'])
submitted = st.form_submit_button("UPLOAD!")
# when submitted run the image for predicting the dog breed
if submitted and uploadedFile is not None:
imgPath = Image.open(uploadedFile)
returnString = analyseImage(efficientnetModel, imgPath, classNames)
st.image(uploadedFile)
st.title(returnString)

You need to run the code by using — streamlit run yourFile.py in Pycharm powershell window. This will open the app in your default browser at the address — http://localhost:8501 .You can see the sample app user interface below:

The complete code is below for reference:

# import all required dependencies
import tensorflow as tf
import cv2
import streamlit as st
from PIL import Image
import numpy as np
# function to run model on user provided image
def analyseImage(efficientnetModel,imgPath,classNames):
# converting the image uploaded by user to numpy array for
# opencv to read properly
readImage = np.array(imgPath.convert('RGB'))
# resizing and expanding dimension for model to predict image
resizedImg = cv2.resize(readImage,(224,224))
expandImage = tf.expand_dims(resizedImg,axis=0)
index = efficientnetModel.predict(expandImage)
# finding the probability having more than 50%
findProb = index > 0.5
# flattening and conversion to list for finding the dog breed
tempData = findProb.flatten()
probList = tempData.tolist()
try:
return 'The image is a ' + classNames[probList.index(True)]
except ValueError:
return 'Sorry Could not recognise image. Please give only the images as displayed above'
# drawing image in columns of streamlit
def drawCols(col,pathString,headerString,capString):
with col:
st.header(headerString)
st.image(pathString,caption = capString)
# loading model and classes
efficientnetModel = tf.keras.models.load_model('effModel')
# class names are in the order as defined when training the model
classNames = ['French Bulldog', 'Husky', 'Malamute', 'Boston Terrier']
# setting some simple streamlit messages
st.set_page_config(layout="wide")
st.title('Dog Breed Detection')
st.subheader('This Web App detects one of the below dog breeds:')
# setting some column
colLength = 4
col0,col1,col2,col3 = st.columns(colLength)
# setting image paths for app
allDogPath = {'Boston Terrier':'Images/For_app/BT129.jpg',
'French Bulldog':'Images/For_app/FB1.jpg',
'Husky':'Images/For_app/HD151.jpg',
'Malamute':'Images/For_app/MD6.jpg'}
# setting column for each breed
allDogColumns = {'Boston Terrier':col0,
'French Bulldog':col1,
'Husky':col2,
'Malamute':col3}
# copyright to their owner
allDogCaptions = {'Boston Terrier': 'Copyright: https://www.thegoodypet.com/how-much-does-a-boston-terrier-cost',
'French Bulldog':'Copyright: https://thichthucung.com/',
'Husky':'Copyright: https://siberiianblog.tumblr.com/post/188834198272/officialhuskylovers',
'Malamute':'Copyright: ©liliya kulianionak - stock.adobe.com'}
# assigning each column data
for key in allDogPath.keys():
drawCols(allDogColumns[key],allDogPath[key],key,allDogCaptions[key])
# user upload image
# taken from Streamlit community pages after going through the comments
with st.form("my-form", clear_on_submit=True):
uploadedFile = st.file_uploader("Choose a file", type=['jpg','png','jpeg'])
submitted = st.form_submit_button("UPLOAD!")
# when submitted run the image for predicting the dog breed
if submitted and uploadedFile is not None:
imgPath = Image.open(uploadedFile)
returnString = analyseImage(efficientnetModel, imgPath, classNames)
st.image(uploadedFile)
st.title(returnString)

And with this we come to the end of this post. I hope that you were able to get some understanding of using Streamlit and creating simple web application with little to no web dev experience. In the next post we will see how to host this web app on cloud.

References:
https://towardsdatascience.com/create-a-photo-converter-app-using-streamlit-surprisingly-easy-and-fun-db291b5010c6
https://docs.streamlit.io/library/api-reference
Along with streamlit community and lots of googling and stackoverflow

Originally published at http://evrythngunder3d.wordpress.com on August 6, 2022.

--

--