Skip to content

Commit

Permalink
feat(lb-components): Add FindTrackIDIndex and AnnotatedBox component
Browse files Browse the repository at this point in the history
  • Loading branch information
lihqi committed Feb 18, 2024
1 parent ed4cb77 commit e6e7487
Show file tree
Hide file tree
Showing 11 changed files with 402 additions and 75 deletions.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,11 @@ export interface IPointCloudContext
selectedPointCloudBox?: IPointCloudBox;
setPointCloudValid: (valid?: boolean) => void;
addSelectedID: (selectedID: string) => void;
addHighlightID: (highlightID: number) => void;
selectedAllBoxes: () => void;
selectedID: string;
highlightIDs: number[];
setHighlightIDs: (ids: number[]) => void;
addPointCloudBox: (boxParams: IPointCloudBox) => IPointCloudBox[];
addPointCloudSphere: (sphereParams: IPointCloudSphere) => IPointCloudSphere[];

Expand Down Expand Up @@ -129,6 +132,8 @@ export const PointCloudContext = React.createContext<IPointCloudContext>({
lineList: [],
selectedID: '',
selectedIDs: [],
highlightIDs: [],
setHighlightIDs: () => {},
valid: true,
setSelectedIDs: () => {},
setPointCloudResult: () => {},
Expand All @@ -139,6 +144,7 @@ export const PointCloudContext = React.createContext<IPointCloudContext>({
setBackViewInstance: () => {},
setMainViewInstance: () => {},
addSelectedID: () => {},
addHighlightID: () => {},
selectedAllBoxes: () => {},
addPointCloudBox: () => {
return [];
Expand Down Expand Up @@ -191,6 +197,7 @@ export const PointCloudProvider: React.FC<{}> = ({ children }) => {
const [polygonList, setPolygonList] = useState<IPolygonData[]>([]);
const [lineList, setLineList] = useState<ILine[]>([]);
const [selectedIDs, setSelectedIDsState] = useState<string[]>([]);
const [highlightIDs, setHighlightIDs] = useState<number[]>([]);
const [valid, setValid] = useState<boolean>(true);
const [cuboidBoxIn2DView, setCuboidBoxIn2DView] = useState<boolean>(true);
const [zoom, setZoom] = useState<number>(1);
Expand Down Expand Up @@ -281,6 +288,14 @@ export const PointCloudProvider: React.FC<{}> = ({ children }) => {
}
};

const addHighlightID = (highlightID: number) => {
if (highlightIDs.includes(highlightID)) {
setHighlightIDs([]);
} else {
setHighlightIDs([highlightID]);
}
};

const selectedAllBoxes = () => {
if (pointCloudPattern === EToolName.Rect) {
const ids = pointCloudBoxList.map((i) => i.id);
Expand Down Expand Up @@ -406,6 +421,7 @@ export const PointCloudProvider: React.FC<{}> = ({ children }) => {
selectedPointCloudBox,
setPointCloudValid,
addSelectedID,
addHighlightID,
selectedAllBoxes,
topViewInstance,
setTopViewInstance,
Expand Down Expand Up @@ -448,6 +464,8 @@ export const PointCloudProvider: React.FC<{}> = ({ children }) => {
setCuboidBoxIn2DView,
imageSizes,
cacheImageNodeSize,
highlightIDs,
setHighlightIDs,
};
}, [
valid,
Expand All @@ -471,6 +489,7 @@ export const PointCloudProvider: React.FC<{}> = ({ children }) => {
highlight2DDataList,
cuboidBoxIn2DView,
imageSizes,
highlightIDs,
]);

const updateSelectedIDsAndRenderAfterHide = () => {
Expand Down
26 changes: 8 additions & 18 deletions packages/lb-components/src/utils/audio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,14 @@ import { message as SenseMessage } from 'antd';
import { cStyle, cTool } from '@labelbee/lb-annotation';
import _ from 'lodash';
import { IInputList } from '@/types/main';
import Decimal from 'decimal.js'
import Decimal from 'decimal.js';
import moment from 'moment';
import { ITextConfigItem } from '@labelbee/lb-utils'
import { ITextConfigItem } from '@labelbee/lb-utils';

const {
COLORS_ARRAY,
ICON_ARRAY,
INVALID_ICON,
NULL_COLOR,
NULL_ICON,
WHITE_FONT_COLOR_ARRAY,
} = cStyle
const { COLORS_ARRAY, ICON_ARRAY, INVALID_ICON, NULL_COLOR, NULL_ICON, WHITE_FONT_COLOR_ARRAY } =
cStyle;

const { ETextType } = cTool
const { ETextType } = cTool;

export const ATTRIBUTE_COLORS = [NULL_COLOR].concat(COLORS_ARRAY);

Expand All @@ -42,11 +36,7 @@ export const DEFAULT_TEXT_CONFIG_ITEM: ITextConfigItem = {
* @param attribute
* @param attributeList
*/
export const getAttributeIcon = (
attribute: string,
attributeList: IInputList[],
valid = true,
) => {
export const getAttributeIcon = (attribute: string, attributeList: IInputList[], valid = true) => {
const attributeIndex = attributeList.findIndex((i: any) => i.value === attribute);
let src = ICON_ARRAY[attributeIndex % ICON_ARRAY.length] ?? NULL_ICON;
if (!valid) {
Expand Down Expand Up @@ -322,8 +312,8 @@ const generateIsDoubleClick = (interval: number) => {
};
return fn;
};
// 间隔300ms点击同一元素视为双击
export const isDoubleClick = generateIsDoubleClick(300);
// 间隔500ms点击同一元素视为双击
export const isDoubleClick = generateIsDoubleClick(500);

export const formatTime = (time: number) => {
const milliseconds = Math.floor(time * 1000);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.tag {
color: #666;
background-color: #f3f4ff;
border-color: transparent;
cursor: pointer;
position: relative;
&.disabled {
color: #ccc;
background-color: #f5f5f5;
cursor: not-allowed;
}
&.selected {
color: #fff;
background-color: #666fff;
}
.highlight {
position: absolute;
right: -5px;
top: -5px;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
import React, { useContext, useState, useEffect } from 'react';
import { Checkbox, Popover, Tag } from 'antd';
import { PointCloudUtils } from '@labelbee/lb-utils';
import { PointCloudContext } from '@/components/pointCloudView/PointCloudContext';
import { IFileItem } from '@/types/data';
import { useTranslation } from 'react-i18next';
import styles from './index.module.scss';
import classNames from 'classnames';

import HighlightSvg from '@/assets/annotation/pointCloudTool/highlight.svg';
import HighlightActiveSvg from '@/assets/annotation/pointCloudTool/highlight_a.svg';
import { QuestionCircleOutlined } from '@ant-design/icons';
import { isDoubleClick } from '@/utils/audio';

interface ITrackIDItem {
id: string;
trackID?: number;
disabled: boolean;
selected: boolean;
isHighlight: boolean;
}

const AnnotatedBox = ({ imgList, imgIndex }: { imgList: IFileItem[]; imgIndex: number }) => {
const { t } = useTranslation();

const ptCtx = useContext(PointCloudContext);
const { pointCloudBoxList } = ptCtx;

const [showIDs, setShowIds] = useState<ITrackIDItem[]>([]);
const [onlyShowCurrentIndex, setOnlyShowCurrentIndex] = useState<boolean>(false);

const highlightHandler = (item: ITrackIDItem) => {
ptCtx.addHighlightID(item.trackID as number);
};

const selectHandler = (item: ITrackIDItem) => {
ptCtx.addSelectedID(item.id);
};

useEffect(() => {
const newImgList = imgList as Array<{ result: string }>;
let trackMap = new Map();
const selectedTrackIDs = ptCtx.selectedIDs.map(
(v) => ptCtx.pointCloudBoxList.find((box) => box.id === v)?.trackID,
);
setShowIds(
PointCloudUtils.getAllPointCloudResult({
imgList: newImgList,
extraBoxList: pointCloudBoxList,
ignoreIndexList: [imgIndex],
})
.filter((v) => {
if (!v.trackID) {
return false;
}

if (trackMap.get(v.trackID)) {
return false;
}
trackMap.set(v.trackID, true);
return true;
})
.sort((a, b) => {
const aTrackID = a?.trackID ?? 0;
const bTrackID = b?.trackID ?? 0;

return aTrackID - bTrackID;
})
.map((v) => {
const box = ptCtx.pointCloudBoxList.find((box) => box.trackID === v.trackID);
return {
id: box?.id ?? v.id,
trackID: v.trackID,
disabled: !box,
selected: selectedTrackIDs.includes(v.trackID),
isHighlight: v?.trackID ? ptCtx.highlightIDs.includes(v.trackID) : false,
};
}),
);
}, [ptCtx.pointCloudBoxList, imgList, ptCtx.selectedIDs, ptCtx.highlightIDs, imgIndex]);

useEffect(() => {
const highlightBoxes = ptCtx.pointCloudBoxList.filter(
(box) => box.trackID && ptCtx.highlightIDs.includes(box.trackID),
);

if (highlightBoxes?.length) {
const needSetSelectedIDs = highlightBoxes.every((box) => !ptCtx.selectedIDs.includes(box.id));
if (needSetSelectedIDs) {
const needHighlightSelectedIDs = [...ptCtx.selectedIDs, ...highlightBoxes.map((v) => v.id)];
ptCtx.setSelectedIDs(needHighlightSelectedIDs);
}
}
}, [imgIndex, ptCtx.highlightIDs, ptCtx.selectedIDs]);

return (
<div style={{ padding: 24, borderBottom: '1px solid #eee' }}>
<div style={{ marginBottom: 16 }}>
{t('AllTrackIDs')}
<Popover
placement='topRight'
content={
<>
<div>{t('ClickOnTheIdToHighlightTheMarkupBox')}</div>
<div>{t('DoubleClickOnTheIdToContinuouslyHighlightBoxesAcrossFrames')}</div>
</>
}
>
<QuestionCircleOutlined style={{ marginLeft: 8 }} />
</Popover>
</div>
<div
style={{
display: 'flex',
alignItems: 'center',
marginBottom: 16,
justifyContent: 'flex-end',
}}
>
<Checkbox
checked={onlyShowCurrentIndex}
onChange={(e) => setOnlyShowCurrentIndex(e.target.checked)}
>
{t('OnlyCurrentFrame')}
</Checkbox>
</div>

<div>
{showIDs.map((item) => {
if (item.disabled && onlyShowCurrentIndex) {
return null;
}
return (
<Tag
key={item.trackID}
className={classNames({
[styles.tag]: true,
[styles.disabled]: item.disabled,
[styles.selected]: item.selected,
[styles.highlight]: item.isHighlight,
})}
style={{
marginBottom: 8,
}}
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
if (isDoubleClick(e as any)) {
highlightHandler(item);
return;
}
if (item.disabled) {
return;
}
selectHandler(item);
}}
>
{item.isHighlight && (
<img
src={item.disabled ? HighlightSvg : HighlightActiveSvg}
className={styles.highlight}
/>
)}

{item.trackID}
</Tag>
);
})}
</div>
</div>
);
};

export default AnnotatedBox;
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.container {
padding: 12px 20px;
.content {
display: flex;
justify-content: space-between;
margin-top: 4px;
}
}

0 comments on commit e6e7487

Please sign in to comment.