imi-bigpicture / wsidicomizer

Python library for converting WSI files to DICOM
Apache License 2.0
60 stars 8 forks source link

focal plane mapping in CziImageData #27

Closed ychyss closed 2 years ago

ychyss commented 2 years ago

thanks your code to help me...but i notcie some bug here.

when i try to convert czi to dcm, i notice a bug in CziImageData. The original code is writen as:

def _get_focal_plane_mapping(self) -> List[float]:
        image = get_nested_element(
            ElementTree.fromstring(self.metadata),
            ["Metadata", 'Information', 'Image']
        )
        try:
            size_z = int(get_text_from_element(image, 'SizeZ', '0'))
            z_interval = get_nested_element(
                image,
                ['Dimensions', 'Z', 'Positions', 'Interval']
            )
            start = int(get_text_from_element(z_interval, 'Start'))
            increment = int(get_text_from_element(z_interval, 'Increment'))
            _, _, z_scale = self._get_scaling()
            if z_scale is None:
                raise ValueError("No z scale in metadata")
            start_z = start * z_scale
            step_z = (start+increment*size_z)*z_scale
            end_z = increment*z_scale
            return list(np.arange(start_z, end_z, step_z))
        except ValueError:
            return [0.0]

here the step_z and end_z may be revesed... they should be:

            start_z = start * z_scale
            end_z  = (start+increment*size_z)*z_scale
            step_z = increment*z_scale

and then, in the wsidicom->WsiDataset->_get_spacing_between_slices_for_focal_planes, the computing of spacing may have wrong because of the float precision. in my exmaple, the incresment is 0.10073184462375681 between every Z plane.

so, i add a rough way to solve this problem..

        if len(focal_planes) == 1:
            return 0.0
        distances: Set[float] = set()
        d_first = 0.0
        sorted_focal_planes = sorted(focal_planes)
        for index in range(len(sorted_focal_planes)-1):
            distance = (
                sorted_focal_planes[index + 1]
                - sorted_focal_planes[index]
            ) 
            if len(distances) == 0:
                d_first = distance
            else:
                if abs(d_first-distance) < 0.000000001:  # if the distance bias less then an epsilon, i think they are same.
                    distance = d_first
            distances.add(distance)

hope this problem will be fix in a better way...

erikogabrielsson commented 2 years ago

Hi @ychyss Yes it looks like step_z and end_z has been mixed up. And your solution for allowing float precision errors seems reasonable. I will implement these changes.

I also noticed that CziImageData currently does not check the axis order when getting the image size. Did you notice the image size being wrong? Which axes were present in the file you tested?

Also, if you have a czi file with z-stacking to share that would be helpful.

erikogabrielsson commented 2 years ago

These issues have now been fixed by #28. Thanks for reporting!