@@ -30,27 +30,27 @@ async function setDefaultVolumeVOI(
30
30
) : Promise < void > {
31
31
let voi = getVOIFromMetadata ( imageVolume ) ;
32
32
33
- if ( ! voi ) {
33
+ if ( ! voi && imageVolume ?. imageIds ?. length ) {
34
34
voi = await getVOIFromMinMax ( imageVolume , useNativeDataType ) ;
35
+ voi = handlePreScaledVolume ( imageVolume , voi ) ;
35
36
}
36
-
37
- if ( ! voi || voi . lower === undefined || voi . upper === undefined ) {
38
- throw new Error (
39
- 'Could not get VOI from metadata, nor from the min max of the image middle slice'
40
- ) ;
41
- }
42
-
43
- voi = handlePreScaledVolume ( imageVolume , voi ) ;
44
- const { lower, upper } = voi ;
45
-
46
- if ( lower === 0 && upper === 0 ) {
37
+ // if (!voi || voi.lower === undefined || voi.upper === undefined) {
38
+ // throw new Error(
39
+ // 'Could not get VOI from metadata, nor from the min max of the image middle slice'
40
+ // );
41
+ // }
42
+ if (
43
+ ( voi ?. lower === 0 && voi ?. upper === 0 ) ||
44
+ voi ?. lower === undefined ||
45
+ voi ?. upper === undefined
46
+ ) {
47
47
return ;
48
48
}
49
49
50
50
volumeActor
51
51
. getProperty ( )
52
52
. getRGBTransferFunction ( 0 )
53
- . setMappingRange ( lower , upper ) ;
53
+ . setMappingRange ( voi . lower , voi . upper ) ;
54
54
}
55
55
56
56
function handlePreScaledVolume ( imageVolume : IImageVolume , voi : VOIRange ) {
@@ -128,84 +128,83 @@ async function getVOIFromMinMax(
128
128
useNativeDataType : boolean
129
129
) : Promise < VOIRange > {
130
130
const { imageIds } = imageVolume ;
131
- const numImages = imageIds ?. length || imageVolume . dimensions [ 2 ] ;
132
- let image ;
133
- if ( imageIds ?. length ) {
134
- // Get index of the middle image
135
- const imageIdIndex = Math . floor ( numImages / 2 ) ;
136
- const imageId = imageVolume . imageIds [ imageIdIndex ] ;
137
- const generalSeriesModule =
138
- metaData . get ( 'generalSeriesModule' , imageId ) || { } ;
139
- const { modality } = generalSeriesModule ;
140
- const modalityLutModule = metaData . get ( 'modalityLutModule' , imageId ) || { } ;
141
- const scalingParameters : ScalingParameters = {
142
- rescaleSlope : modalityLutModule . rescaleSlope ,
143
- rescaleIntercept : modalityLutModule . rescaleIntercept ,
144
- modality,
145
- } ;
146
- let scalingParametersToUse ;
147
- if ( modality === 'PT' ) {
148
- const suvFactor = metaData . get ( 'scalingModule' , imageId ) ;
149
- if ( suvFactor ) {
150
- scalingParametersToUse = {
151
- ...scalingParameters ,
152
- suvbw : suvFactor . suvbw ,
153
- } ;
154
- }
155
- }
156
- const options = {
157
- targetBuffer : {
158
- type : useNativeDataType ? undefined : 'Float32Array' ,
159
- } ,
160
- priority : PRIORITY ,
161
- requestType : REQUEST_TYPE ,
162
- useNativeDataType,
163
- preScale : {
164
- enabled : true ,
165
- scalingParameters : scalingParametersToUse ,
166
- } ,
167
- } ;
168
- // Loading the middle slice image for a volume has two scenarios, the first one is that
169
- // uses the same volumeLoader which might not resolve to an image (since for performance
170
- // reasons volumes' pixelData is set via offset and length on the volume arrayBuffer
171
- // when each slice is loaded). The second scenario is that the image might not reach
172
- // to the volumeLoader, and an already cached image (with Image object) is used
173
- // instead. For the first scenario, we use the arrayBuffer of the volume to get the correct
174
- // slice for the imageScalarData, and for the second scenario we use the getPixelData
175
- // on the Cornerstone IImage object to get the pixel data.
176
- // Note: we don't want to use the derived or generated images for setting the
177
- // default VOI, because they are not the original. This is ugly but don't
178
- // know how to do it better.
179
- image = cache . getImage ( imageId ) ;
180
- if ( ! imageVolume . referencedImageIds ?. length ) {
181
- // we should ignore the cache here,
182
- // since we want to load the image from with the most
183
- // recent prescale settings
184
- image = await loadAndCacheImage ( imageId , {
185
- ...options ,
186
- ignoreCache : true ,
187
- } ) ;
131
+ const scalarData = imageVolume . getScalarData ( ) ;
132
+
133
+ // Get the middle image from the list of imageIds
134
+ const imageIdIndex = Math . floor ( imageIds . length / 2 ) ;
135
+ const imageId = imageVolume . imageIds [ imageIdIndex ] ;
136
+ const generalSeriesModule =
137
+ metaData . get ( 'generalSeriesModule' , imageId ) || { } ;
138
+ const { modality } = generalSeriesModule ;
139
+ const modalityLutModule = metaData . get ( 'modalityLutModule' , imageId ) || { } ;
140
+
141
+ const numImages = imageIds . length ;
142
+ const bytesPerImage = scalarData . byteLength / numImages ;
143
+ const voxelsPerImage = scalarData . length / numImages ;
144
+ const bytePerPixel = scalarData . BYTES_PER_ELEMENT ;
145
+
146
+ const scalingParameters : ScalingParameters = {
147
+ rescaleSlope : modalityLutModule . rescaleSlope ,
148
+ rescaleIntercept : modalityLutModule . rescaleIntercept ,
149
+ modality,
150
+ } ;
151
+
152
+ let scalingParametersToUse ;
153
+ if ( modality === 'PT' ) {
154
+ const suvFactor = metaData . get ( 'scalingModule' , imageId ) ;
155
+
156
+ if ( suvFactor ) {
157
+ scalingParametersToUse = {
158
+ ...scalingParameters ,
159
+ suvbw : suvFactor . suvbw ,
160
+ } ;
188
161
}
189
162
}
190
- let imageScalarData ;
191
- if ( image ) {
192
- imageScalarData = image . getPixelData ( ) ;
193
- } else {
194
- // If image data is missing such as .nifti and .nrrd image
195
- // calculate offset of the middle slice
196
- const scalarData = imageVolume . getScalarData ( ) ;
197
- const imageIdIndex = Math . floor ( numImages / 2 ) ;
198
- const bytesPerImage = scalarData . byteLength / numImages ;
199
- const voxelsPerImage = scalarData . length / numImages ;
200
- const bytePerPixel = scalarData . BYTES_PER_ELEMENT ;
201
- const byteOffset = imageIdIndex * bytesPerImage ;
202
- imageScalarData = _getImageScalarDataFromImageVolume (
203
- imageVolume ,
204
- byteOffset ,
205
- bytePerPixel ,
206
- voxelsPerImage
207
- ) ;
163
+
164
+ const byteOffset = imageIdIndex * bytesPerImage ;
165
+
166
+ const options = {
167
+ targetBuffer : {
168
+ type : useNativeDataType ? undefined : 'Float32Array' ,
169
+ } ,
170
+ priority : PRIORITY ,
171
+ requestType : REQUEST_TYPE ,
172
+ useNativeDataType,
173
+ preScale : {
174
+ enabled : true ,
175
+ scalingParameters : scalingParametersToUse ,
176
+ } ,
177
+ } ;
178
+
179
+ // Loading the middle slice image for a volume has two scenarios, the first one is that
180
+ // uses the same volumeLoader which might not resolve to an image (since for performance
181
+ // reasons volumes' pixelData is set via offset and length on the volume arrayBuffer
182
+ // when each slice is loaded). The second scenario is that the image might not reach
183
+ // to the volumeLoader, and an already cached image (with Image object) is used
184
+ // instead. For the first scenario, we use the arrayBuffer of the volume to get the correct
185
+ // slice for the imageScalarData, and for the second scenario we use the getPixelData
186
+ // on the Cornerstone IImage object to get the pixel data.
187
+ // Note: we don't want to use the derived or generated images for setting the
188
+ // default VOI, because they are not the original. This is ugly but don't
189
+ // know how to do it better.
190
+ let image = cache . getImage ( imageId ) ;
191
+
192
+ if ( ! imageVolume . referencedImageIds ?. length ) {
193
+ // we should ignore the cache here,
194
+ // since we want to load the image from with the most
195
+ // recent prescale settings
196
+ image = await loadAndCacheImage ( imageId , { ...options , ignoreCache : true } ) ;
208
197
}
198
+
199
+ const imageScalarData = image
200
+ ? image . getPixelData ( )
201
+ : _getImageScalarDataFromImageVolume (
202
+ imageVolume ,
203
+ byteOffset ,
204
+ bytePerPixel ,
205
+ voxelsPerImage
206
+ ) ;
207
+
209
208
// Get the min and max pixel values of the middle slice
210
209
const { min, max } = getMinMax ( imageScalarData ) ;
211
210
0 commit comments