Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions client/platform/desktop/backend/native/common.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import type {
DesktopJobUpdate, DesktopJobUpdater, JsonMeta, RunTraining, Settings,
} from 'platform/desktop/constants';

import { MultiTrackRecord } from 'dive-common/apispec';
import { Attribute } from 'vue-media-annotator/use/useAttributes';
import * as common from './common';

const pipelines = {
Expand Down Expand Up @@ -107,6 +109,34 @@ const console = new Console(process.stdout, process.stderr);

const emptyCsvString = '# comment line\n# metadata,fps: 32,"whatever"\n#comment line';

// Below sets up data in the mockfs
type testPairs = [string[], MultiTrackRecord, Record<string, Attribute>];
/* Viame.spec.json is an array in the format [CSV row Array, MultiTrackRecord, Attributes Object][]
This is restructured to be images and annotations files within a folder for the mockfs system
test[index] (folder):
-1.png
-2.png
-3.png
-annotations.csv
This is then used to run a complete load of a folder and then compare
with the results located in the MultiTrackRecord and Attributes for the corresponding index
*/
const testData: testPairs[] = fs.readJSONSync('../testutils/viame.spec.json');
const images: Record<string, string> = {};
//Create a list of numbers 0-9
const imageList = Array.from(Array(10).keys());
imageList.shift(); //remove 0 to line up with source data images list
// eslint-disable-next-line no-return-assign
imageList.forEach((item) => images[`${item}.png`] = ''); // 1.png, 2.png,...
//Create a mockfs file struction of a list of images and a root annotations.csv file
const fileSystemData: Record<string, Record<string, string>> = { };
testData.forEach((triplet, index) => {
fileSystemData[`test${index}`] = {
...images, //list of images [1-9].png
'annotations.csv': triplet[0].join('\n'), //join csv string[] into a string for mockfs
};
});

mockfs({
'/opt/viame': {
configs: {
Expand All @@ -117,6 +147,7 @@ mockfs({
},
},
},
'/home/user/testPairs': { ...fileSystemData },
'/home/user/output': {},
'/home/user/data': {
annotationImport: {
Expand Down Expand Up @@ -703,6 +734,32 @@ describe('native.common', () => {
expect(pipes.utility.pipes).toHaveLength(4);
expect(pipes.trained.pipes).toHaveLength(1);
});

it('Full Annotation Loading and Attributes Testing', async () => {
for (let num = 0; num < testData.length; num += 1) {
// eslint-disable-next-line no-await-in-loop
const payload = await common.beginMediaImport(
settings, `/home/user/testPairs/test${num}`, checkMedia,
);
expect(payload.jsonMeta.originalImageFiles).toEqual([
'1.png',
'2.png',
'3.png',
'4.png',
'5.png',
'6.png',
'7.png',
'8.png',
'9.png',
]);
// eslint-disable-next-line no-await-in-loop
const final = await common.finalizeMediaImport(settings, payload, updater, convertMedia);
expect(final.attributes).toEqual(testData[num][2]);
// eslint-disable-next-line no-await-in-loop
const tracks = await common.loadDetections(settings, final.id);
expect(tracks).toEqual(testData[num][1]);
}
});
});

afterAll(() => {
Expand Down
1 change: 1 addition & 0 deletions client/platform/desktop/backend/native/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,7 @@ async function _ingestFilePath(
}
if (tracks !== null) {
const processed = processTrackAttributes(tracks);
meta.attributes = processed.attributes;
await _saveSerialized(settings, datasetId, processed.data, true);
}
return meta;
Expand Down
4 changes: 0 additions & 4 deletions client/platform/desktop/backend/serializers/nist.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,6 @@ function loadObjects(
track.begin = Math.min(track.begin, frameNum);
track.features.push({
frame: frameNum,
keyframe: true,
bounds: adjustedBounds,
attributes: {
objectID,
Expand Down Expand Up @@ -167,15 +166,12 @@ function loadActivity(
features.push({
frame: parseInt(frame, 10) - 1,
bounds,
keyframe: true,
interpolate: false,
});
} else if (val === 1) {
track.end = parseInt(key, 10) - 1;
features.push({
frame: parseInt(frame, 10) - 1,
bounds,
keyframe: true,
interpolate: true,
});
}
Expand Down
48 changes: 37 additions & 11 deletions client/platform/desktop/backend/serializers/viame.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,14 @@ import { MultiTrackRecord } from 'dive-common/apispec';
import fs from 'fs-extra';
import mockfs from 'mock-fs';
import { JsonMeta } from 'platform/desktop/constants';
import { serialize } from 'platform/desktop/backend/serializers/viame';
import { serialize, parse } from 'platform/desktop/backend/serializers/viame';
import { Attribute } from 'vue-media-annotator/use/useAttributes';
import processTrackAttributes from 'platform/desktop/backend/native/attributeProcessor';


type testPairs = [string[], MultiTrackRecord, Record<string, Attribute>];

const testData: testPairs[] = fs.readJSONSync('../testutils/viame.spec.json');
Comment thread
subdavis marked this conversation as resolved.


const data: MultiTrackRecord = {
Expand All @@ -20,8 +27,6 @@ const data: MultiTrackRecord = {
968,
433,
],
interpolate: false,
keyframe: true,
},
{
frame: 1,
Expand All @@ -31,8 +36,6 @@ const data: MultiTrackRecord = {
968,
433,
],
interpolate: false,
keyframe: true,
},
{
frame: 2,
Expand All @@ -42,8 +45,6 @@ const data: MultiTrackRecord = {
968,
433,
],
interpolate: false,
keyframe: true,
},
{
frame: 3,
Expand All @@ -53,8 +54,6 @@ const data: MultiTrackRecord = {
968,
433,
],
interpolate: false,
keyframe: true,
},
{
frame: 4,
Expand All @@ -64,8 +63,6 @@ const data: MultiTrackRecord = {
968,
433,
],
interpolate: false,
keyframe: true,
},
],
confidencePairs: [
Expand Down Expand Up @@ -118,14 +115,22 @@ const meta = {
multiCam: null,
subType: null,
} as JsonMeta;
const testFiles: Record<string, string> = { };
testData.forEach((item, index) => {
// eslint-disable-next-line prefer-destructuring
testFiles[`${index}.csv`] = item[0].join('\n');
});

mockfs({
'/home': {},
'home/user/media/projectid1data': {
'foo.png': '',
'bar.png': '',
},
'/csv': testFiles,
});


// Returns first confidence pairs output of CSV that isn't a comment
function checkConfidenceOutput(output: string[]) {
for (let i = 0; i < output.length; i += 1) {
Expand All @@ -149,6 +154,26 @@ function getCSVTiming(output: string[]) {
}
return timings;
}

describe('VIAME Python Compatibility Check', () => {
it('testing import and convert', async () => {
for (let i = 0; i < testData.length; i += 1) {
const trackData = testData[i][1];
const testAttributes = testData[i][2];
const testPath = `/csv/${i}.csv`;
const csvStream = fs.createReadStream(testPath);
const trackArray = Object.values(trackData);
// eslint-disable-next-line no-await-in-loop
const results = await parse(csvStream);
expect(results.tracks).toEqual(trackArray);
// eslint-disable-next-line no-await-in-loop
const attData = processTrackAttributes(results.tracks);
expect(testAttributes).toEqual(attData.attributes);
}
});
});


describe('VIAME serialize testing', () => {
it('testing exporting with viame CSV and proper order', async () => {
const path = '/home/test.json';
Expand Down Expand Up @@ -195,6 +220,7 @@ describe('VIAME serialize testing', () => {
});
});


afterAll(() => {
mockfs.restore();
});
11 changes: 6 additions & 5 deletions client/platform/desktop/backend/serializers/viame.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ import Track, {
} from 'vue-media-annotator/track';

const CommentRegex = /^\s*#/g;
const HeadRegex = /^\(kp\) head ([0-9]+\.*[0-9]*) ([0-9]+\.*[0-9]*)/g;
const TailRegex = /^\(kp\) tail ([0-9]+\.*[0-9]*) ([0-9]+\.*[0-9]*)/g;
const HeadRegex = /^\(kp\) head (-?[0-9]+\.*-?[0-9]*) (-?[0-9]+\.*-?[0-9]*)/g;
const TailRegex = /^\(kp\) tail (-?[0-9]+\.*-?[0-9]*) (-?[0-9]+\.*-?[0-9]*)/g;
const AttrRegex = /^\(atr\) (.*?)\s(.+)/g;
const TrackAttrRegex = /^\(trk-atr\) (.*?)\s(.+)/g;
const PolyRegex = /^(\(poly\)) ((?:[0-9]+\.*[0-9]*\s*)+)/g;
const PolyRegex = /^(\(poly\)) ((?:-?[0-9]+\.*-?[0-9]*\s*)+)/g;
const FpsRegex = /fps:\s*(\d+(\.\d+)?)/ig;
const AtrToken = '(atr)';
const TrackAtrToken = '(trk-atr)';
Expand Down Expand Up @@ -220,8 +220,10 @@ function _parseFeature(row: string[]) {
const feature: Feature = {
frame: rowInfo.frame,
bounds: rowInfo.bounds,
fishLength: rowInfo.fishLength,
};
if (rowInfo.fishLength !== -1) {
feature.fishLength = rowInfo.fishLength;
}
if (rowData.attributes) {
feature.attributes = rowData.attributes;
}
Expand Down Expand Up @@ -286,7 +288,6 @@ async function parse(input: Readable, imageMap?: Map<string, number>): Promise<A
begin: rowInfo.frame,
end: rowInfo.frame,
trackId: rowInfo.trackId,
meta: {},
attributes: {},
confidencePairs: [],
features: [],
Expand Down
2 changes: 1 addition & 1 deletion client/src/track.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export interface Feature {
/** TrackData is the json schema for Track transport */
export interface TrackData {
trackId: TrackId;
meta: StringKeyObject;
meta?: StringKeyObject;
attributes: StringKeyObject;
confidencePairs: Array<ConfidencePair>;
features: Array<Feature>;
Expand Down
5 changes: 3 additions & 2 deletions server/dive_utils/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ class Feature(BaseModel):
head: Optional[Tuple[float, float]] = None
tail: Optional[Tuple[float, float]] = None
fishLength: Optional[float] = None
interpolate: Optional[bool] = False
keyframe: Optional[bool] = True
interpolate: Optional[bool] = None
keyframe: Optional[bool] = None


class Track(BaseModel):
Expand All @@ -57,6 +57,7 @@ class Track(BaseModel):
features: List[Feature] = Field(default_factory=lambda: [])
confidencePairs: List[Tuple[str, float]] = Field(default_factory=lambda: [])
attributes: Dict[str, Any] = Field(default_factory=lambda: {})
meta: Optional[Dict[str, Any]]

@validator('features')
@classmethod
Expand Down
6 changes: 3 additions & 3 deletions server/dive_utils/serializers/viame.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,14 +118,14 @@ def _parse_row(row: List[str]) -> Tuple[Dict, Dict, Dict, List]:

for j in range(start, len(row)):
# (kp) head x y
head_regex = re.match(r"^\(kp\) head ([0-9]+\.*[0-9]*) ([0-9]+\.*[0-9]*)", row[j])
head_regex = re.match(r"^\(kp\) head (-?[0-9]+\.*-?[0-9]*) (-?[0-9]+\.*-?[0-9]*)", row[j])
if head_regex:
point = [float(head_regex[1]), float(head_regex[2])]
head_tail.append(point)
create_geoJSONFeature(features, 'Point', point, 'head')

# (kp) tail x y
tail_regex = re.match(r"^\(kp\) tail ([0-9]+\.*[0-9]*) ([0-9]+\.*[0-9]*)", row[j])
tail_regex = re.match(r"^\(kp\) tail (-?[0-9]+\.*-?[0-9]*) (-?[0-9]+\.*-?[0-9]*)", row[j])
if tail_regex:
point = [float(tail_regex[1]), float(tail_regex[2])]
head_tail.append(point)
Expand All @@ -142,7 +142,7 @@ def _parse_row(row: List[str]) -> Tuple[Dict, Dict, Dict, List]:
track_attributes[trk_regex[1]] = _deduceType(trk_regex[2])

# (poly) x1 y1 x2 y2 ...
poly_regex = re.match(r"^(\(poly\)) ((?:[0-9]+\.*[0-9]*\s*)+)", row[j])
poly_regex = re.match(r"^(\(poly\)) ((?:-?[0-9]+\.*-?[0-9]*\s*)+)", row[j])
if poly_regex:
temp = [float(x) for x in poly_regex[2].split()]
coords = list(zip(temp[::2], temp[1::2]))
Expand Down
1 change: 0 additions & 1 deletion server/scripts/generateLargeDataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ def create_track_json(
frame = start_frame + frame
feature = {
"frame": frame,
"keyframe": True,
"bounds": [0, 0, width, height],
}
track_obj["begin"] = min(track_obj["begin"], frame)
Expand Down
Loading