From bfd3d6bb58a6e329dc5da3da533bd5125d2e1304 Mon Sep 17 00:00:00 2001 From: seveibar Date: Mon, 27 Jul 2020 12:01:21 -0400 Subject: [PATCH 1/3] improved pixel segmentation with web workers and configurable quality --- package.json | 2 +- .../ConfigureImagePixelSegmentation/index.js | 62 +++++++++++++++---- src/components/ConfigureInterface/index.js | 30 ++++++--- yarn.lock | 14 +++-- 4 files changed, 81 insertions(+), 27 deletions(-) diff --git a/package.json b/package.json index 72a77947..0bbbff1e 100644 --- a/package.json +++ b/package.json @@ -106,7 +106,7 @@ "react-hotkeys": "^2.0.0", "react-i18next": "^11.4.0", "react-icons": "^3.9.0", - "react-image-annotate": "^1.2.7", + "react-image-annotate": "^1.3.0", "react-material-workspace-layout": "^0.1.6", "react-scripts": "^3.4.1", "react-select": "^3.0.8", diff --git a/src/components/ConfigureImagePixelSegmentation/index.js b/src/components/ConfigureImagePixelSegmentation/index.js index 7179ae38..455ff29c 100644 --- a/src/components/ConfigureImagePixelSegmentation/index.js +++ b/src/components/ConfigureImagePixelSegmentation/index.js @@ -8,6 +8,19 @@ const autoSegmentationOptions = { autoseg: { type: "autoseg" }, } +const maxClusterPresets = { + low: 1000, + medium: 8000, + high: 64000, +} +const maxClusterPresetsRev = Object.entries(maxClusterPresets).reduce( + (acc, curr) => { + acc[curr[1]] = curr[0] + return acc + }, + {} +) + const form = { questions: [ { @@ -32,11 +45,28 @@ const form = { type: "text", }, { - name: "autoseg", + name: "autosegMode", type: "dropdown", title: "Automatic Segmentation Engine", choices: ["simple", "autoseg"], }, + { + name: "autosegPreset", + type: "dropdown", + visibleIf: "{autosegMode}='autoseg'", + title: "Super Pixel Quality", + choices: ["low", "medium", "high", "custom"], + }, + { + name: "autosegMaxClusters", + type: "slider", + visibleIf: "{autosegPreset}='custom'", + title: "Total Super Pixels", + min: 10, + max: 100000, + step: 10, + defaultValue: 1000, + }, ], } @@ -48,7 +78,12 @@ export default ({ iface, onChange }) => { (iface.labels || []).map((a) => typeof a === "string" ? { id: a, description: a } : a ) || [], - autoseg: iface.autoSegmentationEngine?.type, + autosegMode: iface.autoSegmentationEngine?.mode, + autosegPreset: + maxClusterPresetsRev[ + iface.autoSegmentationEngine?.maxClusters || 1000 + ] || "custom", + autosegMaxClusters: iface.autoSegmentationEngine?.maxClusters || 1000, }), [iface] ) @@ -59,17 +94,18 @@ export default ({ iface, onChange }) => { variant="flat" defaultAnswers={defaultAnswers} onQuestionChange={(questionId, newValue, answers) => { - if (questionId === "autoseg") { - onChange( - setIn( - iface, - ["autoSegmentationEngine"], - autoSegmentationOptions[newValue] - ) - ) - } else { - onChange(setIn(iface, [questionId], newValue)) - } + onChange({ + ...iface, + description: answers.description, + labels: answers.labels, + autoSegmentationEngine: { + mode: answers.autosegMode, + maxClusters: + answers.autosegPreset === "custom" + ? answers.autosegMaxClusters + : maxClusterPresets[answers.autosegPreset], + }, + }) }} form={form} /> diff --git a/src/components/ConfigureInterface/index.js b/src/components/ConfigureInterface/index.js index bde52a69..34d17f3b 100644 --- a/src/components/ConfigureInterface/index.js +++ b/src/components/ConfigureInterface/index.js @@ -1,6 +1,6 @@ // @flow weak -import React, { useState, useEffect } from "react" +import React, { useState, useEffect, useReducer } from "react" import { styled } from "@material-ui/core/styles" import templates, { templateMap } from "../StartingPage/templates" import Button from "@material-ui/core/Button" @@ -134,6 +134,16 @@ export const ConfigureInterface = ({ const iface = dataset.interface const [previewChangedTime, changePreviewChangedTime] = useState(0) const [previewLoading, changePreviewLoading] = useState(false) + const [previewVersion, incPreviewVersion] = useReducer( + (state) => state + 1, + 0 + ) + const [previewDataset, setPreviewDataset] = useState({ + interface: iface, + samples: dataset?.samples?.length + ? [dataset.samples[0]] + : [templateMap[iface.type].dataset.samples[0]], + }) const onChange = useEventCallback((...args) => { changePreviewChangedTime(Date.now()) onChangeProp(...args) @@ -143,6 +153,13 @@ export const ConfigureInterface = ({ changePreviewLoading(true) let timeout = setTimeout(() => { changePreviewLoading(false) + incPreviewVersion() + setPreviewDataset({ + interface: iface, + samples: dataset?.samples?.length + ? [dataset.samples[0]] + : [templateMap[iface.type].dataset.samples[0]], + }) }, 1000) return () => { clearTimeout(timeout) @@ -192,18 +209,13 @@ export const ConfigureInterface = ({ - + diff --git a/yarn.lock b/yarn.lock index e2d2ffa2..be2d9d85 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4943,6 +4943,11 @@ autoprefixer@^9.6.1, autoprefixer@^9.7.2: postcss "^7.0.32" postcss-value-parser "^4.1.0" +autoseg@^0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/autoseg/-/autoseg-0.0.8.tgz#30e900afd41db964c5cdaf93f322211548444620" + integrity sha512-Kf6qQXiaxe+J1DrNP4dfWH92tRZ9MMwaO06TtzfKxBR/wtlC745aTP3YmKAP/a2ikpIfPKz9Hf6yR2Y7SeVagg== + ava@^3.7.0: version "3.10.1" resolved "https://registry.yarnpkg.com/ava/-/ava-3.10.1.tgz#a4e68b1a2bb248fa0d96529d23dd83f57082e944" @@ -16143,10 +16148,10 @@ react-icons@^3.9.0: dependencies: camelcase "^5.0.0" -react-image-annotate@^1.2.7: - version "1.2.7" - resolved "https://registry.yarnpkg.com/react-image-annotate/-/react-image-annotate-1.2.7.tgz#e9f050640d8a55474b3b16f8fe9ea98fe324d4e0" - integrity sha512-JZGsaTG6AET0IFGZ408/uzWYDtT71SUpG1ghUN+xzXzmP9MZV+oWyET4i7sXBqZA/5hcWghzQrG1TWp0FAjvaw== +react-image-annotate@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/react-image-annotate/-/react-image-annotate-1.3.0.tgz#f8e03e7ceb98b8dbb5d0c74e3163a503dab2c99f" + integrity sha512-WRH4yVmYOjbdHxh4O4Q/NR5IMZYgZOjd0gn6fk2W77qnM0TbUMHQbSCc48CzNvIZSCf+JLnLZ3DTYi+i8eVEZA== dependencies: "@fortawesome/fontawesome-svg-core" "^1.2.12" "@fortawesome/free-solid-svg-icons" "^5.6.3" @@ -16154,6 +16159,7 @@ react-image-annotate@^1.2.7: "@material-ui/core" "^4.6.0" "@material-ui/icons" "^4.9.1" "@semantic-release/git" "^9.0.0" + autoseg "^0.0.8" color-alpha "^1.0.4" get-image-data "^3.0.1" material-survey "^1.0.34" From 4e686ec4b94910988e0d5f8b3f34a38028fc038b Mon Sep 17 00:00:00 2001 From: seveibar Date: Mon, 27 Jul 2020 12:22:33 -0400 Subject: [PATCH 2/3] fix lint errors --- src/components/ConfigureImagePixelSegmentation/index.js | 6 ------ src/components/ConfigureInterface/index.js | 1 + 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/components/ConfigureImagePixelSegmentation/index.js b/src/components/ConfigureImagePixelSegmentation/index.js index 455ff29c..f87cb04e 100644 --- a/src/components/ConfigureImagePixelSegmentation/index.js +++ b/src/components/ConfigureImagePixelSegmentation/index.js @@ -1,12 +1,6 @@ // @flow import React, { useMemo } from "react" import Survey from "material-survey/components/Survey" -import { setIn } from "seamless-immutable" - -const autoSegmentationOptions = { - simple: { type: "simple" }, - autoseg: { type: "autoseg" }, -} const maxClusterPresets = { low: 1000, diff --git a/src/components/ConfigureInterface/index.js b/src/components/ConfigureInterface/index.js index 34d17f3b..a41819d0 100644 --- a/src/components/ConfigureInterface/index.js +++ b/src/components/ConfigureInterface/index.js @@ -164,6 +164,7 @@ export const ConfigureInterface = ({ return () => { clearTimeout(timeout) } + // eslint-disable-next-line }, [previewChangedTime]) if (!iface.type || iface.type === "empty") { From d41b4c8f68aee7fd14559fc341e411d8ef1049c7 Mon Sep 17 00:00:00 2001 From: seveibar Date: Mon, 27 Jul 2020 13:23:50 -0400 Subject: [PATCH 3/3] update RIA, fix CORs issue --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 0bbbff1e..f1b04752 100644 --- a/package.json +++ b/package.json @@ -106,7 +106,7 @@ "react-hotkeys": "^2.0.0", "react-i18next": "^11.4.0", "react-icons": "^3.9.0", - "react-image-annotate": "^1.3.0", + "react-image-annotate": "^1.3.1", "react-material-workspace-layout": "^0.1.6", "react-scripts": "^3.4.1", "react-select": "^3.0.8", diff --git a/yarn.lock b/yarn.lock index be2d9d85..9584b4ab 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16148,10 +16148,10 @@ react-icons@^3.9.0: dependencies: camelcase "^5.0.0" -react-image-annotate@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/react-image-annotate/-/react-image-annotate-1.3.0.tgz#f8e03e7ceb98b8dbb5d0c74e3163a503dab2c99f" - integrity sha512-WRH4yVmYOjbdHxh4O4Q/NR5IMZYgZOjd0gn6fk2W77qnM0TbUMHQbSCc48CzNvIZSCf+JLnLZ3DTYi+i8eVEZA== +react-image-annotate@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/react-image-annotate/-/react-image-annotate-1.3.1.tgz#721353966c7a25a7c7d832262a50f9488ab78808" + integrity sha512-d3sErEQPmSIjq1ib89PEnIJa6T7eTgpen/fVHBFEJ9e5QyFAF6LQpnAS6s8jZ/wXtBLYTwstavYe2yNmY8kyPw== dependencies: "@fortawesome/fontawesome-svg-core" "^1.2.12" "@fortawesome/free-solid-svg-icons" "^5.6.3"