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