Skip to content

Commit

Permalink
Merge pull request #117 from IDEA-Research/feature/annotator_update
Browse files Browse the repository at this point in the history
Feature/annotator update
  • Loading branch information
xifanii authored Jan 4, 2024
2 parents a19f6e9 + 16fb75a commit 823daf0
Show file tree
Hide file tree
Showing 136 changed files with 9,236 additions and 3,102 deletions.
28 changes: 12 additions & 16 deletions packages/app/src/components/CategoryFilter/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { Select } from 'antd';
import React, { useMemo } from 'react';
import { Select, SelectProps } from 'antd';
import { useLocale } from 'dds-utils/locale';
import styles from './index.less';
import { Category } from '@/types';
Expand All @@ -14,30 +14,26 @@ const CategoryFilter: React.FC<IProps> = (props) => {
const { localeText } = useLocale();
const { categoryId, categories, onCategoryChange } = props;

const options: SelectProps['options'] = useMemo(() => {
return categories.map((item) => ({
label: item.name,
value: item.id,
}));
}, [categories]);

return (
<div className={styles.wrapper}>
{localeText('dataset.detail.category')}:
<Select
showSearch
style={{ width: '160px', marginLeft: '10px' }}
dropdownMatchSelectWidth={false}
placeholder="Select a category"
optionFilterProp="children"
options={options}
optionFilterProp="label"
value={categoryId}
onChange={onCategoryChange}
filterOption={(input, option) =>
(option!.children as unknown as string)
.toLowerCase()
.includes(input.toLowerCase())
}
getPopupContainer={() => document.getElementById('filterWrap')!}
>
{categories.map((item) => (
<Select.Option key={item.id} value={item.id}>
{item.name}
</Select.Option>
))}
</Select>
/>
</div>
);
};
Expand Down
153 changes: 94 additions & 59 deletions packages/app/src/models/dataset/common.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ import {
PageState,
} from './type';
import { isNumber } from 'lodash';
import { IAnnotationObject } from 'dds-components/Annotator';
import { NsDataSet } from '@/types/dataset';

export default () => {
Expand Down Expand Up @@ -275,6 +274,40 @@ export default () => {
displayLabelIds,
isTiledDiff,
};

// filter displayType
const displayType = pageState.filterValues.displayAnnotationType;
objects = objects
.filter((obj) => {
return (
(obj.mask && displayType === AnnotationType.Mask) ||
(obj.alpha && displayType === AnnotationType.Matting) ||
(obj.points && displayType === AnnotationType.KeyPoints) ||
(obj.segmentation && displayType === AnnotationType.Segmentation) ||
(obj.boundingBox && displayType === AnnotationType.Detection)
);
})
.map((obj) => {
return {
...obj,
mask: displayType === AnnotationType.Mask ? obj.mask : undefined,
alpha:
displayType === AnnotationType.Matting ? obj.alpha : undefined,
points:
displayType === AnnotationType.KeyPoints ? obj.points : undefined,
segmentation:
displayType === AnnotationType.Segmentation
? obj.segmentation
: undefined,
boundingBox: [
AnnotationType.Detection,
AnnotationType.KeyPoints,
].includes(displayType!)
? obj.boundingBox
: undefined,
};
});

// Analysis mode -> filter fn/fp to display
if (analysisMode) {
const predObjects = objects.filter(
Expand Down Expand Up @@ -314,37 +347,69 @@ export default () => {
});
}

return objects.filter((item) => {
const { showAnnotations, showAllCategory } = displayOptionsResult;
const categoryId = pageState.filterValues.categoryId || '';
if (
!showAnnotations ||
(!showAllCategory && item.categoryId !== categoryId) ||
(diffMode &&
item.labelId &&
!diffMode.displayLabelIds.includes(item.labelId)) ||
(diffMode &&
diffMode.isTiledDiff &&
item.labelId !== imageData.curLabelId)
) {
return false;
}
if (!analysisMode && diffMode) {
const label = diffMode.labels.find(
(label) => label.id === item.labelId,
);
if (!label) return false;
if (label.source === LABEL_SOURCE.gt) return true;
return (
item.conf !== undefined &&
item.conf >= label?.confidenceRange[0] &&
item.conf <= label?.confidenceRange[1]
return objects
.filter((item) => {
const { showAnnotations, showAllCategory } = displayOptionsResult;
const categoryId = pageState.filterValues.categoryId || '';
if (
!showAnnotations ||
(!showAllCategory && item.categoryId !== categoryId) ||
(diffMode &&
item.labelId &&
!diffMode.displayLabelIds.includes(item.labelId)) ||
(diffMode &&
diffMode.isTiledDiff &&
item.labelId !== imageData.curLabelId)
) {
return false;
}
if (!analysisMode && diffMode) {
const label = diffMode.labels.find(
(label) => label.id === item.labelId,
);
if (!label) return false;
if (label.source === LABEL_SOURCE.gt) return true;
return (
item.conf !== undefined &&
item.conf >= label?.confidenceRange[0] &&
item.conf <= label?.confidenceRange[1]
);
}
return true;
})
.map((item) => {
// get custom style
const newItem = { ...item };
const {
colorAplha: pointAplha,
strokeDash,
lineWidth: thickness,
} = getLabelCustomStyles(
item.labelId,
displayLabelIds,
isTiledDiff || Boolean(pageState.comparisons),
);
}
return true;
});
if (analysisMode && item.compareResult) {
newItem.customStyles = {
pointAplha,
strokeDash,
thickness,
fillColor:
// @ts-ignore
COMPARE_RESULT_FILL_COLORS[item.compareResult] || 'transparent',
};
} else {
newItem.customStyles = {
pointAplha,
strokeDash,
thickness,
};
}
return newItem;
});
},
[
pageState.filterValues.displayAnnotationType,
pageState.comparisons,
pageData.filters.labels,
displayLabelIds,
Expand All @@ -353,35 +418,6 @@ export default () => {
],
);

const getCustomObjectStyles = useCallback(
(object: IAnnotationObject) => {
const {
colorAplha: pointAplha,
strokeDash,
lineWidth: thickness,
} = getLabelCustomStyles(
object.labelId,
displayLabelIds,
isTiledDiff || Boolean(pageState.comparisons),
);
if (Boolean(pageState.comparisons) && object.compareResult) {
return {
pointAplha,
strokeDash,
thickness,
fillColor:
COMPARE_RESULT_FILL_COLORS[object.compareResult] || 'transparent',
};
}
return {
pointAplha,
strokeDash,
thickness,
};
},
[displayLabelIds, isTiledDiff, Boolean(pageState.comparisons)],
);

return {
// page var
pageState,
Expand All @@ -405,6 +441,5 @@ export default () => {

// common render
displayObjectsFilter,
getCustomObjectStyles,
};
};
137 changes: 4 additions & 133 deletions packages/app/src/pages/Annotator/index.tsx
Original file line number Diff line number Diff line change
@@ -1,139 +1,10 @@
import React, { useEffect, useState } from 'react';
import React from 'react';
import QuickLabel from 'dds-components/QuickLabel';
import { useModel } from '@umijs/max';
import styles from './index.less';
import { AnnotateEditor, EditorMode } from 'dds-components/Annotator';
import { ImageList } from './components/ImageList';
import { Button } from 'antd';
import { SettingOutlined } from '@ant-design/icons';
import { FormModal } from './components/FormModal';
import { useLocale } from 'dds-utils/locale';
import { useKeyPress } from 'ahooks';
import { BaseObject } from '@/types';

const Page: React.FC = () => {
const {
images,
setImages,
current,
setCurrent,
categories,
setCategories,
exportAnnotations,
} = useModel('Annotator.model');

const { localeText } = useLocale();
const [openModal, setModalOpen] = useState(true);

useEffect(() => {
// const handleBeforeUnload = (event: BeforeUnloadEvent) => {
// event.preventDefault();
// event.returnValue =
// 'The current changes will not be saved. Please export before leaving.';
// };
// window.addEventListener('beforeunload', handleBeforeUnload);
// return () => {
// window.removeEventListener('beforeunload', handleBeforeUnload);
// };
}, []);

// local test
useEffect(
() => {
// if(images.length > 0 && categories.length > 0) {
// localStorage.setItem('images', JSON.stringify(images));
// localStorage.setItem('categories', JSON.stringify(categories));
// console.log('>>> save localStorage');
// }
const images = localStorage.getItem('images');
const categories = localStorage.getItem('categories');
if (images && categories) {
setImages(JSON.parse(images));
setCategories(JSON.parse(categories));
setModalOpen(false);
}
},
// [images, categories]
[],
);

useKeyPress(
'uparrow',
() => {
setCurrent(Math.max(0, current - 1));
},
{ exactMatch: true },
);

useKeyPress(
'downarrow',
() => {
setCurrent(Math.min(current + 1, images.length - 1));
},
{ exactMatch: true },
);

return (
<div className={styles.container}>
<div
className={styles.left}
onMouseDown={(event) => {
event.stopPropagation();
}}
onMouseUp={(event) => {
event.stopPropagation();
}}
>
<Button
type="primary"
icon={<SettingOutlined />}
onClick={() => {
setModalOpen(true);
}}
>
{localeText('annotator.setting')}
</Button>
<ImageList
images={images}
selected={current}
onImageSelected={(index) => {
setCurrent(index);
}}
/>
</div>
<div className={styles.right}>
<AnnotateEditor
isSeperate={true}
visible={true}
mode={EditorMode.Edit}
categories={categories}
setCategories={setCategories}
list={images}
current={current}
actionElements={[
<Button type="primary" key={'export'} onClick={exportAnnotations}>
{localeText('annotator.export')}
</Button>,
]}
onAutoSave={(annos: BaseObject[], naturalSize: ISize) => {
setImages((images) => {
if (images[current]) {
images[current].objects = annos;
images[current].width = naturalSize.width;
images[current].height = naturalSize.height;
}
});
}}
/>
</div>
<div
className={styles.modal}
onMouseDown={(e) => e.stopPropagation()}
onMouseUp={(e) => e.stopPropagation()}
>
<FormModal open={openModal} setOpen={setModalOpen} />
</div>
</div>
);
const props = useModel('Annotator.model');
return <QuickLabel {...props} />;
};

export default Page;
Loading

0 comments on commit 823daf0

Please sign in to comment.