@@ -11,7 +11,8 @@ import {
11
11
rotateDirectionCosinesInPlane ,
12
12
flipImageOrientationPatient as flipIOP ,
13
13
flipMatrix2D ,
14
- rotateMatrix902D
14
+ rotateMatrix902D ,
15
+ nearlyEqual
15
16
} from "../../utilities/orientation/index.js" ;
16
17
import {
17
18
encode ,
@@ -258,9 +259,10 @@ function _createSegFromImages(images, isMultiframe, options) {
258
259
* generateToolState - Given a set of cornrstoneTools imageIds and a Segmentation buffer,
259
260
* derive cornerstoneTools toolState and brush metadata.
260
261
*
261
- * @param {string[] } imageIds An array of the imageIds.
262
- * @param {ArrayBuffer } arrayBuffer The SEG arrayBuffer.
263
- * @param {* } metadataProvider
262
+ * @param {string[] } imageIds - An array of the imageIds.
263
+ * @param {ArrayBuffer } arrayBuffer - The SEG arrayBuffer.
264
+ * @param {* } metadataProvider.
265
+ * @param {number } tolerance - checks tolerance, default value 1.e-3.
264
266
*
265
267
* @return {[]ArrayBuffer }a list of array buffer for each labelMap
266
268
* @return {Object } an object from which the segment metadata can be derived
@@ -272,7 +274,8 @@ function generateToolState(
272
274
imageIds ,
273
275
arrayBuffer ,
274
276
metadataProvider ,
275
- skipOverlapping = false
277
+ skipOverlapping = false ,
278
+ tolerance = 1e-3
276
279
) {
277
280
const dicomData = DicomMessage . readFile ( arrayBuffer ) ;
278
281
const dataset = DicomMetaDictionary . naturalizeDataset ( dicomData . dict ) ;
@@ -340,11 +343,12 @@ function generateToolState(
340
343
}
341
344
}
342
345
343
- const orientation = checkOrientation ( multiframe , validOrientations , [
344
- imagePlaneModule . rows ,
345
- imagePlaneModule . columns ,
346
- imageIds . length
347
- ] ) ;
346
+ const orientation = checkOrientation (
347
+ multiframe ,
348
+ validOrientations ,
349
+ [ imagePlaneModule . rows , imagePlaneModule . columns , imageIds . length ] ,
350
+ tolerance
351
+ ) ;
348
352
349
353
let overlapping = false ;
350
354
if ( ! skipOverlapping ) {
@@ -353,7 +357,8 @@ function generateToolState(
353
357
multiframe ,
354
358
imageIds ,
355
359
validOrientations ,
356
- metadataProvider
360
+ metadataProvider ,
361
+ tolerance
357
362
) ;
358
363
}
359
364
@@ -401,7 +406,8 @@ function generateToolState(
401
406
multiframe ,
402
407
imageIds ,
403
408
validOrientations ,
404
- metadataProvider
409
+ metadataProvider ,
410
+ tolerance
405
411
) ;
406
412
407
413
return {
@@ -617,7 +623,8 @@ function checkSEGsOverlapping(
617
623
multiframe ,
618
624
imageIds ,
619
625
validOrientations ,
620
- metadataProvider
626
+ metadataProvider ,
627
+ tolerance
621
628
) {
622
629
const {
623
630
SharedFunctionalGroupsSequence,
@@ -678,7 +685,8 @@ function checkSEGsOverlapping(
678
685
const alignedPixelDataI = alignPixelDataWithSourceData (
679
686
pixelDataI2D ,
680
687
ImageOrientationPatientI ,
681
- validOrientations
688
+ validOrientations ,
689
+ tolerance
682
690
) ;
683
691
684
692
if ( ! alignedPixelDataI ) {
@@ -777,7 +785,8 @@ function insertOverlappingPixelDataPlanar(
777
785
multiframe ,
778
786
imageIds ,
779
787
validOrientations ,
780
- metadataProvider
788
+ metadataProvider ,
789
+ tolerance
781
790
) {
782
791
const {
783
792
SharedFunctionalGroupsSequence,
@@ -850,7 +859,8 @@ function insertOverlappingPixelDataPlanar(
850
859
const alignedPixelDataI = alignPixelDataWithSourceData (
851
860
pixelDataI2D ,
852
861
ImageOrientationPatientI ,
853
- validOrientations
862
+ validOrientations ,
863
+ tolerance
854
864
) ;
855
865
856
866
if ( ! alignedPixelDataI ) {
@@ -992,7 +1002,8 @@ function insertPixelDataPlanar(
992
1002
multiframe ,
993
1003
imageIds ,
994
1004
validOrientations ,
995
- metadataProvider
1005
+ metadataProvider ,
1006
+ tolerance
996
1007
) {
997
1008
const {
998
1009
SharedFunctionalGroupsSequence,
@@ -1027,7 +1038,8 @@ function insertPixelDataPlanar(
1027
1038
const alignedPixelDataI = alignPixelDataWithSourceData (
1028
1039
pixelDataI2D ,
1029
1040
ImageOrientationPatientI ,
1030
- validOrientations
1041
+ validOrientations ,
1042
+ tolerance
1031
1043
) ;
1032
1044
1033
1045
if ( ! alignedPixelDataI ) {
@@ -1119,7 +1131,12 @@ function insertPixelDataPlanar(
1119
1131
}
1120
1132
}
1121
1133
1122
- function checkOrientation ( multiframe , validOrientations , sourceDataDimensions ) {
1134
+ function checkOrientation (
1135
+ multiframe ,
1136
+ validOrientations ,
1137
+ sourceDataDimensions ,
1138
+ tolerance
1139
+ ) {
1123
1140
const {
1124
1141
SharedFunctionalGroupsSequence,
1125
1142
PerFrameFunctionalGroupsSequence
@@ -1139,15 +1156,15 @@ function checkOrientation(multiframe, validOrientations, sourceDataDimensions) {
1139
1156
. ImageOrientationPatient ;
1140
1157
1141
1158
const inPlane = validOrientations . some ( operation =>
1142
- compareIOP ( iop , operation )
1159
+ compareIOP ( iop , operation , tolerance )
1143
1160
) ;
1144
1161
1145
1162
if ( inPlane ) {
1146
1163
return "Planar" ;
1147
1164
}
1148
1165
1149
1166
if (
1150
- checkIfPerpendicular ( iop , validOrientations [ 0 ] ) &&
1167
+ checkIfPerpendicular ( iop , validOrientations [ 0 ] , tolerance ) &&
1151
1168
sourceDataDimensions . includes ( multiframe . Rows ) &&
1152
1169
sourceDataDimensions . includes ( multiframe . Rows )
1153
1170
) {
@@ -1159,14 +1176,15 @@ function checkOrientation(multiframe, validOrientations, sourceDataDimensions) {
1159
1176
}
1160
1177
1161
1178
/**
1162
- * compareIOP - Returns true if iop1 and iop2 are equal
1163
- * within a tollerance, dx .
1179
+ * checkIfPerpendicular - Returns true if iop1 and iop2 are perpendicular
1180
+ * within a tolerance .
1164
1181
*
1165
1182
* @param {Number[6] } iop1 An ImageOrientationPatient array.
1166
1183
* @param {Number[6] } iop2 An ImageOrientationPatient array.
1167
- * @return {Boolean } True if iop1 and iop2 are equal.
1184
+ * @param {Number } tolerance.
1185
+ * @return {Boolean } True if iop1 and iop2 are equal.
1168
1186
*/
1169
- function checkIfPerpendicular ( iop1 , iop2 ) {
1187
+ function checkIfPerpendicular ( iop1 , iop2 , tolerance ) {
1170
1188
const absDotColumnCosines = Math . abs (
1171
1189
iop1 [ 0 ] * iop2 [ 0 ] + iop1 [ 1 ] * iop2 [ 1 ] + iop1 [ 2 ] * iop2 [ 2 ]
1172
1190
) ;
@@ -1175,8 +1193,10 @@ function checkIfPerpendicular(iop1, iop2) {
1175
1193
) ;
1176
1194
1177
1195
return (
1178
- ( absDotColumnCosines < dx || Math . abs ( absDotColumnCosines - 1 ) < dx ) &&
1179
- ( absDotRowCosines < dx || Math . abs ( absDotRowCosines - 1 ) < dx )
1196
+ ( absDotColumnCosines < tolerance ||
1197
+ Math . abs ( absDotColumnCosines - 1 ) < tolerance ) &&
1198
+ ( absDotRowCosines < tolerance ||
1199
+ Math . abs ( absDotRowCosines - 1 ) < tolerance )
1180
1200
) ;
1181
1201
}
1182
1202
@@ -1343,44 +1363,50 @@ function getValidOrientations(iop) {
1343
1363
/**
1344
1364
* alignPixelDataWithSourceData -
1345
1365
*
1346
- * @param {Ndarray } pixelData2D The data to align.
1347
- * @param {Number[6] } iop The orientation of the image slice.
1348
- * @param {Number[8][6] } orientations An array of valid imageOrientationPatient values.
1349
- * @return {Ndarray } The aligned pixelData.
1366
+ * @param {Ndarray } pixelData2D - The data to align.
1367
+ * @param {Number[6] } iop - The orientation of the image slice.
1368
+ * @param {Number[8][6] } orientations - An array of valid imageOrientationPatient values.
1369
+ * @param {Number } tolerance.
1370
+ * @return {Ndarray } The aligned pixelData.
1350
1371
*/
1351
- function alignPixelDataWithSourceData ( pixelData2D , iop , orientations ) {
1352
- if ( compareIOP ( iop , orientations [ 0 ] ) ) {
1372
+ function alignPixelDataWithSourceData (
1373
+ pixelData2D ,
1374
+ iop ,
1375
+ orientations ,
1376
+ tolerance
1377
+ ) {
1378
+ if ( compareIOP ( iop , orientations [ 0 ] , tolerance ) ) {
1353
1379
return pixelData2D ;
1354
- } else if ( compareIOP ( iop , orientations [ 1 ] ) ) {
1380
+ } else if ( compareIOP ( iop , orientations [ 1 ] , tolerance ) ) {
1355
1381
// Flipped vertically.
1356
1382
1357
1383
// Undo Flip
1358
1384
return flipMatrix2D . v ( pixelData2D ) ;
1359
- } else if ( compareIOP ( iop , orientations [ 2 ] ) ) {
1385
+ } else if ( compareIOP ( iop , orientations [ 2 ] , tolerance ) ) {
1360
1386
// Flipped horizontally.
1361
1387
1362
1388
// Unfo flip
1363
1389
return flipMatrix2D . h ( pixelData2D ) ;
1364
- } else if ( compareIOP ( iop , orientations [ 3 ] ) ) {
1390
+ } else if ( compareIOP ( iop , orientations [ 3 ] , tolerance ) ) {
1365
1391
//Rotated 90 degrees
1366
1392
1367
1393
// Rotate back
1368
1394
return rotateMatrix902D ( pixelData2D ) ;
1369
- } else if ( compareIOP ( iop , orientations [ 4 ] ) ) {
1395
+ } else if ( compareIOP ( iop , orientations [ 4 ] , tolerance ) ) {
1370
1396
//Rotated 90 degrees and fliped horizontally.
1371
1397
1372
1398
// Undo flip and rotate back.
1373
1399
return rotateMatrix902D ( flipMatrix2D . h ( pixelData2D ) ) ;
1374
- } else if ( compareIOP ( iop , orientations [ 5 ] ) ) {
1400
+ } else if ( compareIOP ( iop , orientations [ 5 ] , tolerance ) ) {
1375
1401
// Rotated 90 degrees and fliped vertically
1376
1402
1377
1403
// Unfo flip and rotate back.
1378
1404
return rotateMatrix902D ( flipMatrix2D . v ( pixelData2D ) ) ;
1379
- } else if ( compareIOP ( iop , orientations [ 6 ] ) ) {
1405
+ } else if ( compareIOP ( iop , orientations [ 6 ] , tolerance ) ) {
1380
1406
// Rotated 180 degrees. // TODO -> Do this more effeciently, there is a 1:1 mapping like 90 degree rotation.
1381
1407
1382
1408
return rotateMatrix902D ( rotateMatrix902D ( pixelData2D ) ) ;
1383
- } else if ( compareIOP ( iop , orientations [ 7 ] ) ) {
1409
+ } else if ( compareIOP ( iop , orientations [ 7 ] , tolerance ) ) {
1384
1410
// Rotated 270 degrees
1385
1411
1386
1412
// Rotate back.
@@ -1390,24 +1416,23 @@ function alignPixelDataWithSourceData(pixelData2D, iop, orientations) {
1390
1416
}
1391
1417
}
1392
1418
1393
- const dx = 1e-5 ;
1394
-
1395
1419
/**
1396
1420
* compareIOP - Returns true if iop1 and iop2 are equal
1397
- * within a tollerance, dx .
1421
+ * within a tolerance .
1398
1422
*
1399
- * @param {Number[6] } iop1 An ImageOrientationPatient array.
1400
- * @param {Number[6] } iop2 An ImageOrientationPatient array.
1401
- * @return {Boolean } True if iop1 and iop2 are equal.
1423
+ * @param {Number[6] } iop1 - An ImageOrientationPatient array.
1424
+ * @param {Number[6] } iop2 - An ImageOrientationPatient array.
1425
+ * @param {Number } tolerance.
1426
+ * @return {Boolean } True if iop1 and iop2 are equal.
1402
1427
*/
1403
- function compareIOP ( iop1 , iop2 ) {
1428
+ function compareIOP ( iop1 , iop2 , tolerance ) {
1404
1429
return (
1405
- Math . abs ( iop1 [ 0 ] - iop2 [ 0 ] ) < dx &&
1406
- Math . abs ( iop1 [ 1 ] - iop2 [ 1 ] ) < dx &&
1407
- Math . abs ( iop1 [ 2 ] - iop2 [ 2 ] ) < dx &&
1408
- Math . abs ( iop1 [ 3 ] - iop2 [ 3 ] ) < dx &&
1409
- Math . abs ( iop1 [ 4 ] - iop2 [ 4 ] ) < dx &&
1410
- Math . abs ( iop1 [ 5 ] - iop2 [ 5 ] ) < dx
1430
+ nearlyEqual ( iop1 [ 0 ] , iop2 [ 0 ] , tolerance ) &&
1431
+ nearlyEqual ( iop1 [ 1 ] , iop2 [ 1 ] , tolerance ) &&
1432
+ nearlyEqual ( iop1 [ 2 ] , iop2 [ 2 ] , tolerance ) &&
1433
+ nearlyEqual ( iop1 [ 3 ] , iop2 [ 3 ] , tolerance ) &&
1434
+ nearlyEqual ( iop1 [ 4 ] , iop2 [ 4 ] , tolerance ) &&
1435
+ nearlyEqual ( iop1 [ 5 ] , iop2 [ 5 ] , tolerance )
1411
1436
) ;
1412
1437
}
1413
1438
0 commit comments