You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

lungsegmentation.py 5.6 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. """
  2. /**
  3. * Copyright 2020 Tianshu AI Platform. All Rights Reserved.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. * =============================================================
  17. */
  18. """
  19. #!/usr/bin/env python3
  20. # -*- coding: utf-8 -*-
  21. import sched
  22. import sys
  23. sys.path.append("../../")
  24. import logging
  25. import time
  26. import json
  27. import numpy as np
  28. import luascript.delaytaskscript as delay_script
  29. import common.config as config
  30. from datetime import datetime
  31. from skimage.morphology import disk, binary_erosion, binary_closing
  32. from skimage.measure import label,regionprops, find_contours
  33. from skimage.filters import roberts
  34. from scipy import ndimage as ndi
  35. from skimage.segmentation import clear_border
  36. import pydicom as dicom
  37. import os
  38. import logging
  39. schedule = sched.scheduler(time.time, time.sleep)
  40. base_path = "/nfs/"
  41. delayId = ""
  42. def process(task_dict, key):
  43. """Lung segmentation based on dcm task method.
  44. Args:
  45. task_dict: imagenet task details.
  46. key: imagenet task key.
  47. """
  48. global delayId
  49. delayId = "\"" + eval(str(key, encoding="utf-8")) + "\""
  50. task_dict = json.loads(task_dict)
  51. base_path = task_dict["annotationPath"]
  52. if not os.path.exists(base_path):
  53. logging.info("make annotation path.")
  54. os.makedirs(base_path)
  55. for dcm in task_dict["dcms"]:
  56. image, image_path = preprocesss_dcm_image(dcm)
  57. # segmentation and wirte coutours to result_path
  58. result_path = os.path.join(base_path, image_path)
  59. contour(segmentation(image), result_path)
  60. logging.info("all dcms in one task are processed.")
  61. return True
  62. def preprocesss_dcm_image(path):
  63. """Load and preprocesss dcm image.
  64. Args:
  65. path: dcm file path.
  66. """
  67. # result_path = os.path.basename(path).split(".", 1)[0] + ".json"
  68. result_path = ".".join(os.path.basename(path).split(".")[0:-1]) + ".json"
  69. dcm = dicom.dcmread(path)
  70. image = dcm.pixel_array.astype(np.int16)
  71. # Set outside-of-scan pixels to 0.
  72. image[image == -2000] = 0
  73. # Convert to Hounsfield units (HU)
  74. intercept = dcm.RescaleIntercept
  75. slope = dcm.RescaleSlope
  76. if slope != 1:
  77. image = slope * image.astype(np.float64)
  78. image = image.astype(np.int16)
  79. image += np.int16(intercept)
  80. logging.info("preprocesss_dcm_image done.")
  81. return np.array(image, dtype=np.int16), result_path
  82. def segmentation(image):
  83. """Segments the lung from the given 2D slice.
  84. Args:
  85. image: single image in one dcm.
  86. """
  87. # Step 1: Convert into a binary image.
  88. binary = image < -350
  89. # Step 2: Remove the blobs connected to the border of the image.
  90. cleared = clear_border(binary)
  91. # Step 3: Label the image.
  92. label_image = label(cleared)
  93. # Step 4: Keep the labels with 2 largest areas.
  94. areas = [r.area for r in regionprops(label_image)]
  95. areas.sort()
  96. if len(areas) > 2:
  97. for region in regionprops(label_image):
  98. if region.area < areas[-2]:
  99. for coordinates in region.coords:
  100. label_image[coordinates[0], coordinates[1]] = 0
  101. binary = label_image > 0
  102. # Step 5: Erosion operation with a disk of radius 2. This operation is seperate the lung nodules attached to the blood vessels.
  103. selem = disk(1)
  104. binary = binary_erosion(binary, selem)
  105. # Step 6: Closure operation with a disk of radius 10. This operation is to keep nodules attached to the lung wall.
  106. selem = disk(16)
  107. binary = binary_closing(binary, selem)
  108. # Step 7: Fill in the small holes inside the binary mask of lungs.
  109. for _ in range(3):
  110. edges = roberts(binary)
  111. binary = ndi.binary_fill_holes(edges)
  112. logging.info("lung segmentation done.")
  113. return binary
  114. def contour(image, path):
  115. """Get contours of segmentation.
  116. Args:
  117. seg: segmentation of lung.
  118. """
  119. result = []
  120. contours = find_contours(image, 0.5)
  121. if len(contours) > 2:
  122. contours.sort(key = lambda x: int(x.shape[0]))
  123. contours = contours[-2:]
  124. for n, contour in enumerate(contours):
  125. # result.append({"type":n, "annotation":contour.tolist()})
  126. result.append({"type":n, "annotation":np.flip(contour, 1).tolist()})
  127. # write json
  128. with open(path, 'w') as f:
  129. json.dump(result, f)
  130. logging.info("write {} done.".format(path))
  131. def delaySchduled(inc, redisClient):
  132. """Delay task method.
  133. Args:
  134. inc: scheduled task time.
  135. redisClient: redis client.
  136. """
  137. try:
  138. print("delay:" + datetime.now().strftime("B%Y-%m-%d %H:%M:%S"))
  139. redisClient.eval(delay_script.delayTaskLua, 1, config.dcmStartQueue, delayId, int(time.time()))
  140. schedule.enter(inc, 0, delaySchduled, (inc, redisClient))
  141. except Exception as e:
  142. print("delay error" + e)
  143. def delayKeyThread(redisClient):
  144. """Delay task thread.
  145. Args:
  146. redisClient: redis client.
  147. """
  148. schedule.enter(0, 0, delaySchduled, (5, redisClient))
  149. schedule.run()

一站式算法开发平台、高性能分布式深度学习框架、先进算法模型库、视觉模型炼知平台、数据可视化分析平台等一系列平台及工具,在模型高效分布式训练、数据处理和可视分析、模型炼知和轻量化等技术上形成独特优势,目前已在产学研等各领域近千家单位及个人提供AI应用赋能

Contributors (1)