File size: 6,545 Bytes
1ecc339
 
 
 
 
 
 
 
 
 
 
 
 
 
c6c388a
1ecc339
 
 
a8a7e6d
c6c388a
1ecc339
 
 
c6c388a
1ecc339
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c6c388a
1ecc339
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import streamlit as st
import threading
from functions import *
from streamlit.runtime.scriptrunner.script_run_context import add_script_run_ctx
from streamlit.components.v1 import declare_component

st.set_page_config(layout="wide")

car_map = declare_component("car_map", path="./car_map")

if "reset" not in st.session_state:
    st.session_state["reset"] = False

with st.sidebar:
    name = st.text_input("Name *", value=st.session_state.get("name", ""))
    name = name.strip().lower()
    name_error_placeholder = st.empty()

    parts_filter = st.multiselect("Filter images by damaged parts (optional)", get_car_parts_count(), help="Select one or more parts to filter the images by.")

    if st.button("Start annotation"):
        if name:
            st.session_state["name"] = name
            st.session_state["img"], st.session_state["img_name"] = get_random_image(parts_filter)
            st.rerun()
        else:
            name_error_placeholder.error("Name is required")

    with st.expander("Annotation statistics", expanded=True):
        st.write(f"**Total images**: {len(df)}")
        st.write(f"**Total annotated images**: {len(df[df['validated'] == True])}")
        st.write(f"**Images left to annotate**: {len(df[df['validated'] == False])}")
        if "name" in st.session_state:
            st.write(f"**Images annotated by you**: {len(df[(df['annotator_name'] == st.session_state['name']) & (df['validated'] == True)])}")

    with st.expander("Annotation instructions", expanded=False):
        st.markdown("- Rotate the image of the car if necessary using the rotation buttons.")
        st.markdown("- Switch between viewing the car map from the back and the front for a better view.")
        st.markdown("- Check the image for damages and mark the damaged parts on the car map on the right.")
        st.markdown("- Right click on the car map to increase the severity level of the damage, and left click to decrease it.")
        st.markdown("- Severity **level 1** is for scratches, **level 2** is for dents, and **level 3** is for cracks, breaks and severe damages.")
        st.markdown("**⏭ Skip this image**: If you are not sure about the damages, the image will be shown to another annotator.")
        st.markdown("**❌ Not car**: If the image is taken inside of the car or does not contain a car at all, or the image is not clear (blurry, zoomed-in, bad lighting, etc.)")
        st.markdown("**✅ Validate**: save the annotations and move to the next image.")
        st.markdown("🔙: Go back to your previous annotation.")

    # st.download_button("Download annotations", data=df.to_csv(index=False), file_name="annotations.csv", mime="text/csv")
    
if "name" in st.session_state:
    if st.session_state["img"]:
        col1, col2 = st.columns([10, 8])

        rotation_btns = col1.columns([1, 1])
        left_btn = rotation_btns[0].button("↶ 90°", help="Rotate image 90° left", use_container_width=True)
        right_btn = rotation_btns[1].button("↷ 90°", help="Rotate image 90° right", use_container_width=True)
            
        if "rotation" not in st.session_state:
            st.session_state["rotation"] = 0
        if left_btn:
            st.session_state["img"] = st.session_state["img"].rotate(90, expand=True).resize((1000, 800))
            st.session_state["rotation"] = (st.session_state["rotation"] + 90) % 360
        if right_btn:
            st.session_state["img"] = st.session_state["img"].rotate(-90, expand=True).resize((1000, 800))
            st.session_state["rotation"] = (st.session_state["rotation"] - 90) % 360

        reset_annotation_btn = col2.button("🧹 Reset annotation", help="Remove all the annotation and start over", use_container_width=True)
        if reset_annotation_btn:
            st.session_state["reset"] = True
        car_map_view = col2.radio("Car map view", ["Back", "Front"], index=0, horizontal=True, label_visibility="collapsed")

        img = st.session_state.get("img")
        img_name = st.session_state.get("img_name")
        col1_c1, col1_c2 = col1.columns([1, 10])
        prev_img_name = st.session_state["prev_img_name"] if "prev_img_name" in st.session_state else None
        previous_btn = col1_c1.button("🔙", use_container_width=True, help="Go back to the previous image", disabled=(not prev_img_name))
        if previous_btn:
            st.session_state["img"] = st.session_state["prev_img"]
            st.session_state["img_name"] = st.session_state["prev_img_name"]
            st.session_state["rotation"] = st.session_state["prev_rotation"]
            st.session_state["prev_img_name"] = None
            st.session_state["prev_rotation"] = None
            st.rerun()
        col1_c2.button(img_name, use_container_width=True, disabled=True)
        # col1_c2.write(img_name)
        col1.image(img, use_column_width=True)

        with col2:
            img_damages = get_img_damages(img_name)
            annotated_damages = car_map(damages=img_damages, img_name=img_name, view=car_map_view, reset=st.session_state["reset"])
        bnt_cols = st.columns(3)
        skip_btn = bnt_cols[0].button("⏭ Skip this image", use_container_width=True, help="Skip this image if you are not sure")
        not_car_btn = bnt_cols[1].button("❌ Not car", use_container_width=True, help="Click this if the image does not contain a car")
        next_btn = bnt_cols[2].button("✅ Validate", use_container_width=True, type="primary", help="Validate annotations and move to the next one")

        with open('custom_style.css') as f:
            st.markdown(f'<style>{f.read()}</style>', unsafe_allow_html=True) 

        if not_car_btn or next_btn or skip_btn:
            annot_name = st.session_state["name"]
            rotation = st.session_state["rotation"]
            process_thread = threading.Thread(target=process_image, args=(img_name, annot_name, not not_car_btn, skip_btn, rotation, annotated_damages), daemon=True)
            add_script_run_ctx(process_thread)
            process_thread.start()
            st.session_state["prev_img_name"] = img_name
            st.session_state["prev_img"] = img
            st.session_state["prev_rotation"] = st.session_state["rotation"]
            st.session_state["img"], st.session_state["img_name"] = get_random_image(parts_filter)
            st.session_state["rotation"] = 0
            st.session_state["reset"] = False
            st.rerun()

    else:
        st.write("No images left to annotate. Thank you for your contribution!")