Skip to content

Commit d96d266

Browse files
authored
Merge branch 'master' into image_upload_progress_track
2 parents e1efad9 + 0772640 commit d96d266

File tree

33 files changed

+390
-541
lines changed

33 files changed

+390
-541
lines changed

.github/workflows/python-app.yml

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
name: Python application
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
- master
8+
pull_request:
9+
branches:
10+
- main
11+
- master
12+
13+
jobs:
14+
build:
15+
runs-on: ubuntu-latest
16+
17+
steps:
18+
- name: Checkout repository
19+
uses: actions/checkout@v3
20+
21+
- name: Set up Python 3.9
22+
uses: actions/setup-python@v3
23+
with:
24+
python-version: 3.9
25+
26+
- name: Install dependencies
27+
run: |
28+
python -m venv venv
29+
source venv/bin/activate
30+
pip install -r server/requirements.txt
31+
32+
- name: Run tests
33+
run: |
34+
source venv/bin/activate
35+
cd server
36+
python3 -m unittest tests/test_app.py

README.md

+7-5
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# Annotate-Lab
22

3-
Annotate-Lab is an open-source application designed for image annotation, comprising two main components: the client and the server. The client, a React application, is responsible for the user interface where users perform annotations. On the other hand, the server, a Flask application, manages persisting the annotated changes and generating masked and annotated images, along with configuration settings. More information can be found in our [documentation](./docs/annotate-lab.md).
3+
Annotate-Lab is an open-source application designed for image annotation, comprising two main components: the client and the server. The client, a React application, is responsible for the user interface where users perform annotations. On the other hand, the server, a Flask application, manages persisting the annotated changes and generating masked and annotated images, along with configuration settings. More information can be found in our [documentation](https://annotate-docs.dwaste.live/).
44

5-
![example](./example.png)
5+
![example](./sample_images/example.png)
66

77
# Demo
88
[![Annotate Lab](https://img.youtube.com/vi/b78BJhbasVw/0.jpg)](https://www.youtube.com/watch?v=b78BJhbasVw)
@@ -34,6 +34,7 @@ annotation-lab/
3434
│ └── ... (other React app files)
3535
├── server/
3636
│ ├── db/
37+
│ ├── tests/
3738
│ ├── venv/
3839
│ ├── app.py
3940
│ ├── requirements.txt
@@ -50,13 +51,14 @@ annotation-lab/
5051
### Server
5152
- **db/**: Database-related files and handlers.
5253
- **venv/**: Python virtual environment (not included in version control).
54+
- **tests/**: Contains test files.
5355
- **app.py**: Main Flask application file.
5456
- **requirements.txt**: Contains server dependencies.
5557

5658
## Settings
5759
One can configure the tools, tags, upload images and do many more from the settings.
5860

59-
![configuration](./configuration.png)
61+
![configuration](./sample_images/configuration.png)
6062
## Dependencies
6163

6264
### Client
@@ -144,8 +146,8 @@ docker-compose up -d #running in detached mode
144146
## Outputs
145147
Sample of annotated image along with its mask and settings is show below.
146148

147-
![orange_annotation](./docs/orange_annotated-image.png)
148-
![orange_annotation_mask](./docs/orange_masked-image.png)
149+
![orange_annotation](./sample_images/orange_annotated-image.png)
150+
![orange_annotation_mask](./sample_images/orange_masked-image.png)
149151

150152
```json
151153
{

client/.npmignore

-3
This file was deleted.

client/src/ConfigurationTask/index.jsx

+23-23
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,31 @@ import React, { useMemo } from "react"
33
import Survey from "material-survey/components/Survey"
44
import { setIn } from "seamless-immutable"
55
import { CssBaseline, GlobalStyles } from "@mui/material";
6-
7-
const form = {
8-
questions: [
9-
{
10-
name: "taskDescription",
11-
title: "Task Information",
12-
type: "text",
13-
placeHolder: "Enter task details...",
14-
isRequired: true
15-
},
16-
{
17-
name: "taskChoice",
18-
title: "Choice of Task",
19-
type: "radiogroup",
20-
isRequired: true,
21-
choices: [
22-
{ value: "image_classification", text: "Image Classification" },
23-
{ value: "image_segmentation", text: "Image Segmentation" },
24-
],
25-
},
26-
27-
],
28-
}
6+
import {useTranslation} from "react-i18next"
297

308
export default ({ config, onChange }) => {
9+
const { t } = useTranslation();
10+
const form = {
11+
questions: [
12+
{
13+
name: "taskDescription",
14+
title: t("setup.tabs.taskinfo.task_info"),
15+
type: "text",
16+
isRequired: true
17+
},
18+
{
19+
name: "taskChoice",
20+
title: t("setup.tabs.taskinfo.task_choice"),
21+
type: "radiogroup",
22+
isRequired: true,
23+
choices: [
24+
{ value: "image_classification", text: t("setup.tabs.taskinfo.task_choice_classification")},
25+
{ value: "image_segmentation", text: t("setup.tabs.taskinfo.task_choice_segmentation") },
26+
],
27+
},
28+
29+
],
30+
}
3131
const defaultAnswers = useMemo(
3232
() => ({
3333
taskDescription: config.taskDescription || "",

client/src/ConfigureImageClassification/index.jsx

+48-45
Original file line numberDiff line numberDiff line change
@@ -3,55 +3,58 @@ import React, { useMemo } from "react"
33
import Survey from "material-survey/components/Survey"
44
import { setIn } from "seamless-immutable"
55
import { CssBaseline, GlobalStyles } from "@mui/material";
6+
import { useTranslation } from "react-i18next"
67

7-
const form = {
8-
questions: [
9-
{
10-
name: "multipleRegions",
11-
title: "Can multiple regions be created?",
12-
type: "boolean",
13-
},
14-
{
15-
name: "multipleRegionLabels",
16-
title: "Multiple Region Labels Allowed?",
17-
type: "boolean",
18-
},
19-
{
20-
name: "regionTypesAllowed",
21-
title: "Region Types Allowed",
22-
description: "What types of regions can be drawn on the image.",
23-
type: "checkbox",
24-
choices: ["bounding-box", "polygon", "circle"],
8+
export default ({ config, onChange }) => {
9+
const { t } = useTranslation();
10+
11+
const form = {
12+
questions: [
13+
{
14+
name: "multipleRegions",
15+
title: t("configuration.multiple_regions"),
16+
type: "boolean",
2517
},
26-
{
27-
name: "labels",
28-
title: "Labels",
29-
description: "Classifications or tags to be labeled.",
30-
type: "matrixdynamic",
31-
columns: [
32-
{ cellType: "text", name: "id", title: "id" , isRequired: true},
33-
{
34-
cellType: "text",
35-
name: "description",
36-
title: "Description (optional)",
18+
{
19+
name: "multipleRegionLabels",
20+
title:t("configuration.multiple_region_labels"),
21+
type: "boolean",
22+
},
23+
{
24+
name: "regionTypesAllowed",
25+
title: t("configuration.region_types_allowed"),
26+
description: t("configuration.region_types_allowed.description"),
27+
type: "checkbox",
28+
choices: ["bounding-box", "polygon", "circle"],
3729
},
38-
],
39-
},
40-
{
41-
name: "regions",
42-
title: "Default Region Type",
43-
description: "Choose default region type that can be drawn on the image.",
44-
type: "dropdown",
45-
choices: [
46-
"Polygon",
47-
"Bounding Box",
48-
"Point",
49-
],
50-
}
51-
],
52-
}
30+
{
31+
name: "labels",
32+
title: t("configuration.labels"),
33+
description: t("configuration.labels.description"),
34+
type: "matrixdynamic",
35+
columns: [
36+
{ cellType: "text", name: "id", title: t("configuration.labels.option.id") , isRequired: true},
37+
{
38+
cellType: "text",
39+
name: "description",
40+
title: t("configuration.labels.option.id"),
41+
},
42+
],
43+
},
44+
{
45+
name: "regions",
46+
title: t("configuration.regions"),
47+
description: t("configuration.regions.description"),
48+
type: "dropdown",
49+
choices: [
50+
"Polygon",
51+
"Bounding Box",
52+
"Point",
53+
],
54+
}
55+
],
56+
}
5357

54-
export default ({ config, onChange }) => {
5558
const defaultAnswers = useMemo(
5659
() => ({
5760
multipleRegions: Boolean(config.multipleRegions ? config.multipleRegions : true),

client/src/ConfigureImageSegmentation/index.jsx

+14-10
Original file line numberDiff line numberDiff line change
@@ -3,45 +3,49 @@ import React, { useMemo } from "react"
33
import Survey from "material-survey/components/Survey"
44
import { setIn, asMutable } from "seamless-immutable"
55
import { CssBaseline, GlobalStyles } from "@mui/material";
6+
import { useTranslation } from "react-i18next"
67

7-
const form = {
8+
9+
export default ({ config, onChange }) => {
10+
const { t } = useTranslation();
11+
12+
const form = {
813
questions: [
914
{
1015
name: "regionTypesAllowed",
11-
title: "Region Types Allowed",
12-
description: "What types of regions can be drawn on the image.",
16+
title: t("configuration.region_types_allowed"),
17+
description: t("configuration.region_types_allowed.description"),
1318
type: "multiple-dropdown",
1419
choices: ["bounding-box", "polygon", "circle"],
1520
},
1621
{
1722
name: "multipleRegions",
18-
title: "Can multiple regions be created?",
23+
title: t("configuration.multiple_regions"),
1924
type: "boolean",
2025
},
2126
{
2227
name: "multipleRegionLabels",
23-
title: "Multiple Region Labels Allowed?",
28+
title: t("configuration.multiple_region_labels"),
2429
type: "boolean",
2530
},
2631
{
2732
name: "labels",
28-
title: "Available Labels",
33+
title: t("configuration.labels"),
2934
description:
30-
"If you're labeling regions on an image, these are the allowed classifications or tags.",
35+
t("configuration.labels.description"),
3136
type: "matrixdynamic",
3237
columns: [
33-
{ cellType: "text", name: "id", title: "id" },
38+
{ cellType: "text", name: "id", title: t("configuration.labels.option.id") , isRequired: true},
3439
{
3540
cellType: "text",
3641
name: "description",
37-
title: "Description (optional)",
42+
title: t("configuration.labels.option.description"),
3843
},
3944
],
4045
},
4146
],
4247
}
4348

44-
export default ({ config, onChange }) => {
4549
const defaultAnswers = useMemo(
4650
() =>
4751
asMutable(

client/src/DemoSite/index.jsx

+3-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,9 @@ export default () => {
6868
})[0]
6969

7070
let selectedImageIndex = imageNames.indexOf(selectedImage)
71+
if(selectedImageIndex != -1){
7172
changeSelectedImageIndex(selectedImageIndex)
73+
}
7274
}
7375

7476
const getEnabledTools = (selectedTools) => {
@@ -139,7 +141,7 @@ export default () => {
139141
enabledTools={getEnabledTools(settings.configuration.regionTypesAllowed) || []}
140142
regionClsList={settings.configuration.labels.map(label => label.id) || []}
141143
selectedImage={selectedImageIndex}
142-
enabledRegionProps= {["class", "comment"]}
144+
enabledRegionProps= {["class", "name"]}
143145
userReducer= {userReducer}
144146
onExit={(output) => {
145147
preprocessDataBeforeSend(output)

client/src/FilesListMenu/index.jsx

+3-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import capitalize from "lodash/capitalize"
99
import classnames from "classnames"
1010
import Checkbox from "@mui/material/Checkbox"
1111
import getActiveImage from "../Annotator/reducers/get-active-image"
12+
import { useTranslation } from "react-i18next"
1213

1314
const theme = createTheme()
1415
const LabelContainer = styled("div")(({ theme }) => ({
@@ -64,6 +65,7 @@ export const FilesListMenu = ({
6465
onClick
6566
}) => {
6667
const [change, setChange] = useState('')
68+
const { t } = useTranslation();
6769
const handleClickLabel = (label) => {
6870
onClick(getActiveImage(state))
6971
saveActiveImage(getActiveImage(state).activeImage)
@@ -74,7 +76,7 @@ export const FilesListMenu = ({
7476
return (
7577
<ThemeProvider theme={theme}>
7678
<SidebarBoxContainer
77-
title={`Images [${allImages.length > 0 ? allImages.length : 0}]`}
79+
title={`${t("menu.images")} [${allImages.length > 0 ? allImages.length : 0}]`}
7880
subTitle=""
7981
icon={<CollectionsIcon style={{ color: muiColors.grey[700] }} />}
8082
noScroll={true}

0 commit comments

Comments
 (0)