Spaces:
Runtime error
Runtime error
Commit ·
7600da2
1
Parent(s): aa634ce
Add interface
Browse files- app.py +124 -0
- img/annotation.jpeg +0 -0
- packages.txt +3 -0
- requirements.txt +6 -0
- saved_state.json +41 -0
- 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  <img src="https://streamlit.io/images/brand/streamlit-mark-color.png" alt="Streamlit logo" height="16">  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
|