GithubHelp home page GithubHelp logo

hirune924 / streamlit-image-annotation Goto Github PK

View Code? Open in Web Editor NEW
73.0 1.0 11.0 11.02 MB

Streamlit component for image annotation.

License: Apache License 2.0

Python 40.93% HTML 5.26% TypeScript 53.81%
image-annotation streamlit-component

streamlit-image-annotation's Introduction

Streamlit Image Annotation

Streamlit component for image annotation.

Streamlit App PyPI

Features

  • You can easily launch an image annotation tool using streamlit.
  • By customizing the pre- and post-processing, you can achieve your preferred annotation workflow.
  • Currently supports classification, detection, point detection tasks.
  • Simple UI that is easy to navigate.

Install

pip install streamlit-image-annotation

Example Usage

If you want to see other use cases, please check inside the examples folder.

from glob import glob
import pandas as pd
import streamlit as st
from streamlit_image_annotation import classification

label_list = ['deer', 'human', 'dog', 'penguin', 'framingo', 'teddy bear']
image_path_list = glob('image/*.jpg')
if 'result_df' not in st.session_state:
    st.session_state['result_df'] = pd.DataFrame.from_dict({'image': image_path_list, 'label': [0]*len(image_path_list)}).copy()

num_page = st.slider('page', 0, len(image_path_list)-1, 0)
label = classification(image_path_list[num_page], 
                        label_list=label_list, 
                        default_label_index=int(st.session_state['result_df'].loc[num_page, 'label']))

if label is not None and label['label'] != st.session_state['result_df'].loc[num_page, 'label']:
    st.session_state['result_df'].loc[num_page, 'label'] = label_list.index(label['label'])
st.table(st.session_state['result_df'])

API

classification(
    image_path: str,
    label_list: List[str],
    default_label_index: Optional[int] = None,
    height: int = 512,
    width: int = 512,
    key: Optional[str] = None
)
  • image_path: Image path.

  • label_list: List of label candidates.

  • default_label_index: Initial label index.

  • height: The maximum height of the displayed image.

  • width: The maximum width of the displayed image.

  • key: An optional string to use as the unique key for the widget. Assign a key so the component is not remount every time the script is rerun.

  • Component Value: {'label': label_name}

Example: example code

detection(
    image_path: str,
    label_list: List[str],
    bboxes: Optional[List[List[int, int, int, int]]] = None,
    labels: Optional[List[int]] = None,
    height: int = 512,
    width: int = 512,
    line_width: int = 5,
    use_space: bool = False,
    key: Optional[str] = None
)
  • image_path: Image path.

  • label_list: List of label candidates.

  • bboxes: Initial list of bounding boxes, where each bbox is in the format [x, y, w, h].

  • labels: List of label for each initial bbox.

  • height: The maximum height of the displayed image.

  • width: The maximum width of the displayed image.

  • line_width: The stroke width of the bbox.

  • use_space: Enable Space key for complete.

  • key: An optional string to use as the unique key for the widget. Assign a key so the component is not remount every time the script is rerun.

  • Component Value: [{'bbox':[x,y,width, height], 'label_id': label_id, 'label': label_name},...]

Example: example code

pointdet(
    image_path: str,
    label_list: List[str],
    points: Optional[List[List[int, int]]] = None,
    labels: Optional[List[int]] = None,
    height: int = 512,
    width: int = 512,
    point_width: int =3,
    use_space: bool = False,
    key: Optional[str] = None
)
  • image_path: Image path.

  • label_list: List of label candidates.

  • points: Initial list of points, where each point is in the format [x, y].

  • labels: List of label for each initial bbox.

  • height: The maximum height of the displayed image.

  • width: The maximum width of the displayed image.

  • point_width: The stroke width of the bbox.

  • use_space: Enable Space key for complete.

  • key: An optional string to use as the unique key for the widget. Assign a key so the component is not remount every time the script is rerun.

  • Component Value: [{'bbox':[x,y], 'label_id': label_id, 'label': label_name},...]

Example: example code

Future Work

  • Addition of component for segmentation task.

Development

setup

cd Streamlit-Image-Annotation/
export PYTHONPATH=$PWD

and set IS_RELEASE = False in Streamlit-Image-Annotation/__init__.py.

start frontend

git clone https://github.com/hirune924/Streamlit-Image-Annotation.git
cd Streamlit-Image-Annotation/streamlit_image_annotation/Detection/frontend
yarn
yarn start

start streamlit

cd Streamlit-Image-Annotation/
streamlit run streamlit_image_annotation/Detection/__init__.py

build

cd Streamlit-Image-Annotation/Classification/frontend
yarn build
cd Streamlit-Image-Annotation/Detection/frontend
yarn build
cd Streamlit-Image-Annotation/Point/frontend
yarn build

and set IS_RELEASE = True in Streamlit-Image-Annotation/__init__.py.

make wheel

python setup.py sdist bdist_wheel

upload

python3 -m twine upload --repository testpypi dist/*
python -m pip install --index-url https://test.pypi.org/simple/ --no-deps streamlit-image-annotation
twine upload dist/*

streamlit-image-annotation's People

Contributors

hirune924 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

streamlit-image-annotation's Issues

Adding hotkeys to save changes on an image

Hello dear developer,currently I'm working on a task to make annotations on some hundred images,and I found it a little inconvenient having to click that "complete" button every time I finish my work on an image.So is it possible to save the changes on an image by pressing a hotkey or something?Thanks.

canvas will not rerender when data change comes from streamlit

canvas will not rerender if rect info change(such as delete tags), it just change when we do some mouse action.

I found that in fontend file streamlit_image_annotation/Detection/frontend/src/Detection.tsx
we just listen image size change, not listen bbox_info updates.

So we need to add these code to update bbox_info:

useEffect(() => {
 setRectangles(bbox_info.map((bb, i) => {
      return {
        x: bb.bbox[0],
        y: bb.bbox[1],
        width: bb.bbox[2],
        height: bb.bbox[3],
        label: bb.label,
        stroke: color_map[bb.label],
        id: 'bbox-' + i
      }
    }))
}, [bbox_info])

Cant render the foto

Hello!

Firstly, thank you for making this!

I am working with your code but the images are not showing.
image

can you help me with this issue?

this is my code:

import os
import streamlit as st
from streamlit_img_label import st_img_label
from streamlit_img_label.manage import ImageManager, ImageDirManager
from glob import glob
import pandas as pd
from streamlit_image_annotation import detection
import json

label_list = ['Bottle cap', 'human', 'dog', 'penguin', 'framingo', 'teddy bear']
image_path_list = glob('img_dir/*.jpg')
json_files = glob('img_dir/*.json')  # Update with the actual path to your JSON files

def load_annotation_file(annotation_file_path):
    with open(annotation_file_path, 'r') as file:
        annotation_data = json.load(file)
        annotation_dataXYXY = annotation_data["json_data"][0]["xyxyn"]
    return annotation_dataXYXY

def save_annotation_file(annotation_file_path, annotation_data):
    with open(annotation_file_path, 'w') as file:
        json.dump(annotation_data, file)

def main():
    # File Selection
    selected_image_path = st.selectbox("Select Image", image_path_list)

    # JSON File Selection
    selected_json_file = st.selectbox("Select JSON File", json_files)

    with open(selected_json_file, 'r') as file:
        annotation_data = json.load(file)

    X1 = annotation_data["json_data"][0]["xyxyn"][0][0]
    Y1 = annotation_data["json_data"][0]["xyxyn"][0][1]
    X2 = annotation_data["json_data"][0]["xyxyn"][0][2]
    Y2 = annotation_data["json_data"][0]["xyxyn"][0][3]
    hoogte = annotation_data["json_data"][0]["image_shape"][0]
    breedte = annotation_data["json_data"][0]["image_shape"][1]
    class_label = annotation_data["json_data"][0]["class_label"]
    #convert to coords
    X1_B = X1 * breedte
    Y1_H = Y1 * hoogte
    X2_B = X2 * breedte
    Y2_H = Y2 * hoogte

    if selected_json_file is not None:
        annotation_data = load_annotation_file(selected_json_file)

    if 'result_dict_det' not in st.session_state:
        result_dict = {}
        for img in image_path_list:
            result_dict[img] = {'bboxes': [[X1_B,Y1_H,X2_B,Y2_H]], 'labels': [0]}
        st.session_state['result_dict_det'] = result_dict.copy()

    new_labels = detection(image_path=selected_image_path,
                           bboxes=st.session_state['result_dict_det'][selected_image_path]['bboxes'],
                           labels=st.session_state['result_dict_det'][selected_image_path]['labels'],
                           label_list=label_list, key=selected_image_path + '_det')

    if new_labels is not None:
        st.session_state['result_dict_det'][selected_image_path]['bboxes'] = [v['bbox'] for v in new_labels]
        st.session_state['result_dict_det'][selected_image_path]['labels'] = [v['label_id'] for v in new_labels]
    
    # Save edited annotations
    if st.button("Save Annotations"):
        if annotation_data is not None:
            annotation_data["image_path"] = selected_image_path
            annotation_data["json_data"][0]["xyxyn"] = new_labels[0]["bbox"]  # Assuming there's only one bbox
            save_annotation_file("edited_annotations.json", annotation_data)

    st.json(st.session_state['result_dict_det'])

if __name__ == "__main__":
    main()

stroke_width

thank you for this lib, its excatly what i was looking for.

is it possible to add stroke_width as a variable in detection function? the draggable boxes have very fat border now , difficult to annotate small area.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.