Skip to content

Commit

Permalink
feat: improve annotations of ROI
Browse files Browse the repository at this point in the history
  • Loading branch information
wadjih-bencheikh18 authored Aug 24, 2023
1 parent babd5ef commit bc800a1
Show file tree
Hide file tree
Showing 7 changed files with 245 additions and 82 deletions.
147 changes: 98 additions & 49 deletions src/components/roi/ROIEditPreference.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { CSSProperties, memo, useCallback, useMemo, useState } from 'react';
import {
Checkbox,
ColorPickerDropdown,
Input,
PanelPreferencesToolbar,
Table,
ValueRenderers,
Expand All @@ -23,6 +24,7 @@ import {
import { SET_EDIT_ROI_PREFERENCE } from '../../state/view/ViewActionTypes';

const PaddedContent = styled.div`
overflow: auto;
padding: 0.5rem;
`;

Expand All @@ -37,23 +39,6 @@ const EditGroup = styled.div`
margin-bottom: 1rem;
`;

const CheckboxGroup = styled.div`
display: flex;
flex-direction: column;
& > * {
}
`;

const AnnotationGroup = styled.div`
display: flex;
flex-direction: row;
margin-bottom: 0.5rem;
& > :first-of-type {
white-space: nowrap;
}
`;

const tableStyle: CSSProperties = {
width: '100%',
};
Expand Down Expand Up @@ -115,7 +100,14 @@ function ROIEditPreference() {
const handleCancel = useMemo(() => close, [close]);

return (
<>
<div
style={{
display: 'flex',
flexDirection: 'column',
height: '100%',
width: '100%',
}}
>
<PanelPreferencesToolbar onClose={handleCancel} onSave={handleSave} />
<PaddedContent>
<EditGroup>
Expand Down Expand Up @@ -144,41 +136,98 @@ function ROIEditPreference() {
</EditGroup>
<EditGroup>
<RoiEditTitle>Annotations</RoiEditTitle>
<CheckboxGroup>
<Table style={tableStyle}>
<Table.Header>
<ValueRenderers.Title value="Kind" />
<ValueRenderers.Title value="Color" />
<ValueRenderers.Title value="Display" />
<ValueRenderers.Title value="Display value" />
<ValueRenderers.Title value="Font size" />
<ValueRenderers.Title value="Font color" />
</Table.Header>
{Object.keys(annotationsPreferences).map((key) => (
<AnnotationGroup key={key}>
<Checkbox
label={startCase(key)}
checked={annotationsPreferences[key].enabled}
onChange={(checked) =>
setAnnotationsPreferences({
...annotationsPreferences,
[key]: {
...annotationsPreferences[key],
enabled: checked as boolean,
},
})
}
/>
<ColorPickerDropdown
disableAlpha
color={{ hex: annotationsPreferences[key].color }}
onChange={(color) =>
setAnnotationsPreferences({
...annotationsPreferences,
[key]: {
...annotationsPreferences[key],
color: color.hex,
},
})
}
/>
</AnnotationGroup>
<Table.Row key={key}>
<ValueRenderers.Text value={startCase(key)} />
<ValueRenderers.Component>
<ColorPickerDropdown
disableAlpha
color={{ hex: annotationsPreferences[key].color }}
onChange={(color) =>
setAnnotationsPreferences({
...annotationsPreferences,
[key]: {
...annotationsPreferences[key],
color: color.hex,
},
})
}
/>
</ValueRenderers.Component>
<ValueRenderers.Component>
<Checkbox
checked={annotationsPreferences[key].enabled}
onChange={(checked) =>
setAnnotationsPreferences({
...annotationsPreferences,
[key]: {
...annotationsPreferences[key],
enabled: checked as boolean,
},
})
}
/>
</ValueRenderers.Component>
<ValueRenderers.Component>
<Checkbox
checked={annotationsPreferences[key].displayValue}
onChange={(checked) =>
setAnnotationsPreferences({
...annotationsPreferences,
[key]: {
...annotationsPreferences[key],
displayValue: checked as boolean,
},
})
}
/>
</ValueRenderers.Component>
<ValueRenderers.Component>
<Input
type="number"
value={annotationsPreferences[key].fontSize}
onChange={(event) => {
const newValue = event.target.valueAsNumber;
setAnnotationsPreferences({
...annotationsPreferences,
[key]: {
...annotationsPreferences[key],
fontSize: newValue,
},
});
}}
/>
</ValueRenderers.Component>
<ValueRenderers.Component>
<ColorPickerDropdown
disableAlpha
color={{ hex: annotationsPreferences[key].fontColor }}
onChange={(color) =>
setAnnotationsPreferences({
...annotationsPreferences,
[key]: {
...annotationsPreferences[key],
fontColor: color.hex,
},
})
}
/>
</ValueRenderers.Component>
</Table.Row>
))}
</CheckboxGroup>
</Table>
</EditGroup>
</PaddedContent>
</>
</div>
);
}

Expand Down
30 changes: 23 additions & 7 deletions src/components/roi/annotation/ConvexHullAnnotation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,8 @@ function ConvexHullAnnotation({ roi }: ConvexHullAnnotationProps) {
);

const preferences = usePreferences();
const color = useMemo(
() => preferences.rois.annotations.convexHull.color,
[preferences.rois.annotations.convexHull.color],
);
const { color, enabled, fontColor, fontSize, displayValue } =
preferences.rois.annotations.convexHull;

const polygonStyle: CSSProperties = useMemo(
() => ({
Expand All @@ -30,10 +28,28 @@ function ConvexHullAnnotation({ roi }: ConvexHullAnnotationProps) {
}),
[color],
);
const textStyle: CSSProperties = useMemo(
() => ({
fill: fontColor,
fontSize,
textAnchor: 'middle',
dominantBaseline: 'text-before-edge',
}),
[fontColor, fontSize],
);

if (!preferences.rois.annotations.convexHull.enabled) return null;

return <polygon points={svgPoints} style={polygonStyle} />;
if (!enabled && !displayValue) return null;

return (
<g>
{enabled && <polygon points={svgPoints} style={polygonStyle} />}
{displayValue && (
<text x={roi.width / 2} y={roi.height + 1} style={textStyle}>
{roi.convexHull.surface}
</text>
)}
</g>
);
}

export default memo(ConvexHullAnnotation);
58 changes: 41 additions & 17 deletions src/components/roi/annotation/FeretAnnotation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,46 +18,70 @@ function FeretAnnotation({ roi }: FeretAnnotationProps) {
{ column: columnA, row: rowA },
{ column: columnB, row: rowB },
],
length,
}) => ({
x1: columnA,
y1: rowA,
x2: columnB,
y2: rowB,
length,
}),
),
[maxDiameter, minDiameter],
);

const preferences = usePreferences();
const color = useMemo(
() => preferences.rois.annotations.feretDiameters.color,
[preferences.rois.annotations.feretDiameters.color],
);
const { color, enabled, fontColor, fontSize, displayValue } =
preferences.rois.annotations.feretDiameters;

const lineStyle: CSSProperties = useMemo(
() => ({
fill: 'none',
stroke: color,
strokewidth: 1,
strokewidth: 2,
}),
[color],
);

if (!preferences.rois.annotations.feretDiameters.enabled) return null;
const textStyle: CSSProperties = useMemo(
() => ({
fill: fontColor,
fontSize,
textAnchor: 'middle',
dominantBaseline: 'central',
}),
[fontColor, fontSize],
);

if (!enabled && !displayValue) return null;

return (
<>
{lines.map(({ x1, y1, x2, y2 }, index) => (
<line
// eslint-disable-next-line react/no-array-index-key
key={`${roi.id}-${index}`}
x1={x1}
y1={y1}
x2={x2}
y2={y2}
style={lineStyle}
/>
))}
{lines.map(({ x1, y1, x2, y2, length }, index) => {
const rotation = Math.atan((y2 - y1) / (x2 - x1)) * (180 / Math.PI);
const x = x2 > x1 ? (x2 + x1 + 2) / 2 : (x2 + x1 - 2) / 2;
const y = y1 > y2 ? (y2 + y1 + 2) / 2 : (y2 + y1 - 2) / 2;
return (
<g
// eslint-disable-next-line react/no-array-index-key
key={`${roi.id}-${index}`}
>
{enabled && (
<line x1={x1} y1={y1} x2={x2} y2={y2} style={lineStyle} />
)}
{displayValue && (
<text
x={0}
y={0}
transform={`translate(${x}, ${y}) rotate(${rotation})`}
style={textStyle}
>
{length.toFixed(2)}
</text>
)}
</g>
);
})}
</>
);
}
Expand Down
30 changes: 22 additions & 8 deletions src/components/roi/annotation/MBRAnnotation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,8 @@ function MBRAnnotation({ roi }: MBRAnnotationProps) {
[roi.mbr.points],
);
const preferences = usePreferences();
const color = useMemo(
() => preferences.rois.annotations.minimalBoundingRectangle.color,
[preferences.rois.annotations.minimalBoundingRectangle.color],
);
const { color, enabled, fontSize, fontColor, displayValue } =
preferences.rois.annotations.minimalBoundingRectangle;

const polygonStyle: CSSProperties = useMemo(
() => ({
Expand All @@ -29,12 +27,28 @@ function MBRAnnotation({ roi }: MBRAnnotationProps) {
}),
[color],
);
const textStyle: CSSProperties = useMemo(
() => ({
fill: fontColor,
fontSize,
textAnchor: 'middle',
dominantBaseline: 'text-after-edge',
}),
[fontColor, fontSize],
);

if (!preferences.rois.annotations.minimalBoundingRectangle.enabled) {
return null;
}
if (!enabled && !displayValue) return null;

return <polygon points={svgPoints} style={polygonStyle} />;
return (
<g>
{enabled && <polygon points={svgPoints} style={polygonStyle} />}
{displayValue && (
<text x={roi.width / 2} y={-1} style={textStyle}>
{roi.width} x {roi.height} ({roi.surface} pixels)
</text>
)}
</g>
);
}

export default memo(MBRAnnotation);
2 changes: 2 additions & 0 deletions src/components/roi/annotation/ROIAnnotation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { memo, useMemo } from 'react';
import ConvexHullAnnotation from './ConvexHullAnnotation';
import FeretAnnotation from './FeretAnnotation';
import MBRAnnotation from './MBRAnnotation';
import SurfaceAnnotation from './SurfaceAnnotation';

interface ROIAnnotationProps {
roi: Roi;
Expand All @@ -15,6 +16,7 @@ function ROIAnnotation({ roi }: ROIAnnotationProps) {

return (
<g transform={transform}>
<SurfaceAnnotation roi={roi} />
<MBRAnnotation roi={roi} />
<FeretAnnotation roi={roi} />
<ConvexHullAnnotation roi={roi} />
Expand Down
Loading

0 comments on commit bc800a1

Please sign in to comment.