-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fixed propagate in ground truth tasks with sparsed frames #8550
Changes from all commits
d18272d
5f6151c
86ae603
ac68a16
16f1b36
c9b0211
87cb5f4
adf6368
49abaac
f20c523
892adad
1b8dac1
8340b9c
706fd99
60b2693
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
### Fixed | ||
|
||
- Propagation creates copies on non-existing frames in a ground truth job | ||
(<https://github.com/cvat-ai/cvat/pull/8550>) |
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -2,7 +2,7 @@ | |||||||||
// | ||||||||||
// SPDX-License-Identifier: MIT | ||||||||||
|
||||||||||
import { omit, throttle } from 'lodash'; | ||||||||||
import { omit, range, throttle } from 'lodash'; | ||||||||||
import { ArgumentError } from './exceptions'; | ||||||||||
import { SerializedCollection, SerializedShape } from './server-response-types'; | ||||||||||
import { Job, Task } from './session'; | ||||||||||
|
@@ -107,13 +107,15 @@ class PropagateShapes extends BaseSingleFrameAction { | |||||||||
} | ||||||||||
|
||||||||||
public async run( | ||||||||||
instance, | ||||||||||
instance: Job | Task, | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Ensure consistent parameter naming with the base class In the |
||||||||||
{ collection: { shapes }, frameData: { number } }, | ||||||||||
): Promise<SingleFrameActionOutput> { | ||||||||||
if (number === this.#targetFrame) { | ||||||||||
return { collection: { shapes } }; | ||||||||||
} | ||||||||||
const propagatedShapes = propagateShapes<SerializedShape>(shapes, number, this.#targetFrame); | ||||||||||
|
||||||||||
const frameNumbers = instance instanceof Job ? await instance.frames.frameNumbers() : range(0, instance.size); | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Consider using native JavaScript methods for generating ranges Instead of using Example: -const frameNumbers = instance instanceof Job ? await instance.frames.frameNumbers() : range(0, instance.size);
+const frameNumbers = instance instanceof Job
+ ? await instance.frames.frameNumbers()
+ : Array.from({ length: instance.size }, (_, i) => i); 📝 Committable suggestion
Suggested change
|
||||||||||
const propagatedShapes = propagateShapes<SerializedShape>(shapes, number, this.#targetFrame, frameNumbers); | ||||||||||
return { collection: { shapes: [...shapes, ...propagatedShapes] } }; | ||||||||||
} | ||||||||||
|
||||||||||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -452,6 +452,7 @@ export function propagateObjectAsync(from: number, to: number): ThunkAction { | |||||||||||||||||||||
const { | ||||||||||||||||||||||
job: { | ||||||||||||||||||||||
instance: sessionInstance, | ||||||||||||||||||||||
frameNumbers, | ||||||||||||||||||||||
}, | ||||||||||||||||||||||
annotations: { | ||||||||||||||||||||||
activatedStateID, | ||||||||||||||||||||||
|
@@ -465,12 +466,17 @@ export function propagateObjectAsync(from: number, to: number): ThunkAction { | |||||||||||||||||||||
throw new Error('There is not an activated object state to be propagated'); | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
await sessionInstance.logger.log(EventScope.propagateObject, { count: Math.abs(to - from) }); | ||||||||||||||||||||||
const states = cvat.utils.propagateShapes<ObjectState>([objectState], from, to); | ||||||||||||||||||||||
if (!sessionInstance) { | ||||||||||||||||||||||
throw new Error('SessionInstance is not defined, propagation is not possible'); | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
await sessionInstance.annotations.put(states); | ||||||||||||||||||||||
const history = await sessionInstance.actions.get(); | ||||||||||||||||||||||
const states = cvat.utils.propagateShapes<ObjectState>([objectState], from, to, frameNumbers); | ||||||||||||||||||||||
if (states.length) { | ||||||||||||||||||||||
await sessionInstance.logger.log(EventScope.propagateObject, { count: states.length }); | ||||||||||||||||||||||
await sessionInstance.annotations.put(states); | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
const history = await sessionInstance.actions.get(); | ||||||||||||||||||||||
dispatch({ | ||||||||||||||||||||||
type: AnnotationActionTypes.PROPAGATE_OBJECT_SUCCESS, | ||||||||||||||||||||||
payload: { history }, | ||||||||||||||||||||||
|
@@ -596,10 +602,10 @@ export function confirmCanvasReadyAsync(): ThunkAction { | |||||||||||||||||||||
return async (dispatch: ThunkDispatch, getState: () => CombinedState): Promise<void> => { | ||||||||||||||||||||||
try { | ||||||||||||||||||||||
const state: CombinedState = getState(); | ||||||||||||||||||||||
const { instance: job } = state.annotation.job; | ||||||||||||||||||||||
const job = state.annotation.job.instance as Job; | ||||||||||||||||||||||
const includedFrames = state.annotation.job.frameNumbers; | ||||||||||||||||||||||
bsekachev marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||
const { changeFrameEvent } = state.annotation.player.frame; | ||||||||||||||||||||||
const chunks = await job.frames.cachedChunks() as number[]; | ||||||||||||||||||||||
const includedFrames = await job.frames.frameNumbers() as number[]; | ||||||||||||||||||||||
const { frameCount, dataChunkSize } = job; | ||||||||||||||||||||||
|
||||||||||||||||||||||
const ranges = chunks.map((chunk) => ( | ||||||||||||||||||||||
|
@@ -916,7 +922,6 @@ export function getJobAsync({ | |||||||||||||||||||||
} | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
const jobMeta = await cvat.frames.getMeta('job', job.id); | ||||||||||||||||||||||
// frame query parameter does not work for GT job | ||||||||||||||||||||||
const frameNumber = Number.isInteger(initialFrame) && gtJob?.id !== job.id ? | ||||||||||||||||||||||
initialFrame as number : | ||||||||||||||||||||||
|
@@ -925,6 +930,8 @@ export function getJobAsync({ | |||||||||||||||||||||
)) || job.startFrame; | ||||||||||||||||||||||
|
||||||||||||||||||||||
const frameData = await job.frames.get(frameNumber); | ||||||||||||||||||||||
const jobMeta = await cvat.frames.getMeta('job', job.id); | ||||||||||||||||||||||
const frameNumbers = await job.frames.frameNumbers(); | ||||||||||||||||||||||
Comment on lines
+933
to
+934
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add error handling for external calls to The calls to Apply this diff to add error handling: const [job] = await cvat.jobs.get({ jobID });
+ let jobMeta;
+ let frameNumbers;
+ try {
+ jobMeta = await cvat.frames.getMeta('job', job.id);
+ frameNumbers = await job.frames.frameNumbers();
+ } catch (error) {
+ throw new Error(`Failed to retrieve job metadata or frame numbers: ${error.message}`);
+ } 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||
try { | ||||||||||||||||||||||
// call first getting of frame data before rendering interface | ||||||||||||||||||||||
// to load and decode first chunk | ||||||||||||||||||||||
|
@@ -962,6 +969,7 @@ export function getJobAsync({ | |||||||||||||||||||||
payload: { | ||||||||||||||||||||||
openTime, | ||||||||||||||||||||||
job, | ||||||||||||||||||||||
frameNumbers, | ||||||||||||||||||||||
jobMeta, | ||||||||||||||||||||||
queryParameters, | ||||||||||||||||||||||
groundTruthInstance: gtJob || null, | ||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -67,6 +67,7 @@ const defaultState: AnnotationState = { | |
groundTruthJobFramesMeta: null, | ||
groundTruthInstance: null, | ||
}, | ||
frameNumbers: [], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ensure TypeScript interfaces include The addition of |
||
instance: null, | ||
meta: null, | ||
attributes: {}, | ||
|
@@ -165,6 +166,7 @@ export default (state = defaultState, action: AnyAction): AnnotationState => { | |
job, | ||
jobMeta, | ||
openTime, | ||
frameNumbers, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Handle possible undefined When extracting |
||
frameNumber: number, | ||
frameFilename: filename, | ||
relatedFiles, | ||
|
@@ -209,6 +211,7 @@ export default (state = defaultState, action: AnyAction): AnnotationState => { | |
job: { | ||
...state.job, | ||
openTime, | ||
frameNumbers, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Validate Before assigning |
||
fetching: false, | ||
instance: job, | ||
meta: jobMeta, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Import only necessary functions to optimize bundle size
While importing
range
fromlodash
, consider importing only the specific functions you need to reduce the bundle size. This can be done by importing fromlodash/range
instead:This ensures that only the required modules are included, improving the performance of the application.
📝 Committable suggestion