Skip to content

Commit 772db6c

Browse files
authoredSep 15, 2020
feat: Merge pull request #93 from UniversalDataTool/pose-estimation
Pose / Keypoint Annotation Interface
2 parents d9e5a65 + f230c82 commit 772db6c

File tree

18 files changed

+435
-18
lines changed

18 files changed

+435
-18
lines changed
 

‎package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@
7676
"babel-loader": "^8.0.5",
7777
"babel-preset-react-app": "^7.0.0",
7878
"gh-pages": "^2.0.1",
79-
"prettier": "^2.0.5",
79+
"prettier": "^2.1.1",
8080
"raw.macro": "^0.3.0",
8181
"react-github-btn": "^1.1.1",
8282
"react-scripts": "^3.4.1"

‎src/Annotator/index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import type {
1010
MainLayoutState,
1111
Action,
1212
} from "../MainLayout/types"
13+
import type { KeypointsDefinition } from "../ImageCanvas/region-tools"
1314
import SettingsProvider from "../SettingsProvider"
1415

1516
import combineReducers from "./reducers/combine-reducers.js"
@@ -41,6 +42,7 @@ type Props = {
4142
videoSrc?: string,
4243
keyframes?: Object,
4344
videoName?: string,
45+
keypointDefinitions: KeypointsDefinition,
4446
fullImageSegmentationMode?: boolean,
4547
autoSegmentationOptions?:
4648
| {| type: "simple" |}
@@ -77,6 +79,7 @@ export const Annotator = ({
7779
onExit,
7880
onNextImage,
7981
onPrevImage,
82+
keypointDefinitions,
8083
autoSegmentationOptions = { type: "autoseg" },
8184
}: Props) => {
8285
if (typeof selectedImage === "string") {
@@ -112,6 +115,7 @@ export const Annotator = ({
112115
enabledTools,
113116
history: [],
114117
videoName,
118+
keypointDefinitions,
115119
...(annotationType === "image"
116120
? {
117121
selectedImage,

‎src/Annotator/index.story.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,7 @@ storiesOf("Annotator", module)
441441
videoSrc="https://s3.amazonaws.com/asset.workaround.online/SampleVideo_1280x720_1mb.mp4"
442442
videoTime={1000}
443443
keyframes={{
444-
"0": {
444+
0: {
445445
regions: [
446446
{
447447
type: "point",
@@ -465,7 +465,7 @@ storiesOf("Annotator", module)
465465
},
466466
],
467467
},
468-
"3333": {
468+
3333: {
469469
regions: [
470470
{
471471
type: "point",

‎src/Annotator/poses.story.js

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// @flow
2+
3+
import React, { useState } from "react"
4+
5+
import { storiesOf } from "@storybook/react"
6+
import { action as actionAddon } from "@storybook/addon-actions"
7+
import dancingManImage from "../ImageCanvas/dancing-man.story.jpg"
8+
import Annotator from "./"
9+
10+
const middlewares = [
11+
(store) => (next) => (action) => {
12+
actionAddon(action.type)(action)
13+
return next(action)
14+
},
15+
]
16+
17+
storiesOf("Annotator (Poses)", module).add("Basic", () => (
18+
<Annotator
19+
onExit={actionAddon("onExit")}
20+
middlewares={middlewares}
21+
labelImages
22+
enabledTools={["create-keypoints"]}
23+
keypointDefinitions={{
24+
human: {
25+
connections: [
26+
["head", "sternum"],
27+
["sternum", "leftElbow"],
28+
["sternum", "rightElbow"],
29+
],
30+
landmarks: {
31+
head: {
32+
label: "Head",
33+
color: "#f00",
34+
defaultPosition: [0, -0.05],
35+
},
36+
sternum: {
37+
label: "Torso",
38+
color: "#0f0",
39+
defaultPosition: [0, 0],
40+
},
41+
leftElbow: {
42+
label: "Left Elbow",
43+
color: "#00f",
44+
defaultPosition: [-0.05, 0],
45+
},
46+
rightElbow: {
47+
label: "Right Elbow",
48+
color: "#00f",
49+
defaultPosition: [0.05, 0],
50+
},
51+
},
52+
},
53+
}}
54+
images={[
55+
{
56+
src: dancingManImage,
57+
name: "Dancing Man",
58+
regions: [
59+
{
60+
type: "keypoints",
61+
id: "keypoints1",
62+
keypointsDefinitionId: "human",
63+
highlighted: true,
64+
points: {
65+
head: { x: 0.54, y: 0.2 },
66+
sternum: { x: 0.57, y: 0.3 },
67+
leftElbow: { x: 0.4, y: 0.39 },
68+
rightElbow: { x: 0.7, y: 0.32 },
69+
},
70+
visible: true,
71+
},
72+
],
73+
},
74+
]}
75+
/>
76+
))

‎src/Annotator/reducers/general-reducer.js

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import colors from "../../colors"
1010
import fixTwisted from "./fix-twisted"
1111
import convertExpandingLineToPolygon from "./convert-expanding-line-to-polygon"
1212
import clamp from "clamp"
13+
import getLandmarksWithTransform from "../../utils/get-landmarks-with-transform"
1314

1415
const getRandomId = () => Math.random().toString().split(".")[1]
1516

@@ -206,6 +207,16 @@ export default (state: MainLayoutState, action: Action) => {
206207
pointIndex,
207208
})
208209
}
210+
case "BEGIN_MOVE_KEYPOINT": {
211+
const { region, keypointId } = action
212+
state = closeEditors(state)
213+
state = saveToHistory(state, "Move Keypoint")
214+
return setIn(state, ["mode"], {
215+
mode: "MOVE_KEYPOINT",
216+
regionId: region.id,
217+
keypointId,
218+
})
219+
}
209220
case "ADD_POLYGON_POINT": {
210221
const { polygon, point, pointIndex } = action
211222
const regionIndex = getRegionIndex(polygon)
@@ -240,6 +251,22 @@ export default (state: MainLayoutState, action: Action) => {
240251
[x, y]
241252
)
242253
}
254+
case "MOVE_KEYPOINT": {
255+
const { keypointId, regionId } = state.mode
256+
const [region, regionIndex] = getRegion(regionId)
257+
if (regionIndex === null) return state
258+
return setIn(
259+
state,
260+
[
261+
...pathToActiveImage,
262+
"regions",
263+
regionIndex,
264+
"points",
265+
keypointId,
266+
],
267+
{ ...(region: any).points[keypointId], x, y }
268+
)
269+
}
243270
case "MOVE_REGION": {
244271
const { regionId } = state.mode
245272
if (regionId === "$$allowed_area") {
@@ -312,6 +339,20 @@ export default (state: MainLayoutState, action: Action) => {
312339
h: dh,
313340
})
314341
}
342+
case "RESIZE_KEYPOINTS": {
343+
const { regionId, landmarks, centerX, centerY } = state.mode
344+
const distFromCenter = Math.sqrt(
345+
(centerX - x) ** 2 + (centerY - y) ** 2
346+
)
347+
const scale = distFromCenter / 0.15
348+
return modifyRegion(regionId, {
349+
points: getLandmarksWithTransform({
350+
landmarks,
351+
center: { x: centerX, y: centerY },
352+
scale,
353+
}),
354+
})
355+
}
315356
case "DRAW_POLYGON": {
316357
const { regionId } = state.mode
317358
const [region, regionIndex] = getRegion(regionId)
@@ -541,6 +582,34 @@ export default (state: MainLayoutState, action: Action) => {
541582
})
542583
break
543584
}
585+
case "create-keypoints": {
586+
state = saveToHistory(state, "Create Keypoints")
587+
const [
588+
[keypointsDefinitionId, { landmarks, connections }],
589+
] = (Object.entries(state.keypointDefinitions): any)
590+
591+
newRegion = {
592+
type: "keypoints",
593+
keypointsDefinitionId,
594+
points: getLandmarksWithTransform({
595+
landmarks,
596+
center: { x, y },
597+
scale: 1,
598+
}),
599+
highlighted: true,
600+
editingLabels: false,
601+
id: getRandomId(),
602+
}
603+
state = setIn(state, ["mode"], {
604+
mode: "RESIZE_KEYPOINTS",
605+
landmarks,
606+
centerX: x,
607+
centerY: y,
608+
regionId: newRegion.id,
609+
isNew: true,
610+
})
611+
break
612+
}
544613
default:
545614
break
546615
}
@@ -581,9 +650,13 @@ export default (state: MainLayoutState, action: Action) => {
581650
}
582651
}
583652
case "MOVE_REGION":
653+
case "RESIZE_KEYPOINTS":
584654
case "MOVE_POLYGON_POINT": {
585655
return { ...state, mode: null }
586656
}
657+
case "MOVE_KEYPOINT": {
658+
return { ...state, mode: null }
659+
}
587660
case "CREATE_POINT_LINE": {
588661
return state
589662
}

‎src/Annotator/video.story.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ storiesOf("Annotator(video)", module).add("Video Annotator", () => {
1111
regionClsList: ["valid", "invalid"],
1212
enabledTools: ["select", "create-box", "create-polygon", "create-point"],
1313
keyframes: {
14-
"0": {
14+
0: {
1515
regions: [
1616
{
1717
id: "910517662556203",
@@ -25,7 +25,7 @@ storiesOf("Annotator(video)", module).add("Video Annotator", () => {
2525
},
2626
],
2727
},
28-
"2656": {
28+
2656: {
2929
regions: [
3030
{
3131
id: "910517662556203",

‎src/ImageCanvas/dancing-man.story.jpg

126 KB
Loading

‎src/ImageCanvas/index.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,14 @@ import React, {
1010
import type { Node } from "react"
1111
import { Matrix } from "transformation-matrix-js"
1212
import Crosshairs from "../Crosshairs"
13-
import type { Region, Point, Polygon, Box } from "./region-tools.js"
13+
import type {
14+
Region,
15+
Point,
16+
Polygon,
17+
Box,
18+
Keypoints,
19+
KeypointsDefinition,
20+
} from "./region-tools.js"
1421
import { makeStyles } from "@material-ui/core/styles"
1522
import styles from "./styles"
1623
import PreventScrollToParents from "../PreventScrollToParents"
@@ -36,6 +43,7 @@ type Props = {
3643
imageSrc?: string,
3744
videoSrc?: string,
3845
videoTime?: number,
46+
keypointDefinitions?: KeypointDefinitions,
3947
onMouseMove?: ({ x: number, y: number }) => any,
4048
onMouseDown?: ({ x: number, y: number }) => any,
4149
onMouseUp?: ({ x: number, y: number }) => any,
@@ -65,6 +73,7 @@ type Props = {
6573
onDeleteRegion: (Region) => any,
6674
onBeginBoxTransform: (Box, [number, number]) => any,
6775
onBeginMovePolygonPoint: (Polygon, index: number) => any,
76+
onBeginMoveKeypoint: (Keypoints, index: number) => any,
6877
onAddPolygonPoint: (Polygon, point: [number, number], index: number) => any,
6978
onSelectRegion: (Region) => any,
7079
onBeginMovePoint: (Point) => any,
@@ -120,6 +129,7 @@ export const ImageCanvas = ({
120129
onBeginBoxTransform,
121130
onBeginMovePolygonPoint,
122131
onAddPolygonPoint,
132+
onBeginMoveKeypoint,
123133
onSelectRegion,
124134
onBeginMovePoint,
125135
onDeleteRegion,
@@ -128,6 +138,7 @@ export const ImageCanvas = ({
128138
onRegionClassAdded,
129139
zoomOnAllowedArea = true,
130140
modifyingAllowedArea = false,
141+
keypointDefinitions,
131142
}: Props) => {
132143
const classes = useStyles()
133144

@@ -356,6 +367,7 @@ export const ImageCanvas = ({
356367
mat={mat}
357368
onBeginBoxTransform={onBeginBoxTransform}
358369
onBeginMovePolygonPoint={onBeginMovePolygonPoint}
370+
onBeginMoveKeypoint={onBeginMoveKeypoint}
359371
onAddPolygonPoint={onAddPolygonPoint}
360372
showHighlightBox={showHighlightBox}
361373
/>
@@ -440,6 +452,7 @@ export const ImageCanvas = ({
440452
/>
441453
<RegionShapes
442454
mat={mat}
455+
keypointDefinitions={keypointDefinitions}
443456
imagePosition={imagePosition}
444457
regions={regions}
445458
fullSegmentationMode={fullImageSegmentationMode}

0 commit comments

Comments
 (0)