@@ -30,27 +30,27 @@ async function setDefaultVolumeVOI(
3030) : Promise < void > {
3131 let voi = getVOIFromMetadata ( imageVolume ) ;
3232
33- if ( ! voi ) {
33+ if ( ! voi && imageVolume ?. imageIds ?. length ) {
3434 voi = await getVOIFromMinMax ( imageVolume , useNativeDataType ) ;
35+ voi = handlePreScaledVolume ( imageVolume , voi ) ;
3536 }
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+ ) {
4747 return ;
4848 }
4949
5050 volumeActor
5151 . getProperty ( )
5252 . getRGBTransferFunction ( 0 )
53- . setMappingRange ( lower , upper ) ;
53+ . setMappingRange ( voi . lower , voi . upper ) ;
5454}
5555
5656function handlePreScaledVolume ( imageVolume : IImageVolume , voi : VOIRange ) {
@@ -128,84 +128,83 @@ async function getVOIFromMinMax(
128128 useNativeDataType : boolean
129129) : Promise < VOIRange > {
130130 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+ } ;
188161 }
189162 }
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 } ) ;
208197 }
198+
199+ const imageScalarData = image
200+ ? image . getPixelData ( )
201+ : _getImageScalarDataFromImageVolume (
202+ imageVolume ,
203+ byteOffset ,
204+ bytePerPixel ,
205+ voxelsPerImage
206+ ) ;
207+
209208 // Get the min and max pixel values of the middle slice
210209 const { min, max } = getMinMax ( imageScalarData ) ;
211210
0 commit comments