Source code for brain_feature_extractor.BrainFeatureExtractorGMM
import numpy as np
import pandas as pd
import cv2
import pydicom
import time
from brain_feature_extractor.ExtractorGMM import ExtractorGMM
[docs]class BrainFeatureExtractorGMM:
"""
The instance extracts features related to brain regions from an entire brain scan.
The features represent the segmentation of the brain in the regions defined in the configuration file.
:param percentage: Input image reduction percentage.
:type percentage: float
:param pixel_level_feature: If true, the segmentation returns the brain region of each pixel (MGABTD-pixel extractor).
If false returns the percentage of pixels in each brain region (MGABTD-percent).
:type pixel_level_feature: bool
"""
def __init__(self, percentage: float = 0.3, pixel_level_feature: bool = False):
self.percentage = percentage
self.pixel_level_feature = pixel_level_feature
def _load_dcm(self, img_path: str):
"""
Loading a DICOM image of a brain scan.
:param img_path: Local path with DICOM file.
:type img_path: str
:return: Array with the radiodensities of the DICOM image.
:rtype: np.array
"""
dcm = pydicom.read_file(img_path)
rescale_intercept = int(dcm.data_element('RescaleIntercept').value)
img = np.array(dcm.pixel_array, dtype=np.int16) + rescale_intercept
return img
def _extract_brain(self, src: np.array, inf_limit: int = 0, sup_limit: int = 100):
"""
Removing the skull from the brain CT scan.
:param src: Array with the radiodensities of the DICOM image.
:type src: np.array
:param sup_limit: Upper limit of Hounsfield Units (HU) that will be considered the skull region.
:type sup_limit: int
:param inf_limit: Lower limit of Hounsfield Units (HU) that will be considered the skull region.
:type inf_limit: np.array
:return: Array with the radiodensities of the DICOM image without the skull region.
:rtype: np.array
"""
# Restrict the HU values to be between 0 and 255
brain_image = np.where(src < inf_limit, 0, src)
new_img = np.where(brain_image > sup_limit, 255, brain_image)
# Get only the skull
img = np.asarray(new_img, np.uint8)
binary_image = np.where(img != 255, 0, img)
# Remove the skull from the original image
new_img = np.where(binary_image == 255, 0, new_img)
new_img = np.where(new_img > sup_limit, 0, new_img)
# Apply threshold
ret, binary_image = cv2.threshold(new_img, 0, 255, cv2.THRESH_BINARY)
binary_image = np.asarray(binary_image, np.uint8)
# Get the binaryImage biggest component
connectivity = 4
_, labels, stats, centroids = cv2.connectedComponentsWithStats(binary_image, connectivity, cv2.CV_8U)
img_max = np.zeros(binary_image.shape, binary_image.dtype)
large_component = 1 + stats[1:, cv2.CC_STAT_AREA].argmax()
img_max[labels == large_component] = 255
img_max[labels != large_component] = 0
# Compare the biggest component with the original image and get only the intersection
output = np.where(img_max == 255, src, 0)
return output
[docs] def extract_features(self, path, verbose=False):
""" Extract features of brain regions from a brain tomography DICOM file. """
brain_image = self._load_dcm(path)
new_img = self._extract_brain(brain_image, inf_limit=0, sup_limit=120)
new_img = cv2.resize(new_img, (0, 0), fx=self.percentage, fy=self.percentage)
left_img = new_img[0:new_img.shape[0], 0:int(new_img.shape[1] / 2)]
right_img = new_img[0:new_img.shape[0], int(new_img.shape[1] / 2):int(new_img.shape[1])]
init_time = time.time()
left_extractor = ExtractorGMM(left_img, self.pixel_level_feature)
right_extractor = ExtractorGMM(right_img, self.pixel_level_feature)
left_feat = left_extractor.segmentation()
right_feat = right_extractor.segmentation()
final_time = time.time() - init_time
if verbose:
print(f'Extract feature of {path} - TIME: {round(final_time, 2)}, seconds ...')
features = left_feat + right_feat
return [round(feat, 6) for feat in features]