Skip to content

fastapi image processing

This is an exploratory on-going project to understand how to process several hundreds of gigabytes to terabytes of publicly free downloaded large image datasets on the web by building an "AI Super Image Processor."

The goal of this project is to use fastAPI with the help of artificial intelligence modeling to process large free downloaded public image datasets through the internet archive for images and pixabay. Build a supervised training model and expand to unsupervised training model to train thethat is AI image processor with the ability to randomly generate a matching image as accurate as it can based on the provided image datasets that is fetched.

Why fastAPI?

  • It's fast with its asynchronous features underneath the hood
  • Very performant on request management
  • Super scalable for large user-based platform
  • Dynamically API-centric especially if you deal with constant changing data that needs to adapt to volatile business needs
  • Self-generated API documentation through .../docs or .../redocs. This enforces proper documentation and reduced further development work.
  • It also uses Pydantic - automated type hints validation and enforcer at runtime. This is super powerful when you're dealing with massive data identification and classification labeling. This helps ensure data types are properly annotated to avoid running into formatting errors, which can lead to the inability to build correct the machine learning model at runtime!

deep dive

There are obviously different approaches to fetching image datasets using various open source libraries. I'm going to talk briefly about a few of the main ones that are currently widely supported, leveraged, extended, and finally how deep learning neural network like CNN comes into play which was historically built through neuroscience deep learning brain studies of cats. These studies showed that our visual cortices have neurons that could fired up in small regions of the brain when an external stimuli are presented known as the "receptive field." it then helped form a visual mapping of the contralateral cortex of the brain. Pretty interesting!

open computer vision library (Opencv)

Opencv is an open source computer vision and machine learning software library written in C, which makes it super portable amongst various OS and mobile platforms to being used to build robots! Though, it is mainly written in C++ algorithms. Python and Java wrappers already developed to further extend opencv's usability frameworks and to support a wider community.

It's very popular and heavily contributed within the Python community. It's built to support the computer vision application infrastructure. It's designed to be cross-platform.

tensorflow

keras

convolutionary neural network (CNN)

CNN innovation is inspired by our brain's architecture to helps develop a deep learning neural network. It is used for building complex algorithms and artificial neural networks to train machines and computers to learn through experiences; and to help classify and recognize those experiences through the data and images that we fetch to train the computers to have the ability to generate classification and model them to what the human brain is capable of.

implementation

You can install all fastapi dependencies via [all]. I recommend this feature as it takes care of all the dependencies you'll need like the app server uvicorn that's used to render the api web framework.

install

pip install "fastapi[all]" # installs all dependencies in one go

All will installed all the prerequisites needed.

anyio==3.6.2
certifi==2022.12.7
click==8.1.3
dnspython==2.3.0
email-validator==1.3.1
fastapi==0.92.0
h11==0.14.0
httpcore==0.16.3
httptools==0.5.0
httpx==0.23.3
idna==3.4
itsdangerous==2.1.2
Jinja2==3.1.2
MarkupSafe==2.1.2
orjson==3.8.6
pydantic==1.10.5
python-dotenv==0.21.1
python-multipart==0.0.5
PyYAML==6.0
rfc3986==1.5.0
six==1.16.0
sniffio==1.3.0
starlette==0.25.0
typing_extensions==4.5.0
ujson==5.7.0
uvicorn==0.20.0
uvloop==0.17.0
watchfiles==0.18.1
websockets==10.4

tutorial snippets

Here's a quick litte "hello world" tutorial to get the gist of this!

I'm going to just break this down quickly in simple steps here. This should test the basics of getting your fastapi and dependencies working!

We are going to leverage asyncio to build functions. It's not necessary, however if you're dealing with heavy I/O-bound tasks such as web page development or fetching data primarily from APIs - it comes hand to ensure concurrency tasks execution are optimal and efficient.

1.Generate a main.py file, add this code in there.

from fastapi import FastAPI

# instantiates fastAPI
app = FastAPI()

# pass in @app decorator from fastAPI
# you can also pass in the "path parameter" to the decorator 
# for a more descriptive API framework
@app.get("/")
async def root():
    return {"message": "Hello World"}

2.Run this command in your terminal.

  • main -> Name of your python module. I saved it as main.
  • app -> It's the name used to instantiate FastAPI(). It can be any name, really!
# reload will automatically reflect any dev changes you make 
# in your localhost browser.

uvicorn main:app --reload 
# you can also test your code directly in fastAPI dev mode.
# this will automatically runs and creates your API in a default localhost:8000

fastAPI dev <script>

3.Verify it's working!

official build

In fastAPI, we'll need to use fastapi.Uploading() object. This is crucial for any files is being rendered as form data in fastapi.

from fastapi import FastAPI, File, UploadFile

from typing import Union    
from pydantic import BaseModel

Note that it is important to recognize to leverage pydantic module, you'll need to reference the pydantic.Basemodel() class object.

from typing import Union

from fastapi import FastAPI
from pydantic import BaseModel


app = FastAPI()


class Item(BaseModel):
    name: str
    price: float
    is_offer: Union[bool, None] = None


@app.get("/", description="root endpoint")
async def read_root():
    return {"Hello": "Yen!"}


# path params and passing it as params - item_id
@app.get("/items/{item_id:}")
# pydantic allows us to pass in item_id as int typing declaration?
async def read_item(item_id: int, q: Union[str, None] = None):
    return {"item_id": item_id, "q": q}


@app.post("/")
async def post(name: str):
    """_summary_

    Args:
        name (str): _description_

    Returns:
        _type_: _description_
    """
    return f"hellos {name}!"


@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
    return {"item_price": item.price, "item_id": item_id}


@app.post("/upload/")
async def create_upload_file(file: UploadFile = File(...)):
    """Upload a file or an image. A crucial method.

    Args:
        file (UploadFile, optional): _description_. Defaults to File(...).

    Returns:
        _type_: file you rendered
    """

    file.filename = f"{uuid.uuid4()}.jpg"
    contents = await file.read()

    # save the file
    with open(f"{IMAGEDIR}{file.filename}", "wb") as f:
        f.write(contents)

    return {"filename": file.filename}

This is a sample snippet of how to train a model using tensorflow.keras. Configuring a new class object is a prerequisite to train your model.

from fastapi import FastAPI, File, UploadFile
from fastapi.responses import JSONResponse
from pydantic import BaseModel
from PIL import Image
import numpy as np
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Conv2D, Flatten, MaxPooling2D
import io

app = FastAPI()


class TrainingConfig(BaseModel):
    """Define a base model for your training config.

    Args:
        BaseModel (_type_): Your base model inherits Pydandic Class Basemodel() object.

    Returns:
        _type_: Your Training Config returns validated integer arguments for epocs and batch_size.
    """

    epochs: int
    batch_size: int


# Create an empty array for storing images and labels for your training dataset.
images = []
labels = []


@app.post("/upload-image/{label}")
async def upload_image(label: int, file: UploadFile = File(...)):
    """Create an upload image feature to label every uploaded file for your training model.

    Args:
        label (int):
        file (UploadFile, optional): _description_. Defaults to File(...).

    Returns:
        _type_: JSON content object from image upload.
    """
    content = await file.read()
    image = Image.open(io.BytesIO(content)).convert("RGB")
    image = image.resize((128, 128))  # Resize for simplicity
    images.append(np.array(image))
    labels.append(label)
    return JSONResponse(
        content={"message": "Image uploaded successfully"}, status_code=200
    )


@app.post("/train/")
async def train_model(config: TrainingConfig):
    """Create a train model config feature. Check if images are label for training.
    Use CNN model once images are normalized with the labels.


    Args:
        config (TrainingConfig): Run the config and fit the regression model.

    Returns:
        _type_: a fitted model with epocs and batch_size with JSON object output.
    """
    if not images or not labels:
        return JSONResponse(
            content={"message": "No images or labels to train on"}, status_code=400
        )

    X = np.array(images)
    y = np.array(labels)

    # Normalize the images
    X = X / 255.0

    # Simple CNN model
    model = Sequential(
        [
            Conv2D(
                32, kernel_size=(3, 3), activation="relu", input_shape=(128, 128, 3)
            ),
            MaxPooling2D(pool_size=(2, 2)),
            Flatten(),
            Dense(128, activation="relu"),
            Dense(
                len(set(labels)), activation="softmax"
            ),  # Adjust output layer according to your classes
        ]
    )

    model.compile(
        optimizer="adam", loss="sparse_categorical_crossentropy", metrics=["accuracy"]
    )

    model.fit(X, y, epochs=config.epochs, batch_size=config.batch_size)

    return JSONResponse(
        content={"message": "Model trained successfully"}, status_code=200
    )


if __name__ == "__main__":
    import uvicorn

    uvicorn.run(app, host="0.0.0.0", port=8000)

useful resources

Image Processing using OpenCV, CNN, and Keras backed by Tensor Flow

FastAPI

Asyncio inner workings

CNN history