def test_downsampling_image_produces_correct_resolution_and_data_shape( from_resolution, to_resolution): image = Image(channels=np.arange(24).reshape(1, 6, 4), resolution_um=from_resolution) image2 = image.resample(resolution_um=to_resolution) assert image2.resolution_um == to_resolution assert image2.num_channels == image.num_channels # don't want to lose original channels scale_ratio = from_resolution / to_resolution assert approx(image.width * scale_ratio == image2.width, abs=1) assert approx(image.height * scale_ratio == image2.height, abs=1)
def test_resolution_matrix_matches_resolution(r): image = Image(channels=np.empty((2, 11, 13)), resolution_um=r) expected = np.array([ [r, 0, 0, 0], [0, r, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1], ]) npt.assert_almost_equal(image.resolution_matrix, expected)
def test_full_shift_matrix_is_height_and_width_of_image(width, height): image = Image(channels=np.empty(shape=(2, height, width))) expected = np.array([ [1, 0, 0, height], [0, 1, 0, width], [0, 0, 1, 0], [0, 0, 0, 1], ]) npt.assert_equal(image.full_shift_matrix, expected)
def test_inds_homog_example(): image = Image(channels=np.empty(shape=(3, 2, 3))) expected = np.array([ [0, 0, 0, 1, 1, 1], [0, 1, 2, 0, 1, 2], [0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1], ]) npt.assert_equal(image.inds_homog, expected)
def slice_atlas(self) -> Image: """The Image that results from a slice through the Atlas with Section's transforms and dimensions.""" si = self.section.image width, height = si.width, si.height inds = si.inds_homog.astype(float) atlas_inds = self.image_to_volume_transform @ inds atlas_inds = atlas_inds[:3, :] # grab just ijk coords atlas_inds = atlas_inds.astype(np.int32) # round to nearest integer, for indexing brightness_3d = _fancy_index_3d_numba(volume=self.atlas.volume, inds=atlas_inds.T) atlas_slice = Image(channels=brightness_3d.reshape(1, height, width), resolution_um=self.section.image.resolution_um) return atlas_slice
def test_shift_matrix_is_ij_ordered_and_in_pixel_coordinate_space(width, height, j_shift, i_shift, theta): section = Section.create( image=Image(channels=np.empty((2, height, width)), resolution_um=99,), image_transform=ImageTransformer(i_shift=i_shift, j_shift=j_shift, theta=theta) ) expected_shift_matrix = np.array([ [1, 0, 0, i_shift * height], [0, 1, 0, j_shift * width], [0, 0, 1, 0], [0, 0, 0, 1] ]) expected_image_transform = section.image_transform.rot_matrix @ expected_shift_matrix npt.assert_almost_equal(section._image_transform_matrix, expected_image_transform)
def test_section_registration_cuts_correctly_with_diff_resolutions(case): volume = np.zeros((3, 3, 3)) volume[1, 1, 1] = 1 registration = Registration(section=Section.create( image=Image(channels=np.empty((1, 3, 3)), resolution_um=case["section_res"]), physical_transform=PhysicalTransformer(**case["pos"]), ), atlas=Atlas( volume=volume, resolution_um=case['atlas_res'], )) atlas_slice = registration.slice_atlas() npt.assert_almost_equal(atlas_slice.channels[0], case['expected'])
def __call__(self, filename: str, resolution: Optional[float] = None) -> Result[LoadImageData, str]: image_filename = read_quicknii_xml(filename).image_path if Path(filename).suffix == '.xml' else filename image_data = self._image_reader.read(filename=image_filename) if image_data is None: return Err("Image failed to load.") resolution = resolution if isinstance((resolution := image_data.resolution_um), float) else 1. image = Image(channels=image_data.channels, resolution_um=resolution) image = image.resample(resolution_um=10) section = Section.create( image=image, image_transform=ImageTransformer(i_shift=-0.5, j_shift=-0.5) ) self._repo.save_section(section=section) return Ok(LoadImageData( section_id=section.id, section_image=section.image.channels[0], resolution_um=image.resolution_um, num_channels=image.num_channels, ))
def test_section_registration_to_an_atlas_gets_an_image_with_same_image_parameters( ): registration = Registration( section=Section.create( image=Image(channels=np.empty((3, 4, 5)), resolution_um=10), image_transform=ImageTransformer(i_shift=3, j_shift=5, theta=20), physical_transform=PhysicalTransformer(x=10, y=-5, z=10, rx=20, ry=0, rz=-5), ), atlas=Atlas(volume=np.empty((5, 5, 5)), resolution_um=20), ) atlas_slice = registration.slice_atlas() assert type(atlas_slice) is Image assert atlas_slice.width == 5 and atlas_slice.height == 4
def test_can_get_3d_position_from_2d_pixel_coordinate_in_section(i, j, i_shift, j_shift, theta, x, y, z, res): section = Section.create( image=Image(channels=np.empty((2, 3, 4)), resolution_um=res), image_transform=ImageTransformer(i_shift=i_shift, j_shift=j_shift, theta=theta), physical_transform=PhysicalTransformer(x=x, y=y, z=z), ) t = -radians(theta) # image is left-handed, so flip rotation xyz = section.map_ij_to_xyz(i=i, j=j) # observed 3D positions # do shift first, to make final 2d rotation calculation easier https://academo.org/demos/rotation-about-point/ j2 = (j + (j_shift * section.image.width)) i2 = (-i - (i_shift * section.image.height)) expected = ( (j2 * cos(t) + i2 * sin(t)) * res + x, (i2 * cos(t) - j2 * sin(t)) * res + y, z, ) assert approx(xyz == expected)
def test_section_creates_an_identical_registration_image_from_the_original_upon_construction(): section = Section.create(image=Image(np.empty((2, 10, 10)), resolution_um=10)) assert section.image == section.registration_image
def test_downsampling_beyond_dimensions_produces_valueerror(to_resolution): image = Image(channels=np.arange(24).reshape(1, 4, 6), resolution_um=12) with pytest.raises(ValueError, match=r".* positive.*"): image.resample(resolution_um=to_resolution)
def test_inds_homog_has_correct_shape(chans, height, width): image = Image(channels=np.random.random(size=(chans, height, width))) assert image.inds_homog.shape == (4, height * width)
def test_image_reports_correct_dimensions(chans, height, width): image = Image(channels=np.random.random(size=(chans, height, width))) assert image.num_channels == chans assert image.height == height assert image.width == width