Skip to content

Commit f5d7f7b

Browse files
authored
Merge pull request #757 from PaulHax/gaussy
Gaussian smoothing process for a segment
2 parents db620f2 + 58f56b9 commit f5d7f7b

18 files changed

Lines changed: 953 additions & 229 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,4 @@ reports
3434
.tmp/
3535

3636
.github/copilot
37+
CLAUDE.md

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"test": "vitest",
1212
"test:e2e:chrome": "npm run build && wdio run ./wdio.chrome.conf.ts",
1313
"test:e2e:dev": "concurrently -P \"npm run dev\" \"wdio run ./wdio.dev.conf.ts --watch {@}\"",
14-
"lint": "eslint",
14+
"lint": "vue-tsc --noEmit && eslint \"src/**/*.{js,ts,vue}\" \"tests/**/*.{js,ts}\"",
1515
"build:all": "npm run build:dicom && npm run build:resample && npm run build",
1616
"build:dicom": "itk-wasm -s src/io/itk-dicom/ build ",
1717
"build:dicom:debug": "itk-wasm -s src/io/itk-dicom/ build -- -DCMAKE_BUILD_TYPE=Debug",

src/components/FillBetweenControls.vue

Lines changed: 0 additions & 72 deletions
This file was deleted.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<template>
2+
<div class="d-flex align-center">
3+
<mini-expansion-panel>
4+
<template #title> Interpolate segmentation between slices. </template>
5+
<ul>
6+
<li>
7+
Will only fill between segmented slices where none of their direct
8+
neighbors are segmented.
9+
</li>
10+
<li>Only the selected segment will be filled between.</li>
11+
<li>
12+
Uses
13+
<a
14+
href="https://insight-journal.org/browse/publication/977"
15+
target="_blank"
16+
>
17+
morphological contour interpolation
18+
</a>
19+
method.
20+
</li>
21+
</ul>
22+
</mini-expansion-panel>
23+
</div>
24+
</template>
25+
26+
<script setup lang="ts">
27+
import MiniExpansionPanel from './MiniExpansionPanel.vue';
28+
</script>
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<template>
2+
<div class="d-flex align-center">
3+
<mini-expansion-panel>
4+
<template #title>Gaussian smooth selected segment.</template>
5+
<ul>
6+
<li>
7+
Applies Gaussian smoothing to reduce noise and smooth boundaries.
8+
</li>
9+
<li>Only the selected segment will be smoothed.</li>
10+
<li>
11+
Higher sigma values create more smoothing effect but may reduce fine
12+
details.
13+
</li>
14+
</ul>
15+
</mini-expansion-panel>
16+
</div>
17+
18+
<div class="w-100 mb-4">
19+
<v-slider
20+
class="mx-4"
21+
label="Smoothing Strength (σ)"
22+
:min="MIN_SIGMA"
23+
:max="MAX_SIGMA"
24+
:step="0.1"
25+
density="compact"
26+
hide-details
27+
thumb-label
28+
:model-value="sigma"
29+
:disabled="isDisabled"
30+
@update:model-value="setSigma"
31+
/>
32+
</div>
33+
</template>
34+
35+
<script setup lang="ts">
36+
import { computed } from 'vue';
37+
import {
38+
useGaussianSmoothStore,
39+
MIN_SIGMA,
40+
MAX_SIGMA,
41+
} from '@/src/store/tools/gaussianSmooth';
42+
import { usePaintProcessStore } from '@/src/store/tools/paintProcess';
43+
import MiniExpansionPanel from './MiniExpansionPanel.vue';
44+
45+
const gaussianSmoothStore = useGaussianSmoothStore();
46+
const processStore = usePaintProcessStore();
47+
48+
const sigma = computed(() => gaussianSmoothStore.sigma);
49+
const isDisabled = computed(() => processStore.processStep === 'previewing');
50+
const { setSigma } = gaussianSmoothStore;
51+
</script>

src/components/PaintControls.vue

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
<template>
22
<v-container>
3-
<v-row no-gutters align="center" class="mb-4 ml-1">
3+
<v-row no-gutters align="center" justify="center" class="mb-4">
44
<v-item-group
55
v-model="mode"
66
mandatory
77
selected-class="selected"
8-
class="d-flex align-center justify-space-between w-100"
8+
class="d-flex align-center justify-center"
99
>
1010
<v-item
1111
:value="PaintMode.CirclePaint"
@@ -15,7 +15,7 @@
1515
variant="tonal"
1616
rounded="8"
1717
stacked
18-
:class="['mode-button', selectedClass]"
18+
:class="['mode-button', 'mx-2', selectedClass]"
1919
@click.stop="toggle"
2020
>
2121
<v-icon>mdi-brush</v-icon>
@@ -27,26 +27,23 @@
2727
variant="tonal"
2828
rounded="8"
2929
stacked
30-
:class="['mode-button', selectedClass]"
30+
:class="['mode-button', 'mx-2', selectedClass]"
3131
@click.stop="toggle"
3232
>
3333
<v-icon>mdi-eraser</v-icon>
3434
<span class="text-caption">Eraser</span>
3535
</v-btn>
3636
</v-item>
37-
<v-item
38-
:value="PaintMode.FillBetween"
39-
v-slot="{ selectedClass, toggle }"
40-
>
37+
<v-item :value="PaintMode.Process" v-slot="{ selectedClass, toggle }">
4138
<v-btn
4239
variant="tonal"
4340
rounded="8"
4441
stacked
45-
:class="['mode-button', selectedClass]"
42+
:class="['mode-button', 'mx-2', selectedClass]"
4643
@click.stop="toggle"
4744
>
48-
<v-icon>mdi-layers-triple</v-icon>
49-
<span class="text-caption">Fill Between</span>
45+
<v-icon>mdi-cogs</v-icon>
46+
<span class="text-caption">Process</span>
5047
</v-btn>
5148
</v-item>
5249
</v-item-group>
@@ -119,9 +116,9 @@
119116
</v-range-slider>
120117
</v-row>
121118
</template>
122-
<template v-if="mode === PaintMode.FillBetween">
119+
<template v-if="mode === PaintMode.Process">
123120
<v-row no-gutters align="center">
124-
<FillBetweenControls />
121+
<ProcessControls />
125122
</v-row>
126123
</template>
127124
</v-container>
@@ -132,7 +129,7 @@ import { computed } from 'vue';
132129
import { storeToRefs } from 'pinia';
133130
import { PaintMode } from '@/src/core/tools/paint';
134131
import { usePaintToolStore } from '@/src/store/tools/paint';
135-
import FillBetweenControls from '@/src/components/FillBetweenControls.vue';
132+
import ProcessControls from '@/src/components/ProcessControls.vue';
136133
import { useCurrentImage } from '@/src/composables/useCurrentImage';
137134
import { useImageStatsStore } from '@/src/store/image-stats';
138135

src/components/ProcessControls.vue

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<template>
2+
<div class="d-flex flex-column align-center w-100">
3+
<ProcessTypeSelector />
4+
5+
<template v-if="activeProcessType === ProcessType.FillBetween">
6+
<FillBetweenParameterControls />
7+
<ProcessWorkflow :algorithm="fillBetweenAlgorithm" />
8+
</template>
9+
10+
<template v-if="activeProcessType === ProcessType.GaussianSmooth">
11+
<GaussianSmoothParameterControls />
12+
<ProcessWorkflow :algorithm="gaussianSmoothAlgorithm" />
13+
</template>
14+
</div>
15+
</template>
16+
17+
<script setup lang="ts">
18+
import { computed } from 'vue';
19+
import {
20+
ProcessType,
21+
usePaintProcessStore,
22+
} from '@/src/store/tools/paintProcess';
23+
import ProcessTypeSelector from './ProcessTypeSelector.vue';
24+
import ProcessWorkflow from './ProcessWorkflow.vue';
25+
import FillBetweenParameterControls from './FillBetweenParameterControls.vue';
26+
import GaussianSmoothParameterControls from './GaussianSmoothParameterControls.vue';
27+
import { useFillBetweenStore } from '../store/tools/fillBetween';
28+
import { useGaussianSmoothStore } from '../store/tools/gaussianSmooth';
29+
30+
const processStore = usePaintProcessStore();
31+
const fillBetweenStore = useFillBetweenStore();
32+
const gaussianSmoothStore = useGaussianSmoothStore();
33+
34+
const activeProcessType = computed(() => processStore.activeProcessType);
35+
36+
const fillBetweenAlgorithm = fillBetweenStore.computeAlgorithm;
37+
const gaussianSmoothAlgorithm = gaussianSmoothStore.computeAlgorithm;
38+
</script>
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<template>
2+
<v-row no-gutters align="center" justify="center" class="mb-4">
3+
<v-item-group
4+
v-model="activeProcessType"
5+
mandatory
6+
selected-class="selected"
7+
class="d-flex align-center justify-center"
8+
>
9+
<v-item
10+
:value="ProcessType.FillBetween"
11+
v-slot="{ selectedClass, toggle }"
12+
>
13+
<v-btn
14+
variant="tonal"
15+
rounded="8"
16+
stacked
17+
:class="['process-button', 'mx-2', selectedClass]"
18+
@click.stop="toggle"
19+
>
20+
<v-icon>mdi-layers-triple</v-icon>
21+
<span class="text-caption">Fill Between</span>
22+
</v-btn>
23+
</v-item>
24+
<v-item
25+
:value="ProcessType.GaussianSmooth"
26+
v-slot="{ selectedClass, toggle }"
27+
>
28+
<v-btn
29+
variant="tonal"
30+
rounded="8"
31+
stacked
32+
:class="['process-button', 'mx-2', selectedClass]"
33+
@click.stop="toggle"
34+
>
35+
<v-icon>mdi-blur</v-icon>
36+
<span class="text-caption">Smooth</span>
37+
</v-btn>
38+
</v-item>
39+
</v-item-group>
40+
</v-row>
41+
</template>
42+
43+
<script setup lang="ts">
44+
import { computed } from 'vue';
45+
import {
46+
ProcessType,
47+
usePaintProcessStore,
48+
} from '@/src/store/tools/paintProcess';
49+
50+
const processStore = usePaintProcessStore();
51+
52+
const activeProcessType = computed({
53+
get: () => processStore.activeProcessType,
54+
set: (type) => {
55+
processStore.setActiveProcessType(type);
56+
},
57+
});
58+
</script>
59+
60+
<style scoped>
61+
.selected {
62+
background-color: rgb(var(--v-theme-selection-bg-color));
63+
border-color: rgb(var(--v-theme-selection-border-color));
64+
}
65+
66+
.process-button {
67+
min-height: 56px;
68+
min-width: 110px;
69+
height: 56px;
70+
width: 110px;
71+
}
72+
</style>

0 commit comments

Comments
 (0)