Skip to content

Commit

Permalink
feat(configJson): configurable extension for auto seg group
Browse files Browse the repository at this point in the history
  • Loading branch information
PaulHax committed Apr 29, 2024
1 parent 6d2ea50 commit 73c7bf8
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 40 deletions.
10 changes: 6 additions & 4 deletions documentation/content/doc/configuration_file.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,17 @@ hdf5, iwi.cbor, mha, nii, nii.gz, nrrd, vtk
## Automatic Segment Groups by File Name

When loading files, VolView can automatically convert images to segment groups
if they follow this naming convention: An image with name like `foo.segmentation.bar`
if they follow a naming convention. For example, an image with name like `foo.segmentation.bar`
will be converted to a segment group for a base image named like `foo.baz`.
The key is the `segmentation` extension to identify the segment group image.
Also the `matchNames` key must be set to `true`. The default is false.
The `segmentation` extension is defined by the `io.segmentGroupExtension` key, which takes a
string. Files `foo.[segmentGroupExtension].bar` will be automatilly converted to segment groups for a base image named `foo.baz`. The default is `''` and will disable the feature.

This will define `myFile.seg.nrrd` as a segment group for a `myFile.nii` base file.

```json
{
"io": {
"matchNames": true
"segmentGroupExtension": "seg"
}
}
```
Expand Down
44 changes: 25 additions & 19 deletions src/actions/loadUserFiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@ const BASE_MODALITY_TYPES = {
DX: { priority: 1 },
} as const;

const SEGMENTATION_EXTENSION = 'segmentation';

function findBaseDicom(loadableDataSources: Array<LoadableResult>) {
// find dicom dataset for primary selection if available
const dicoms = loadableDataSources.filter(
Expand Down Expand Up @@ -76,18 +74,22 @@ function findBaseDicom(loadableDataSources: Array<LoadableResult>) {
}

function isSegmentation(extension: string, name: string) {
if (!extension) return false; // avoid 'foo..bar' if extension is ''
const extensions = name.split('.').slice(1);
return extensions.includes(extension);
}

// does not pick segmentation images
function findBaseImage(loadableDataSources: Array<LoadableResult>) {
function findBaseImage(
loadableDataSources: Array<LoadableResult>,
segmentGroupExtension: string
) {
const baseImages = loadableDataSources
.filter(({ dataType }) => dataType === 'image')
.filter((importResult) => {
const name = getDataSourceName(importResult.dataSource);
if (!name) return false;
return !isSegmentation(SEGMENTATION_EXTENSION, name);
return !isSegmentation(segmentGroupExtension, name);
});

if (baseImages.length) return baseImages[0];
Expand Down Expand Up @@ -135,12 +137,14 @@ function getStudyUID(volumeID: string) {
}

function findBaseDataSource(
succeeded: Array<PipelineResultSuccess<ImportResult>>
succeeded: Array<PipelineResultSuccess<ImportResult>>,
segmentGroupExtension: string
) {
const loadableDataSources = filterLoadableDataSources(succeeded);
const baseDicom = findBaseDicom(loadableDataSources);
if (baseDicom) return baseDicom;
const baseImage = findBaseImage(loadableDataSources);

const baseImage = findBaseImage(loadableDataSources, segmentGroupExtension);
if (baseImage) return baseImage;
return loadableDataSources[0];
}
Expand Down Expand Up @@ -186,23 +190,21 @@ function loadLayers(
layersStore.addLayer(primarySelection, layerSelection);
}

// Loads other DataSources Segment Groups:
// Loads other DataSources as Segment Groups:
// - DICOM SEG modalities with matching StudyUIDs.
// - DataSources that have a name like foo.segmentation.bar and the primary DataSource is named foo.baz
function loadSegmentations(
primaryDataSource: VolumeResult,
succeeded: Array<PipelineResultSuccess<ImportResult>>,
matchNames: boolean
segmentGroupExtension: string
) {
const matchingNames = matchNames
? filterMatchingNames(
primaryDataSource,
succeeded,
SEGMENTATION_EXTENSION
).filter(
isVolumeResult // filter out models
)
: [];
const matchingNames = filterMatchingNames(
primaryDataSource,
succeeded,
segmentGroupExtension
).filter(
isVolumeResult // filter out models
);

const dicomStore = useDICOMStore();
const otherSegVolumesInStudy = filterOtherVolumesInStudy(
Expand Down Expand Up @@ -240,15 +242,19 @@ function loadDataSources(sources: DataSource[]) {
const [succeeded, errored] = partitionResults(results);

if (!dataStore.primarySelection && succeeded.length) {
const primaryDataSource = findBaseDataSource(succeeded);
const primaryDataSource = findBaseDataSource(
succeeded,
loadDataStore.segmentGroupExtension
);

if (isVolumeResult(primaryDataSource)) {
const selection = toDataSelection(primaryDataSource);
dataStore.setPrimarySelection(selection);
loadLayers(primaryDataSource, succeeded);
loadSegmentations(
primaryDataSource,
succeeded,
loadDataStore.matchNames
loadDataStore.segmentGroupExtension
);
} // then must be primaryDataSource.type === 'model'
}
Expand Down
10 changes: 8 additions & 2 deletions src/io/import/configJson.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ import { useSegmentGroupStore } from '@/src/store/segmentGroups';
import { AnnotationToolStore } from '@/src/store/tools/useAnnotationTool';
import useLoadDataStore from '@/src/store/load-data';

// --------------------------------------------------------------------------
// Interface

const layout = z
.object({
activeLayout: zodEnumFromObjKeys(Layouts).optional(),
Expand Down Expand Up @@ -57,10 +60,13 @@ const labels = z
})
.optional();

// --------------------------------------------------------------------------
// IO

const io = z
.object({
segmentGroupSaveFormat: z.string().optional(),
matchNames: z.boolean().optional(),
segmentGroupExtension: z.string().default(''),
})
.optional();

Expand Down Expand Up @@ -131,7 +137,7 @@ const applyIo = (manifest: Config) => {

if (manifest.io.segmentGroupSaveFormat)
useSegmentGroupStore().saveFormat = manifest.io.segmentGroupSaveFormat;
useLoadDataStore().matchNames = manifest.io.matchNames ?? false;
useLoadDataStore().segmentGroupExtension = manifest.io.segmentGroupExtension;
};

export const applyConfig = (manifest: Config) => {
Expand Down
15 changes: 2 additions & 13 deletions src/store/datasets-layers.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
import { ref } from 'vue';
import vtkITKHelper from '@kitware/vtk.js/Common/DataModel/ITKHelper';
import vtkImageData from '@kitware/vtk.js/Common/DataModel/ImageData';
import vtkBoundingBox from '@kitware/vtk.js/Common/DataModel/BoundingBox';
import { defineStore } from 'pinia';
import { compareImageSpaces } from '@/src/utils/imageSpace';
import {
DataSelection,
getImage,
makeDICOMSelection,
makeImageSelection,
selectionEquals,
} from '@/src/utils/dataSelection';
import { resample } from '../io/resample/resample';
import { ensureSameSpace } from '@/src/io/resample/resample';
import { useErrorMessage } from '../composables/useErrorMessage';
import { Manifest, StateFile } from '../io/state-file/schema';

Expand Down Expand Up @@ -89,16 +87,7 @@ export const useLayersStore = defineStore('layer', () => {
);
}

let image: vtkImageData;
if (compareImageSpaces(parentImage, sourceImage)) {
image = sourceImage;
} else {
const itkImage = await resample(
vtkITKHelper.convertVtkToItkImage(parentImage),
vtkITKHelper.convertVtkToItkImage(sourceImage)
);
image = vtkITKHelper.convertItkToVtkImage(itkImage);
}
const image = await ensureSameSpace(parentImage, sourceImage);

this.layerImages[id] = image;
}
Expand Down
4 changes: 2 additions & 2 deletions src/store/load-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,10 @@ const useLoadDataStore = defineStore('loadData', () => {
const { startLoading, stopLoading, setError, isLoading } =
useLoadingNotifications();

const matchNames = ref(false);
const segmentGroupExtension = ref('');

return {
matchNames,
segmentGroupExtension,
isLoading,
startLoading,
stopLoading,
Expand Down

0 comments on commit 73c7bf8

Please sign in to comment.