Skip to content
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

Convert a loaded image to segment group #528

Merged
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
33 changes: 32 additions & 1 deletion src/components/ImageDataBrowser.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import ItemGroup from '@/src/components/ItemGroup.vue';
import GroupableItem from '@/src/components/GroupableItem.vue';
import ImageListCard from '@/src/components/ImageListCard.vue';
import { createVTKImageThumbnailer } from '@/src/core/thumbnailers/vtk-image';
import { useSegmentGroupStore } from '@/src/store/segmentGroups';
import { useImageStore } from '../store/datasets-images';
import { useDICOMStore } from '../store/datasets-dicom';
import {
Expand All @@ -30,6 +31,7 @@ export default defineComponent({
const dicomStore = useDICOMStore();
const dataStore = useDatasetStore();
const layersStore = useLayersStore();
const segmentGroupStore = useSegmentGroupStore();

const primarySelection = computed(() => dataStore.primarySelection);

Expand Down Expand Up @@ -62,7 +64,8 @@ export default defineComponent({
const isLayer = layerImageIDs.includes(id);
const layerLoaded = loadedLayerImageIDs.includes(id);
const layerLoading = isLayer && !layerLoaded;
const layerable = id !== selectedImageID && primarySelection.value;
const layerable =
id !== selectedImageID && primarySelection.value != null;
return {
id,
cacheKey: imageCacheKey(id),
Expand Down Expand Up @@ -132,6 +135,15 @@ export default defineComponent({
selected.value = [];
}

function convertToLabelMap(key: string) {
if (primarySelection.value) {
segmentGroupStore.convertImageToLabelmap(
{ type: 'image', dataID: key },
primarySelection.value
);
}
}

function removeData(id: string) {
imageStore.deleteData(id);
}
Expand All @@ -143,6 +155,7 @@ export default defineComponent({
toggleSelectAll,
removeSelection,
removeData,
convertToLabelMap,
images,
thumbnails,
primarySelection,
Expand Down Expand Up @@ -244,6 +257,24 @@ export default defineComponent({
<span v-else>Add as layer</span>
</template>
</v-list-item>
<v-list-item
@click="
image.layerable ? convertToLabelMap(image.id) : null
"
>
<v-icon v-if="!image.layerable" class="mr-1"
>mdi-alert</v-icon
>
Convert to Segment Group
<v-tooltip
activator="parent"
location="end"
max-width="200px"
:disabled="image.layerable"
>
Must load a background image before converting
</v-tooltip>
</v-list-item>
<v-list-item @click="removeData(image.id)">
Delete
</v-list-item>
Expand Down
63 changes: 61 additions & 2 deletions src/components/SegmentGroupControls.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
<script setup lang="ts">
import SegmentList from '@/src/components/SegmentList.vue';
import { useCurrentImage } from '@/src/composables/useCurrentImage';
import { selectionEquals, useDatasetStore } from '@/src/store/datasets';
import { useDICOMStore } from '@/src/store/datasets-dicom';
import { useImageStore } from '@/src/store/datasets-images';
import { useSegmentGroupStore } from '@/src/store/segmentGroups';
import { usePaintToolStore } from '@/src/store/tools/paint';
import { Maybe } from '@/src/types';
Expand All @@ -10,6 +13,9 @@ const UNNAMED_GROUP_NAME = 'Unnamed Segment Group';

const segmentGroupStore = useSegmentGroupStore();
const { currentImageID } = useCurrentImage();
const imageStore = useImageStore();
const dicomStore = useDICOMStore();
const dataStore = useDatasetStore();

const currentSegmentGroups = computed(() => {
if (!currentImageID.value) return [];
Expand Down Expand Up @@ -110,14 +116,40 @@ function createSegmentGroup() {

startEditing(id);
}

// Filter and collect all acceptable images, excluding
// the current background image, that can be converted into
// a SegmentGroup (labelmap) for the current background image.
const nonDICOMImages = computed(() => {
const primarySelection = dataStore.primarySelection;
const ids = imageStore.idList.filter(
(id) =>
!(id in dicomStore.imageIDToVolumeKey) &&
primarySelection &&
!selectionEquals({ type: 'image', dataID: id }, primarySelection)
);
return ids.map((id) => ({ id, name: imageStore.metadata[id].name }));
});

function createSegmentGroupFromImage(selectedImageID: string) {
if (!selectedImageID) {
throw new Error('Cannot create a labelmap without a base image');
}
const primarySelection = dataStore.primarySelection;
if (primarySelection) {
segmentGroupStore.convertImageToLabelmap(
{ type: 'image', dataID: selectedImageID },
primarySelection
);
}
}
</script>

<template>
<div class="my-2" v-if="currentImageID">
<div
class="text-grey text-subtitle-2 d-flex flex-row align-center justify-space-between mb-2"
class="text-grey text-subtitle-2 d-flex align-center justify-space-evenly mb-2"
>
<div>Segment Groups</div>
<v-btn
variant="tonal"
color="secondary"
Expand All @@ -126,6 +158,33 @@ function createSegmentGroup() {
>
<v-icon class="mr-1">mdi-plus</v-icon> New Group
</v-btn>
<v-menu location="bottom">
<template v-slot:activator="{ props }">
<v-btn
variant="tonal"
color="secondary"
density="compact"
v-bind="props"
>
<v-icon class="mr-1">mdi-chevron-down</v-icon>From Image
</v-btn>
</template>
<v-list v-if="nonDICOMImages.length !== 0">
<v-list-item
v-for="(item, index) in nonDICOMImages"
:key="index"
@click="createSegmentGroupFromImage(item.id)"
>
{{ item.name }}
<v-tooltip activator="parent" location="end" max-width="200px">
Convert to segment group
</v-tooltip>
</v-list-item>
</v-list>
<v-list v-else>
<v-list-item class="font-italic" title="No eligible images found" />
</v-list>
</v-menu>
</div>
<v-divider />
<v-radio-group
Expand Down