Skip to content
Merged
4 changes: 3 additions & 1 deletion client/dive-common/apispec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { TrackData } from 'vue-media-annotator/track';
import { Attribute } from 'vue-media-annotator/use/AttributeTypes';
import { CustomStyle } from 'vue-media-annotator/StyleManager';
import { AttributeTrackFilter } from 'vue-media-annotator/AttributeTrackFilterControls';
import { ImageEnhancements } from 'vue-media-annotator/use/useImageEnhancements';

type DatasetType = 'image-sequence' | 'video' | 'multi' | 'large-image';
type MultiTrackRecord = Record<string, TrackData>;
Expand Down Expand Up @@ -132,10 +133,11 @@ interface DatasetMetaMutable {
customTypeStyling?: Record<string, CustomStyle>;
customGroupStyling?: Record<string, CustomStyle>;
confidenceFilters?: Record<string, number>;
imageEnhancements?: ImageEnhancements;
attributes?: Readonly<Record<string, Attribute>>;
attributeTrackFilters?: Readonly<Record<string, AttributeTrackFilter>>;
}
const DatasetMetaMutableKeys = ['attributes', 'confidenceFilters', 'customTypeStyling', 'customGroupStyling', 'attributeTrackFilters'];
const DatasetMetaMutableKeys = ['attributes', 'confidenceFilters', 'imageEnhancements', 'customTypeStyling', 'customGroupStyling', 'attributeTrackFilters'];

interface DatasetMeta extends DatasetMetaMutable {
id: Readonly<string>;
Expand Down
16 changes: 15 additions & 1 deletion client/dive-common/components/Viewer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
} from 'vue';
import type { Vue } from 'vue/types/vue';
import type Vuetify from 'vuetify/lib';
import { cloneDeep } from 'lodash';
import { cloneDeep, debounce } from 'lodash';

/* VUE MEDIA ANNOTATOR */
import {
Expand Down Expand Up @@ -167,6 +167,7 @@ export default defineComponent({
imageEnhancements,
imageEnhancementOutputs,
isDefaultImage,
setImageEnhancements,
setSVGFilters,
} = useImageEnhancements();

Expand Down Expand Up @@ -430,6 +431,7 @@ export default defineComponent({
customTypeStyling: trackStyleManager.getTypeStyles(trackFilters.allTypes),
customGroupStyling: groupStyleManager.getTypeStyles(groupFilters.allTypes),
confidenceFilters: trackFilters.confidenceFilters.value,
imageEnhancements: imageEnhancements.value,
// TODO Group confidence filters are not yet supported.
}, saveSet);
} catch (err) {
Expand All @@ -454,6 +456,15 @@ export default defineComponent({
});
}

function saveImageEnhancements() {
saveMetadata(datasetId.value, {
imageEnhancements: imageEnhancements.value,
});
}
const debouncedSaveImageEnhancements = debounce(saveImageEnhancements, 1000, { trailing: true });

watch(imageEnhancements, debouncedSaveImageEnhancements, { deep: true });

// Navigation Guards used by parent component
async function warnBrowserExit(event: BeforeUnloadEvent) {
if (pendingSaveCount.value === 0) return;
Expand Down Expand Up @@ -564,6 +575,9 @@ export default defineComponent({
loadAttributes(meta.attributes);
}
trackFilters.setConfidenceFilters(meta.confidenceFilters);
if (meta.imageEnhancements) {
setImageEnhancements(meta.imageEnhancements);
}
datasetName.value = meta.name;
initTime({
frameRate: meta.fps,
Expand Down
3 changes: 3 additions & 0 deletions client/platform/desktop/backend/native/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,9 @@ async function saveMetadata(settings: Settings, datasetId: string, args: Dataset
if (args.confidenceFilters) {
existing.confidenceFilters = args.confidenceFilters;
}
if (args.imageEnhancements) {
existing.imageEnhancements = args.imageEnhancements;
}
if (args.customTypeStyling) {
existing.customTypeStyling = args.customTypeStyling;
}
Expand Down
4 changes: 4 additions & 0 deletions client/platform/desktop/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type {
} from 'dive-common/apispec';
import { Attribute } from 'vue-media-annotator/use/AttributeTypes';
import { AttributeTrackFilter } from 'vue-media-annotator/AttributeTrackFilterControls';
import { ImageEnhancements } from 'vue-media-annotator/use/useImageEnhancements';

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

// image enhancement settings
imageEnhancement?: ImageEnhancements;

// Stereo or multi-camera datasets with uniform type (all images, all video)
multiCam: MultiCamDesktop | null;

Expand Down
4 changes: 3 additions & 1 deletion client/src/components/annotators/ImageAnnotator.vue
Original file line number Diff line number Diff line change
Expand Up @@ -370,9 +370,11 @@ export default defineComponent({
});
// Set quadFeature and conditionally apply brightness filter
local.quadFeature = quadFeatureLayer.createFeature('quad');
local.quadFeature.layer().node().css('filter', 'url(#imageEhancements)');
data.ready = true;
seek(0);
if (!props.isDefaultImage) {
local.quadFeature.layer().node().css('filter', 'url(#imageEhancements)');
}
});
}
}
Expand Down
3 changes: 3 additions & 0 deletions client/src/components/annotators/VideoAnnotator.vue
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,9 @@ export default defineComponent({
// Force the first frame to load on slow networks.
// See https://github.com/Kitware/dive/issues/447 for more details.
seek(0);
if (!props.isDefaultImage) {
quadFeatureLayer.node().css('filter', 'url(#imageEhancements)');
}
data.ready = true;
data.volume = video.volume;
data.speed = video.playbackRate;
Expand Down
11 changes: 11 additions & 0 deletions client/src/use/useImageEnhancements.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,21 @@ export default function useImageEnhancements() {
&& imageEnhancements.value.saturation === 1
&& imageEnhancements.value.sharpen === 0
));

const setImageEnhancements = (enhancements: ImageEnhancements) => {
imageEnhancements.value = {
brightness: enhancements.brightness,
contrast: enhancements.contrast,
saturation: enhancements.saturation,
sharpen: enhancements.sharpen,
};
};

return {
imageEnhancements,
imageEnhancementOutputs,
isDefaultImage,
setSVGFilters,
setImageEnhancements,
};
}
1 change: 1 addition & 0 deletions docs/DataFormats.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ interface DatasetMetaMutable {
customTypeStyling?: Record<string, CustomStyle>;
customGroupStyling?: Record<string, CustomStyle>;
confidenceFilters?: Record<string, number>;
imageEnhancments?: ImageEnhancements;
attributes?: Readonly<Record<string, Attribute>>;
}
```
Expand Down
1 change: 1 addition & 0 deletions server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ Image chips that compose a video are stored as girder items in a folder. Videos
* `fps` (number) annotation framerate, not to be confused with video raw framerate
* `ffprobe_info` (JSON) output of ffprobe for raw input video
* `confidenceFilters` (JSON) map of filter name to float in [0, 1]
* `imageEnhancements` (JSON) values for image enhancements (brightness, contrast, saturation, sharpen)
* `customTypeStyline` (JSON) map of class name to GeoJS display attributes.
* `foreign_media_id` (string) For "cloned" datasets, this is an objectId pointer to the source media

Expand Down
1 change: 1 addition & 0 deletions server/dive_tasks/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@ def upload_exported_zipped_dataset(
"customTypeStyling": meta.get("customTypeStyling", None),
"customGroupStyling": meta.get("customGroupStyling", None),
"confidenceFilters": meta.get("confidenceFilters", None),
"imageEnhancements": meta.get("imageEnhancements", None),
"fps": meta["fps"],
"version": meta["version"],
}
Expand Down
1 change: 1 addition & 0 deletions server/dive_utils/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@
OriginalFPSMarker = "originalFps"
OriginalFPSStringMarker = "originalFpsString"
ConfidenceFiltersMarker = "confidenceFilters"
ImageEnhancementsMarker = "imageEnhancements"
AnnotationFileFutureProcessMarker = "importAnnotationFile"

# Other constants
Expand Down
1 change: 1 addition & 0 deletions server/dive_utils/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ class MetadataMutable(BaseModel):
customTypeStyling: Optional[Dict[str, CustomStyle]]
customGroupStyling: Optional[Dict[str, CustomStyle]]
confidenceFilters: Optional[Dict[str, float]]
imageEnhancements: Optional[Dict[str, Any]]
attributes: Optional[Dict[str, Attribute]]
attributeTrackFilters: Optional[Dict[str, AttributeTrackFilter]]
fps: Optional[float]
Expand Down
Loading