コード例 #1
0
ファイル: test_meta.py プロジェクト: jerrylee9310/paperStudy
def test_serialize():
    meta = ismrmrd.Meta(META)
    xml = meta.serialize()

    root = ET.fromstring(xml)
    assert root.tag == 'ismrmrdMeta'
    children = root.findall('meta')

    # check that all expected Name-Value pairs can be found
    for k, v in META.items():
        values = None
        for child in children:
            name = child.find('name')
            assert name is not None
            _values = child.findall('value')
            assert _values is not None
            if name.text == k:
                # found! sort it for later!
                values = [x.text for x in _values]
                break

        assert values is not None

        # make the META value a list
        if type(v) != list:
            v = [v]
        # sort both lists for simpler comparison
        v = sorted([str(x) for x in v])
        values = sorted(values)
        assert v == values
コード例 #2
0
 def put_next(self, *args):
     if self.next_gadget is not None:
         if isinstance(self.next_gadget, Gadget):
             if len(args) == 3 and not isinstance(
                     args[2], ismrmrd.Meta):  #Data with meta data we assume
                 meta = ismrmrd.Meta()
                 meta = ismrmrd.Meta.deserialize(args[2])
                 new_args = (args[0], args[1], meta)
                 self.next_gadget.process(*new_args)
             else:
                 self.next_gadget.process(*args)
         elif isinstance(self.next_gadget,
                         GadgetronPythonMRI.GadgetReference):
             if len(args) > 3:
                 raise Exception(
                     "Only two or 3 return arguments are currently supported when returning to Gadgetron framework"
                 )
             if isinstance(args[0], ismrmrd.AcquisitionHeader):
                 self.next_gadget.return_acquisition(
                     args[0], args[1].astype('complex64'))
             elif isinstance(args[0], IsmrmrdImageArray):
                 self.next_gadget.return_ismrmrd_image_array(args[0])
             elif isinstance(args[0], ismrmrd.ImageHeader):
                 header = args[0]
                 if (args[1].dtype == np.uint16):
                     if len(args) == 3:
                         self.next_gadget.return_image_ushort_attr(
                             header, args[1], args[2].serialize())
                     else:
                         self.next_gadget.return_image_ushort(
                             header, args[1])
                 elif (args[1].dtype == np.float32):
                     if len(args) == 3:
                         self.next_gadget.return_image_float_attr(
                             header, args[1], args[2].serialize())
                     else:
                         self.next_gadget.return_image_float(
                             header, args[1])
                 else:
                     if len(args) == 3:
                         self.next_gadget.return_image_cplx_attr(
                             header, args[1].astype('complex64'),
                             args[2].serialize())
                     else:
                         self.next_gadget.return_image_cplx(
                             header, args[1].astype('complex64'))
             elif len(args[0]) > 0 and isinstance(args[0][0],
                                                  IsmrmrdReconBit):
                 self.next_gadget.return_recondata(args[0])
             else:
                 raise (
                     "Unsupported types when returning to Gadgetron framework"
                 )
         else:
             raise ("next_gadget is set to unsupported type")
     else:
         self.results.append(list(args))
コード例 #3
0
def process_group(group, config, metadata):
    # Create folder, if necessary
    if not os.path.exists(debugFolder):
        os.makedirs(debugFolder)
        logging.debug("Created folder " + debugFolder +
                      " for debug output files")

    # Format data into single [cha RO PE] array
    data = [acquisition.data for acquisition in group]
    data = np.stack(data, axis=-1)

    logging.debug("Raw data is size %s" % (data.shape, ))
    np.save(debugFolder + "/" + "raw.npy", data)

    # Fourier Transform
    data = fft.fftshift(data, axes=(1, 2))
    data = fft.ifft2(data)
    data = fft.ifftshift(data, axes=(1, 2))

    # Sum of squares coil combination
    data = np.abs(data)
    data = np.square(data)
    data = np.sum(data, axis=0)
    data = np.sqrt(data)

    logging.debug("Image data is size %s" % (data.shape, ))
    np.save(debugFolder + "/" + "img.npy", data)

    # Normalize and convert to int16
    data *= 32767 / data.max()
    data = np.around(data)
    data = data.astype(np.int16)

    # Remove phase oversampling
    nRO = np.size(data, 0)
    data = data[int(nRO / 4):int(nRO * 3 / 4), :]
    logging.debug("Image without oversampling is size %s" % (data.shape, ))
    np.save(debugFolder + "/" + "imgCrop.npy", data)

    # Format as ISMRMRD image data
    image = ismrmrd.Image.from_array(data, acquisition=group[0])
    image.image_index = 1

    # Set ISMRMRD Meta Attributes
    meta = ismrmrd.Meta({
        'DataRole': 'Image',
        'ImageProcessingHistory': ['FIRE', 'PYTHON'],
        'WindowCenter': '16384',
        'WindowWidth': '32768'
    })
    xml = meta.serialize()
    logging.debug("Image MetaAttributes: %s", xml)
    logging.debug("Image data has %d elements", image.data.size)

    image.attribute_string = xml
    return image
コード例 #4
0
def process_image(image, config, metadata):
    # Create folder, if necessary
    if not os.path.exists(debugFolder):
        os.makedirs(debugFolder)
        logging.debug("Created folder " + debugFolder +
                      " for debug output files")

    logging.debug("Incoming image data of type %s",
                  ismrmrd.get_dtype_from_data_type(image.data_type))

    # Extract image data itself
    data = image.data
    logging.debug("Original image data is size %s" % (data.shape, ))
    np.save(debugFolder + "/" + "imgOrig.npy", data)

    # Normalize and convert to int16
    data = data.astype(np.float64)
    data *= 32767 / data.max()
    data = np.around(data)
    data = data.astype(np.int16)

    # Invert image contrast
    data = 32767 - data
    data = np.abs(data)
    data = data.astype(np.int16)
    np.save(debugFolder + "/" + "imgInverted.npy", data)

    # Create new MRD instance for the inverted image
    imageInverted = ismrmrd.Image.from_array(data.transpose())
    data_type = imageInverted.data_type

    np.save(debugFolder + "/" + "imgInvertedMrd.npy", imageInverted.data)

    # Copy the fixed header information
    oldHeader = image.getHead()
    oldHeader.data_type = data_type
    imageInverted.setHead(oldHeader)

    # Set ISMRMRD Meta Attributes
    meta = ismrmrd.Meta({
        'DataRole': 'Image',
        'ImageProcessingHistory': ['FIRE', 'PYTHON'],
        'WindowCenter': '16384',
        'WindowWidth': '32768'
    })
    xml = meta.serialize()
    logging.debug("Image MetaAttributes: %s", xml)
    logging.debug("Image data has %d elements", image.data.size)

    imageInverted.attribute_string = xml

    return imageInverted
コード例 #5
0
def process_raw(group, connection, config, metadata):
    # Start timer
    tic = perf_counter()

    # Create folder, if necessary
    if not os.path.exists(debugFolder):
        os.makedirs(debugFolder)
        logging.debug("Created folder " + debugFolder +
                      " for debug output files")

    # Format data into single [cha PE RO phs] array
    lin = [acquisition.idx.kspace_encode_step_1 for acquisition in group]
    phs = [acquisition.idx.phase for acquisition in group]

    # Use the zero-padded matrix size
    data = np.zeros(
        (group[0].data.shape[0],
         metadata.encoding[0].encodedSpace.matrixSize.y,
         metadata.encoding[0].encodedSpace.matrixSize.x, max(phs) + 1),
        group[0].data.dtype)

    rawHead = [None] * (max(phs) + 1)

    for acq, lin, phs in zip(group, lin, phs):
        if (lin < data.shape[1]) and (phs < data.shape[3]):
            # TODO: Account for asymmetric echo in a better way
            data[:, lin, -acq.data.shape[1]:, phs] = acq.data

            # center line of k-space is encoded in user[5]
            if (rawHead[phs] is
                    None) or (np.abs(acq.getHead().idx.kspace_encode_step_1 -
                                     acq.getHead().idx.user[5]) <
                              np.abs(rawHead[phs].idx.kspace_encode_step_1 -
                                     rawHead[phs].idx.user[5])):
                rawHead[phs] = acq.getHead()

    # Flip matrix in RO/PE to be consistent with ICE
    data = np.flip(data, (1, 2))

    logging.debug("Raw data is size %s" % (data.shape, ))
    np.save(debugFolder + "/" + "raw.npy", data)

    # Remove readout oversampling
    data = fft.ifft(data, axis=2)
    data = np.delete(
        data, np.arange(int(data.shape[2] * 1 / 4),
                        int(data.shape[2] * 3 / 4)), 2)
    data = fft.fft(data, axis=2)

    logging.debug("Raw data is size after readout oversampling removal %s" %
                  (data.shape, ))
    np.save(debugFolder + "/" + "rawNoOS.npy", data)

    # Fourier Transform
    data = fft.fftshift(data, axes=(1, 2))
    data = fft.ifft2(data, axes=(1, 2))
    data = fft.ifftshift(data, axes=(1, 2))

    # Sum of squares coil combination
    # Data will be [PE RO phs]
    data = np.abs(data)
    data = np.square(data)
    data = np.sum(data, axis=0)
    data = np.sqrt(data)

    logging.debug("Image data is size %s" % (data.shape, ))
    np.save(debugFolder + "/" + "img.npy", data)

    # Normalize and convert to int16
    data *= 32767 / data.max()
    data = np.around(data)
    data = data.astype(np.int16)

    # Remove readout oversampling
    offset = int(
        (data.shape[1] - metadata.encoding[0].reconSpace.matrixSize.x) / 2)
    data = data[:,
                offset:offset + metadata.encoding[0].reconSpace.matrixSize.x]

    # Remove phase oversampling
    offset = int(
        (data.shape[0] - metadata.encoding[0].reconSpace.matrixSize.y) / 2)
    data = data[offset:offset +
                metadata.encoding[0].reconSpace.matrixSize.y, :]

    logging.debug("Image without oversampling is size %s" % (data.shape, ))
    np.save(debugFolder + "/" + "imgCrop.npy", data)

    # Measure processing time
    toc = perf_counter()
    strProcessTime = "Total processing time: %.2f ms" % ((toc - tic) * 1000.0)
    logging.info(strProcessTime)

    # Send this as a text message back to the client
    connection.send_logging(constants.MRD_LOGGING_INFO, strProcessTime)

    # Format as ISMRMRD image data
    imagesOut = []
    for phs in range(data.shape[2]):
        # Create new MRD instance for the processed image
        # NOTE: from_array() takes input data as [x y z coil], which is
        # different than the internal representation in the "data" field as
        # [coil z y x], so we need to transpose
        tmpImg = ismrmrd.Image.from_array(data[..., phs].transpose())

        # Set the header information
        tmpImg.setHead(
            mrdhelper.update_img_header_from_raw(tmpImg.getHead(),
                                                 rawHead[phs]))
        tmpImg.field_of_view = (
            ctypes.c_float(metadata.encoding[0].reconSpace.fieldOfView_mm.x),
            ctypes.c_float(metadata.encoding[0].reconSpace.fieldOfView_mm.y),
            ctypes.c_float(metadata.encoding[0].reconSpace.fieldOfView_mm.z))
        tmpImg.image_index = phs

        # Set ISMRMRD Meta Attributes
        tmpMeta = ismrmrd.Meta()
        tmpMeta['DataRole'] = 'Image'
        tmpMeta['ImageProcessingHistory'] = ['FIRE', 'PYTHON']
        tmpMeta['WindowCenter'] = '16384'
        tmpMeta['WindowWidth'] = '32768'
        tmpMeta['Keep_image_geometry'] = 1

        xml = tmpMeta.serialize()
        logging.debug("Image MetaAttributes: %s", xml)
        tmpImg.attribute_string = xml
        imagesOut.append(tmpImg)

    # Call process_image() to invert image contrast
    imagesOut = process_image(imagesOut, connection, config, metadata)

    return imagesOut
コード例 #6
0
def main(args):
    dsetsAll = []
    for entryPath in GetDicomFiles(args.folder):
        dsetsAll.append(pydicom.dcmread(entryPath))

    # Group by series number
    uSeriesNum = np.unique([dset.SeriesNumber for dset in dsetsAll])
    print("Found %d unique series from %d files in folder %s" %
          (len(uSeriesNum), len(dsetsAll), args.folder))

    print("Creating MRD XML header from file %s" % dsetsAll[0].filename)
    mrdHead = CreateMrdHeader(dsetsAll[0])
    print(mrdHead.toXML())

    imgAll = [None] * len(uSeriesNum)

    for iSer in range(len(uSeriesNum)):
        dsets = [
            dset for dset in dsetsAll if dset.SeriesNumber == uSeriesNum[iSer]
        ]

        imgAll[iSer] = [None] * len(dsets)

        # Sort images by instance number, as they may be read out of order
        def get_instance_number(item):
            return item.InstanceNumber

        dsets = sorted(dsets, key=get_instance_number)

        # Build a list of unique SliceLocation and TriggerTimes, as the MRD
        # slice and phase counters index into these
        uSliceLoc = np.unique([dset.SliceLocation for dset in dsets])
        if dsets[0].SliceLocation != uSliceLoc[0]:
            uSliceLoc = uSliceLoc[::-1]

        try:
            # This field may not exist for non-gated sequences
            uTrigTime = np.unique([dset.TriggerTime for dset in dsets])
            if dsets[0].TriggerTime != uTrigTime[0]:
                uTrigTime = uTrigTime[::-1]
        except:
            uTrigTime = np.zeros_like(uSliceLoc)

        print("Series %d has %d images with %d slices and %d phases" %
              (uSeriesNum[iSer], len(dsets), len(uSliceLoc), len(uTrigTime)))

        for iImg in range(len(dsets)):
            tmpDset = dsets[iImg]

            # Create new MRD image instance.
            # NOTE: from_array() takes input data as [x y z coil], but the
            # pixel_array() output returns data as [row col], so need to transpose.
            # This will also set the data_type and matrix_size fields.
            tmpMrdImg = ismrmrd.Image.from_array(
                tmpDset.pixel_array.transpose())
            tmpMeta = ismrmrd.Meta()

            try:
                tmpMrdImg.image_type = imtype_map[tmpDset.ImageType[2]]
            except:
                print(
                    "Unsupported ImageType %s -- defaulting to IMTYPE_MAGNITUDE"
                    % tmpDset.ImageType[2])
                tmpMrdImg.image_type = ismrmrd.IMTYPE_MAGNITUDE

            tmpMrdImg.field_of_view = (tmpDset.PixelSpacing[0] * tmpDset.Rows,
                                       tmpDset.PixelSpacing[1] *
                                       tmpDset.Columns, tmpDset.SliceThickness)
            tmpMrdImg.position = tuple(np.stack(tmpDset.ImagePositionPatient))
            tmpMrdImg.read_dir = tuple(
                np.stack(tmpDset.ImageOrientationPatient[0:3]))
            tmpMrdImg.phase_dir = tuple(
                np.stack(tmpDset.ImageOrientationPatient[3:7]))
            tmpMrdImg.slice_dir = tuple(
                np.cross(np.stack(tmpDset.ImageOrientationPatient[0:3]),
                         np.stack(tmpDset.ImageOrientationPatient[3:7])))
            tmpMrdImg.acquisition_time_stamp = round(
                (int(tmpDset.AcquisitionTime[0:2]) * 3600 +
                 int(tmpDset.AcquisitionTime[2:4]) * 60 +
                 int(tmpDset.AcquisitionTime[4:6]) +
                 float(tmpDset.AcquisitionTime[6:])) * 1000 / 2.5)
            try:
                tmpMrdImg.physiology_time_stamp[0] = round(
                    int(tmpDset.TriggerTime / 2.5))
            except:
                pass

            try:
                ImaAbsTablePosition = tmpDset.get_private_item(
                    0x0019, 0x13, 'SIEMENS MR HEADER').value
                tmpMrdImg.patient_table_position = (
                    ctypes.c_float(ImaAbsTablePosition[0]),
                    ctypes.c_float(ImaAbsTablePosition[1]),
                    ctypes.c_float(ImaAbsTablePosition[2]))
            except:
                pass

            tmpMrdImg.image_series_index = uSeriesNum.tolist().index(
                tmpDset.SeriesNumber)
            tmpMrdImg.image_index = tmpDset.get('InstanceNumber', 0)
            tmpMrdImg.slice = uSliceLoc.tolist().index(tmpDset.SliceLocation)
            try:
                tmpMrdImg.phase = uTrigTime.tolist().index(tmpDset.TriggerTime)
            except:
                pass

            try:
                res = re.search(r'(?<=_v).*$', tmpDset.SequenceName)
                venc = re.search(r'^\d+', res.group(0))
                dir = re.search(r'(?<=\d)[^\d]*$', res.group(0))

                tmpMeta['FlowVelocity'] = float(venc.group(0))
                tmpMeta['FlowDirDisplay'] = venc_dir_map[dir.group(0)]
            except:
                pass

            tmpMeta['SequenceDescription'] = tmpDset.SeriesDescription

            # Remove pixel data from pydicom class
            del tmpDset['PixelData']

            # Store the complete base64, json-formatted DICOM header so that non-MRD fields can be
            # recapitulated when generating DICOMs from MRD images
            tmpMeta['DicomJson'] = base64.b64encode(
                tmpDset.to_json().encode('utf-8')).decode('utf-8')

            tmpMrdImg.attribute_string = tmpMeta.serialize()
            imgAll[iSer][iImg] = tmpMrdImg

    # Create an MRD file
    print("Creating MRD file %s with group %s" % (args.outFile, args.outGroup))
    mrdDset = ismrmrd.Dataset(args.outFile, args.outGroup)
    mrdDset._file.require_group(args.outGroup)

    # Write MRD Header
    mrdDset.write_xml_header(bytes(mrdHead.toXML(), 'utf-8'))

    # Write all images
    for iSer in range(len(imgAll)):
        for iImg in range(len(imgAll[iSer])):
            mrdDset.append_image(
                "images_%d" % imgAll[iSer][iImg].image_series_index,
                imgAll[iSer][iImg])

    mrdDset.close()
コード例 #7
0
def process_image(images, config, metadata):
    # Create folder, if necessary
    if not os.path.exists(debugFolder):
        os.makedirs(debugFolder)
        logging.debug("Created folder " + debugFolder +
                      " for debug output files")

    logging.debug("Incoming image data of type %s",
                  ismrmrd.get_dtype_from_data_type(images[0].data_type))

    # Display MetaAttributes for first image
    meta = ismrmrd.Meta.deserialize(images[0].attribute_string)
    logging.debug("MetaAttributes: %s", ismrmrd.Meta.serialize(meta))

    # Optional serialization of ICE MiniHeader
    if 'IceMiniHead' in meta:
        logging.debug("IceMiniHead: %s",
                      base64.b64decode(meta['IceMiniHead']).decode('utf-8'))

    # Extract image data into a 5D array of size [img cha z y x]
    data = np.stack([img.data for img in images])
    head = [img.getHead() for img in images]

    logging.debug("Original image data is size %s" % (data.shape, ))
    np.save(debugFolder + "/" + "imgOrig.npy", data)

    # Normalize and convert to int16
    data = data.astype(np.float64)
    data *= 32767 / data.max()
    data = np.around(data)
    data = data.astype(np.int16)

    # Invert image contrast
    data = 32767 - data
    data = np.abs(data)
    data = data.astype(np.int16)
    np.save(debugFolder + "/" + "imgInverted.npy", data)

    # Re-slice back into 2D images
    imagesOut = [None] * data.shape[0]
    for iImg in range(data.shape[0]):
        # Create new MRD instance for the inverted image
        imagesOut[iImg] = ismrmrd.Image.from_array(data[iImg, ...].transpose())
        data_type = imagesOut[iImg].data_type

        # Copy the fixed header information
        oldHeader = head[iImg]
        oldHeader.data_type = data_type

        imagesOut[iImg].setHead(oldHeader)

        # Set ISMRMRD Meta Attributes
        meta = ismrmrd.Meta({
            'DataRole': 'Image',
            'ImageProcessingHistory': ['FIRE', 'PYTHON'],
            'WindowCenter': '16384',
            'WindowWidth': '32768'
        })
        xml = meta.serialize()
        logging.debug("Image MetaAttributes: %s", xml)
        logging.debug("Image data has %d elements", imagesOut[iImg].data.size)

        imagesOut[iImg].attribute_string = xml

    return imagesOut
コード例 #8
0
def process_raw(group, config, metadata):
    # Create folder, if necessary
    if not os.path.exists(debugFolder):
        os.makedirs(debugFolder)
        logging.debug("Created folder " + debugFolder +
                      " for debug output files")

    # Format data into single [cha PE RO phs] array
    lin = [acquisition.idx.kspace_encode_step_1 for acquisition in group]
    phs = [acquisition.idx.phase for acquisition in group]

    # Use the zero-padded matrix size
    data = np.zeros(
        (group[0].data.shape[0],
         metadata.encoding[0].encodedSpace.matrixSize.y,
         metadata.encoding[0].encodedSpace.matrixSize.x, max(phs) + 1),
        group[0].data.dtype)

    rawHead = [None] * (max(phs) + 1)

    for acq, lin, phs in zip(group, lin, phs):
        if (lin < data.shape[1]) and (phs < data.shape[3]):
            # TODO: Account for asymmetric echo in a better way
            data[:, lin, -acq.data.shape[1]:, phs] = acq.data

            # center line of k-space is encoded in user[5]
            if (rawHead[phs] is
                    None) or (np.abs(acq.getHead().idx.kspace_encode_step_1 -
                                     acq.getHead().idx.user[5]) <
                              np.abs(rawHead[phs].idx.kspace_encode_step_1 -
                                     rawHead[phs].idx.user[5])):
                rawHead[phs] = acq.getHead()

    # Flip matrix in RO/PE to be consistent with ICE
    data = np.flip(data, (1, 2))

    # Format as [row col phs cha] for BART
    data = data.transpose((1, 2, 3, 0))

    logging.debug("Raw data is size %s" % (data.shape, ))
    np.save(debugFolder + "/" + "raw.npy", data)

    # Fourier Transform with BART
    logging.info("Calling BART FFT")
    data = bart(1, 'fft -u -i 3', data)

    # Re-format as [cha row col phs]
    data = data.transpose((3, 0, 1, 2))

    # Sum of squares coil combination
    # Data will be [PE RO phs]
    data = np.abs(data)
    data = np.square(data)
    data = np.sum(data, axis=0)
    data = np.sqrt(data)

    logging.debug("Image data is size %s" % (data.shape, ))
    np.save(debugFolder + "/" + "img.npy", data)

    # Normalize and convert to int16
    data *= 32767 / data.max()
    data = np.around(data)
    data = data.astype(np.int16)

    # Remove readout oversampling
    offset = int(
        (data.shape[1] - metadata.encoding[0].reconSpace.matrixSize.x) / 2)
    data = data[:,
                offset:offset + metadata.encoding[0].reconSpace.matrixSize.x]

    # Remove phase oversampling
    offset = int(
        (data.shape[0] - metadata.encoding[0].reconSpace.matrixSize.y) / 2)
    data = data[offset:offset +
                metadata.encoding[0].reconSpace.matrixSize.y, :]

    logging.debug("Image without oversampling is size %s" % (data.shape, ))
    np.save(debugFolder + "/" + "imgCrop.npy", data)

    # Format as ISMRMRD image data
    imagesOut = []
    for phs in range(data.shape[2]):
        # Create new MRD instance for the processed image
        # NOTE: from_array() takes input data as [x y z coil], which is
        # different than the internal representation in the "data" field as
        # [coil z y x], so we need to transpose
        tmpImg = ismrmrd.Image.from_array(data[..., phs].transpose())

        # Set the header information
        tmpImg.setHead(
            mrdhelper.update_img_header_from_raw(tmpImg.getHead(),
                                                 rawHead[phs]))
        tmpImg.field_of_view = (
            ctypes.c_float(metadata.encoding[0].reconSpace.fieldOfView_mm.x),
            ctypes.c_float(metadata.encoding[0].reconSpace.fieldOfView_mm.y),
            ctypes.c_float(metadata.encoding[0].reconSpace.fieldOfView_mm.z))
        tmpImg.image_index = phs

        # Set ISMRMRD Meta Attributes
        tmpMeta = ismrmrd.Meta()
        tmpMeta['DataRole'] = 'Image'
        tmpMeta['ImageProcessingHistory'] = ['PYTHON', 'BART']
        tmpMeta['WindowCenter'] = '16384'
        tmpMeta['WindowWidth'] = '32768'
        tmpMeta['Keep_image_geometry'] = 1

        # Add image orientation directions to MetaAttributes if not already present
        if tmpMeta.get('ImageRowDir') is None:
            tmpMeta['ImageRowDir'] = [
                "{:.18f}".format(tmpImg.getHead().read_dir[0]),
                "{:.18f}".format(tmpImg.getHead().read_dir[1]),
                "{:.18f}".format(tmpImg.getHead().read_dir[2])
            ]

        if tmpMeta.get('ImageColumnDir') is None:
            tmpMeta['ImageColumnDir'] = [
                "{:.18f}".format(tmpImg.getHead().phase_dir[0]),
                "{:.18f}".format(tmpImg.getHead().phase_dir[1]),
                "{:.18f}".format(tmpImg.getHead().phase_dir[2])
            ]

        xml = tmpMeta.serialize()
        logging.debug("Image MetaAttributes: %s", xml)
        tmpImg.attribute_string = xml
        imagesOut.append(tmpImg)

    return imagesOut
コード例 #9
0
def process_group(group, config, metadata):
    # Create folder, if necessary
    if not os.path.exists(debugFolder):
        os.makedirs(debugFolder)
        logging.debug("Created folder " + debugFolder +
                      " for debug output files")

    # Format data into single [cha RO PE] array
    data = [acquisition.data for acquisition in group]
    data = np.stack(data, axis=-1)

    logging.debug("Raw data is size %s" % (data.shape, ))
    np.save(debugFolder + "/" + "raw.npy", data)

    # Remove readout oversampling
    data = fft.ifft(data, axis=1)
    data = np.delete(
        data, np.arange(int(data.shape[1] * 1 / 4),
                        int(data.shape[1] * 3 / 4)), 1)
    data = fft.fft(data, axis=1)

    logging.debug("Raw data is size after readout oversampling removal %s" %
                  (data.shape, ))
    np.save(debugFolder + "/" + "rawNoOS.npy", data)

    # Fourier Transform
    data = fft.fftshift(data, axes=(1, 2))
    data = fft.ifft2(data, axes=(1, 2))
    data = fft.ifftshift(data, axes=(1, 2))

    # Sum of squares coil combination
    data = np.abs(data)
    data = np.square(data)
    data = np.sum(data, axis=0)
    data = np.sqrt(data)

    logging.debug("Image data is size %s" % (data.shape, ))
    np.save(debugFolder + "/" + "img.npy", data)

    # Normalize and convert to int16
    data *= 32767 / data.max()
    data = np.around(data)
    data = data.astype(np.int16)

    # Remove readout oversampling
    offset = int(
        (data.shape[0] - metadata.encoding[0].reconSpace.matrixSize.x) / 2)
    data = data[offset:offset +
                metadata.encoding[0].reconSpace.matrixSize.x, :]

    # Remove phase oversampling
    offset = int(
        (data.shape[1] - metadata.encoding[0].reconSpace.matrixSize.y) / 2)
    data = data[:,
                offset:offset + metadata.encoding[0].reconSpace.matrixSize.y]

    logging.debug("Image without oversampling is size %s" % (data.shape, ))
    np.save(debugFolder + "/" + "imgCrop.npy", data)

    # Format as ISMRMRD image data
    image = ismrmrd.Image.from_array(data, acquisition=group[0])
    image.image_index = 1

    # Set field of view
    image.field_of_view = (
        ctypes.c_float(metadata.encoding[0].reconSpace.fieldOfView_mm.x),
        ctypes.c_float(metadata.encoding[0].reconSpace.fieldOfView_mm.y),
        ctypes.c_float(metadata.encoding[0].reconSpace.fieldOfView_mm.z))

    # Set ISMRMRD Meta Attributes
    meta = ismrmrd.Meta({
        'DataRole': 'Image',
        'ImageProcessingHistory': ['FIRE', 'PYTHON'],
        'WindowCenter': '16384',
        'WindowWidth': '32768'
    })

    # Add image orientation directions to MetaAttributes if not already present
    if meta.get('ImageRowDir') is None:
        meta['ImageRowDir'] = [
            "{:.18f}".format(image.getHead().read_dir[0]),
            "{:.18f}".format(image.getHead().read_dir[1]),
            "{:.18f}".format(image.getHead().read_dir[2])
        ]

    if meta.get('ImageColumnDir') is None:
        meta['ImageColumnDir'] = [
            "{:.18f}".format(image.getHead().phase_dir[0]),
            "{:.18f}".format(image.getHead().phase_dir[1]),
            "{:.18f}".format(image.getHead().phase_dir[2])
        ]

    xml = meta.serialize()
    logging.debug("Image MetaAttributes: %s", xml)
    logging.debug("Image data has %d elements", image.data.size)

    image.attribute_string = xml
    return image