Skip to content

Commit e254d7e

Browse files
authored
Save image enhancments (#1527)
* update browsers caniuse * swap imageEhanacements to using brightness, contrast, saturation, sharpen * image enhancement controls update * implementing enhancements into media annotator views * add imageEhancements to metadata mutable for back-end/front-end and electron/desktop * implement saving of imageEnhancement settings * export imageEhancements with other settings * ensure that the imageEhancements are loaded if they aren't default for media views * doc: update imageEnhancement documentation
1 parent 24b7239 commit e254d7e

File tree

12 files changed

+47
-3
lines changed

12 files changed

+47
-3
lines changed

client/dive-common/apispec.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { TrackData } from 'vue-media-annotator/track';
77
import { Attribute } from 'vue-media-annotator/use/AttributeTypes';
88
import { CustomStyle } from 'vue-media-annotator/StyleManager';
99
import { AttributeTrackFilter } from 'vue-media-annotator/AttributeTrackFilterControls';
10+
import { ImageEnhancements } from 'vue-media-annotator/use/useImageEnhancements';
1011

1112
type DatasetType = 'image-sequence' | 'video' | 'multi' | 'large-image';
1213
type MultiTrackRecord = Record<string, TrackData>;
@@ -132,10 +133,11 @@ interface DatasetMetaMutable {
132133
customTypeStyling?: Record<string, CustomStyle>;
133134
customGroupStyling?: Record<string, CustomStyle>;
134135
confidenceFilters?: Record<string, number>;
136+
imageEnhancements?: ImageEnhancements;
135137
attributes?: Readonly<Record<string, Attribute>>;
136138
attributeTrackFilters?: Readonly<Record<string, AttributeTrackFilter>>;
137139
}
138-
const DatasetMetaMutableKeys = ['attributes', 'confidenceFilters', 'customTypeStyling', 'customGroupStyling', 'attributeTrackFilters'];
140+
const DatasetMetaMutableKeys = ['attributes', 'confidenceFilters', 'imageEnhancements', 'customTypeStyling', 'customGroupStyling', 'attributeTrackFilters'];
139141

140142
interface DatasetMeta extends DatasetMetaMutable {
141143
id: Readonly<string>;

client/dive-common/components/Viewer.vue

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
} from 'vue';
66
import type { Vue } from 'vue/types/vue';
77
import type Vuetify from 'vuetify/lib';
8-
import { cloneDeep } from 'lodash';
8+
import { cloneDeep, debounce } from 'lodash';
99
1010
/* VUE MEDIA ANNOTATOR */
1111
import {
@@ -167,6 +167,7 @@ export default defineComponent({
167167
imageEnhancements,
168168
imageEnhancementOutputs,
169169
isDefaultImage,
170+
setImageEnhancements,
170171
setSVGFilters,
171172
} = useImageEnhancements();
172173
@@ -430,6 +431,7 @@ export default defineComponent({
430431
customTypeStyling: trackStyleManager.getTypeStyles(trackFilters.allTypes),
431432
customGroupStyling: groupStyleManager.getTypeStyles(groupFilters.allTypes),
432433
confidenceFilters: trackFilters.confidenceFilters.value,
434+
imageEnhancements: imageEnhancements.value,
433435
// TODO Group confidence filters are not yet supported.
434436
}, saveSet);
435437
} catch (err) {
@@ -454,6 +456,15 @@ export default defineComponent({
454456
});
455457
}
456458
459+
function saveImageEnhancements() {
460+
saveMetadata(datasetId.value, {
461+
imageEnhancements: imageEnhancements.value,
462+
});
463+
}
464+
const debouncedSaveImageEnhancements = debounce(saveImageEnhancements, 1000, { trailing: true });
465+
466+
watch(imageEnhancements, debouncedSaveImageEnhancements, { deep: true });
467+
457468
// Navigation Guards used by parent component
458469
async function warnBrowserExit(event: BeforeUnloadEvent) {
459470
if (pendingSaveCount.value === 0) return;
@@ -564,6 +575,9 @@ export default defineComponent({
564575
loadAttributes(meta.attributes);
565576
}
566577
trackFilters.setConfidenceFilters(meta.confidenceFilters);
578+
if (meta.imageEnhancements) {
579+
setImageEnhancements(meta.imageEnhancements);
580+
}
567581
datasetName.value = meta.name;
568582
initTime({
569583
frameRate: meta.fps,

client/platform/desktop/backend/native/common.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,9 @@ async function saveMetadata(settings: Settings, datasetId: string, args: Dataset
555555
if (args.confidenceFilters) {
556556
existing.confidenceFilters = args.confidenceFilters;
557557
}
558+
if (args.imageEnhancements) {
559+
existing.imageEnhancements = args.imageEnhancements;
560+
}
558561
if (args.customTypeStyling) {
559562
existing.customTypeStyling = args.customTypeStyling;
560563
}

client/platform/desktop/constants.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type {
44
} from 'dive-common/apispec';
55
import { Attribute } from 'vue-media-annotator/use/AttributeTypes';
66
import { AttributeTrackFilter } from 'vue-media-annotator/AttributeTrackFilterControls';
7+
import { ImageEnhancements } from 'vue-media-annotator/use/useImageEnhancements';
78

89
export const JsonMetaCurrentVersion = 1;
910
export const SettingsCurrentVersion = 1;
@@ -117,6 +118,9 @@ export interface JsonMeta extends DatasetMetaMutable {
117118
// confidence filter threshold for exporting
118119
confidenceFilters?: Record<string, number>;
119120

121+
// image enhancement settings
122+
imageEnhancement?: ImageEnhancements;
123+
120124
// Stereo or multi-camera datasets with uniform type (all images, all video)
121125
multiCam: MultiCamDesktop | null;
122126

client/src/components/annotators/ImageAnnotator.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,9 +370,11 @@ export default defineComponent({
370370
});
371371
// Set quadFeature and conditionally apply brightness filter
372372
local.quadFeature = quadFeatureLayer.createFeature('quad');
373-
local.quadFeature.layer().node().css('filter', 'url(#imageEhancements)');
374373
data.ready = true;
375374
seek(0);
375+
if (!props.isDefaultImage) {
376+
local.quadFeature.layer().node().css('filter', 'url(#imageEhancements)');
377+
}
376378
});
377379
}
378380
}

client/src/components/annotators/VideoAnnotator.vue

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,9 @@ export default defineComponent({
250250
// Force the first frame to load on slow networks.
251251
// See https://github.com/Kitware/dive/issues/447 for more details.
252252
seek(0);
253+
if (!props.isDefaultImage) {
254+
quadFeatureLayer.node().css('filter', 'url(#imageEhancements)');
255+
}
253256
data.ready = true;
254257
data.volume = video.volume;
255258
data.speed = video.playbackRate;

client/src/use/useImageEnhancements.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,21 @@ export default function useImageEnhancements() {
6666
&& imageEnhancements.value.saturation === 1
6767
&& imageEnhancements.value.sharpen === 0
6868
));
69+
70+
const setImageEnhancements = (enhancements: ImageEnhancements) => {
71+
imageEnhancements.value = {
72+
brightness: enhancements.brightness,
73+
contrast: enhancements.contrast,
74+
saturation: enhancements.saturation,
75+
sharpen: enhancements.sharpen,
76+
};
77+
};
78+
6979
return {
7080
imageEnhancements,
7181
imageEnhancementOutputs,
7282
isDefaultImage,
7383
setSVGFilters,
84+
setImageEnhancements,
7485
};
7586
}

docs/DataFormats.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ interface DatasetMetaMutable {
141141
customTypeStyling?: Record<string, CustomStyle>;
142142
customGroupStyling?: Record<string, CustomStyle>;
143143
confidenceFilters?: Record<string, number>;
144+
imageEnhancments?: ImageEnhancements;
144145
attributes?: Readonly<Record<string, Attribute>>;
145146
}
146147
```

server/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ Image chips that compose a video are stored as girder items in a folder. Videos
128128
* `fps` (number) annotation framerate, not to be confused with video raw framerate
129129
* `ffprobe_info` (JSON) output of ffprobe for raw input video
130130
* `confidenceFilters` (JSON) map of filter name to float in [0, 1]
131+
* `imageEnhancements` (JSON) values for image enhancements (brightness, contrast, saturation, sharpen)
131132
* `customTypeStyline` (JSON) map of class name to GeoJS display attributes.
132133
* `foreign_media_id` (string) For "cloned" datasets, this is an objectId pointer to the source media
133134

server/dive_tasks/utils.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,7 @@ def upload_exported_zipped_dataset(
277277
"customTypeStyling": meta.get("customTypeStyling", None),
278278
"customGroupStyling": meta.get("customGroupStyling", None),
279279
"confidenceFilters": meta.get("confidenceFilters", None),
280+
"imageEnhancements": meta.get("imageEnhancements", None),
280281
"fps": meta["fps"],
281282
"version": meta["version"],
282283
}

0 commit comments

Comments
 (0)