"""
``sfftk.formats.seg``
=====================
User-facing reader classes for Segger files
"""
import sfftkrw.schema.adapter_v0_8_0_dev1 as schema
from sfftkrw.core import _str
from .base import Annotation, Volume, Segment, Header, \
Segmentation
from ..readers import segreader
__author__ = "Paul K. Korir, PhD"
__email__ = "pkorir@ebi.ac.uk, paul.korir@gmail.com"
__date__ = "2017-02-02"
__updated__ = '2018-02-23'
[docs]
class SeggerAnnotation(Annotation):
"""Annotation class"""
def __init__(self, segmentation, region_id):
self._segmentation = segmentation
self._region_id = region_id
@property
def name(self):
return ''
@property
def description(self):
return ''
@property
def colour(self):
r, g, b, a = self._segmentation.region_colours[self._region_id]
return r, g, b, a
[docs]
def convert(self, **kwargs):
"""Convert to a :py:class:`sfftkrw.SFFBiologicalAnnotation` object"""
annotation = schema.SFFBiologicalAnnotation()
annotation.name = self.name
annotation.description = self.description
annotation.number_of_instances = 1
# colour = schema.SFFColour()
r, g, b, a = self.colour
colour = schema.SFFRGBA(
red=r,
green=g,
blue=b,
alpha=a,
)
return annotation, colour
[docs]
class SeggerVolume(Volume):
"""Volume class"""
def __init__(self, segmentation):
self._segmentation = segmentation
@property
def file(self):
return self._segmentation.file_name
@property
def map_level(self):
return self._segmentation.map_level
[docs]
def convert(self, **kwargs):
"""Convert to a :py:class:`sfftkrw.SFFThreeDVolume` object"""
volume = schema.SFFThreeDVolume()
# volume.file = self.file
# volume.contourLevel = self.map_level
# volume.transformId = 1
# volume.format = "Segger"
return volume
[docs]
class SeggerSegment(Segment):
"""Segment class"""
def __init__(self, segmentation, region_id):
self._segmentation = segmentation
self._region_id = region_id
@property
def annotation(self):
return SeggerAnnotation(self._segmentation, self.region_id)
@property
def region_id(self):
return self._region_id
@property
def parent_id(self):
return self._segmentation.get_parent_id(self.region_id)
@property
def volume(self):
return SeggerVolume(self._segmentation)
[docs]
def convert(self, **kwargs):
"""Convert to a :py:class:`sfftkrw.SFFSegment` object"""
segment = schema.SFFSegment()
segment.id = self.region_id
segment.parent_id = self.parent_id
# annotation
segment.biological_annotation, segment.colour = self.annotation.convert()
# geometry
# segment.volume = self.volume.convert()
segment.three_d_volume = schema.SFFThreeDVolume()
segment.three_d_volume.lattice_id = 0
segment.three_d_volume.value = self.region_id
return segment
[docs]
class SeggerSegmentation(Segmentation):
"""Class representing an Segger segmentation
.. code-block:: python
from sfftk.formats.seg import SeggerSegmentation
seg_seg = SeggerSegmentation('file.seg')
"""
def __init__(self, fn, top_level=True, *args, **kwargs):
"""Initialise the reader"""
self._fn = fn
self._segmentation = segreader.get_data(self._fn, *args, **kwargs)
self._top_level = top_level
if self._top_level:
self._segments = [SeggerSegment(self._segmentation, region_id) for region_id in self.header.root_parent_ids]
else:
self._segments = [SeggerSegment(self._segmentation, region_id) for region_id in self.header.region_ids if
region_id != 0]
@property
def header(self):
"""The header for this segmentation"""
return SeggerHeader(self._segmentation)
@property
def segments(self):
"""The segments in this segmentation"""
return self._segments
[docs]
def convert(self, name=None, software_version=None, processing_details=None, details=None, verbose=False,
transform=None):
"""Method to convert a :py:class:`sfftkrw.SFFSegmentation` object
:param str name: optional name of the segmentation used in <name/>
:param str software_version: optional software version for Amira use in <software><version/></software>
:param str processing_details: optional processings used in Amira used in <software><processingDetails/></software>
:param str details: optional details associated with this segmentation used in <details/>
:param bool verbose: option to determine whether conversion should be verbose
:param transform: a 3x4 numpy.ndarray for the image-to-physical space transform
:type transform: `numpy.ndarray`
"""
segmentation = schema.SFFSegmentation()
segmentation.name = name if name is not None else "Segger Segmentation"
segmentation.software_list = schema.SFFSoftwareList()
segmentation.software_list.append(
schema.SFFSoftware(
name=self.header.name,
version=software_version if software_version is not None else self.header.version,
processing_details=processing_details,
)
)
segmentation.transform_list = schema.SFFTransformList()
if transform is not None:
segmentation.transform_list.append(
schema.SFFTransformationMatrix.from_array(transform)
)
else:
segmentation.transform_list.append(
schema.SFFTransformationMatrix.from_array(self.header.ijk_to_xyz_transform)
)
segmentation.primary_descriptor = "three_d_volume"
segments = schema.SFFSegmentList()
for s in self.segments:
segment = s.convert()
segments.append(segment)
# finally pack everything together
segmentation.segment_list = segments
# lattice
segmentation.lattice_list = schema.SFFLatticeList()
# check the order: c,r,s or r,c,s???
cols, rows, sections = self.header.map_size
lattice = schema.SFFLattice(
mode='uint32',
endianness='little',
size=schema.SFFVolumeStructure(cols=cols, rows=rows, sections=sections),
start=schema.SFFVolumeIndex(cols=0, rows=0, sections=0),
data=self.header.simplified_mask
)
segmentation.lattice_list.append(lattice)
# details
segmentation.details = details
return segmentation