Skip to content

Commit

Permalink
Merge pull request #9164 from cvat-ai/release-2.31.0
Browse files Browse the repository at this point in the history
Release v2.31.0
  • Loading branch information
cvat-bot[bot] authored Mar 3, 2025
2 parents 552bd53 + d3c7766 commit 140301a
Show file tree
Hide file tree
Showing 231 changed files with 16,216 additions and 3,905 deletions.
8 changes: 1 addition & 7 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
# Project Specific
/data/
/models/
/events/
/share/
/static/
/db.sqlite3
/keys
/logs
/profiles
/ssh/*
!/ssh/README.md
/Mask_RCNN/
/letsencrypt-webroot/

# Ignore temporary files
docker-compose.override.yml
Expand Down Expand Up @@ -63,8 +59,6 @@ cvat-canvas/dist
cvat-canvas3d/dist
cvat-ui/dist

# produced by npm run docs in cvat-core
cvat-core/docs
# produced by prepare in the root package.json script
.husky

Expand Down
43 changes: 43 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,26 @@
],
"justMyCode": false,
},
{
"name": "REST API tests: Attach to RQ consensus worker",
"type": "debugpy",
"request": "attach",
"connect": {
"host": "127.0.0.1",
"port": 9096
},
"pathMappings": [
{
"localRoot": "${workspaceFolder}",
"remoteRoot": "/home/django/"
},
{
"localRoot": "${workspaceFolder}/.env",
"remoteRoot": "/opt/venv",
}
],
"justMyCode": false,
},
{
"type": "pwa-chrome",
"request": "launch",
Expand Down Expand Up @@ -383,6 +403,28 @@
},
"console": "internalConsole"
},
{
"name": "server: RQ - consensus",
"type": "debugpy",
"request": "launch",
"stopOnEntry": false,
"justMyCode": false,
"python": "${command:python.interpreterPath}",
"program": "${workspaceRoot}/manage.py",
"args": [
"rqworker",
"consensus",
"--worker-class",
"cvat.rqworker.SimpleWorker"
],
"django": true,
"cwd": "${workspaceFolder}",
"env": {
"DJANGO_LOG_SERVER_HOST": "localhost",
"DJANGO_LOG_SERVER_PORT": "8282"
},
"console": "internalConsole"
},
{
"name": "server: migrate",
"type": "debugpy",
Expand Down Expand Up @@ -566,6 +608,7 @@
"server: RQ - analytics reports",
"server: RQ - cleaning",
"server: RQ - chunks",
"server: RQ - consensus",
]
}
]
Expand Down
51 changes: 51 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,57 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

<!-- scriv-insert-here -->

<a id='changelog-2.31.0'></a>
## \[2.31.0\] - 2025-03-03

### Added

- \[SDK\] Auto-annotation detection functions can now output shape/keypoint attributes
(<https://github.com/cvat-ai/cvat/pull/9090>)

- \[SDK\] Added a utility module for working with label attributes,
`cvat_sdk.attributes`
(<https://github.com/cvat-ai/cvat/pull/9090>)

- Simple merging for consensus-enabled tasks
(<https://github.com/cvat-ai/cvat/pull/8953>)

- A setting to display rectangles and ellipses dimensions and rotation
(<https://github.com/cvat-ai/cvat/pull/9142>)

### Changed

- Hidden points in skeletons now also contribute to the skeleton similarity
in quality computations and in consensus merging
(<https://github.com/cvat-ai/cvat/pull/8953>)

- SDK `task.upload_data()` can accept resources of the `Path` type
when `resource_type` is `REMOTE` or `SHARE`
(<https://github.com/cvat-ai/cvat/pull/9114>)

### Deprecated

- Utilizing `PUT /api/tasks|jobs/id/annotations?rq_id=rq_id` API endpoint
to check the status of the import process
(<https://github.com/cvat-ai/cvat/pull/9102>)

### Fixed

- 500 status code returned by API endpoints that support TUS OPTIONS requests
(<https://github.com/cvat-ai/cvat/pull/9077>)

- Possible race condition that could occur when importing annotations
(<https://github.com/cvat-ai/cvat/pull/9102>)

- Issue label scaling on image filter application
(<https://github.com/cvat-ai/cvat/pull/9126>)

- Invalid display of images in simple GT jobs
(<https://github.com/cvat-ai/cvat/pull/9155>)

- Related images in a simple GT jobs are displayed incorrectly
(<https://github.com/cvat-ai/cvat/pull/9162>)

<a id='changelog-2.30.0'></a>
## \[2.30.0\] - 2025-02-14

Expand Down
3 changes: 1 addition & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ RUN --mount=type=cache,target=/root/.cache/pip/http-v2 \
-r /tmp/cvat/requirements/${CVAT_CONFIGURATION}.txt \
-w /tmp/wheelhouse

FROM golang:1.23.0 AS build-smokescreen
FROM golang:1.24.0 AS build-smokescreen

RUN git clone --filter=blob:none --no-checkout https://github.com/stripe/smokescreen.git
RUN cd smokescreen && git checkout eb1ac09 && go build -o /tmp/smokescreen
Expand Down Expand Up @@ -192,7 +192,6 @@ RUN python -m pip uninstall -y pip

# Install and initialize CVAT, copy all necessary files
COPY cvat/nginx.conf /etc/nginx/nginx.conf
COPY --chown=${USER} components /tmp/components
COPY --chown=${USER} supervisord/ ${HOME}/supervisord
COPY --chown=${USER} manage.py backend_entrypoint.sh wait_for_deps.sh ${HOME}/
COPY --chown=${USER} utils/ ${HOME}/utils
Expand Down
18 changes: 0 additions & 18 deletions Dockerfile.ci
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,9 @@ USER root

RUN apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get --no-install-recommends install -yq \
gpg-agent \
gnupg2 \
apt-utils \
build-essential \
python3-dev \
ruby \
&& \
curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \
echo 'deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main' | tee /etc/apt/sources.list.d/google-chrome.list && \
curl https://deb.nodesource.com/setup_20.x | bash - && \
DEBIAN_FRONTEND=noninteractive apt-get --no-install-recommends install -yq \
google-chrome-stable \
nodejs \
&& \
npm install --global yarn && \
rm -rf /var/lib/apt/lists/*;

COPY cvat/requirements/ /tmp/cvat/requirements/
Expand All @@ -28,12 +16,6 @@ COPY utils/dataset_manifest/requirements.txt /tmp/utils/dataset_manifest/require
RUN python3 -m ensurepip
RUN DATUMARO_HEADLESS=1 python3 -m pip install --no-cache-dir -r /tmp/cvat/requirements/testing.txt

COPY cvat-core ${HOME}/cvat-core
COPY cvat-data ${HOME}/cvat-data
COPY package.json ${HOME}/
COPY yarn.lock ${HOME}/
COPY tests ${HOME}/tests

COPY .coveragerc .

ENTRYPOINT []
2 changes: 1 addition & 1 deletion Dockerfile.ui
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ DISABLE_SOURCE_MAPS="${DISABLE_SOURCE_MAPS}" \
UI_APP_CONFIG="${UI_APP_CONFIG}" \
SOURCE_MAPS_TOKEN="${SOURCE_MAPS_TOKEN}" yarn run build:cvat-ui

FROM nginx:1.26.1-alpine3.19-slim
FROM nginx:1.27.4-alpine3.21-slim

# Replace default.conf configuration to remove unnecessary rules
COPY cvat-ui/react_nginx.conf /etc/nginx/conf.d/default.conf
Expand Down
7 changes: 5 additions & 2 deletions cvat-canvas/src/scss/canvas.scss
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,15 @@ polyline.cvat_shape_drawing_opacity {
font-weight: bold;
fill: white;
cursor: default;
font-family: Calibri, Candara, Segoe, 'Segoe UI', Optima, Arial, sans-serif;
text-shadow: 0 0 4px black;
filter: drop-shadow(1px 1px 1px black) drop-shadow(-1px -1px 1px black);
user-select: none;
pointer-events: none;
}

.cvat_canvas_text_dimensions {
fill: lightskyblue;
}

.cvat_canvas_text_description {
fill: yellow;
font-style: oblique 40deg;
Expand Down
24 changes: 16 additions & 8 deletions cvat-canvas/src/typescript/canvasModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -457,18 +457,18 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {

const { angle } = this.data;

const mutiplier = Math.sin((angle * Math.PI) / 180) + Math.cos((angle * Math.PI) / 180);
const multiplier = Math.sin((angle * Math.PI) / 180) + Math.cos((angle * Math.PI) / 180);
if ((angle / 90) % 2) {
// 90, 270, ..
const topMultiplier = (x - this.data.imageSize.width / 2) * (oldScale / this.data.scale - 1);
const leftMultiplier = (y - this.data.imageSize.height / 2) * (oldScale / this.data.scale - 1);
this.data.top += mutiplier * topMultiplier * this.data.scale;
this.data.left -= mutiplier * leftMultiplier * this.data.scale;
this.data.top += multiplier * topMultiplier * this.data.scale;
this.data.left -= multiplier * leftMultiplier * this.data.scale;
} else {
const leftMultiplier = (x - this.data.imageSize.width / 2) * (oldScale / this.data.scale - 1);
const topMultiplier = (y - this.data.imageSize.height / 2) * (oldScale / this.data.scale - 1);
this.data.left += mutiplier * leftMultiplier * this.data.scale;
this.data.top += mutiplier * topMultiplier * this.data.scale;
this.data.left += multiplier * leftMultiplier * this.data.scale;
this.data.top += multiplier * topMultiplier * this.data.scale;
}

this.notify(UpdateReasons.IMAGE_ZOOMED);
Expand Down Expand Up @@ -590,7 +590,7 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {
};

this.data.image = data;
this.fit();
this.resetScale();

// restore correct image position after switching to a new frame
// if corresponding option is disabled
Expand Down Expand Up @@ -684,7 +684,7 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {
this.notify(UpdateReasons.SHAPE_FOCUSED);
}

public fit(): void {
private resetScale(): boolean {
const { angle } = this.data;

let updatedScale = this.data.scale;
Expand Down Expand Up @@ -713,6 +713,14 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {
// scale is changed during zooming or translating
// so, remember fitted scale to compute fit-relative scaling
this.data.fittedScale = this.data.scale;
return true;
}

return false;
}

public fit(): void {
if (this.resetScale()) {
this.notify(UpdateReasons.IMAGE_FITTED);
}
}
Expand Down Expand Up @@ -939,7 +947,7 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {

if (typeof configuration.textContent === 'string') {
const splitted = configuration.textContent.split(',').filter((entry: string) => !!entry);
if (splitted.every((entry: string) => ['id', 'label', 'attributes', 'source', 'descriptions'].includes(entry))) {
if (splitted.every((entry: string) => ['id', 'label', 'attributes', 'source', 'descriptions', 'dimensions'].includes(entry))) {
this.data.configuration.textContent = configuration.textContent;
}
}
Expand Down
47 changes: 36 additions & 11 deletions cvat-canvas/src/typescript/canvasView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
vectorLength, ShapeSizeElement, DrawnState, rotate2DPoints,
readPointsFromShape, setupSkeletonEdges, makeSVGFromTemplate,
imageDataToDataURL, expandChannels, stringifyPoints, zipChannels,
composeShapeDimensions,
} from './shared';
import {
CanvasModel, Geometry, UpdateReasons, FrameZoom, ActiveElement,
Expand Down Expand Up @@ -2444,10 +2445,10 @@ export class CanvasViewImpl implements CanvasView, Listener {
shape.untransform();
}

if (
state.points.length !== drawnState.points.length ||
state.points.some((p: number, id: number): boolean => p !== drawnState.points[id])
) {
const pointsUpdated = state.points.length !== drawnState.points.length ||
state.points.some((p: number, id: number): boolean => p !== drawnState.points[id]);

if (pointsUpdated) {
if (state.shapeType === 'mask') {
// if masks points were updated, draw from scratch
this.deleteObjects([this.drawnStates[+clientID]]);
Expand Down Expand Up @@ -2493,9 +2494,12 @@ export class CanvasViewImpl implements CanvasView, Listener {

const stateDescriptions = state.descriptions;
const drawnStateDescriptions = drawnState.descriptions;
const rotationUpdated = drawnState.rotation !== state.rotation;

if (
drawnState.label.id !== state.label.id ||
pointsUpdated ||
rotationUpdated ||
drawnStateDescriptions.length !== stateDescriptions.length ||
drawnStateDescriptions.some((desc: string, id: number): boolean => desc !== stateDescriptions[id])
) {
Expand Down Expand Up @@ -3090,6 +3094,7 @@ export class CanvasViewImpl implements CanvasView, Listener {
const withLabel = content.includes('label');
const withSource = content.includes('source');
const withDescriptions = content.includes('descriptions');
const withDimensions = content.includes('dimensions');
const textFontSize = this.configuration.textFontSize || 12;
const {
label, clientID, attributes, source, descriptions,
Expand All @@ -3116,30 +3121,50 @@ export class CanvasViewImpl implements CanvasView, Listener {
`${withSource ? `(${source})` : ''}`).style({
'text-transform': 'uppercase',
});

if (withDimensions && ['rectangle', 'ellipse'].includes(state.shapeType)) {
let width = state.points[2] - state.points[0];
let height = state.points[3] - state.points[1];

if (state.shapeType === 'ellipse') {
width *= 2;
height *= -2;
}

block
.tspan(composeShapeDimensions(width, height, state.rotation))
.attr({
dy: '1.25em',
x: 0,
})
.addClass('cvat_canvas_text_dimensions');
}
if (withDescriptions) {
for (const desc of descriptions) {
descriptions.forEach((desc: string, idx: number) => {
block
.tspan(`${desc}`)
.attr({
dy: '1em',
dy: idx === 0 ? '1.25em' : '1em',
x: 0,
})
.addClass('cvat_canvas_text_description');
}
});
}
if (withAttr) {
for (const attrID of Object.keys(attributes)) {
const values = `${attributes[attrID] === undefinedAttrValue ? '' : attributes[attrID]}`.split('\n');
Object.keys(attributes).forEach((attrID: string, idx: number) => {
const values = `${attributes[attrID] === undefinedAttrValue ?
'' : attributes[attrID]}`.split('\n');
const parent = block.tspan(`${attrNames[attrID]}: `)
.attr({ attrID, dy: '1em', x: 0 }).addClass('cvat_canvas_text_attribute');
.attr({ attrID, dy: idx === 0 ? '1.25em' : '1em', x: 0 })
.addClass('cvat_canvas_text_attribute');
values.forEach((attrLine: string, index: number) => {
parent
.tspan(attrLine)
.attr({
dy: index === 0 ? 0 : '1em',
});
});
}
});
}
})
.move(0, 0)
Expand Down
Loading

0 comments on commit 140301a

Please sign in to comment.