Skip to content

Commit

Permalink
Merge pull request #7005 from opencv/release-2.7.6
Browse files Browse the repository at this point in the history
Release v2.7.6
  • Loading branch information
nmanovic authored Oct 16, 2023
2 parents 7956a18 + 3c05e84 commit 56f527a
Show file tree
Hide file tree
Showing 65 changed files with 632 additions and 248 deletions.
4 changes: 4 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,7 @@ end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.{yml,yaml}]

indent_size = 2
59 changes: 59 additions & 0 deletions .github/workflows/prepare-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
name: Prepare release
on:
workflow_dispatch:
inputs:
newVersion:
description: "Version number for the new release"
required: true
default: X.Y.Z
jobs:
main:
runs-on: ubuntu-latest
steps:
- name: Validate version number
env:
NEW_VERSION: "${{ inputs.newVersion }}"
run: |
if ! [[ "$NEW_VERSION" =~ [0-9]+\.[0-9]+\.[0-9]+ ]]; then
echo "Invalid version number"
exit 1
fi
- uses: actions/checkout@v4

- name: Verify that the release is new
run: |
if git ls-remote --exit-code origin refs/tags/v${{ inputs.newVersion }} > /dev/null; then
echo "Release v${{ inputs.newVersion }} already exists"
exit 1
fi
- name: Create release branch
run:
git checkout -b "release-${{ inputs.newVersion }}"

- name: Collect changelog
run:
pipx run scriv collect --version="${{ inputs.newVersion }}"

- name: Set the new version
run:
./dev/update_version.py --set="${{ inputs.newVersion }}"

- name: Commit release preparation changes
run: |
git -c user.name='github-actions[bot]' -c user.email='github-actions[bot]@users.noreply.github.com' \
commit -a -m "Prepare release v${{ inputs.newVersion }}"
- name: Push release branch
run:
git push -u origin "release-${{ inputs.newVersion }}"

- name: Create release pull request
env:
GH_TOKEN: "${{ github.token }}"
run: |
gh pr create \
--base=master \
--title="Release v${{ inputs.newVersion }}" \
--body="$(awk '/^## / { hn += 1; next } hn == 1 && !/^</' CHANGELOG.md)"
58 changes: 58 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,64 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

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

<a id='changelog-2.7.6'></a>
## \[2.7.6\] - 2023-10-13

### Changed

- Enabled nginx proxy buffering
(<https://github.com/opencv/cvat/pull/6991>)

- Helm: set memory request for keydb
(<https://github.com/opencv/cvat/pull/6945>)

- Supervisord (<https://github.com/opencv/cvat/pull/6945>):
- added `autorestart=true` option for all workers
- unified program names to use dashes as delimiter instead of mixed '_' and '-'
- minor improvements to supervisor configurations

### Removed

- Removed gitter link from about modal
(<https://github.com/opencv/cvat/pull/7002>)

### Fixed

- Persist image filters across jobs
(<https://github.com/opencv/cvat/pull/6953>)

- Splitting skeleton tracks on jobs
(<https://github.com/opencv/cvat/pull/6968>)

- Uploading skeleton tracks in COCO Keypoints format
(<https://github.com/opencv/cvat/pull/6969>)

- Fixed Siammask tracker error on grayscale images
(<https://github.com/opencv/cvat/pull/6982>)

- Fixed memory leak on client side when event listener was not removed together with its context
(<https://github.com/opencv/cvat/pull/6984>)

- Fixed crash related to issue tries to mount to not existing parent
(<https://github.com/opencv/cvat/pull/6977>)

- Added 'notranslate' markers to avoid issues caused by extension translators
(<https://github.com/opencv/cvat/pull/6993>)

- Getting CS content when S3 bucket contains manually created directories
(<https://github.com/opencv/cvat/pull/6997>)

- Optimized huge memory consumption when working with masks in the interface
(<https://github.com/opencv/cvat/pull/6996>)

### Security

- Security upgrade opencv-python-headless from 4.5.5.62 to 4.8.1.78
(<https://github.com/opencv/cvat/pull/6931>)

- Added X-Frame-Options: deny
(<https://github.com/opencv/cvat/pull/6992>)

<a id='changelog-2.7.5'></a>
## \[2.7.5\] - 2023-10-09

Expand Down
2 changes: 1 addition & 1 deletion cvat-canvas/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cvat-canvas",
"version": "2.17.6",
"version": "2.18.0",
"description": "Part of Computer Vision Annotation Tool which presents its canvas library",
"main": "src/canvas.ts",
"scripts": {
Expand Down
4 changes: 2 additions & 2 deletions cvat-canvas/src/typescript/canvasView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1796,7 +1796,7 @@ export class CanvasViewImpl implements CanvasView, Listener {
if (state.shapeType === 'mask') {
const { points } = state;
const [left, top, right, bottom] = points.slice(-4);
const imageBitmap = expandChannels(255, 255, 255, points, 4);
const imageBitmap = expandChannels(255, 255, 255, points);
imageDataToDataURL(imageBitmap, right - left + 1, bottom - top + 1,
(dataURL: string) => new Promise((resolve) => {
const img = document.createElement('img');
Expand Down Expand Up @@ -2893,7 +2893,7 @@ export class CanvasViewImpl implements CanvasView, Listener {
const colorization = this.getShapeColorization(state);
const color = fabric.Color.fromHex(colorization.fill).getSource();
const [left, top, right, bottom] = points.slice(-4);
const imageBitmap = expandChannels(color[0], color[1], color[2], points, 4);
const imageBitmap = expandChannels(color[0], color[1], color[2], points);

const image = this.adoptedContent.image().attr({
clientID: state.clientID,
Expand Down
2 changes: 1 addition & 1 deletion cvat-canvas/src/typescript/groupHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ export class GroupHandlerImpl implements GroupHandler {
const { points } = objectState;
const colorRGB = [139, 0, 139];
const [left, top, right, bottom] = points.slice(-4);
const imageBitmap = expandChannels(colorRGB[0], colorRGB[1], colorRGB[2], points, 4);
const imageBitmap = expandChannels(colorRGB[0], colorRGB[1], colorRGB[2], points);

const bbox = shape.bbox();
const image = this.canvas.image().attr({
Expand Down
2 changes: 1 addition & 1 deletion cvat-canvas/src/typescript/interactionHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ export class InteractionHandlerImpl implements InteractionHandler {
this.selectize(true, this.drawnIntermediateShape, erroredShape);
} else if (shapeType === 'mask') {
const [left, top, right, bottom] = points.slice(-4);
const imageBitmap = expandChannels(255, 255, 255, points, 4);
const imageBitmap = expandChannels(255, 255, 255, points);

const image = this.canvas.image().attr({
'color-rendering': 'optimizeQuality',
Expand Down
37 changes: 19 additions & 18 deletions cvat-canvas/src/typescript/masksHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
import consts from './consts';
import { DrawHandler } from './drawHandler';
import {
PropType, computeWrappingBox, alphaChannelOnly, expandChannels, imageDataToDataURL,
PropType, computeWrappingBox, zipChannels, expandChannels, imageDataToDataURL,
} from './shared';

interface WrappingBBox {
Expand Down Expand Up @@ -348,12 +348,12 @@ export class MasksHandlerImpl implements MasksHandler {
const continueInserting = options.e.ctrlKey;
const wrappingBbox = this.getDrawnObjectsWrappingBox();
const imageData = this.imageDataFromCanvas(wrappingBbox);
const alpha = alphaChannelOnly(imageData);
alpha.push(wrappingBbox.left, wrappingBbox.top, wrappingBbox.right, wrappingBbox.bottom);
const rle = zipChannels(imageData);
rle.push(wrappingBbox.left, wrappingBbox.top, wrappingBbox.right, wrappingBbox.bottom);

this.onDrawDone({
shapeType: this.drawData.shapeType,
points: alpha,
points: rle,
}, Date.now() - this.startTimestamp, continueInserting, this.drawData);

if (!continueInserting) {
Expand Down Expand Up @@ -528,7 +528,7 @@ export class MasksHandlerImpl implements MasksHandler {
const { points } = drawData.initialState;
const color = fabric.Color.fromHex(this.getStateColor(drawData.initialState)).getSource();
const [left, top, right, bottom] = points.slice(-4);
const imageBitmap = expandChannels(color[0], color[1], color[2], points, 4);
const imageBitmap = expandChannels(color[0], color[1], color[2], points);
imageDataToDataURL(imageBitmap, right - left + 1, bottom - top + 1,
(dataURL: string) => new Promise((resolve) => {
fabric.Image.fromURL(dataURL, (image: fabric.Image) => {
Expand All @@ -547,28 +547,29 @@ export class MasksHandlerImpl implements MasksHandler {
}));

this.isInsertion = true;
} else if (!this.isDrawing) {
// initialize drawing pipeline if not started
this.isDrawing = true;
this.redraw = drawData.redraw || null;
} else {
this.updateBrushTools(drawData.brushTool);
if (!this.isDrawing) {
// initialize drawing pipeline if not started
this.isDrawing = true;
this.redraw = drawData.redraw || null;
}
}

this.canvas.getElement().parentElement.style.display = 'block';
this.startTimestamp = Date.now();
}

this.updateBrushTools(drawData.brushTool);

if (!drawData.enabled && this.isDrawing) {
try {
if (this.drawnObjects.length) {
const wrappingBbox = this.getDrawnObjectsWrappingBox();
const imageData = this.imageDataFromCanvas(wrappingBbox);
const alpha = alphaChannelOnly(imageData);
alpha.push(wrappingBbox.left, wrappingBbox.top, wrappingBbox.right, wrappingBbox.bottom);
const rle = zipChannels(imageData);
rle.push(wrappingBbox.left, wrappingBbox.top, wrappingBbox.right, wrappingBbox.bottom);
this.onDrawDone({
shapeType: this.drawData.shapeType,
points: alpha,
points: rle,
...(Number.isInteger(this.redraw) ? { clientID: this.redraw } : {}),
}, Date.now() - this.startTimestamp, drawData.continue, this.drawData);
}
Expand Down Expand Up @@ -600,7 +601,7 @@ export class MasksHandlerImpl implements MasksHandler {
const { points } = editData.state;
const color = fabric.Color.fromHex(this.getStateColor(editData.state)).getSource();
const [left, top, right, bottom] = points.slice(-4);
const imageBitmap = expandChannels(color[0], color[1], color[2], points, 4);
const imageBitmap = expandChannels(color[0], color[1], color[2], points);
imageDataToDataURL(imageBitmap, right - left + 1, bottom - top + 1,
(dataURL: string) => new Promise((resolve) => {
fabric.Image.fromURL(dataURL, (image: fabric.Image) => {
Expand Down Expand Up @@ -634,9 +635,9 @@ export class MasksHandlerImpl implements MasksHandler {
if (this.drawnObjects.length) {
const wrappingBbox = this.getDrawnObjectsWrappingBox();
const imageData = this.imageDataFromCanvas(wrappingBbox);
const alpha = alphaChannelOnly(imageData);
alpha.push(wrappingBbox.left, wrappingBbox.top, wrappingBbox.right, wrappingBbox.bottom);
this.onEditDone(this.editData.state, alpha);
const rle = zipChannels(imageData);
rle.push(wrappingBbox.left, wrappingBbox.top, wrappingBbox.right, wrappingBbox.bottom);
this.onEditDone(this.editData.state, rle);
}
} finally {
this.releaseEdit();
Expand Down
55 changes: 42 additions & 13 deletions cvat-canvas/src/typescript/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -383,24 +383,53 @@ export function imageDataToDataURL(
}, 'image/png');
}

export function alphaChannelOnly(imageData: Uint8ClampedArray): number[] {
const alpha = new Array(imageData.length / 4);
export function zipChannels(imageData: Uint8ClampedArray): number[] {
const rle = [];

let prev = 0;
let summ = 0;
for (let i = 3; i < imageData.length; i += 4) {
alpha[Math.floor(i / 4)] = imageData[i] > 0 ? 1 : 0;
const alpha = imageData[i] > 0 ? 1 : 0;
if (prev !== alpha) {
rle.push(summ);
prev = alpha;
summ = 1;
} else {
summ++;
}
}
return alpha;

rle.push(summ);
return rle;
}

export function expandChannels(r: number, g: number, b: number, alpha: number[], endOffset = 0): Uint8ClampedArray {
const imageBitmap = new Uint8ClampedArray((alpha.length - endOffset) * 4);
for (let i = 0; i < alpha.length - endOffset; i++) {
const val = alpha[i] ? 1 : 0;
imageBitmap[i * 4] = r;
imageBitmap[i * 4 + 1] = g;
imageBitmap[i * 4 + 2] = b;
imageBitmap[i * 4 + 3] = val * 255;
export function expandChannels(r: number, g: number, b: number, encoded: number[]): Uint8ClampedArray {
function rle2Mask(rle: number[], width: number, height: number): Uint8ClampedArray {
const decoded = new Uint8ClampedArray(width * height * 4).fill(0);
const { length } = rle;
let decodedIdx = 0;
let value = 0;
let i = 0;

while (i < length - 4) {
let count = rle[i];
while (count > 0) {
decoded[decodedIdx + 0] = r;
decoded[decodedIdx + 1] = g;
decoded[decodedIdx + 2] = b;
decoded[decodedIdx + 3] = value * 255;
decodedIdx += 4;
count--;
}
i++;
value = Math.abs(value - 1);
}

return decoded;
}
return imageBitmap;

const [left, top, right, bottom] = encoded.slice(-4);
return rle2Mask(encoded, right - left + 1, bottom - top + 1);
}

export type PropType<T, Prop extends keyof T> = T[Prop];
2 changes: 1 addition & 1 deletion cvat-cli/requirements/base.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
cvat-sdk~=2.7.5
cvat-sdk~=2.7.6
Pillow>=10.0.1
setuptools>=65.5.1 # not directly required, pinned by Snyk to avoid a vulnerability
2 changes: 1 addition & 1 deletion cvat-cli/src/cvat_cli/version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
VERSION = "2.7.5"
VERSION = "2.7.6"
2 changes: 1 addition & 1 deletion cvat-core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cvat-core",
"version": "11.1.0",
"version": "12.0.0",
"description": "Part of Computer Vision Tool which presents an interface for client-side integration",
"main": "src/api.ts",
"scripts": {
Expand Down
8 changes: 2 additions & 6 deletions cvat-core/src/annotations-collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import Statistics from './statistics';
import { Label } from './labels';
import { ArgumentError, ScriptingError } from './exceptions';
import ObjectState from './object-state';
import { mask2Rle, truncateMask } from './object-utils';
import { cropMask } from './object-utils';
import config from './config';
import {
HistoryActions, ShapeType, ObjectType, colors, Source,
Expand Down Expand Up @@ -844,11 +844,7 @@ export default class Collection {
occluded: state.occluded || false,
points: state.shapeType === 'mask' ? (() => {
const { width, height } = this.frameMeta[state.frame];
const points = truncateMask(state.points, 0, width, height);
const [left, top, right, bottom] = points.splice(-4);
const rlePoints = mask2Rle(points);
rlePoints.push(left, top, right, bottom);
return rlePoints;
return cropMask(state.points, width, height);
})() : state.points,
rotation: state.rotation || 0,
type: state.shapeType,
Expand Down
Loading

0 comments on commit 56f527a

Please sign in to comment.