Spaces:
Sleeping
Sleeping
Commit
•
3989022
1
Parent(s):
d69049c
hugging-face-app (#1)
Browse files- Add application files (61a5924e45a0b86be3001966a7c172f6307d7d91)
Co-authored-by: Nolan Boukachab <NBoukachab@users.noreply.huggingface.co>
- app.py +86 -0
- config.json +10 -0
- config.py +25 -0
- requirements.txt +2 -0
- resource/hugging_face_1.jpg +0 -0
- resource/hugging_face_2.jpg +0 -0
app.py
ADDED
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
|
3 |
+
import os
|
4 |
+
from pathlib import Path
|
5 |
+
import gradio as gr
|
6 |
+
from PIL import Image, ImageDraw
|
7 |
+
|
8 |
+
from doc_ufcn import models
|
9 |
+
from doc_ufcn.main import DocUFCN
|
10 |
+
from config import parse_configurations
|
11 |
+
|
12 |
+
# Load the config
|
13 |
+
config = parse_configurations(Path("config.json"))
|
14 |
+
|
15 |
+
# Download the model
|
16 |
+
model_path, parameters = models.download_model(name=config["model_name"])
|
17 |
+
|
18 |
+
# Store classes_colors list
|
19 |
+
classes_colors = config["classes_colors"]
|
20 |
+
|
21 |
+
# Store classes
|
22 |
+
classes = parameters["classes"]
|
23 |
+
|
24 |
+
# Check that the number of colors is equal to the number of classes -1
|
25 |
+
assert len(classes) - 1 == len(
|
26 |
+
classes_colors
|
27 |
+
), f"The parameter classes_colors was filled with the wrong number of colors. {len(classes)-1} colors are expected instead of {len(classes_colors)}."
|
28 |
+
|
29 |
+
# Check that the paths of the examples are valid
|
30 |
+
for example in config["examples"]:
|
31 |
+
assert os.path.exists(example), f"The path of the image '{example}' does not exist."
|
32 |
+
|
33 |
+
# Load the model
|
34 |
+
model = DocUFCN(
|
35 |
+
no_of_classes=len(classes),
|
36 |
+
model_input_size=parameters["input_size"],
|
37 |
+
device="cpu",
|
38 |
+
)
|
39 |
+
model.load(model_path=model_path, mean=parameters["mean"], std=parameters["std"])
|
40 |
+
|
41 |
+
|
42 |
+
def query_image(image):
|
43 |
+
"""
|
44 |
+
Draws the predicted polygons with the color provided by the model on an image
|
45 |
+
|
46 |
+
:param image: An image to predict
|
47 |
+
:return: Image, an image with the predictions
|
48 |
+
"""
|
49 |
+
|
50 |
+
# Make a prediction with the model
|
51 |
+
detected_polygons, probabilities, mask, overlap = model.predict(
|
52 |
+
input_image=image, raw_output=True, mask_output=True, overlap_output=True
|
53 |
+
)
|
54 |
+
|
55 |
+
# Load image
|
56 |
+
image = Image.fromarray(image)
|
57 |
+
|
58 |
+
# Make a copy of the image to keep the source and also to be able to use Pillow's blend method
|
59 |
+
img2 = image.copy()
|
60 |
+
|
61 |
+
# Create the polygons on the copy of the image for each class with the corresponding color
|
62 |
+
# We do not draw polygons of the background channel (channel 0)
|
63 |
+
for channel in range(1, len(classes)):
|
64 |
+
for polygon in detected_polygons[channel]:
|
65 |
+
# Draw the polygons on the image copy.
|
66 |
+
# Loop through the class_colors list (channel 1 has color 0)
|
67 |
+
ImageDraw.Draw(img2).polygon(
|
68 |
+
polygon["polygon"], fill=classes_colors[channel - 1]
|
69 |
+
)
|
70 |
+
|
71 |
+
# Return the blend of the images
|
72 |
+
return Image.blend(image, img2, 0.5)
|
73 |
+
|
74 |
+
|
75 |
+
# Create an interface with the config
|
76 |
+
process_image = gr.Interface(
|
77 |
+
fn=query_image,
|
78 |
+
inputs=[gr.Image()],
|
79 |
+
outputs=[gr.Image()],
|
80 |
+
title=config["title"],
|
81 |
+
description=config["description"],
|
82 |
+
examples=config["examples"],
|
83 |
+
)
|
84 |
+
|
85 |
+
# Launch the application with the public mode (True or False)
|
86 |
+
process_image.launch()
|
config.json
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"model_name": "doc-ufcn-generic-historical-line",
|
3 |
+
"classes_colors": ["green"],
|
4 |
+
"title":"doc-ufcn Line Detection Demo",
|
5 |
+
"description":"A demo showing a prediction from the [Teklia/doc-ufcn-generic-historical-line](https://huggingface.co/Teklia/doc-ufcn-generic-historical-line) model. The generic historical line detection model predicts text lines from document images.",
|
6 |
+
"examples":[
|
7 |
+
"resource/hugging_face_1.jpg",
|
8 |
+
"resource/hugging_face_2.jpg"
|
9 |
+
]
|
10 |
+
}
|
config.py
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
|
3 |
+
from pathlib import Path
|
4 |
+
from teklia_toolbox.config import ConfigParser
|
5 |
+
|
6 |
+
def parse_configurations(config_path: Path):
|
7 |
+
"""
|
8 |
+
Parse multiple JSON configuration files into a single source
|
9 |
+
of configuration for the HuggingFace app
|
10 |
+
|
11 |
+
:param config_path: pathlib.Path, Path to the .json config file
|
12 |
+
:return: dict, containing the configuration. Ensures config is complete and with correct typing
|
13 |
+
"""
|
14 |
+
|
15 |
+
parser = ConfigParser()
|
16 |
+
|
17 |
+
parser.add_option(
|
18 |
+
"model_name", type=str, default="doc-ufcn-generic-historical-line"
|
19 |
+
)
|
20 |
+
parser.add_option("classes_colors", type=list, default=["green"])
|
21 |
+
parser.add_option("title", type=str)
|
22 |
+
parser.add_option("description", type=str)
|
23 |
+
parser.add_option("examples", type=list)
|
24 |
+
|
25 |
+
return parser.parse(config_path)
|
requirements.txt
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
1 |
+
doc-ufcn==0.1.9-rc2
|
2 |
+
teklia_toolbox==0.1.3
|
resource/hugging_face_1.jpg
ADDED
resource/hugging_face_2.jpg
ADDED