---
# System prepended metadata

title: Instructions to build a quick skeleton Flask app for Cat/Dog Classifier

---

# Instructions to build a quick skeleton Flask app for Cat/Dog Classifier

This guide will help you to create a simple skeleton of flask app which allow you to upload a image file and call tensorflow to predict the image for you. Then result will be displayed on classify HTML page.

Remember, there are a lot of potential improvement ideas for your flask apps:

- Change POST request to Ajax so the page will be never reloaded
- Style up the website (specially the upload form)
- Add more pages about yourself and model 
- Add options to use multiple different models
- Go further, make one-page web application (everything handled by Ajax)


## Project structure

* simple_flask
    * static
        * images
        * script.js
        * style.css
    * templates
        * classify.html
        * home.html
    * uploads
    * app.py


### Make the main flask directory called simple_flask

Ubuntu/Mac
```bash
mkdir simple_flask
```
Windows
```bash
mkdir "simple_flask"
```
### Change directory
```bash
cd simple_flask
```

### Create the following folders and files

Ubuntu/Mac

```bash
mkdir static templates uploads static/images
touch app.py static/script.js static/style.css templates/classify.html templates/home.html
```

Windows
```bash
mkdir "static" "templates" "uploads" "static/images"
copy nul "app.py"
copy nul "static/script.js"
copy nul "static/style.css"
copy nul "templates/classify.html"
copy nul "templates/home.html"
```

### Add this routing and prediction code in **flask_app/app.py**
```python
import os
from flask import Flask, render_template, request
from flask import send_from_directory
import numpy as np
import tensorflow as tf

app = Flask(__name__)

dir_path = os.path.dirname(os.path.realpath(__file__))
UPLOAD_FOLDER = 'uploads'
STATIC_FOLDER = 'static'

# Load model
cnn_model = tf.keras.models.load_model(STATIC_FOLDER + '/' + 'catdog_classifier_Xception.h5')

IMAGE_SIZE = 224

# Preprocess an image
def preprocess_image(image):
    image = tf.image.decode_jpeg(image, channels=3)
    image = tf.image.resize(image, [IMAGE_SIZE, IMAGE_SIZE])
    image /= 255.0  # normalize to [0,1] range

    return image

# Read the image from path and preprocess
def load_and_preprocess_image(path):
    image = tf.io.read_file(path)
    return preprocess_image(image)

# Predict & classify image
def classify(model, image_path):

    preprocessed_imgage = load_and_preprocess_image(image_path)
    preprocessed_imgage = tf.reshape(preprocessed_imgage, (1,IMAGE_SIZE ,IMAGE_SIZE ,3))

    prob = cnn_model.predict(preprocessed_imgage)
    label = "Cat" if prob >= 0.5 else "Dog"
    classified_prob = prob if prob >= 0.5 else 1 - prob
    
    return label, classified_prob

# home page
@app.route('/')
def home():
   return render_template('home.html')

@app.route('/classify', methods=['POST','GET'])
def upload_file():

    if request.method == 'GET':
        return render_template('home.html')
    else:
        file = request.files["image"]
        upload_image_path = os.path.join(UPLOAD_FOLDER, file.filename)
        print(upload_image_path)
        file.save(upload_image_path)

        label, prob = classify(cnn_model, upload_image_path)

        prob = round((prob[0][0] * 100), 2)

    return render_template('classify.html', image_file_name = file.filename, label = label, prob = prob)

@app.route('/classify/<filename>')
def send_file(filename):
    return send_from_directory(UPLOAD_FOLDER, filename)

if __name__ == '__main__':
    app.debug = True
    app.run(debug=True)
    app.debug = True
```

### Add some css styles in **flask_app/static/style.css**
```css
h2 {
    letter-spacing: 2px; 
    font-size: 1.5rem
}

form {
  padding-top:20px;
  font-size: 24px;
}

.classify{
  text-align:center;
  margin:auto;
  margin-top:200px;
}

.image-prediction, 
.text-prediction{
  margin-top: 100px;
  text-align:center;
}

.pred_img {
  width: 400px; 
  height: 400px;
}

#pred  {
  font-size: 60px; 
  text-transform: uppercase;
}

#label {  
  color: red; 
  font-size: 4rem; 
  text-transform: uppercase;
}

#classify_button {
  font-size: 2rem; 
  font-weight: bold;
}
```



## HTML Template

###  Create template for our home page at **flask_app/templates/home.html**

> *Hints: most of this code can be automaticaly generated with a VSCode Extension called flask-snippets by only writting "fapp"*
> ![](https://i.imgur.com/npmdsha.png =500x)



```html
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Catto & Doggo Classifier</title>
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
  <link rel="stylesheet" href="/static/style.css" type="text/css">

</head>

<body>

  <nav class="navbar navbar-expand-lg navbar-light bg-light">
    <a class="navbar-brand" href="#">Simple Catto Doggo</a>
    <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarText" aria-controls="navbarText" aria-expanded="false" aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse" id="navbarText">
      <ul class="navbar-nav mr-auto">
        <li class="nav-item active">
          <a class="nav-link" href="/">Home <span class="sr-only">(current)</span></a>
        </li>
      </ul>
      <span class="navbar-text">
        Simple Flask With Upload Functionality
      </span>
    </div>
  </nav>

  <div class="container-fluid">

    <div class="classify">
      <div>
        <h2>
          Hi, Please upload your dog or cat image here!
        </h2>
      </div>
      <div>
        <form action="/classify" method="post" enctype="multipart/form-data">
          <div class="file has-name is-centered">
            <label class="file-label">
              <input class="file-input" type="file" id="image" name="image">
            </label>
          </div>
          <br>
          <input type="submit" value="Classify" class="btn btn-danger" name="image" id="classify_button">
        </form>
      </div>
    </div>
  </div>
  <script src="/static/script.js"></script>
</body>

</html>
```
> *Hints: most of this code can be automaticaly generated with VSCode Extensions called Bootstrap 4, Font awesome 4, Font Awesome 5 Free & Pro snippets by only writting "b4-$"*

###  Create template for our classify/prediction page at **flask_app/templates/classify.html**


```html
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Catto & Doggo Classifier</title>
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
    integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
  <link rel="stylesheet" href="/static/style.css" type="text/css">
</head>
<body>
  <nav class="navbar navbar-expand-lg navbar-light bg-light">
    <a class="navbar-brand" href="#">Simple Catto Doggo</a>
    <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarText"
      aria-controls="navbarText" aria-expanded="false" aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse" id="navbarText">
      <ul class="navbar-nav mr-auto">
        <li class="nav-item active">
          <a class="nav-link" href="/">Home <span class="sr-only">(current)</span></a>
        </li>
      </ul>
      <span class="navbar-text">
        Simple Flask With Upload Functionality
      </span>
    </div>
  </nav>
  <div class="container-fluid">
    <div class="row">
      <div class="col image-prediction">
        <img class="pred_img" src="{{ url_for('send_file', filename=image_file_name)}}" />
      </div>
      <div class="col text-prediction">

        <h1 id="pred">
          This is a
        </h1>

        <h1 class="box" id="label">
          {{ label }}
        </h1>
        
        <h2>
          Confidence: <span>{{prob}}%</span>
        </h2>
        <br>
        <a href="/" class="btn btn-primary">Back to Home</a>
      </div>
    </div>
  </div>
  <script src="/static/script.js"></script>
</body>

</html>
```

### Add trained Xception model of Mina have built before:

Download the saved model in the link: https://drive.google.com/file/d/1W4uEBbCLFTsdYk6dWeEkzte1jk0X95XP/view?usp=sharing

And copy that catdog_classifier_Xception.h5 into our **simple_flask/static/** folder

**For fun, you should train your own model and replace this model with your model.**


### Run the flask app

Change directory
```bash
flask run 
```

On Docker, you need to expose that IP address to public so run:
```bash
flask run --host=0.0.0.0
```
:confetti_ball: Congratulation, you have just created your Flask app. Here is the link of your Flask app: http://127.0.0.1:5000
Or
http://localhost:5000

