From e4ea999708653a2b1227f5ea6355fdb9fc643c72 Mon Sep 17 00:00:00 2001 From: simoncampredon-lang Date: Mon, 7 Sep 2026 15:49:34 +0200 Subject: [PATCH] fix: missing documenation addition and inaccuracies fix --- docs/raw_format.rst | 26 +++--- docs/roi_format.rst | 2 +- docs/scan_format.rst | 48 +++++++----- docs/usage.rst | 6 +- src/pyiconeus/io/base.py | 4 +- src/pyiconeus/models/Raw.py | 27 ++++--- src/pyiconeus/models/Roi.py | 31 +++++--- src/pyiconeus/models/Scan.py | 148 ++++++++++++++++++++++++++++++++--- 8 files changed, 219 insertions(+), 73 deletions(-) diff --git a/docs/raw_format.rst b/docs/raw_format.rst index 8f4f592..9a301cf 100644 --- a/docs/raw_format.rst +++ b/docs/raw_format.rst @@ -28,33 +28,36 @@ MetaData Attributes +++++++++++ +acquisitionMode: str + Description of the type of acquisition (ex: 2Dscan, 3Dscan, ...) + transmitFrequency : float - The transmit frequency of the acquisition + The transmit frequency of the acquisition, in MHz prf : float - The pulse repetition frequency + The pulse repetition frequency, Hz speedOfSound : float - The speed of sound + The speed of sound, in meter per second frameRate : float - Frame rate of the acquisition + Frame rate of the acquisition, in Hz receiveAperture : np.ndarray - Receive Aperture + Receive aperture, first and last elements of the aperture depth : Scan.Depth - Near and Far depth + Near and Far depth, in millimeter flatAngles : np.ndarray - Angles of the probe during the acquisition + Angles of the probe during the acquisition, in degrees voxDim : Scan.VoxDim - VoxDim data + Voxel dimension x, y and z, in meters blockDim : np.ndarray - BlockDim data - + Block dimension x, y, z, angle, frame + compound : bool True if the images are compounded, False otherwise @@ -73,6 +76,3 @@ They are one-based and inclusive, and default to block 1. If ``blockEnd`` is greater than ``numberOfBlock``, it is clamped to the available number of blocks and a ``RuntimeWarning`` is emitted. ``blockEnd`` smaller than ``blockStart`` raises ``RuntimeError``. - -acquisitionMode : str - Type of acquisition diff --git a/docs/roi_format.rst b/docs/roi_format.rst index d1d51a8..6cb0f58 100644 --- a/docs/roi_format.rst +++ b/docs/roi_format.rst @@ -26,7 +26,7 @@ Attributes name : str Name of the ROI -color : tuple[float, float, float] +color : tuple[float, ...] Normalized (R, G, B) vector with three components in the range 0..1. vertices : np.ndarray diff --git a/docs/scan_format.rst b/docs/scan_format.rst index ac2bf31..36bdbbe 100644 --- a/docs/scan_format.rst +++ b/docs/scan_format.rst @@ -59,10 +59,10 @@ gender : :class:`~pyiconeus.models.Scan.GenderType` Gender of the subject transferDate : datetime.datetime - Date of the transfer + Date of the transfer, in seconds, time since 00:00:00 Coordinated Universal Time (UTC), Thursday, 1 January 1970, not counting leap seconds ageAtTransfer : int - Age at the transfer + Age at the transfer in days subjectDescription : str Description of the subject @@ -77,10 +77,10 @@ Acquisition parameters ++++++++++++++++++++++++ acquisitionMode : :class:`~pyiconeus.models.Scan.AcquisitionMode` - Description of the type of acquisition (ex: 3DScan, 4DScan, ...) + Description of the type of acquisition (ex: fUS3D, Angio3D, ...) acquisitionDate : datetime.datetime - Date of the acquisition + Date of the transfer, in seconds, time since 00:00:00 Coordinated Universal Time (UTC), Thursday, 1 January 1970, not counting leap seconds type : :class:`~pyiconeus.models.Scan.ScanType` 'Source' or 'Proc', if the scan has been modified @@ -101,19 +101,19 @@ ultrafastSamplingFrequency : float Frequency of the ultra fast sampling, in MHz planeWaveAngles : list[float] - List of the plane waves angles + List of the plane waves angles, in radians transmitVoltage : float - Voltage of the transmit + Voltage of the transmit, in volts delayAfterTrigger : float - Delay after each trigger + Delay after each trigger, in seconds isMultiplane : bool True if the acquisition is multiplane integrationWindowDuration : float - Time of the window duration + Time of the window duration, in seconds stimulationToggleTimes : list[float] List of the times the stimulation was toggled @@ -123,8 +123,8 @@ Geometry, timing & data sizeX, sizeY, sizeZ : int Dimension of the acquisition: - - sizeX: Width size in number of voxels - - sizeY: Height size in number of voxels + - sizeX: Lateral size in number of voxels + - sizeY: Elevation size in number of voxels - sizeZ: Depth in number of voxels nTime : int @@ -140,20 +140,20 @@ dim6 : :class:`~pyiconeus.models.Scan.Dim6` Description about additional filters, see the :ref:`dim6-section` section below. measuredTimes : list[float] - List containing the times of every acquired block + List containing the times of every acquired block, in seconds theoreticalTimeIndices : list[int] Indices of the measuredTimes list probeToLabsTranslations : numpy.ndarray - Array of mean translations, with shape ``(nPose, 3)``. + Array of translation in the Lab space, with shape ``(nPose, 3)``. probeToLabsRotations : numpy.ndarray - Array of rotations in radians, with shape ``(nPose, 3)``. + Array of euler angles in radians, with shape ``(nPose, 3)``. -The :meth:`~pyiconeus.models.Scan.Scan.get_ProbeToLab` method combines these +The :meth:`~pyiconeus.models.Scan.Scan.get_probe_to_lab` method combines these values into one 4x4 affine matrix per pose. The -:meth:`~pyiconeus.models.Scan.Scan.get_VoxelToProbe` method returns the 4x4 +:meth:`~pyiconeus.models.Scan.Scan.get_voxel_to_probe` method returns the 4x4 voxel-to-probe affine matrix. voxels : numpy.ndarray @@ -180,7 +180,7 @@ dx, dy, dz : float Voxel size along each axis in meters dt : float - Time in seconds at the end of the acquisition of the first block of the first probe position including the pause. This is not necessarily volumetric dt + Time in seconds at the end of the first block of the first probe position including the pause. This is not necessarily volumetric dt dr : float Voxel angle in radians @@ -209,7 +209,7 @@ probeElevationAperture : float or None Elevation aperture in millimeters when available. probeRadiusOfCurvature : float - in millimeters + Radius of curvature in millimeters. probeNumberOfElements : int or None Number of probe elements when available. @@ -252,9 +252,15 @@ ClutterFiltering clutterFilter : clutterFilterType (``StaticSVD`` | ``DynamicSVD`` | ``Butterworth``) clutterFilterWindowDuration : float - Duration of the filter in seconds + Duration of the window in seconds -clutterFilterCutoffLow, clutterFilterCutoffHigh : float +clutterFilterCutoffLow, clutterFilterCutoffHigh: + For 'StaticSVD': int + - First and last singular value contribution + For 'DynamicSVD': int + - Low and high eigen values + For 'Butterworth': float + - Left edge of the first bin and right edge of the last bin VelocityBandwidthFiltering ++++++++++++++++++++++++++++ @@ -295,7 +301,7 @@ AcquisitionMode ``fUS2D``, ``Angio3D``, ``fUS3D``, ``fUS3DCustom`` -Legacy ``.scan`` files may store the raw acquisition-mode labels ``2DScan``, -``3DScan``, ``4DScan``, ``4DScanCustom``, ``4DscanRCA`` and ``3DscanRCA``; +Legacy ``.scan`` files may store the raw acquisition-mode labels ``2Dscan``, +``3Dscan``, ``4Dscan``, ``4DscanCustom``, ``4DscanRCA`` and ``3DscanRCA``; the two RCA variants are remapped to ``fUS3D`` and ``Angio3D`` respectively when the file is read. diff --git a/docs/usage.rst b/docs/usage.rst index fd71d7e..c08eed5 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -58,7 +58,11 @@ Errors ``open_path`` raises ``FileNotFoundError`` when either path does not exist, ``ValueError`` for an unsupported extension, a missing/invalid ``.hraw`` -header, or an invalid block range, and ``OSError`` when a file cannot be read. +header, or an invalid ``blockStart`` range. If ``blockEnd`` is +greater than ``numberOfBlock``, it is clamped to the available number of +blocks and a ``RuntimeWarning`` is emitted. ``blockEnd`` smaller than +``blockStart`` raises ``RuntimeError``. Raises ``OSError`` when a file cannot be read, +and ``TypeError`` if a non-integer argument is passed. More complete, runnable walkthroughs are available as notebooks in the `examples `_ diff --git a/src/pyiconeus/io/base.py b/src/pyiconeus/io/base.py index 51fe938..7bbf50b 100644 --- a/src/pyiconeus/io/base.py +++ b/src/pyiconeus/io/base.py @@ -54,9 +54,9 @@ def open_path( Parameters ---------- - **path**: str + **filepath**: str | os.PathLike[str] File path of the wanted PyIconeus object - **path2**: str (optional) + **raw_header_filepath**: str | os.PathLike[str] | None (optional) File path of the header file. (Only used with .raw files) **blockStart**: int = 1 (optional) The starting block number to get from the raw data diff --git a/src/pyiconeus/models/Raw.py b/src/pyiconeus/models/Raw.py index 20d07aa..4ced54e 100644 --- a/src/pyiconeus/models/Raw.py +++ b/src/pyiconeus/models/Raw.py @@ -27,7 +27,9 @@ class Raw: **metadata**: Raw.Metadata The metadata of the acquisition **data**: np.ndarray - The raw data of the acquisition + NumPy array containing the complex IQ data after beamforming. The leading + dimensions are ordered as ``(sizeZ, sizeY, sizeX, compound, frames, blocks)`` + before singleton dimensions are removed by ``numpy.squeeze``. """ class MetaData: @@ -37,32 +39,35 @@ class MetaData: Attributes ---------- + **acquisitionMode**: *str* + Description of the type of acquisition (ex: 2Dscan, 3Dscan, ...) + **transmitFrequency**: float - The transmit frequency of the acquisition + The transmit frequency of the acquisition, in MHz **prf**: float - The pulse repetition frequency + The pulse repetition frequency, in Hz **speedOfSound**: float - The speed of sound + The speed of sound, in meter per second **frameRate**: float - Frame rate of the acquisition + Frame rate of the acquisition, in Hz **receiveAperture**: np.ndarray - Receive Aperture + Receive aperture, first and last elements of the aperture **depth**: Scan.Depth - Near and Far depth + Near and Far depth, in millimeter **flatAngles**: np.ndarray - Angles of the probe during the acquisition + Angles of the probe during the acquisition, in degrees **voxDim**: Scan.VoxDim - VoxDim data + Voxel dimension x, y, z, in millimeters **blockDim**: np.ndarray - BlockDim data + Block dimension x, y, z, angle, frame **compound**: bool True if the images are compounded, False otherwise @@ -74,8 +79,6 @@ class MetaData: True if the file uses the legacy raw data block layout from early '.raw' acquisitions, False otherwise - **acquisitionMode**: *str* - Type of acquisition """ @staticmethod diff --git a/src/pyiconeus/models/Roi.py b/src/pyiconeus/models/Roi.py index 3d2f5d3..8a8efc0 100644 --- a/src/pyiconeus/models/Roi.py +++ b/src/pyiconeus/models/Roi.py @@ -23,17 +23,9 @@ class Roi: Attributes ---------- - color: RoiColor - The displayed color of the Roi + list: list[RoiElements] + List containing the different ROIs of the file - label: str - The name of the Roi - - vertices: np.ndarray (N, 3) - The points in Brain space of the volume - - faces: np.ndarray (N, 3) - Each row contains the indices of the vertices composing a triangle of the volume """ ROI_4CC_STR = "bri_" @@ -102,6 +94,25 @@ def __str__(self) -> str: class RoiElements: + """ + Region of Interest properties and values. + + Attributes + ---------- + + color : tuple[float, ...] + Normalized (R, G, B) vector with three components in the range 0..1. + + name: str + The name of the Roi + + vertices: np.ndarray (N, 3) + The points in Brain space of the volume + + faces: np.ndarray (N, 3) + Each row contains the indices of the vertices composing a triangle of the volume + """ + def __init__( self, color: tuple[float, ...], diff --git a/src/pyiconeus/models/Scan.py b/src/pyiconeus/models/Scan.py index 0d6c613..a2de88b 100644 --- a/src/pyiconeus/models/Scan.py +++ b/src/pyiconeus/models/Scan.py @@ -54,7 +54,9 @@ class Scan: voxDim : VoxDim Voxel and frame spacing information. acquisitionMode : AcquisitionMode - Type of the acquired scan. + Description of the type of acquisition (ex: fUS3D, Angio3D, ...) + acquisitionDate: datetime.datetime + Date of the transfer, time in seconds since 00:00:00 Coordinated Universal Time (UTC), Thursday, 1 January 1970, not counting leap seconds probe : Probe Information about the ultrasound probe used. depth : Depth @@ -66,31 +68,33 @@ class Scan: ultrafastSamplingFrequency : float Sampling frequency of the raw channel data in MHz. planeWaveAngles : list[float] - Plane wave angles used in the acquisition (degrees). + Plane wave angles used in the acquisition in radians. transmitVoltage : float - Transmit voltage in volts. + Transmit voltage, in volts. delayAfterTrigger : float - Delay after trigger, seconds. + Delay after trigger, in seconds. isMultiplane : bool Whether multi-plane imaging was used. integrationWindowDuration : float - Integration window duration, seconds. + Integration window duration, in seconds. sequenceName : str Ultrasound sequence name. projectTag, subjectTag, sessionTag, scanTag : str Identifying tags for the project and subject. + subjectDescription: str + Description of the subject projectDescription : str User comment / description of the acquisition. species : str Species of the subject (e.g., "Mouse"). gender : GenderType Subject gender enum. - transferDate, acquisitionDate : datetime - Dates when data was acquired and transferred. + transferDate: datetime + Date of the transfer, time in seconds since 00:00:00 Coordinated Universal Time (UTC), Thursday, 1 January 1970, not counting leap seconds ageAtTransfer : int Age at data transfer in days. weight : float - Subject weight. + Subject weight, in **weightUnit**. weightUnit : WeightUnitType Unit of the subject weight. treatment : str @@ -102,7 +106,7 @@ class Scan: type : ScanType Whether this is a source or processed scan. stimulationToggleTimes : list[float] - Times of external stimulation toggles (seconds). + Times of external stimulation toggles, in seconds. icoScanVersion : IcoScanVersion | None Version of the IcoScan software that acquired the data. voxels : np.ndarray @@ -143,15 +147,13 @@ def is_static_multiarray( SCAN_4CC_STR = "scan" def __init__(self, filepath: str | os.PathLike[str]) -> None: - """Scan class constructor. Reads the input file depending on the type set in 'is_binary'. + """Scan class constructor. Reads the input file depending on the version of the scan, determined by the `utils.check_fourCC` function. For scans v1 (not binary), the scan is filled with a lot of default values, matching the v2 format. Parameters ---------- **filepath**: str The file path for the scan - **is_binary**: bool - Boolean indicating the version of the scan Returns ------- @@ -748,6 +750,25 @@ def __str__(self) -> str: class VoxDim: + """ + Voxel dimension + + Attributes + ---------- + + dx, dy, dz : float + Voxel size along each axis in meters + + dt : float + Time in seconds at the end of the first block of the first probe position including the pause. This is not necessarily volumetric dt + + dr : float + Voxel angle in radians + + dtheta : float + Voxel angle in radians + """ + def __init__(self, dx=0, dy=0, dz=0, dt=0, dr=0, dtheta=0) -> None: self.dx: float = dx self.dy: float = dy @@ -812,6 +833,17 @@ def __str__(self) -> str: class IcoScanVersion: + """ + IcoScan Version information + + Attributes + ---------- + + major, minor, patch : int + Version identification numbers + + """ + def __init__(self, major: int, minor: int, patch: int) -> None: self.major = major self.minor = minor @@ -824,6 +856,19 @@ def __str__(self) -> str: class Dim6: + """ + Dimension in the data containing information about filtering + + Attributes + ---------- + + count : int + Number of dim6 elements. + + dim6element : set[tuple[Dim6Intent, object]] + Set of all the Dim6Intents + """ + class Dim6Intent(IntEnum): ClutterFiltering = 0 EnhancedDoppler = 1 @@ -831,6 +876,26 @@ class Dim6Intent(IntEnum): BrainMaskedDoppler = 3 class ClutterFiltering: + """ + Clutter filtering informations + + Attributes + ---------- + + clutterFilter : clutterFilterType (``StaticSVD`` | ``DynamicSVD`` | ``Butterworth``) + + clutterFilterWindowDuration : float + Duration of the window in seconds + + clutterFilterCutoffLow, clutterFilterCutoffHigh: + For 'StaticSVD': int + - First and last singular value contribution + For 'DynamicSVD': int + - Low and high eigen values + For 'Butterworth': float + - Left edge of the first bin and right edge of the last bin + """ + class clutterFilterType(IntEnum): StaticSVD = 0 DynamicSVD = 1 @@ -879,6 +944,19 @@ def __str__(self) -> str: __repr__ = __str__ class VelocityBandwidthFiltering: + """ + Velocity bandwith filtering informations + + Attributes + ---------- + + velocityMin, velocityMax : float + Minimum and maximum velocity values as stored in the file. The reader does + not convert their unit. + + + """ + def __init__(self) -> None: self.velocityMin: float self.velocityMax: float @@ -970,6 +1048,37 @@ class AcquisitionMode(IntEnum): class Probe: + """ + Probe class, containing the metadata of the probe used for the acquisition + + Attributes + ---------- + + name : str + Name of the probe + + probeType : Probe.ProbeType + One of ``Linear``, ``MultiArray``, ``RCA``, ``Phased``, ``Matrix``. + + probeCentralFrequency : float or None + Probe central frequency in MHz when available. + + probePitch : float or None + Probe pitch in millimeters when available. + + probeElevationAperture : float or None + Elevation aperture in millimeters when available. + + probeRadiusOfCurvature : float + Radius of curvature in millimeters. + + probeNumberOfElements : int or None + Number of probe elements when available. + + probeModel : str or None + Probe model or serial number when available. + """ + _DZ_ICO_BRIGHT = np.trunc(1e8 * 1540 * 1e-6 / 12.5) _DZ_ICO_PRIME = np.trunc(1e8 * 1540 * 1e-6 / 15.625) _DZ_ICO_RANGE = np.trunc(1e8 * 1540 * 1e-6 / 8.9290) @@ -989,7 +1098,7 @@ def __init__(self) -> None: self.probeCentralFrequency: float | None self.probePitch: float | None self.probeElevationAperture: float | None - self.probeRadiusOfCurvature: float | None + self.probeRadiusOfCurvature: float self.probeNumberOfElements: int | None self.probeModel: str | None @@ -1101,6 +1210,19 @@ def __str__(self) -> str: class Depth: + """ + Depth informations + + Attributes + ---------- + + depthNear : float + in millimeters + + depthFar : float + in millimeters + """ + def __init__(self) -> None: self.depthNear: float self.depthFar: float