Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft: Mapping mode draft #283

Open
wants to merge 1 commit into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/lb-components/src/utils/ToolUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ class ToolUtils {
return tool ? (Object.values(EPointCloudName) as string[]).includes(tool) : false;
}

public static isMappingTool(tool?: string) {
return tool ? ([EToolName.Point, EToolName.Tag, EToolName.Polygon, EToolName.Line] as string[]).includes(tool) : false;
}

public static getPointCloudToolList() {
return [EToolName.Point, EToolName.Line, EToolName.PointCloudPolygon];
}
Expand Down
8 changes: 8 additions & 0 deletions packages/lb-components/src/views/MainView/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import PreviewResult from '@/components/predictTracking/previewResult';
import { LabelBeeContext } from '@/store/ctx';
import { EToolName } from '@/data/enums/ToolType';
import LLMLayout from './LLMLayout';
import { AnnotationMappingWrapper } from './mappingWrapper/AnnotationMappingWrapper'

interface IProps {
path: string;
Expand Down Expand Up @@ -61,6 +62,7 @@ const AnnotatedArea: React.FC<AppProps & IProps> = (props) => {
const currentToolName = getStepConfig(stepList, step)?.tool;
const isVideoTool = ToolUtils.isVideoTool(currentToolName);
const isPointCloudTool = ToolUtils.isPointCloudTool(currentToolName);
const isMappingTool = ToolUtils.isMappingTool(currentToolName)

if (isVideoTool) {
return <VideoAnnotate {...props} />;
Expand All @@ -70,6 +72,12 @@ const AnnotatedArea: React.FC<AppProps & IProps> = (props) => {
return <PointCloudAnnotate {...props} />;
}

if (isMappingTool) {
return <AnnotationMappingWrapper>
<ImageAnnotate {...props} />
</AnnotationMappingWrapper>
}

return <ImageAnnotate {...props} />;
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/**
* @author lijingchi <[email protected]>
* @file 标注页面的映射视图,注入annotation的数据以嵌入到标注工具组件
* @date 2021-12-15
*/

import React, { useMemo } from 'react';
import { getImageFromMappingUnit } from '@/utils/ImageManager';
import { connectComponent } from '@/utils/store';
import { jsonParser } from '@/utils/tool/common';
import { EAnnotationMapping } from '@/constant/task';
import { StateType } from '@/models/annotation';
import { StateType as EditAnnotationType } from '@/models/editAnnotation';
import { IMappingWrapperRenderProps, MappingWrapperRender } from './index';
import _ from 'lodash';

export interface IAnnotationMappingWrapper {
annotation: StateType;
editAnnotation: EditAnnotationType;
children: JSX.Element;
result: any[];
rotate: number;
basicResult: any;
}

/**
* 标注页面(包含编辑步骤),根据标注单元(unitType)判读是否需要显示对应的视图
* @param props: IAnnotationMappingWrapper
*/
export const AnnotationMappingWrapper = (props: IAnnotationMappingWrapper) => {
const { annotation, editAnnotation, children, result, rotate, basicResult } = props;
const isEdit = annotation.isEdit || editAnnotation.isEdit;
const anno: StateType | EditAnnotationType = isEdit ? editAnnotation : annotation;
const imageBSrc = getImageFromMappingUnit(anno, 'B');
const imageASrc = getImageFromMappingUnit(anno);
const { currentStep, stepList } = anno;
const completeResult = isEdit ? {} : jsonParser(annotation.result) || {};
const mappingConfig = annotation?.mappingConfig;
const mappingType = mappingConfig?.mappingType;
const isNoMapping = mappingType === EAnnotationMapping.No;
const writtingResult = useMemo(() => {
return isNoMapping ? [] : _.cloneDeep(result);
}, [JSON.stringify(result), isNoMapping]);
const unitType = annotation?.unitType;

const mappingWrapperRenderProps: IMappingWrapperRenderProps = {
imageBSrc,
imageASrc,
writtingResult,
stepList,
step: currentStep,
rotate,
unitType,
children,
mappingConfig,
completeResult,
basicResult: isNoMapping ? undefined : basicResult,
isAnnotatePage: true,
};

return <MappingWrapperRender {...mappingWrapperRenderProps} />;
};

export const AnnoCtxMappingWrapper = connectComponent(
['annotation', 'editAnnotation', 'createStep'],
AnnotationMappingWrapper,
);

/**
* 计算A图的宽度
* @param size
* @param right
*/
export const canvasSizeForAImage = (size: ISize, right?: number) => {
if (right) {
return { ...size, width: size.width * right };
}

return size;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
/**
* @author lijingchi <[email protected]>
* @file B图映射渲染组件,根据A图的结果进行悬案
* @date 2021-12-15
*/

import React, { useContext, useMemo } from 'react';
import { BasicOperationContext } from '../tools/basicOperation';
import { EToolName } from '@/constant/tool';
import DrawPolygon from '@/pages/checkTool/components/DrawPolygon';
import DrawLine from '@/pages/checkTool/components/DrawLine';
import DrawPoint from '@/components/tools/pointTool/drawPoint';
import DrawTag from '@/pages/checkTool/components/tagTool';
import DrawImage from '@/components/tools/drawImage';
import { StaticViewWithRelyData } from '../StaticView';
import { getCurrentStepInfo, jsonParser } from '@/utils/tool/common';
import { IStepConfig } from '@/service/task';
import { ITagConfig } from '@/types/toolConfig';
import { uniqWith } from 'lodash';
import { EStepType } from '@/constant/task';
import { ReactComponent as BPoint } from '@/assets/icon/BPoint.svg';
import { connectComponent } from '@/utils/store';

export interface IMappingViewGraphicProps {
transferedResult: any[];
step: number;
stepList: IStepConfig[];
isCheckTool?: boolean;
isAnnotatePage?: boolean;
}

const fillLableAndFindCoordForTags = (transferedResult: any[], config: ITagConfig) => {
const tags = transferedResult.map((i) => {
const resultKeyFromInputList: any = {};
if (i.result) {
Object.keys(i.result).forEach((r) => {
const inputItem = config.inputList.find((s) => s.value === r);
const valueItem = inputItem && inputItem.subSelected?.find((s) => s.value === i.result[r]);

if (inputItem && valueItem) {
resultKeyFromInputList[inputItem.key] = valueItem.key;
} else {
resultKeyFromInputList[r] = i.result[r];
}
});

return {
...i,
result: resultKeyFromInputList,
};
}

return i;
});

return tags;
};

/**
* 支持多个形式的参数传递
* @param props
*/
export const GraphicMappingViewWrapper = (props: IMappingViewGraphicProps) => {
const { transferedResult, stepList, step, isCheckTool } = props;
const stepArray = isCheckTool
? uniqWith(transferedResult, (arrVal, othVal) => {
return arrVal.step === othVal.step && arrVal.stepType === othVal.stepType;
})
: [{ step }];

return stepArray.map((s) => {
const stepType = s.stepType ?? EStepType.ANNOTATION;
const isPre = stepType === EStepType.PRE_ANNOTATION;
const stepInfo = isPre
? { tool: s.tool, step: s.step, config: '{}' }
: getCurrentStepInfo(s.step, stepList);

const result = isCheckTool
? transferedResult.filter((r) => r.step === s.step && r.stepType === stepType)
: transferedResult;

return (
<GraphicMappingView
stepInfo={stepInfo}
result={result}
key={stepInfo?.step + stepInfo?.stepType}
/>
);
});
};

/**
* 映射视图,目前支持 多边形、线条、标点、标签
* @param IMappingViewGraphicProps
*/
const GraphicMappingView = (props: { result: any[]; stepInfo: any }) => {
const { result, stepInfo } = props;
const { tool, config: configStr } = stepInfo || {};
const config = jsonParser(configStr);
const { imgNode, currentPos, zoom, rotate, size } = useContext(BasicOperationContext);

const toolProps = {
imgNode,
currentPos,
zoom,
rotate,
size,
config,
result,
};

if (tool === EToolName.Polygon) {
return <DrawPolygon {...toolProps} isShowBackground={true} />;
}

if (tool === EToolName.Line) {
return <DrawLine {...toolProps} />;
}

if (tool === EToolName.Point) {
return <DrawPoint {...toolProps} point={result} />;
}

if (tool === EToolName.Tag) {
const tags = fillLableAndFindCoordForTags(result, config);
const hasPos = tags.some((i) => i.x || i.y);

return (
<DrawTag
{...toolProps}
tag={tags}
style={{
backgroundColor: hasPos ? 'initial' : '#666fff',
opacity: hasPos ? 1 : 0.6,
}}
/>
);
}

return null;
};

const ImageViewUsedContext = () => {
const context = useContext(BasicOperationContext);
return <DrawImage {...context} />;
};

/** 图片B光标中心点, 在syncMappingView(缩放同步)开启后显示 */
const ImageBCursor = connectComponent(
['imgAttribute'],
({
isAnnotatePage,
imgAttribute,
}: {
isAnnotatePage?: boolean;
imgAttribute: IImageAttribute;
}) => {
const context = useContext(BasicOperationContext);
const { top, left } = useMemo(() => {
/** 中心点对齐 图片size为 12*12 */
return {
top: context.imageACoord.y - 6,
left: context.imageACoord.x - 6,
};
}, [context.imageACoord.x, context.imageACoord.y]);

if (isAnnotatePage && imgAttribute.syncMappingView) {
return <BPoint style={{ top, left, position: 'absolute' }} />;
}

return null;
},
);

export const MappingView = (
props: IMappingViewGraphicProps & { completeResult: any; transferedResult: any },
) => {
const {
transferedResult,
step,
stepList,
completeResult,
basicResult,
isCheckTool,
isAnnotatePage,
} = props;

return (
<>
<ImageViewUsedContext />
<StaticViewWithRelyData
step={step}
stepList={stepList}
completeResult={completeResult}
basicResult={basicResult}
/>
<GraphicMappingViewWrapper
transferedResult={transferedResult}
step={step}
stepList={stepList}
isCheckTool={isCheckTool}
/>
<ImageBCursor isAnnotatePage={isAnnotatePage} />
</>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
* @author lijingchi <[email protected]>
* @file 映射视图左上角Tag组件
* @date 2021-12-15
*/

import React from 'react';
import { EAnnotationMapping } from '@/constant/task';
import { MappingImageType } from '@/types/task';

/**
* 根据mappingType, 获取B图映射描述
* @param mappingType
*/
const getImageBDesc = (mappingType?: EAnnotationMapping) => {
if (mappingType === EAnnotationMapping.OneOne) {
return '(A图映射)';
}

if (mappingType === EAnnotationMapping.Fisheye) {
return '(A图鱼眼映射)';
}

return '';
};

/**
* 映射Tag, 定位在A、B图的左上角
* @param props
*/
export const ImageMappingTag = (props: {
imageType: MappingImageType;
mappingType?: EAnnotationMapping;
}) => {
const { imageType, mappingType } = props;
const text = imageType === 'A' ? 'A图' : `B图,仅预览${getImageBDesc(mappingType)}`;

return (
<div
style={{
background: 'rgba(153, 153, 153, 0.8)',
color: 'white',
position: 'absolute',
top: 0,
left: 0,
padding: '4px 12px',
zIndex: 12,
lineHeight: '20px',
}}
>
{text}
</div>
);
};
Loading
Loading