const assert = require("assert");
|
const { kebabCase } = require("lodash");
|
|
Feature("Images' labels type matching");
|
|
const IMAGE =
|
"https://htx-pub.s3.us-east-1.amazonaws.com/examples/images/nick-owuor-astro-nic-visuals-wDifg5xc9Z4-unsplash.jpg";
|
|
const createConfig = ({ shapes = ["Rectangle"], props } = {}) => {
|
return `<View>
|
<Image name="image" value="$image" zoomControl="false" selectionControl="false"></Image>
|
${shapes
|
.map(
|
(shapeName) => `
|
<${shapeName} name="image${shapeName}" toName="image" ${props} />
|
<${shapeName}Labels name="image${shapeName}Labels" toName="image" allowEmpty="true" ${props}>
|
<Label value="${shapeName}Create"/>
|
<Label value="${shapeName}Append"/>
|
</${shapeName}Labels>
|
`,
|
)
|
.join("\n")}
|
<Labels name="imageLabels" toName="image" allowEmpty="true">
|
<Label value="Label"/>
|
</Labels>
|
</View>`;
|
};
|
|
const createShape = {
|
Rectangle: {
|
byBBox(x, y, width, height, opts = {}) {
|
return {
|
...opts,
|
action: "drawByDrag",
|
params: [x, y, width, height],
|
result: {
|
width,
|
height,
|
rotation: 0,
|
x,
|
y,
|
},
|
};
|
},
|
},
|
Ellipse: {
|
byBBox(x, y, width, height, opts = {}) {
|
return {
|
...opts,
|
action: "drawByDrag",
|
params: [x + width / 2, y + height / 2, width / 2, height / 2],
|
result: { radiusX: width / 2, radiusY: height / 2, rotation: 0, x: x + width / 2, y: y + height / 2 },
|
};
|
},
|
},
|
Polygon: {
|
byBBox(x, y, width, height, opts = {}) {
|
const points = [];
|
|
points.push([x, y]);
|
points.push([x + width, y]);
|
points.push([x + width, y + height]);
|
points.push([x, y + height]);
|
return {
|
...opts,
|
action: "drawByClickingPoints",
|
params: [[...points, points[0]]],
|
result: {
|
points,
|
closed: true,
|
},
|
};
|
},
|
},
|
KeyPoint: {
|
byBBox(x, y, width, height, opts = {}) {
|
return {
|
...opts,
|
action: "drawByClickingPoints",
|
params: [[[x + width / 2, y + height / 2]]],
|
result: {
|
x: x + width / 2,
|
y: y + height / 2,
|
width: 5,
|
},
|
};
|
},
|
},
|
Brush: {
|
byBBox(x, y, width, height, opts = {}) {
|
const points = [];
|
const startPoint = { x: x + 5, y: y + 5 };
|
const endPoint = { x: x + width - 5, y: y + height - 5 };
|
const rows = Math.ceil((endPoint.y - startPoint.y) / 10);
|
const step = (endPoint.y - startPoint.y) / rows;
|
|
for (let j = 0; j < rows; j++) {
|
const cY = startPoint.y + step * j;
|
|
points.push([startPoint.x, cY]);
|
points.push([endPoint.x, cY]);
|
}
|
return {
|
...opts,
|
action: "drawThroughPoints",
|
params: [points],
|
};
|
},
|
},
|
};
|
|
const DataStore = Data(Object.keys(createShape));
|
|
DataStore.Scenario(
|
"Preventing applying labels of mismatch types",
|
async ({ I, LabelStudio, AtImageView, AtOutliner, AtLabels, AtPanels, current }) => {
|
const shape = current;
|
const config = createConfig({
|
shapes: [shape],
|
props: 'strokewidth="5"',
|
});
|
|
const params = {
|
config,
|
data: { image: IMAGE },
|
};
|
const AtDetailsPanel = AtPanels.usePanel(AtPanels.PANEL.DETAILS);
|
|
I.amOnPage("/");
|
LabelStudio.init(params);
|
AtDetailsPanel.collapsePanel();
|
LabelStudio.waitForObjectsReady();
|
AtOutliner.seeRegions(0);
|
const canvasSize = await AtImageView.getCanvasSize();
|
const size = Math.min(canvasSize.width, canvasSize.height);
|
const offset = size * 0.05;
|
const toolSelectors = [
|
(shapeName, shapeIdx) => {
|
I.click(
|
locate(".lsf-toolbar")
|
.find(".lsf-tool")
|
.at(+shapeIdx + 1),
|
);
|
},
|
(_, shapeIdx) => {
|
I.click(AtLabels.locateLabel("blank").at(+shapeIdx + 1));
|
},
|
(shapeName) => {
|
AtLabels.clickLabel(`${shapeName}Create`);
|
},
|
];
|
|
for (const creator of Object.values(createShape[shape])) {
|
const regions = toolSelectors.map((selector, idx) => {
|
const x1 = (size / 3) * idx + offset;
|
const x2 = (size / 3) * (idx + 1) - offset;
|
const y1 = size / 3;
|
const y2 = (size / 3) * 2;
|
|
return creator(x1, y1, x2 - x1, y2 - y1, { shape });
|
});
|
|
const labelsCounter = (results, currentLabelName = "Label") => {
|
return results.reduce((counter, result) => {
|
const { type, value } = result;
|
|
return counter + (type.endsWith("labels") && value[type] && value[type].includes(currentLabelName));
|
}, 0);
|
};
|
|
const toolSelector = `[aria-label=${kebabCase(`${shape}-tool`)}]`;
|
|
LabelStudio.init(params);
|
LabelStudio.waitForObjectsReady();
|
AtOutliner.seeRegions(0);
|
I.click(toolSelector);
|
await AtImageView.lookForStage();
|
I.say(`${shape}: Drawing.`);
|
|
regions.forEach((region, idx) => {
|
toolSelectors[idx](shape, 0);
|
AtImageView[region.action](...region.params);
|
AtOutliner.seeRegions(idx + 1);
|
I.pressKey(["u"]);
|
});
|
|
I.click(toolSelector);
|
I.say(`${shape}: Labeling.`);
|
|
const currentLabelName = `${shape}Append`;
|
|
regions.forEach((region, idx) => {
|
AtOutliner.clickRegion(+idx + 1);
|
AtLabels.clickLabel(currentLabelName);
|
I.pressKey(["u"]);
|
});
|
|
const results1 = await LabelStudio.serialize();
|
|
assert.strictEqual(labelsCounter(results1, currentLabelName), 3, "Labels number don't match");
|
|
regions.forEach((region, idx) => {
|
I.say(`Click label ${idx}`);
|
AtOutliner.clickRegion(+idx + 1);
|
AtLabels.clickLabel("Label");
|
});
|
|
const results = await LabelStudio.serialize();
|
|
assert.strictEqual(labelsCounter(results, "Label"), 3, "Labels number don't match");
|
}
|
},
|
);
|