Mercurial > hg > orthanc-tests
comparison Plugins/WSI/Run.py @ 573:31ab8bb2ac5a
merge
author | Alain Mazy <am@osimis.io> |
---|---|
date | Thu, 20 Jul 2023 10:57:39 +0200 |
parents | e6cee85fe421 |
children | 8aa101e126d0 |
comparison
equal
deleted
inserted
replaced
572:3a5260cc6d55 | 573:31ab8bb2ac5a |
---|---|
54 help = 'Username to the REST API') | 54 help = 'Username to the REST API') |
55 parser.add_argument('--password', | 55 parser.add_argument('--password', |
56 default = 'orthanctest', | 56 default = 'orthanctest', |
57 help = 'Password to the REST API') | 57 help = 'Password to the REST API') |
58 parser.add_argument('--dicomizer', | 58 parser.add_argument('--dicomizer', |
59 default = '/home/jodogne/Subversion/orthanc-wsi/Applications/i/OrthancWSIDicomizer', | 59 default = os.path.join(os.environ['HOME'], 'Subversion/orthanc-wsi/Applications/i/OrthancWSIDicomizer'), |
60 help = 'Password to the REST API') | 60 help = 'Password to the REST API') |
61 parser.add_argument('--to-tiff', | 61 parser.add_argument('--to-tiff', |
62 default = '/home/jodogne/Subversion/orthanc-wsi/Applications/i/OrthancWSIDicomToTiff', | 62 default = os.path.join(os.environ['HOME'], 'Subversion/orthanc-wsi/Applications/i/OrthancWSIDicomToTiff'), |
63 help = 'Password to the REST API') | 63 help = 'Password to the REST API') |
64 parser.add_argument('--valgrind', help = 'Use valgrind while running the DICOM-izer', | 64 parser.add_argument('--valgrind', help = 'Use valgrind while running the DICOM-izer', |
65 action = 'store_true') | 65 action = 'store_true') |
66 parser.add_argument('--force', help = 'Do not warn the user', | 66 parser.add_argument('--force', help = 'Do not warn the user', |
67 action = 'store_true') | 67 action = 'store_true') |
98 if args.valgrind: | 98 if args.valgrind: |
99 prefix = [ 'valgrind' ] | 99 prefix = [ 'valgrind' ] |
100 | 100 |
101 log = subprocess.check_output(prefix + command, | 101 log = subprocess.check_output(prefix + command, |
102 stderr=subprocess.STDOUT) | 102 stderr=subprocess.STDOUT) |
103 | 103 |
104 if sys.version_info >= (3, 0): | |
105 log = log.decode('ascii') | |
106 | |
104 # If using valgrind, only print the lines from the log starting | 107 # If using valgrind, only print the lines from the log starting |
105 # with '==' (they contain the report from valgrind) | 108 # with '==' (they contain the report from valgrind) |
106 if args.valgrind: | 109 if args.valgrind: |
107 print('\n'.join(filter(lambda x: x.startswith('=='), log.splitlines()))) | 110 print('\n'.join(filter(lambda x: x.startswith('=='), log.splitlines()))) |
108 | 111 |
129 try: | 132 try: |
130 tiff = subprocess.check_output([ 'tiffinfo', temp.name ]) | 133 tiff = subprocess.check_output([ 'tiffinfo', temp.name ]) |
131 except: | 134 except: |
132 print('\ntiffinfo is probably not installed => sudo apt-get install libtiff-tools\n') | 135 print('\ntiffinfo is probably not installed => sudo apt-get install libtiff-tools\n') |
133 tiff = None | 136 tiff = None |
137 | |
138 if (tiff != None and sys.version_info >= (3, 0)): | |
139 tiff = tiff.decode('ascii') | |
134 | 140 |
135 os.unlink(temp.name) | 141 os.unlink(temp.name) |
136 | 142 |
137 return tiff | 143 return tiff |
138 | 144 |
178 self.assertEqual(512, pyramid['TotalHeight']) | 184 self.assertEqual(512, pyramid['TotalHeight']) |
179 self.assertEqual(1, pyramid['TilesCount'][0][0]) | 185 self.assertEqual(1, pyramid['TilesCount'][0][0]) |
180 self.assertEqual(1, pyramid['TilesCount'][0][1]) | 186 self.assertEqual(1, pyramid['TilesCount'][0][1]) |
181 | 187 |
182 tiff = CallTiffInfoOnSeries(s[0]) | 188 tiff = CallTiffInfoOnSeries(s[0]) |
183 p = filter(lambda x: 'Photometric Interpretation' in x, tiff.splitlines()) | 189 p = list(filter(lambda x: 'Photometric Interpretation' in x, tiff.splitlines())) |
184 self.assertEqual(1, len(p)) | 190 self.assertEqual(1, len(p)) |
185 self.assertTrue('YCbCr' in p[0]) | 191 self.assertTrue('YCbCr' in p[0]) |
186 | 192 |
187 | 193 |
188 def test_grayscale_pyramid(self): | 194 def test_grayscale_pyramid(self): |
233 self.assertEqual(2, pyramid['TilesCount'][2][1]) | 239 self.assertEqual(2, pyramid['TilesCount'][2][1]) |
234 self.assertEqual(1, pyramid['TilesCount'][3][0]) | 240 self.assertEqual(1, pyramid['TilesCount'][3][0]) |
235 self.assertEqual(1, pyramid['TilesCount'][3][1]) | 241 self.assertEqual(1, pyramid['TilesCount'][3][1]) |
236 | 242 |
237 tiff = CallTiffInfoOnSeries(s[0]) | 243 tiff = CallTiffInfoOnSeries(s[0]) |
238 p = filter(lambda x: 'Photometric Interpretation' in x, tiff.splitlines()) | 244 p = list(filter(lambda x: 'Photometric Interpretation' in x, tiff.splitlines())) |
239 self.assertEqual(4, len(p)) | 245 self.assertEqual(4, len(p)) |
240 for j in range(4): | 246 for j in range(4): |
241 self.assertTrue('min-is-black' in p[j]) | 247 self.assertTrue('min-is-black' in p[j]) |
242 | 248 |
243 | 249 |
249 | 255 |
250 pyramid = DoGet(ORTHANC, '/wsi/pyramids/%s' % s[0]) | 256 pyramid = DoGet(ORTHANC, '/wsi/pyramids/%s' % s[0]) |
251 self.assertEqual(4, len(pyramid['Resolutions'])) | 257 self.assertEqual(4, len(pyramid['Resolutions'])) |
252 | 258 |
253 tiff = CallTiffInfoOnSeries(s[0]) | 259 tiff = CallTiffInfoOnSeries(s[0]) |
254 p = filter(lambda x: 'Photometric Interpretation' in x, tiff.splitlines()) | 260 p = list(filter(lambda x: 'Photometric Interpretation' in x, tiff.splitlines())) |
255 self.assertEqual(4, len(p)) | 261 self.assertEqual(4, len(p)) |
256 for j in range(4): | 262 for j in range(4): |
257 self.assertTrue('min-is-black' in p[j]) | 263 self.assertTrue('min-is-black' in p[j]) |
258 | 264 |
259 | 265 |
265 | 271 |
266 pyramid = DoGet(ORTHANC, '/wsi/pyramids/%s' % s[0]) | 272 pyramid = DoGet(ORTHANC, '/wsi/pyramids/%s' % s[0]) |
267 self.assertEqual(4, len(pyramid['Resolutions'])) | 273 self.assertEqual(4, len(pyramid['Resolutions'])) |
268 | 274 |
269 tiff = CallTiffInfoOnSeries(s[0]) | 275 tiff = CallTiffInfoOnSeries(s[0]) |
270 p = filter(lambda x: 'Photometric Interpretation' in x, tiff.splitlines()) | 276 p = list(filter(lambda x: 'Photometric Interpretation' in x, tiff.splitlines())) |
271 self.assertEqual(4, len(p)) | 277 self.assertEqual(4, len(p)) |
272 for j in range(4): | 278 for j in range(4): |
273 self.assertTrue('YCbCr' in p[j]) | 279 self.assertTrue('YCbCr' in p[j]) |
274 | 280 |
275 | 281 |
281 | 287 |
282 pyramid = DoGet(ORTHANC, '/wsi/pyramids/%s' % s[0]) | 288 pyramid = DoGet(ORTHANC, '/wsi/pyramids/%s' % s[0]) |
283 self.assertEqual(4, len(pyramid['Resolutions'])) | 289 self.assertEqual(4, len(pyramid['Resolutions'])) |
284 | 290 |
285 tiff = CallTiffInfoOnSeries(s[0]) | 291 tiff = CallTiffInfoOnSeries(s[0]) |
286 p = filter(lambda x: 'Photometric Interpretation' in x, tiff.splitlines()) | 292 p = list(filter(lambda x: 'Photometric Interpretation' in x, tiff.splitlines())) |
287 self.assertEqual(4, len(p)) | 293 self.assertEqual(4, len(p)) |
288 for j in range(4): | 294 for j in range(4): |
289 self.assertTrue('RGB' in p[j]) | 295 self.assertTrue('RGB' in p[j]) |
290 | 296 |
291 | 297 |
359 s = spacings[str(4 ** i)].split('\\') | 365 s = spacings[str(4 ** i)].split('\\') |
360 self.assertEqual(2, len(s)) | 366 self.assertEqual(2, len(s)) |
361 self.assertEqual(20.0 / 512.0 * (2.0 ** (3 - i)), float(s[0])) | 367 self.assertEqual(20.0 / 512.0 * (2.0 ** (3 - i)), float(s[0])) |
362 self.assertEqual(10.0 / 512.0 * (2.0 ** (3 - i)), float(s[1])) | 368 self.assertEqual(10.0 / 512.0 * (2.0 ** (3 - i)), float(s[1])) |
363 | 369 |
370 | |
371 def test_http_accept(self): | |
372 # https://discourse.orthanc-server.org/t/orthanc-wsi-image-quality-issue/3331 | |
373 | |
374 def TestTransferSyntax(s, expected): | |
375 instance = DoGet(ORTHANC, '/series/%s' % s[0]) ['Instances'][0] | |
376 self.assertEqual(expected, DoGet(ORTHANC, '/instances/%s/metadata/TransferSyntax' % instance)) | |
364 | 377 |
378 def TestDefaultAccept(s, mime): | |
379 tile = GetImage(ORTHANC, '/wsi/tiles/%s/0/0/0' % s[0]) | |
380 self.assertEqual(mime, tile.format) | |
381 | |
382 tile = GetImage(ORTHANC, '/wsi/tiles/%s/0/0/0' % s[0], { | |
383 'Accept' : 'text/html,*/*' | |
384 }) | |
385 self.assertEqual(mime, tile.format) | |
386 | |
387 tile = GetImage(ORTHANC, '/wsi/tiles/%s/0/0/0' % s[0], { | |
388 'Accept' : 'image/*,text/html' | |
389 }) | |
390 self.assertEqual(mime, tile.format) | |
391 | |
392 tile = DoGetRaw(ORTHANC, '/wsi/tiles/%s/0/0/0' % s[0], headers = { | |
393 'Accept' : 'text/html' | |
394 }) | |
395 self.assertEqual(406, int(tile[0]['status'])) | |
396 | |
397 def TestForceAccept(s): | |
398 tile = GetImage(ORTHANC, '/wsi/tiles/%s/0/0/0' % s[0], { | |
399 'Accept' : 'image/jpeg' | |
400 }) | |
401 self.assertEqual('JPEG', tile.format) | |
402 | |
403 tile = GetImage(ORTHANC, '/wsi/tiles/%s/0/0/0' % s[0], { | |
404 'Accept' : 'image/png' | |
405 }) | |
406 self.assertEqual('PNG', tile.format) | |
407 | |
408 tile = GetImage(ORTHANC, '/wsi/tiles/%s/0/0/0' % s[0], { | |
409 'Accept' : 'image/jp2' | |
410 }) | |
411 self.assertEqual('JPEG2000', tile.format) | |
412 | |
413 | |
414 CallDicomizer([ GetDatabasePath('Lena.jpg') ]) | |
415 | |
416 s = DoGet(ORTHANC, '/series') | |
417 self.assertEqual(1, len(s)) | |
418 TestTransferSyntax(s, '1.2.840.10008.1.2.4.50') | |
419 TestDefaultAccept(s, 'JPEG') | |
420 TestForceAccept(s) | |
421 | |
422 DoDelete(ORTHANC, '/series/%s' % s[0]) | |
423 | |
424 CallDicomizer([ GetDatabasePath('Lena.jpg'), '--compression', 'none' ]) | |
425 s = DoGet(ORTHANC, '/series') | |
426 self.assertEqual(1, len(s)) | |
427 | |
428 TestTransferSyntax(s, '1.2.840.10008.1.2') | |
429 TestDefaultAccept(s, 'PNG') | |
430 TestForceAccept(s) | |
431 | |
432 DoDelete(ORTHANC, '/series/%s' % s[0]) | |
433 | |
434 CallDicomizer([ GetDatabasePath('Lena.jpg'), '--compression', 'jpeg2000' ]) | |
435 s = DoGet(ORTHANC, '/series') | |
436 self.assertEqual(1, len(s)) | |
437 | |
438 TestTransferSyntax(s, '1.2.840.10008.1.2.4.90') | |
439 TestDefaultAccept(s, 'PNG') | |
440 TestForceAccept(s) | |
441 | |
442 def test_iiif(self): | |
443 CallDicomizer([ GetDatabasePath('LenaGrayscale.png'), # Image is 512x512 | |
444 '--levels=3', '--tile-width=128', '--tile-height=128' ]) | |
445 | |
446 self.assertEqual(3, len(DoGet(ORTHANC, '/instances'))) | |
447 | |
448 s = DoGet(ORTHANC, '/series') | |
449 self.assertEqual(1, len(s)) | |
450 | |
451 uri = '/wsi/iiif/tiles/%s' % s[0] | |
452 info = DoGet(ORTHANC, '%s/info.json' % uri) | |
453 self.assertEqual('http://iiif.io/api/image/3/context.json', info['@context']) | |
454 self.assertEqual('http://iiif.io/api/image', info['protocol']) | |
455 self.assertEqual('http://localhost:8042%s' % uri, info['id']) | |
456 self.assertEqual('level0', info['profile']) | |
457 self.assertEqual('ImageService3', info['type']) | |
458 self.assertEqual(512, info['width']) | |
459 self.assertEqual(512, info['height']) | |
460 | |
461 self.assertEqual(3, len(info['sizes'])) | |
462 self.assertEqual(512, info['sizes'][0]['width']) | |
463 self.assertEqual(512, info['sizes'][0]['height']) | |
464 self.assertEqual(256, info['sizes'][1]['width']) | |
465 self.assertEqual(256, info['sizes'][1]['height']) | |
466 self.assertEqual(128, info['sizes'][2]['width']) | |
467 self.assertEqual(128, info['sizes'][2]['height']) | |
468 | |
469 self.assertEqual(1, len(info['tiles'])) | |
470 self.assertEqual(128, info['tiles'][0]['width']) | |
471 self.assertEqual(128, info['tiles'][0]['height']) | |
472 self.assertEqual([ 1, 2, 4 ], info['tiles'][0]['scaleFactors']) | |
473 | |
474 # The list of URIs below was generated by "orthanc-wsi/Resources/TestIIIFTiles.py" | |
475 | |
476 # Level 0 | |
477 GetImage(ORTHANC, '/%s/0,0,128,128/128,128/0/default.jpg' % uri) | |
478 GetImage(ORTHANC, '/%s/128,0,128,128/128,128/0/default.jpg' % uri) | |
479 GetImage(ORTHANC, '/%s/256,0,128,128/128,128/0/default.jpg' % uri) | |
480 GetImage(ORTHANC, '/%s/384,0,128,128/128,128/0/default.jpg' % uri) | |
481 GetImage(ORTHANC, '/%s/0,128,128,128/128,128/0/default.jpg' % uri) | |
482 GetImage(ORTHANC, '/%s/128,128,128,128/128,128/0/default.jpg' % uri) | |
483 GetImage(ORTHANC, '/%s/256,128,128,128/128,128/0/default.jpg' % uri) | |
484 GetImage(ORTHANC, '/%s/384,128,128,128/128,128/0/default.jpg' % uri) | |
485 GetImage(ORTHANC, '/%s/0,256,128,128/128,128/0/default.jpg' % uri) | |
486 GetImage(ORTHANC, '/%s/128,256,128,128/128,128/0/default.jpg' % uri) | |
487 GetImage(ORTHANC, '/%s/256,256,128,128/128,128/0/default.jpg' % uri) | |
488 GetImage(ORTHANC, '/%s/384,256,128,128/128,128/0/default.jpg' % uri) | |
489 GetImage(ORTHANC, '/%s/0,384,128,128/128,128/0/default.jpg' % uri) | |
490 GetImage(ORTHANC, '/%s/128,384,128,128/128,128/0/default.jpg' % uri) | |
491 GetImage(ORTHANC, '/%s/256,384,128,128/128,128/0/default.jpg' % uri) | |
492 GetImage(ORTHANC, '/%s/384,384,128,128/128,128/0/default.jpg' % uri) | |
493 | |
494 # Level 1 | |
495 GetImage(ORTHANC, '/%s/0,0,256,256/128,128/0/default.jpg' % uri) | |
496 GetImage(ORTHANC, '/%s/256,0,256,256/128,128/0/default.jpg' % uri) | |
497 GetImage(ORTHANC, '/%s/0,256,256,256/128,128/0/default.jpg' % uri) | |
498 GetImage(ORTHANC, '/%s/256,256,256,256/128,128/0/default.jpg' % uri) | |
499 | |
500 # Level 2 | |
501 i = GetImage(ORTHANC, '/%s/0,0,512,512/128,128/0/default.jpg' % uri) | |
502 self.assertEqual(128, i.width) | |
503 self.assertEqual(128, i.height) | |
504 | |
505 uri2 = '/wsi/iiif/series/%s/manifest.json' % s[0] | |
506 manifest = DoGet(ORTHANC, uri2) | |
507 self.assertEqual('http://iiif.io/api/presentation/3/context.json', manifest['@context']) | |
508 self.assertEqual('http://localhost:8042%s' % uri2, manifest['id']) | |
509 | |
510 self.assertEqual(1, len(manifest['items'])) | |
511 self.assertEqual(1, len(manifest['items'][0]['items'])) | |
512 self.assertEqual(1, len(manifest['items'][0]['items'][0]['items'])) | |
513 | |
514 self.assertEqual('Manifest', manifest['type']) | |
515 self.assertEqual('Canvas', manifest['items'][0]['type']) | |
516 self.assertEqual('AnnotationPage', manifest['items'][0]['items'][0]['type']) | |
517 self.assertEqual('Annotation', manifest['items'][0]['items'][0]['items'][0]['type']) | |
518 | |
519 self.assertEqual(512, manifest['items'][0]['width']) | |
520 self.assertEqual(512, manifest['items'][0]['height']) | |
521 | |
522 body = manifest['items'][0]['items'][0]['items'][0]['body'] | |
523 self.assertEqual(1, len(body['service'])) | |
524 self.assertEqual('image/jpeg', body['format']) | |
525 self.assertEqual('Image', body['type']) | |
526 self.assertEqual(512, body['width']) | |
527 self.assertEqual(512, body['height']) | |
528 self.assertEqual('level0', body['service'][0]['profile']) | |
529 self.assertEqual('ImageService3', body['service'][0]['type']) | |
530 self.assertEqual('http://localhost:8042%s' % uri, body['service'][0]['id']) | |
531 | |
532 def test_iiif_radiology(self): | |
533 a = UploadInstance(ORTHANC, 'ColorTestMalaterre.dcm') ['ID'] | |
534 b = UploadInstance(ORTHANC, 'Multiframe.dcm') ['ID'] | |
535 c = UploadInstance(ORTHANC, 'Brainix/Epi/IM-0001-0001.dcm') ['ID'] | |
536 d = UploadInstance(ORTHANC, 'Brainix/Epi/IM-0001-0002.dcm') ['ID'] | |
537 | |
538 s1 = DoGet(ORTHANC, '/instances/%s/series' % a) ['ID'] | |
539 s2 = DoGet(ORTHANC, '/instances/%s/series' % b) ['ID'] | |
540 s3 = DoGet(ORTHANC, '/instances/%s/series' % c) ['ID'] | |
541 | |
542 manifest = DoGet(ORTHANC, '/wsi/iiif/series/%s/manifest.json' % s1) | |
543 self.assertEqual(1, len(manifest['items'])) | |
544 | |
545 manifest = DoGet(ORTHANC, '/wsi/iiif/series/%s/manifest.json' % s2) | |
546 self.assertEqual(76, len(manifest['items'])) | |
547 | |
548 manifest = DoGet(ORTHANC, '/wsi/iiif/series/%s/manifest.json' % s3) | |
549 self.assertEqual(2, len(manifest['items'])) | |
550 | |
551 for (i, width, height) in [ (a, 41, 41), | |
552 (b, 512, 512), | |
553 (c, 256, 256), | |
554 (d, 256, 256) ]: | |
555 uri = '/wsi/iiif/frames/%s/0' % i | |
556 info = DoGet(ORTHANC, uri + '/info.json') | |
557 self.assertEqual(8, len(info)) | |
558 self.assertEqual('http://iiif.io/api/image/3/context.json', info['@context']) | |
559 self.assertEqual('http://iiif.io/api/image', info['protocol']) | |
560 self.assertEqual('http://localhost:8042%s' % uri, info['id']) | |
561 self.assertEqual('level0', info['profile']) | |
562 self.assertEqual('ImageService3', info['type']) | |
563 self.assertEqual(width, info['width']) | |
564 self.assertEqual(height, info['height']) | |
565 self.assertEqual(1, len(info['tiles'])) | |
566 self.assertEqual(3, len(info['tiles'][0])) | |
567 self.assertEqual(width, info['tiles'][0]['width']) | |
568 self.assertEqual(height, info['tiles'][0]['height']) | |
569 self.assertEqual([ 1 ], info['tiles'][0]['scaleFactors']) | |
570 | |
365 try: | 571 try: |
366 print('\nStarting the tests...') | 572 print('\nStarting the tests...') |
367 unittest.main(argv = [ sys.argv[0] ] + args.options) | 573 unittest.main(argv = [ sys.argv[0] ] + args.options) |
368 | 574 |
369 finally: | 575 finally: |