Volumes of interest¶
In this tutorial we will look at how to represent volumes of interest in datasets.
import matplotlib.pyplot as plt
import hoa_tools.dataset
import hoa_tools.voi
First we'll get an overview dataset, of the brain of donor S-20-29.
overview_dataset = hoa_tools.dataset.get_dataset(
"S-20-29_brain_complete-organ_25.33um_bm05"
)
Now we'll define a volume of interest (VOI) object. This represents a cuboid shape volume within the full dataset.
voi = hoa_tools.voi.VOI(
dataset=overview_dataset,
downsample_level=4,
lower_corner={"x": 100, "y": 50, "z": 23},
size={"x": 40, "y": 20, "z": 1},
)
Once we have a VOI object, there's a number of useful things we can do. Lets get the data array for the VOI and plot it:
data_array = voi.get_data_array()
data_array
<xarray.DataArray 'S-20-29_brain_complete-organ_25.33um_bm05' (z: 1, y: 20,
x: 40)> Size: 2kB
dask.array<getitem, shape=(1, 20, 40), dtype=uint16, chunksize=(1, 20, 28), chunktype=numpy.ndarray>
Coordinates:
* z (z) float64 8B 9.321e+03
* y (y) float64 160B 2.026e+04 2.067e+04 ... 2.756e+04 2.796e+04
* x (x) float64 320B 4.053e+04 4.093e+04 ... 5.593e+04 5.633e+04plt.figure()
ax = data_array.plot(cmap="Grays_r")
ax.axes.set_aspect("equal")
ax.axes.set_title("Downsample level = 4")
Text(0.5, 1.0, 'Downsample level = 4')
Transforming between dowsample levels¶
VOIs can be transformed to the different resolution levels of the same dataset. Lets get a higher resolution version of the data we plotted above:
high_res_voi = voi.change_downsample_level(new_downsample_level=2)
Because we've increased the resolution (equivalently, decreased the downsampling level) the VOI is now bigger.
high_res_data_array = high_res_voi.get_data_array()
fig, axs = plt.subplots(nrows=2)
data_array.isel(z=0).plot(cmap="Grays_r", ax=axs[0])
axs[0].set_aspect("equal")
axs[0].set_title("Downsample level = 4")
high_res_data_array.isel(z=0).plot(cmap="Grays_r", ax=axs[1])
axs[1].set_aspect("equal")
axs[1].set_title("Downsample level = 2")
fig.tight_layout()
Transforming between registered datasets¶
Now we'll step through transforming a VOI between two datasets that have been registered to each other. We'll start by getting one of the children of the overview dataset used above.
children = overview_dataset.get_children()
child = children[8]
child.name
'S-20-29_brain_VOI-04_6.5um_bm05'
child_array = child.data_array(downsample_level=0)
child_array
<xarray.DataArray 'S-20-29_brain_VOI-04_6.5um_bm05' (z: 4176, y: 3844, x: 3844)> Size: 123GB dask.array<array, shape=(4176, 3844, 3844), dtype=uint16, chunksize=(128, 128, 128), chunktype=numpy.ndarray> Coordinates: * z (z) float64 33kB 0.0 6.5 13.0 ... 2.712e+04 2.713e+04 2.714e+04 * y (y) float64 31kB 0.0 6.5 13.0 ... 2.497e+04 2.497e+04 2.498e+04 * x (x) float64 31kB 0.0 6.5 13.0 ... 2.497e+04 2.497e+04 2.498e+04
Now we'll select a smaller volume of interest from the child array, and plot it
child_voi = hoa_tools.voi.VOI(
dataset=child,
downsample_level=0,
lower_corner={"x": 3434, "y": 2060, "z": 2656},
size={"x": 256, "y": 256, "z": 128},
)
child_array = child_voi.get_data_array()
plt.figure()
ax = child_array.isel(z=0).plot(cmap="Grays_r")
ax.axes.set_aspect("equal")
ax.axes.set_title("Zoom dataset slice")
Text(0.5, 1.0, 'Zoom dataset slice')
Now lets transform the VOI to the overview dataset
overview_voi = child_voi.transform_to(overview_dataset)
overview_voi
VOI(dataset=Dataset(name='S-20-29_brain_complete-organ_25.33um_bm05', dataset_type='overview', voi='complete-organ', data=Data(shape=[5750, 5750, 6627], voxel_size_um=25.33, gcs_url='n5://gs://ucl-hip-ct-35a68e99feaae8932b1d44da0358940b/S-20-29/brain/25.33um_complete-organ_bm05/'), sample=Sample(organ='brain', organ_context=None, post_mortem_interval_hours=None, fixation_method=None, fixation_medium='formalin', organ_infilled=None, stabilisation_medium='crushed agar', degassing_method='vacuum', scan_solvent='ethanol', scan_solvent_concentration=70.0, scan_temperature='room temperature'), donor=Donor(id='S-20-29', age=Age(root=80), sex='M', weight=Weight(root=90.0), height=Height(root=170.0), cause_of_death='Acute right heart failure with extensive Pulmonary artery thrombembolism, diffuse alveolar damage, shock kidneys bilateral with acute kidney failure, and acute liver failure COVID-19 disease', medical_history='Kidney failure, arterial hypertension, Z.n. Spondylodesis LWK 2 and sacral vertebra 2, SARS-CoV2 infection, symptoms of memory loss and predementia, Dandy-Walker syndrome variant, post-mortem diagnostic.', diabetes='Type 2', hypertension=None, smoker=None), scan=Scan(date=datetime.date(2021, 3, 4), beamline='BM05', energy=Energy(root=80.0), current_start=None, filling_mode=None, n_frames=NFrames(root=9990), n_ref=NRef(root=3), n_dark=NDark(root=0), latency_time=LatencyTime(root=0.0025), exposure_time=ExposureTime(root=0.0025), subframe_time=None, n_subframes=NSubframes(root=5), scan_type='zseries', scan_range=360.0, n_scans=None, acquisition='quarter', z_step=None, scan_time=None, filters=['Mo 0.24mm', 'SiO2 8mm block'], scintillator=None, optic='DZoom', optic_magnification=None, distance_source_sample=None, distance_sample_detector=DistanceSampleDetector(root=3500.0), psho=None, sensor_name='PCO edge 4.2 CLHS', sensor_mode='FFM', sensor_roi_x_size=SensorRoiXSize(root=3100), sensor_roi_y_size=SensorRoiYSize(root=6629), sensor_binning=None, pixel_size=25.33, xray_magnification=None, technique='Hierarchical Phase-Contrast Tomography (HiP-CT)', experiment_type='Tomography'), proposal=Proposal(proposal_number='md1252', title="Multiscale Quantification of Covid-19's impact on lung vasculature from whole lobe to alveolar/microvascular scales", proposers=['Peter Lee', 'Paul Tafforeau', 'Danny Jonigk', 'Maximilian Ackermann', 'Mark P. Kuhnel', 'Elodie Boller', 'Willi Wagner']), registration=None, citation=Citation(title='Overview at 25.33um of the brain of donor S-20-29, scanned at ESRF on beamline BM05.', contributors=[Contributor(first_name='The', last_name='Human Organ Atlas Collaboration', orcid=None, roles=[]), Contributor(first_name='Claire', last_name='Walsh', orcid=Orcid(root='0000-0003-3769-3392'), roles=['Conceptualization', 'Funding acquisition']), Contributor(first_name='Danny', last_name='Jonigk', orcid=Orcid(root='0000-0002-5251-2281'), roles=['Funding acquisition']), Contributor(first_name='David', last_name='Stansby', orcid=Orcid(root='0000-0002-1365-1908'), roles=['Data curation', 'Software']), Contributor(first_name='Elodie', last_name='Boller', orcid=None, roles=['Funding acquisition']), Contributor(first_name='Guillaume', last_name='Gaisne', orcid=Orcid(root='0000-0002-3401-7930'), roles=['Data curation', 'Software']), Contributor(first_name='Hector', last_name='Dejea I Velardo', orcid=Orcid(root='0000-0003-2584-9812'), roles=['Data curation', 'Investigation']), Contributor(first_name='Joanna', last_name='Purzycka', orcid=Orcid(root='0000-0001-8742-5279'), roles=['Data curation']), Contributor(first_name='Joseph', last_name='Brunet', orcid=Orcid(root='0000-0002-8424-9510'), roles=['Data curation', 'Investigation', 'Software']), Contributor(first_name='Mark', last_name='P. Kuhnel', orcid=Orcid(root='0000-0003-3558-2576'), roles=['Funding acquisition']), Contributor(first_name='Maximilian', last_name='Ackermann', orcid=Orcid(root='0000-0001-9996-2477'), roles=['Funding acquisition']), Contributor(first_name='Paul', last_name='Tafforeau', orcid=Orcid(root='0000-0002-5962-1683'), roles=['Conceptualization', 'Data curation', 'Funding acquisition']), Contributor(first_name='Peter', last_name='Lee', orcid=Orcid(root='0000-0002-3898-8881'), roles=['Conceptualization', 'Funding acquisition']), Contributor(first_name='Theresa', last_name='Urban', orcid=Orcid(root='0000-0002-0352-8180'), roles=['Data curation', 'Investigation', 'Software']), Contributor(first_name='Willi', last_name='Wagner', orcid=None, roles=['Funding acquisition'])], doi='10.15151/ESRF-DC-1773961413', author_list=['The Human Organ Atlas Collaboration', 'Claire Walsh', 'Danny Jonigk', 'David Stansby', 'Elodie Boller', 'Guillaume Gaisne', 'Hector Dejea I Velardo', 'Joanna Purzycka', 'Joseph Brunet', 'Mark P. Kuhnel', 'Maximilian Ackermann', 'Paul Tafforeau', 'Peter Lee', 'Theresa Urban', 'Willi Wagner']), metadata_version='1.1'), downsample_level=0, lower_corner=ArrayCoordinate(x=2975, y=1689, z=4316), size=ArrayCoordinate(x=69, y=69, z=33))
Finally, lets plot the overview and child datasets together. We can see that the same structures are visible in both, so the registration is approximately accurate, and all the transformations worked.
In the next tutorial section we'll see how to do a more accurate registration of just these small sub-volumes of data in order to do quantitative comparisons.
overview_array = overview_voi.get_data_array()
overview_array
<xarray.DataArray 'S-20-29_brain_complete-organ_25.33um_bm05' (z: 33, y: 69,
x: 69)> Size: 314kB
dask.array<getitem, shape=(33, 69, 69), dtype=uint16, chunksize=(33, 69, 69), chunktype=numpy.ndarray>
Coordinates:
* z (z) float64 264B 1.093e+05 1.093e+05 ... 1.101e+05 1.101e+05
* y (y) float64 552B 4.278e+04 4.281e+04 ... 4.448e+04 4.45e+04
* x (x) float64 552B 7.536e+04 7.538e+04 ... 7.705e+04 7.708e+04fig, axs = plt.subplots(nrows=2, figsize=(6, 9))
ax = axs[0]
child_array.isel(z=0).plot(cmap="Grays_r", ax=ax)
ax.set_aspect("equal")
ax.set_title("Zoom dataset")
ax = axs[1]
overview_array.isel(z=0).plot(cmap="Grays_r", ax=ax)
ax.set_aspect("equal")
ax.set_title("Overview dataset")
fig.tight_layout()