manfredmichael commited on
Commit
7600da2
·
1 Parent(s): aa634ce

Add interface

Browse files
Files changed (6) hide show
  1. app.py +124 -0
  2. img/annotation.jpeg +0 -0
  3. packages.txt +3 -0
  4. requirements.txt +6 -0
  5. saved_state.json +41 -0
  6. utils.py +67 -0
app.py ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import base64
2
+ import json
3
+ import os
4
+ import re
5
+ import time
6
+ import uuid
7
+ from io import BytesIO
8
+ from pathlib import Path
9
+
10
+ import numpy as np
11
+ import pandas as pd
12
+ import streamlit as st
13
+ from PIL import Image
14
+ from streamlit_drawable_canvas import st_canvas
15
+ from utils import transform_annotations, inference, transform_scale, get_heatmap
16
+
17
+
18
+
19
+ def main():
20
+ if "button_id" not in st.session_state:
21
+ st.session_state["button_id"] = ""
22
+ if "color_to_label" not in st.session_state:
23
+ st.session_state["color_to_label"] = {}
24
+
25
+ color_annotation_app()
26
+
27
+ with st.sidebar:
28
+ st.markdown("---")
29
+ st.markdown(
30
+ '<h6>Made in &nbsp<img src="https://streamlit.io/images/brand/streamlit-mark-color.png" alt="Streamlit logo" height="16">&nbsp forked from <a href="https://twitter.com/andfanilo">@andfanilo</a></h6>',
31
+ unsafe_allow_html=True,
32
+ )
33
+ st.markdown(
34
+ '<div style="margin: 0.75em 0;"><a href="https://www.buymeacoffee.com/andfanilo" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/default-orange.png" alt="Buy Me A Coffee" height="41" width="174"></a></div>',
35
+ unsafe_allow_html=True,
36
+ )
37
+
38
+ def full_app():
39
+ st.sidebar.header("Configuration")
40
+ st.markdown(
41
+ """
42
+ Draw on the canvas, get the drawings back to Streamlit!
43
+ * Configure canvas in the sidebar
44
+ * In transform mode, double-click an object to remove it
45
+ * In polygon mode, left-click to add a point, right-click to close the polygon, double-click to remove the latest point
46
+ """
47
+ )
48
+
49
+ def color_annotation_app():
50
+ st.markdown(
51
+ """
52
+ #
53
+ """
54
+ )
55
+
56
+ try:
57
+ bg_image = Image.open("img/annotation.jpeg")
58
+ except:
59
+ bg_image = None
60
+
61
+ # bg_image = None
62
+ image_file = st.file_uploader('Upload your image', type=['jpg', 'jpeg', 'png'], accept_multiple_files=False)
63
+ if image_file is not None:
64
+ bg_image = Image.open(image_file).convert('RGB')
65
+ bg_image.save('img/annotation.jpeg')
66
+
67
+ label_color = (
68
+ st.sidebar.color_picker("Annotation color: ", "#EA1010") + "77"
69
+ ) # for alpha from 00 to FF
70
+ label = st.sidebar.text_input("Label", "Default")
71
+ mode = "transform" if st.sidebar.checkbox("Adjust ROIs", False) else "rect"
72
+
73
+ if bg_image:
74
+ canvas_result = st_canvas(
75
+ fill_color=label_color,
76
+ stroke_width=3,
77
+ background_image=bg_image,
78
+ height=320,
79
+ width=512,
80
+ drawing_mode=mode,
81
+ key="color_annotation_app",
82
+ )
83
+ if canvas_result.json_data is not None:
84
+ df = pd.json_normalize(canvas_result.json_data["objects"])
85
+ df = transform_scale(df, bg_image.size)
86
+ n_objects = len(canvas_result.json_data['objects'])
87
+ if n_objects < 3:
88
+ st.write('annotate at least {} more object(s)'.format(3 - n_objects))
89
+ pass
90
+ else:
91
+ with st.form("my_form"):
92
+
93
+ # Every form must have a submit button.
94
+ count_button_clicked = st.form_submit_button("Count objects")
95
+ heatmap_button_clicked = st.form_submit_button("Show heatmaps")
96
+ if count_button_clicked:
97
+ annotations = transform_annotations(df)
98
+ prediction = inference(annotations)
99
+ st.write(prediction)
100
+ elif heatmap_button_clicked:
101
+ annotations = transform_annotations(df)
102
+ prediction, heatmap = get_heatmap(annotations)
103
+ st.write(f"predicted count: {prediction}")
104
+ st.image(heatmap)
105
+
106
+
107
+ if len(df) == 0:
108
+ return
109
+ st.session_state["color_to_label"][label_color] = label
110
+ df["label"] = df["fill"].map(st.session_state["color_to_label"])
111
+ st.dataframe(df[["top", "left", "width", "height", "fill", "label"]])
112
+ # st.dataframe(df)
113
+
114
+ def count_objects():
115
+ st.write('bla bla')
116
+
117
+
118
+ if __name__ == "__main__":
119
+ st.set_page_config(
120
+ page_title="Class-agnostic Counting Model", page_icon=":pencil2:"
121
+ )
122
+ st.title("Class-agnostic Counting Demo")
123
+ st.sidebar.subheader("Configuration")
124
+ main()
img/annotation.jpeg ADDED
packages.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ freeglut3-dev
2
+ libgtk2.0-dev
3
+ libgl1-mesa-glx
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ streamlit>=0.88
2
+ streamlit-drawable-canvas>=0.8
3
+ svgpathtools
4
+ svgwrite
5
+ opencv-python-headless
6
+ matplotlib
saved_state.json ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "version": "4.4.0",
3
+ "objects": [
4
+ {
5
+ "type": "circle",
6
+ "version": "4.4.0",
7
+ "originX": "left",
8
+ "originY": "center",
9
+ "left": 52,
10
+ "top": 197,
11
+ "width": 91.02,
12
+ "height": 91.02,
13
+ "fill": "rgba(255, 165, 0, 0.2)",
14
+ "stroke": "black",
15
+ "strokeWidth": 5,
16
+ "strokeDashArray": null,
17
+ "strokeLineCap": "butt",
18
+ "strokeDashOffset": 0,
19
+ "strokeLineJoin": "miter",
20
+ "strokeUniform": false,
21
+ "strokeMiterLimit": 4,
22
+ "scaleX": 1,
23
+ "scaleY": 1,
24
+ "angle": 54.39,
25
+ "flipX": false,
26
+ "flipY": false,
27
+ "opacity": 1,
28
+ "shadow": null,
29
+ "visible": true,
30
+ "backgroundColor": "",
31
+ "fillRule": "nonzero",
32
+ "paintFirst": "fill",
33
+ "globalCompositeOperation": "source-over",
34
+ "skewX": 0,
35
+ "skewY": 0,
36
+ "radius": 45.510987684294435,
37
+ "startAngle": 0,
38
+ "endAngle": 6.283185307179586
39
+ }
40
+ ]
41
+ }
utils.py ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ import json
3
+ from PIL import Image
4
+ from io import BytesIO, StringIO
5
+ from base64 import decodebytes
6
+ import numpy as np
7
+ import cv2
8
+ import matplotlib.pyplot as plt
9
+ import os
10
+
11
+ inference_url = 'ubuntu@ec2-108-137-44-0.ap-southeast-3.compute.amazonaws.com'
12
+
13
+ def transform_annotations(df):
14
+ df['x1'] = df['left']
15
+ df['x2'] = (df['left'] + df['width'])
16
+ df['y1'] = df['top']
17
+ df['y2'] = (df['top'] + df['height'])
18
+
19
+ df['top_left'] = df.apply(lambda x: list([x['x1'], x['y1']]), axis=1)
20
+ df['bottom_left'] = df.apply(lambda x: list([x['x1'], x['y2']]), axis=1)
21
+ df['bottom_right'] = df.apply(lambda x: list([x['x2'], x['y2']]), axis=1)
22
+ df['top_right'] = df.apply(lambda x: list([x['x2'], x['y1']]), axis=1)
23
+ annotations = df[['top_left', 'bottom_left', 'bottom_right', 'top_right']].values.tolist()
24
+ return annotations
25
+
26
+ def transform_scale(df, size):
27
+ if len(df) > 0:
28
+ x_ratio = 512/ size[0]
29
+ y_ratio = 320 / size[1]
30
+
31
+ df['left'] = df['left'] / x_ratio
32
+ df['width'] = df['width'] / x_ratio
33
+ df['top'] = df['top'] / y_ratio
34
+ df['height'] = df['height'] / y_ratio
35
+
36
+ return df
37
+
38
+
39
+ def inference(annotations):
40
+ result = requests.post(
41
+ f"http://{inference_url}:80/predict",
42
+ files = {'file': open(f"img/annotation.jpeg", 'rb'),
43
+ 'data': json.dumps({'annotations': annotations})
44
+ },
45
+ )
46
+
47
+ return result.json()
48
+
49
+ def get_heatmap(annotations):
50
+ result = requests.post(
51
+ f"http://{inference_url}:80/heatmap",
52
+ files = {'file': open(f"img/annotation.jpeg", 'rb'),
53
+ 'data': json.dumps({'annotations': annotations})
54
+ },
55
+ )
56
+
57
+
58
+ heatmap = result.json()['heatmap']
59
+
60
+ heatmap = np.array(heatmap) * 0.1
61
+
62
+
63
+ colormap = plt.get_cmap('inferno')
64
+ heatmap = (colormap(heatmap)).astype(np.float32)[:,:,:3]
65
+
66
+
67
+ return result.json()['count'], heatmap