Example #1
0
def process(img_mtx, dataset):
    img_mtx = apply_modality_lut(img_mtx, dataset)
    p1, p99 = np.percentile(img_mtx, (1, 99))
    img_mtx[img_mtx < p1] = p1
    img_mtx[img_mtx > p99] = p99
    img_mtx = (img_mtx - p1) / (p99 - p1)
    return img_mtx
Example #2
0
    def get_image(self, group, i, slices, clear_cache=True):
        x = torch.zeros(slices, 512, 512, dtype=torch.uint8)  # (C, H, W)
        rows = self.get_slices(group, i, slices)
        #sop_uids = np.empty([slices], dtype=np.dtype('U12'))
        sop_uids = []
        for j, (idx, row) in enumerate(rows.iterrows()):
            if row.SOPInstanceUID not in self.cache:
                p = test_dir / 'test' / row.StudyInstanceUID / row.SeriesInstanceUID / f'{row.SOPInstanceUID}.dcm'
                dcm = pydicom.dcmread(str(p))
                a = apply_modality_lut(dcm.pixel_array, dcm).astype(
                    np.float32)  # TODO: to float32 if memory runs out?
                t = torch.from_numpy(a)
                if t.shape != (384, 384):
                    t = t.view(1, 1, *t.shape)  # HW -> BCHW
                    t = torch.nn.functional.interpolate(
                        t, size=512,
                        mode='nearest')  # resize (FloatTensors only!)
                    t = t.view(t.shape[-2:])  # BCHW -> HW
                ww, wc = h.window
                w0, w1 = wc - ww / 2, wc + ww / 2
                t = torch.clamp(t, w0, w1)  # window
                t = (t - w0) * 255. / ww  # normalize
                self.cache[row.SOPInstanceUID] = t.to(torch.uint8)
            x[j] = self.cache[row.SOPInstanceUID]
            #sop_uids[j] = row.SOPInstanceUID
            sop_uids.append(row.SOPInstanceUID)

        if clear_cache:
            self.cache = {}

        return x, sop_uids
Example #3
0
def read_dcm(path):
    dcm = pydicom.read_file(path)
    img = apply_voi_lut(apply_modality_lut(dcm.pixel_array, dcm), dcm)
    img = ((img - img.min()) / (img.max() - img.min()) * 255).astype(np.uint8)
    img = np.invert(img)
    if len(img.shape) < 3:
        img = np.repeat(img[..., None], 3, axis=-1)
    return img
 def read_dicom_image(self, img_name, invert):
     dcm = pydicom.read_file(img_name)
     img = apply_voi_lut(apply_modality_lut(dcm.pixel_array, dcm), dcm)
     img = ((img - img.min()) / (img.max() - img.min()) * 255).astype(
         np.uint8)
     if invert != None:
         img = np.invert(img)
     img = np.expand_dims(img, axis=-1)
     return img
Example #5
0
def dcm2png(path):
    dcm = pydicom.read_file(path)
    # extracting image (pixels data)
    img = apply_voi_lut(apply_modality_lut(dcm.pixel_array, dcm), dcm)
    if not (("PhotometricInterpretation" in dcm) and
            (dcm.PhotometricInterpretation == 'MONOCHROME2')):
        img = np.invert(img)
    img -= img.min()
    img = img / img.max()
    img = (img * 255)
    img = img.astype(np.uint8)
    path = str(path) + '.png'
    plt.imsave(path, img)
    return path
Example #6
0
    def __getitem__(self, index):
        path_to_folder = os.path.join(self.root_dir, self.case_ids[index])
        files = []

        for r, d, f in os.walk(path_to_folder):
            for file in f:
                if '.dcm' in file:
                    files.append(os.path.join(r, file))

        ct_scan = np.zeros(shape=(512, 512, len(files)))

        for file in files:
            dataset = pydicom.dcmread(file)
            pixel_array = dataset.pixel_array
            hu = apply_modality_lut(pixel_array, dataset)
            ct_scan[:, :, dataset.InstanceNumber - 1] = hu

        ct_scan = torch.from_numpy(ct_scan).float()

        # Resize to 224 by 224 and only take 1 out of 5 elements on the Z axis into account
        ct_scan = F.interpolate(ct_scan[None, None, ...],
                                size=(224, 224, ct_scan.shape[-1] // 5),
                                align_corners=True,
                                mode='trilinear')
        ct_scan = ct_scan.squeeze(0).squeeze(0)
        torch.clamp(ct_scan, min=-500, max=1500, out=ct_scan)

        ct_scan = ct_scan[None, ...]
        if self.stage == 'train' and self.args.data_augment:
            # Default randomly mirroring the second and third axes
            ct_scan, _ = spatial_transforms.augment_mirroring(ct_scan,
                                                              axes=(1, 2))
        ct_scan = ct_scan[0]

        ######################################################
        #  Preprocessing for both train and validation data  #
        ######################################################
        # data should be a numpy array with shape [x, y, z] or [c, x, y, z]
        full_channel = np.stack([ct_scan, ct_scan, ct_scan])
        full_channel = (full_channel - full_channel.min()) / (
            full_channel.max() - full_channel.min())

        if self.stage == 'train' and self.args.data_augment:
            full_channel = self.do_augmentation(full_channel)

        label = self.mapping[self.labels[index]]
        full_channel = np.transpose(full_channel, axes=(3, 0, 1, 2))
        full_channel = torch.from_numpy(full_channel).float()

        return full_channel, label, self.case_ids[index]
Example #7
0
def get_grayscale_from_FileDataset(dicomfile):
    """
    Function converts pixel array of dicom file to grayscale and returns is.
    Before conversion Modality LUT operation is applied.
    :param dicomfile: object pydicom.dataset.FileDataset
    :return: numpy array in grayscale
    """
    # Get pixel array
    image = dicomfile.pixel_array
    # Apply Modality LUT or Rescale Operation
    hu = apply_modality_lut(image, dicomfile)
    # Apply conversion to grayscale
    image_gray = convert_array_to_grayscale(hu)

    return image_gray
Example #8
0
    def __init__(self, folder_name):
        '''
        Reads in the dcm files in a folder which corresponds to a patient.
        It follows carefully the physical slice locations and the frames in a hearth cycle.
        It does not matter if the location is getting higher or lower. 
        '''
        self.images_unordered = list(
        )  # contains the images and additional data_processing

        dcm_files = os.listdir(folder_name)
        for dcm_fl in dcm_files:
            # ignore if not a dcm file
            if not dcm_fl.endswith('.dcm'):
                continue
            # read the image
            path = os.path.join(folder_name, dcm_fl)
            try:
                dcm = dicom.dcmread(path, force=True)
            except InvalidDicomError:
                logger.error("Invalid dicom {}".format(path))
                continue  # if no valid dcm continue with the next file
            # access the required fields
            try:
                _, _, pos_z = self.__get_dcmdata(dcm, "ImagePositionPatient")
                timestamp = self.__get_dcmdata(dcm, "ContentTime")
                image_pixels = dcm.pixel_array  # to get a numpy array
            except AttributeError as ex:
                logger.error(
                    "Accessing elements in dcm file {} yielded: {}".format(
                        path, ex))
                continue
            # modality transformation on pixels (mainly for Philips)
            image = apply_modality_lut(image_pixels, dcm)
            # sequence is ordered according to ImagePatientPosition
            data = (pos_z, timestamp, image)
            self.images_unordered.append(data)
        # ordering the images
        _images_ = sorted(self.images_unordered,
                          key=lambda data: data[0])  # apex to base
        _images_ = self.__group_frames(_images_)
        self.__order_frames(_images_)
        # create the image dictionary
        self.images = list()
        for group in _images_:
            img_in_slice = []
            for data in group:
                img_in_slice.append(data[2])
            self.images.append(img_in_slice)
Example #9
0
def get_array_dicom_lut(file, folder):
    """
    Function reads given dicom file and applies LUT modality operation
    in order to get pixel values in Hounsfield units.
    :param file: name of dicom file
    :param folder: source folder of dicom file
    :return: array of pixel data
    """
    path = Path(folder) / file
    # Get dicom file
    dicomfile = pydicom.dcmread(path)
    # Get pixel array
    image = dicomfile.pixel_array
    # Apply Modality LUT or Rescale Operation
    hu = apply_modality_lut(image, dicomfile)

    return hu
Example #10
0
def dicom2narray(path, voi_lut = False, fix_monochrome = True):
    """
    Converts a DICOM into a NUMPY array and returns this array and 
    its corresponding dataset.
    """
    dicom = pydicom.read_file(path)

    # VOI LUT (if available by DICOM device) is used to transform raw DICOM data
    # to "human-friendly" view 
    if voi_lut:
        # If the modality is CT (Scanner Image) we have to convert the values of 
        # the image first with apply_modality
        # It uses the values of RescaleSlope and RescaleIntercept to convert the 
        # values or the attribute LUT Sequence
        if dicom.Modality == "CT":
            data = apply_modality_lut(dicom.pixel_array, dicom)
            data = apply_voi_lut(data, dicom)
        else:
            data = apply_voi_lut(dicom.pixel_array, dicom)
    else:
        data = dicom.pixel_array

    # depending on this value, X-ray may look inverted - fix that:
    if fix_monochrome and dicom.PhotometricInterpretation == "MONOCHROME1":
        data = np.amax(data) - data

    #If the DICOM are not in one of these two formats, it can bring new problems.
    if dicom.PhotometricInterpretation != "MONOCHROME2" and \
        dicom.PhotometricInterpretation != "MONOCHROME1":
        warnings.warn("PhotometricInterpretation " + 
        dicom.PhotometricInterpretation + " can cause unexpected behaviors.\n" +
        "File concerned : " + path)
        
    data = data - np.min(data)
    data = data / np.max(data)
    data = (data * 255).astype(np.uint8)
    
    return (data, dicom)
Example #11
0
def extract(image_name):

    ending = image_name.split('.')[-1]

    if (ending == 'dcm'):  #dicom ct image
        dataset = pydicom.dcmread(image_name)
        hu = apply_modality_lut(dataset.pixel_array, dataset)

        density = (dataset.RescaleIntercept +
                   dataset.RescaleSlope * hu) / 1000 + 1
        (spacingX, spacingY) = dataset.PixelSpacing
        (sizeX, sizeY) = density.shape
        dimensions = (spacingX * sizeX, spacingY * sizeY)
        return density, dimensions

    else:  # jpg or png
        img = Image.open(image_name).convert('L')  #image data
        I = np.asarray(img)  # image as greyscale
        I = I / 255
        # rescale values to [0,1]
        J = deepcopy(np.flipud(I))
        dimensions = (1, 1)  # [cm]
        return J, dimensions
Example #12
0
def check_dicom_lut_windowing(file, folder):
    """
    Function applies LUT Modality and VOI Modality functions.
    :param file: source dicom filename
    :param folder: source folder
    :return: numpy array
    """
    raise NotImplementedError("Needs to be checked")
    path = Path(folder) / file
    # Get dicom file
    dicomfile = pydicom.dcmread(path)
    # Get pixel array
    image = dicomfile.pixel_array
    # Apply Modality LUT or Rescale Operation
    hu = apply_modality_lut(image, dicomfile)
    width = dicomfile.WindowWidth
    center = dicomfile.WindowCenter
    lower_bound = int(center - width / 2)
    upper_bound = int(center + width / 2)
    array = hu
    array = np.where(array < lower_bound, lower_bound, array)
    array = np.where(array > upper_bound, upper_bound, array)

    return array
Example #13
0
def process_image(image, dataset):
    preproc = apply_modality_lut(image, dataset)
    perc_cut = percentile_cut(preproc)
    return rescale(perc_cut)
Example #14
0
# Specify the .dcm folder path
folder_path = "stage_1_test_images"

# Specify the output jpg/png/tiff folder path
jpg_path = "JPG_test"
png_path = "PNG_test"
tiff_path = "TIFF_test"
images_path = os.listdir(folder_path)

for n, image in enumerate(images_path):
    ds = dicom.dcmread(os.path.join(folder_path, image))
    arr = ds.pixel_array
    if choose == 1:
        image = image.replace('.dcm', '.jpg')
        # apply modality
        arr = util.apply_modality_lut(arr, ds)
        arr = util.apply_voi_lut(arr, ds, index=0)

        cv2.imwrite(os.path.join(jpg_path, image), arr)

    elif choose == 2:
        image = image.replace('.dcm', '.png')
        shape = ds.pixel_array.shape

        # Convert to float to avoid overflow or underflow losses.
        image_2d = ds.pixel_array.astype(float)

        # Rescaling grey scale between 0-255
        image_2d_scaled = (np.maximum(image_2d,0) / image_2d.max()) * 255.0

        # Convert to uint
Example #15
0
 def get_hounsfield(self):
     hu = apply_modality_lut(self.image_data.pixel_array, self.image_data)
     return hu
Example #16
0
def get_manufacturer_independent_pixel_image2d_array(ds, has_TransferSyntax):

    # '1.2.840.10008.1.2.4.90'  #
    # ds.file_meta.TransferSyntaxUID = '1.2.840.10008.1.2.4.99'  # '1.2.840.10008.1.2.1.99'
    # has_TransferSyntax = True
    # print(f"syntax:{ds.file_meta.TransferSyntaxUID}")

    # RLE 1.2.840.10008.1.2.5:  US-PAL-8-10x-echo.dcm is automatically handled as uncompressed case
    if (has_TransferSyntax and ds.file_meta.TransferSyntaxUID in [
            "1.2.840.10008.1.2.4.50", "1.2.840.10008.1.2.4.51",
            "1.2.840.10008.1.2.4.57", "1.2.840.10008.1.2.4.70",
            "1.2.840.10008.1.2.4.80", "1.2.840.10008.1.2.4.81",
            "1.2.840.10008.1.2.4.90", "1.2.840.10008.1.2.4.91"
    ]):
        print("compressed case !!!!!!!!!")

        # return None, ds.PixelData
        # ref: https://github.com/pydicom/pydicom/blob/master/pydicom/pixel_data_handlers/pillow_handler.py
        print(
            "try to get compressed dicom's pixel data manually, can not handle by pydicom in pyodide, lack of some pyodide extension"
        )
        try:
            print(f"pixeldata:{len(ds.PixelData)}")

            # TODO: only get 1st frame for multiple frame case and will improve later
            if getattr(ds, 'NumberOfFrames', 1) > 1:
                print("multi frame")
                j2k_precision, j2k_sign = None, None
                # multiple compressed frames
                # working case (50):
                # 1. 0002.dcm, some are [-5], [-4], [-6]. 512x512
                # 2. color3d_jpeg_baseline , some frames needs [-1] but some do not need. size unknown?
                frame_count = 0
                for frame in decode_data_sequence(ds.PixelData):
                    frame_count += 1
                    # print(f"frame i:{frame_count}, len:{len(frame)}")
                    # a = frame[0]
                    # b = frame[1]
                    # c = frame[len(frame)-2]
                    # d = frame[len(frame)-1]
                    # print(f"{a},{b},{c},{d}")
                    if frame_count == 1:
                        pixel_data = frame
                    # im = _decompress_single_frame(
                    #     frame,
                    #     transfer_syntax,
                    #     ds.PhotometricInterpretation
                    # )
                    # if 'YBR' in ds.PhotometricInterpretation:
                    #     im.draft('YCbCr', (ds.Rows, ds.Columns))
                    # pixel_bytes.extend(im.tobytes())

                    # if not j2k_precision:
                    #     params = get_j2k_parameters(frame)
                    #     j2k_precision = params.setdefault("precision", ds.BitsStored)
                    #     j2k_sign = params.setdefault("is_signed", None)
                # TODO: what is the rule of -5/-1? But even not using pixel_data[:-1], pixel_data[:-5], still work
                p2 = pixel_data
            else:
                print("single frame")
                # working case but browser can not render :
                # - JPGLosslessP14SV1_1s_1f_8b.dcm,  DICOM made JPEG Lossless, 1.2.840.10008.1.2.4.70. 1024x768. local mac is able to view.
                # - JPEG57-MR-MONO2-12-shoulder.dcm from https://barre.dev/medical/samples/, JPEG Lossless, 1.2.840.10008.1.2.4.57.
                #   https://products.groupdocs.app/viewer/jpg can be used to view. local mac seeme not able to view (all black)
                # - JPEG-lossy.dcm 1.2.840.10008.1.2.4.51 from https://github.com/pydicom/pydicom/blob/master/pydicom/data/test_files/JPEG-lossy.dcm,
                #   https://products.groupdocs.app/viewer/jpg can be used to view, local mac seems not able to view (all black)

                pixel_data = defragment_data(ds.PixelData)
                p2 = pixel_data
            print(f"pixel_data:{len(pixel_data)}")
            # return None, pixel_data

            # try:
            #     fio = BytesIO(ds.PixelData)  # pixel_data)
            #     image = Image.open(fio)
            # except Exception as e:
            #     print(f"pillow error:{e}")

            # print('pillow done')
            # JPEG57-MR-MONO2-12-shoulder data:718940 -> data:718924
            return None, p2
        except Exception as e:
            print("failed to get compressed data")
            raise e

    print("incompressed")
    print(
        "start reading dicom pixel_array, uncompressed case uses apply_modality_lut"
    )

    try:
        arr = ds.pixel_array
    except Exception as e:
        if has_TransferSyntax == True:
            raise e
        else:
            # http://dicom.nema.org/dicom/2013/output/chtml/part05/chapter_10.html
            print(
                "read data fail may due to no TransferSyntaxUID, set it as most often used and default ImplicitVRLittleEndian and try read dicom again"
            )
            ds.file_meta.TransferSyntaxUID = pydicom.uid.ImplicitVRLittleEndian
            arr = ds.pixel_array
    print(f"read dicom pixel_array ok, shape:{arr.shape}")
    image2d = apply_modality_lut(arr, ds)
    return image2d, None
Example #17
0
    def __init__(self, folder_name):
        '''
        Reads in the dcm files in a folder which corresponds to a patient.
        It follows carefully the physical slice locations and the frames in a hearth cycle.
        It does not matter if the location is getting higher or lower. 
        '''
        self.num_slices = 0
        self.num_frames = 0
        self.broken = False
        self.pixel_spacing = 0  # UPDATE: pixel spacing
        images = []
        slice_locations = []
        file_paths = []

        dcm_files = sorted(os.listdir(folder_name))
        dcm_files = [d for d in dcm_files if len(d.split('.')[-2]) < 4]
        if len(dcm_files
               ) == 0:  # sometimes the order number is missing at the end
            dcm_files = sorted(os.listdir(folder_name))

        for file in dcm_files:

            if file.find('.dcm') != -1:
                try:
                    temp_ds = dicom.dcmread(os.path.join(folder_name, file))
                    images.append(
                        apply_modality_lut(
                            temp_ds.pixel_array,
                            temp_ds))  # UPDATE: apply modality lut
                    slice_locations.append(temp_ds.SliceLocation)
                    file_paths.append(os.path.join(folder_name, file))
                    if self.pixel_spacing == 0:
                        self.pixel_spacing = temp_ds.PixelSpacing  # UPDATE: pixel spacing

                except:
                    self.broken = True
                    return

        current_sl = -1
        frames = 0
        increasing = False
        indices = []
        for idx, slice_loc in enumerate(slice_locations):
            if abs(slice_loc -
                   current_sl) > 0.01:  # this means a new slice is started
                self.num_slices += 1
                self.num_frames = max(self.num_frames, frames)
                frames = 0
                indices.append(idx)

                if (slice_loc - current_sl) > 0.01:
                    increasing = True
                else:
                    increasing = False

                current_sl = slice_loc
            frames += 1

        if self.num_slices != 0 and self.num_frames != 0:
            self.load_matrices(images, indices, increasing, slice_locations,
                               file_paths)
        else:
            logger.warning(
                "There are no frames. This folder should be deleted. Path: {}".
                format(folder_name))
        self.num_images = len(images)