SkalskiP commited on
Commit
63a1180
โ€ข
1 Parent(s): 4747732

initial commit

Browse files
Files changed (6) hide show
  1. .gitignore +1 -0
  2. README.md +3 -3
  3. app.py +206 -0
  4. configs/car_brands.json +67 -0
  5. configs/license_plates.json +59 -0
  6. requirements.txt +4 -0
.gitignore ADDED
@@ -0,0 +1 @@
 
 
1
+ venv/
README.md CHANGED
@@ -1,8 +1,8 @@
1
  ---
2
  title: Workflows
3
- emoji: ๐Ÿ“Š
4
- colorFrom: pink
5
- colorTo: gray
6
  sdk: gradio
7
  sdk_version: 4.17.0
8
  app_file: app.py
 
1
  ---
2
  title: Workflows
3
+ emoji: ๐Ÿ› 
4
+ colorFrom: green
5
+ colorTo: purple
6
  sdk: gradio
7
  sdk_version: 4.17.0
8
  app_file: app.py
app.py ADDED
@@ -0,0 +1,206 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ from typing import List
3
+
4
+ import cv2
5
+ import os
6
+
7
+ import numpy as np
8
+ import gradio as gr
9
+ import supervision as sv
10
+ from inference_sdk import (
11
+ InferenceHTTPClient,
12
+ InferenceConfiguration,
13
+ VisualisationResponseFormat
14
+ )
15
+
16
+
17
+ def read_json_file(file_path: str) -> dict:
18
+ with open(file_path, 'r') as file:
19
+ return json.load(file)
20
+
21
+
22
+ def split_and_strip(text: str) -> List[str]:
23
+ return [part.strip() for part in text.split(',')]
24
+
25
+
26
+ MARKDOWN = """
27
+ # WORKFLOWS ๐Ÿ› 
28
+
29
+ Define complex ML pipelines in JSON and execute it, running multiple models, fusing
30
+ outputs seamlessly.
31
+
32
+ Use self-hosted Inference HTTP [container](https://inference.roboflow.com/inference_helpers/inference_cli/#inference-server-start)
33
+ or run against Roboflow [API](https://detect.roboflow.com/docs)
34
+ to get results without single line of code written.
35
+ """
36
+
37
+ # LICENSE PLATES WORKFLOW
38
+
39
+ LICENSE_PLATES_MARKDOWN = """
40
+ ![license-plates-detection-workflow](
41
+ https://media.roboflow.com/inference/license-plates-detection-workflow.png)
42
+ """
43
+ LICENSE_PLATES_EXAMPLES = [
44
+ "https://media.roboflow.com/inference/license_plate_1.jpg",
45
+ "https://media.roboflow.com/inference/license_plate_2.jpg",
46
+ ]
47
+ LICENSE_PLATES_SPECIFICATION_PATH = 'configs/license_plates.json'
48
+ LICENSE_PLATES_SPECIFICATION = read_json_file(LICENSE_PLATES_SPECIFICATION_PATH)
49
+ LICENSE_PLATES_SPECIFICATION_STRING = f"""
50
+ ```json
51
+ {json.dumps(LICENSE_PLATES_SPECIFICATION, indent=4)}
52
+ ```
53
+ """
54
+
55
+ # CAR BRAND WORKFLOW
56
+
57
+ CAR_BRANDS_MARKDOWN = """
58
+ ![car-brand-workflow](
59
+ https://media.roboflow.com/inference/car-brand-workflow.png.png)
60
+ """
61
+ CAR_BRANDS_EXAMPLES = [
62
+ ["Lexus, Honda, Seat", "https://media.roboflow.com/inference/multiple_cars_1.jpg"],
63
+ ["Volkswagen, Renault, Mercedes", "https://media.roboflow.com/inference/multiple_cars_2.jpg"],
64
+ ]
65
+ CAR_BRANDS_SPECIFICATION_PATH = 'configs/car_brands.json'
66
+ CAR_BRANDS_SPECIFICATION = read_json_file(CAR_BRANDS_SPECIFICATION_PATH)
67
+ CAR_BRANDS_SPECIFICATION_STRING = f"""
68
+ ```json
69
+ {json.dumps(CAR_BRANDS_SPECIFICATION, indent=4)}
70
+ ```
71
+ """
72
+
73
+ API_URL = os.getenv('API_URL', None)
74
+ API_KEY = os.getenv('API_KEY', None)
75
+
76
+ if API_KEY is None or API_URL is None:
77
+ raise ValueError("API_URL and API_KEY environment variables are required")
78
+
79
+
80
+ CLIENT = InferenceHTTPClient(api_url=API_URL, api_key=API_KEY)
81
+
82
+ CLIENT.configure(InferenceConfiguration(
83
+ output_visualisation_format=VisualisationResponseFormat.NUMPY))
84
+
85
+
86
+ def annotate_image(image: np.ndarray, detections: sv.Detections) -> np.ndarray:
87
+ h, w, _ = image.shape
88
+ annotated_image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
89
+ line_thickness = sv.calculate_dynamic_line_thickness(resolution_wh=(w, h))
90
+ text_scale = sv.calculate_dynamic_text_scale(resolution_wh=(w, h))
91
+ bounding_box_annotator = sv.BoundingBoxAnnotator(thickness=line_thickness)
92
+ label_annotator = sv.LabelAnnotator(
93
+ text_scale=text_scale,
94
+ text_thickness=line_thickness
95
+ )
96
+ annotated_image = bounding_box_annotator.annotate(
97
+ annotated_image, detections)
98
+ annotated_image = label_annotator.annotate(
99
+ annotated_image, detections)
100
+ return cv2.cvtColor(annotated_image, cv2.COLOR_BGR2RGB)
101
+
102
+
103
+ def inference_license_plates(input_image: np.ndarray) -> np.ndarray:
104
+ result = CLIENT.infer_from_workflow(
105
+ specification=LICENSE_PLATES_SPECIFICATION["specification"],
106
+ images={"image": input_image},
107
+ )
108
+ detections = sv.Detections.from_inference(result)
109
+ if len(detections) == 0:
110
+ return input_image
111
+
112
+ detections['class_name'] = (
113
+ result["recognised_plates"]
114
+ if isinstance(result["recognised_plates"], list)
115
+ else [result["recognised_plates"]]
116
+ )
117
+ return annotate_image(input_image, detections)
118
+
119
+
120
+ def inference_car_brands(input_text: str, input_image: np.ndarray) -> np.ndarray:
121
+ classes = split_and_strip(input_text)
122
+ result = CLIENT.infer_from_workflow(
123
+ specification=CAR_BRANDS_SPECIFICATION["specification"],
124
+ images={"image": input_image},
125
+ parameters={"car_types": classes}
126
+ )
127
+
128
+ detections = sv.Detections.from_inference(result)
129
+ if len(detections) == 0:
130
+ return input_image
131
+
132
+ if len(detections) > 1:
133
+ class_ids = np.argmax(result["clip"], axis=1)
134
+ else:
135
+ class_ids = np.array([np.argmax(result["clip"], axis=0)])
136
+
137
+ detections.class_ids = class_ids
138
+ detections['class_name'] = [classes[class_id] for class_id in class_ids]
139
+
140
+ return annotate_image(input_image, detections)
141
+
142
+
143
+ with gr.Blocks() as demo:
144
+ gr.Markdown(MARKDOWN)
145
+ with gr.Tab(label="License Plates"):
146
+ gr.Markdown(LICENSE_PLATES_MARKDOWN)
147
+ with gr.Accordion("Configuration JSON", open=False):
148
+ gr.Markdown(LICENSE_PLATES_SPECIFICATION_STRING)
149
+ with gr.Row():
150
+ license_plates_input_image_component = gr.Image(
151
+ type='numpy',
152
+ label='Input Image'
153
+ )
154
+ license_plates_output_image_component = gr.Image(
155
+ type='numpy',
156
+ label='Output Image'
157
+ )
158
+ with gr.Row():
159
+ license_plates_submit_button_component = gr.Button('Submit')
160
+ gr.Examples(
161
+ fn=inference_license_plates,
162
+ examples=LICENSE_PLATES_EXAMPLES,
163
+ inputs=license_plates_input_image_component,
164
+ outputs=license_plates_output_image_component,
165
+ cache_examples=True
166
+ )
167
+ with gr.Tab(label="Car Brands"):
168
+ gr.Markdown(CAR_BRANDS_MARKDOWN)
169
+ with gr.Accordion("Configuration JSON", open=False):
170
+ gr.Markdown(CAR_BRANDS_SPECIFICATION_STRING)
171
+ with gr.Row():
172
+ with gr.Column():
173
+ car_brands_input_image_component = gr.Image(
174
+ type='numpy',
175
+ label='Input Image'
176
+ )
177
+ car_brands_input_text = gr.Textbox(
178
+ label='Car Brands',
179
+ placeholder='Enter car brands separated by comma'
180
+ )
181
+ car_brands_output_image_component = gr.Image(
182
+ type='numpy',
183
+ label='Output Image'
184
+ )
185
+ with gr.Row():
186
+ car_brands_submit_button_component = gr.Button('Submit')
187
+ gr.Examples(
188
+ fn=inference_car_brands,
189
+ examples=CAR_BRANDS_EXAMPLES,
190
+ inputs=[car_brands_input_text, car_brands_input_image_component],
191
+ outputs=car_brands_output_image_component,
192
+ cache_examples=True
193
+ )
194
+
195
+ license_plates_submit_button_component.click(
196
+ fn=inference_license_plates,
197
+ inputs=license_plates_input_image_component,
198
+ outputs=license_plates_output_image_component
199
+ )
200
+ car_brands_submit_button_component.click(
201
+ fn=inference_car_brands,
202
+ inputs=[car_brands_input_text, car_brands_input_image_component],
203
+ outputs=car_brands_output_image_component
204
+ )
205
+
206
+ demo.launch(debug=False, show_error=True)
configs/car_brands.json ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "specification":{
3
+ "version":"1.0",
4
+ "inputs":[
5
+ {
6
+ "type":"InferenceImage",
7
+ "name":"image"
8
+ },
9
+ {
10
+ "type":"InferenceParameter",
11
+ "name":"car_types"
12
+ },
13
+ {
14
+ "type":"InferenceParameter",
15
+ "name":"detection_model",
16
+ "default_value":"coco/6"
17
+ }
18
+ ],
19
+ "steps":[
20
+ {
21
+ "type":"ObjectDetectionModel",
22
+ "name":"detection",
23
+ "image":"$inputs.image",
24
+ "model_id":"$inputs.detection_model",
25
+ "iou_threshold":0.5,
26
+ "class_filter":[
27
+ "car",
28
+ "truck"
29
+ ]
30
+ },
31
+ {
32
+ "type":"Crop",
33
+ "name":"cropping",
34
+ "image":"$inputs.image",
35
+ "detections":"$steps.detection.predictions"
36
+ },
37
+ {
38
+ "type":"ClipComparison",
39
+ "name":"clip",
40
+ "image":"$steps.cropping.crops",
41
+ "text":"$inputs.car_types"
42
+ }
43
+ ],
44
+ "outputs":[
45
+ {
46
+ "type":"JsonField",
47
+ "name":"predictions",
48
+ "selector":"$steps.detection.predictions"
49
+ },
50
+ {
51
+ "type":"JsonField",
52
+ "name":"image",
53
+ "selector":"$steps.detection.image"
54
+ },
55
+ {
56
+ "type":"JsonField",
57
+ "name":"clip",
58
+ "selector":"$steps.clip.similarity"
59
+ },
60
+ {
61
+ "type":"JsonField",
62
+ "name":"crops",
63
+ "selector":"$steps.cropping.crops"
64
+ }
65
+ ]
66
+ }
67
+ }
configs/license_plates.json ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "specification":{
3
+ "version":"1.0",
4
+ "inputs":[
5
+ {
6
+ "type":"InferenceImage",
7
+ "name":"image"
8
+ }
9
+ ],
10
+ "steps":[
11
+ {
12
+ "type":"ObjectDetectionModel",
13
+ "name":"plates_detector",
14
+ "image":"$inputs.image",
15
+ "model_id":"vehicle-registration-plates-trudk/2"
16
+ },
17
+ {
18
+ "type":"DetectionOffset",
19
+ "name":"offset",
20
+ "predictions":"$steps.plates_detector.predictions",
21
+ "offset_x":200,
22
+ "offset_y":40
23
+ },
24
+ {
25
+ "type":"Crop",
26
+ "name":"cropping",
27
+ "image":"$inputs.image",
28
+ "detections":"$steps.offset.predictions"
29
+ },
30
+ {
31
+ "type":"OCRModel",
32
+ "name":"step_ocr",
33
+ "image":"$steps.cropping.crops"
34
+ }
35
+ ],
36
+ "outputs":[
37
+ {
38
+ "type":"JsonField",
39
+ "name":"predictions",
40
+ "selector":"$steps.plates_detector.predictions"
41
+ },
42
+ {
43
+ "type":"JsonField",
44
+ "name":"image",
45
+ "selector":"$steps.plates_detector.image"
46
+ },
47
+ {
48
+ "type":"JsonField",
49
+ "name":"recognised_plates",
50
+ "selector":"$steps.step_ocr.result"
51
+ },
52
+ {
53
+ "type":"JsonField",
54
+ "name":"crops",
55
+ "selector":"$steps.cropping.crops"
56
+ }
57
+ ]
58
+ }
59
+ }
requirements.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ inference==0.9.9rc23
2
+ inference-sdk==0.9.9rc23
3
+ supervision
4
+ gradio