-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Retina Image in E2E file #20
Comments
Dear @ly1998117, Do you know the shape of the contained image? I find 3 slices (probably the RGB channels), but the image height and width seem to be encoded differently than in the other formats. You can use the code below to read the bytes containing the header and one channel of your image. import eyepy as ep
from eyepy.io import HeE2eReader
from eyepy.io.he.e2e_format import TypesEnum
import numpy as np
with HeE2eReader("H1AMD328.E2E") as e2e_reader:
slices = e2e_reader.series[0].slices
folder = slices[0].folders[TypesEnum.image][0] # slices[0] selects probably one of the channels
b = folder.get_bytes() # Read the complete bytes including the header of the folder
data = np.frombuffer(b, dtype=np.uint8) You can try to decode the bytes to an image by experimenting with different encodings (int8, uint8, float32, etc.), image shapes (this is easier if you already know the shape), and maybe even byte/bit offsets since the header might contain values of different data types. Let me know if you figured it out, then I would include it in eyepy, so it works out of the box. Best, |
Hi @olivier, I’ve investigated the issue further. It seems that the 3 slices actually correspond to 3 images instead of representing the RGB channels, since I have tried another EYE file which has only 2 slices. Additionally, I noticed that the size of the converted JPEG images by HEIDELBERG EYE EXPLORER is significantly larger than the slice data read by eyepy. This could be related to how the data is being decoded or encoded during the conversion process. For your reference, I’ve uploaded the EYE files and the corresponding JPEG images to Google Drive. Feel free to take a look and let me know if you spot anything that could explain the size discrepancy. Let me know if you’d like me to continue exploring this or provide any further details. Best regards, |
By the way, I would like to understand why the Heidelberg Eye Explorer outputs OCT images differently compared to eyepy.
How can I replicate this combined visualization (IR + green scan lines + OCT slices) using eyepy?
|
You are right the slices are 3 different images and I also figured how to read them. The header of the folder is only 16 bytes long here and the remaining bytes contain a JFIF file which can be read with PIL. If I find the time I'll add it to eyepy, but for now you can use the code below to read the images. import eyepy as ep
from eyepy.io import HeE2eReader
from eyepy.io.he.e2e_format import TypesEnum
from io import BytesIO
from PIL import Image
with HeE2eReader("H1AMD328.E2E") as e2e_reader:
slices = e2e_reader.series[0].slices
folder = slices[0].folders[TypesEnum.image][0] # slices[0] selects probably one of the channels
b = folder.get_bytes() # Read the complete bytes including the header of the folder
img = Image.open(io.BytesIO(b[16:]))) Best Olivier |
Hi @olivier, Thank you so much for your insightful reply and for pointing me in the right direction. Your code snippet also works perfectly, and I was able to load the images using PIL as you suggested. I’ll keep an eye on any further improvements for the excellent eyepy library, but in the meantime, I’ll continue using the workaround you provided. Thanks again for your support, and I appreciate you taking the time to share your findings. Best regards, |
The E2E file contains the data and the Heidelberg viewer shows this data in a particular way. You can use matplotlib in python to show the NIR localizer next to one of the B-scans and also indicate the B-scan position on the NIR. Have a look at the EyeVolume EyeEnface and EyeBscan objects, they provide plotting functions which might be usefull for you. I have never tried to visualize the radial Scan layout you show, but the grid layout where Bscans are stacked should work out of the box. For the FA and ICGA Image Concatenatio, I have no experience with this data. |
I just modify the source code, and it works now. class DataType:
localizer = 33620481
oct = 35652097
retina = 33620225
class RetinaAdapter(construct.Adapter):
def _decode(self, obj: bytes, context, path):
data = np.array(Image.open(io.BytesIO(obj)), dtype='uint8')
return data
def _encode(self, obj: np.ndarray, context, path):
return obj.astype(np.uint8).tobytes()
Retina = RetinaAdapter(construct.Bytes(construct.this.n_values))
@dataclasses.dataclass
class Type1073741824(DataclassMixin, TypeMixin):
"""Image data Stores various kinds of images.
Size: variable
Notes:
Different kinds of images are stored in this structure. Currently we know the following types:
* 33620481: LocalizerNIR (`int8u`)
* 35652097: Bscan (`float16u`)
The custom `float16u` used to store the Bscan data, has no sign, a 6-bit exponent und 10-bit mantissa.
"""
size: int = csfield(construct.Int32ul, doc='Size of the data')
type: int = csfield(construct.Int32ul, doc='Type of the data')
n_values: int = csfield(construct.Int32ul, doc='Number of values in the data')
height: int = csfield(construct.Int32ul, doc='Height of the image')
width: t.Optional[int] = csfield(If(lambda ctx: ctx.type != DataType.retina, construct.Int32ul), doc='Width of the image')
data: t.Any = csfield(construct.Switch(construct.this.type, {
DataType.localizer: LocalizerNIR,
DataType.oct: Bscan,
DataType.retina: Retina,
},
default=construct.Bytes(construct.this.size)),
doc='Image data') I also discovered that the type |
Description
I have an RGB Retina E2E file where the head information is readable, but the main image cannot be read. The Image data.type of the main image is 33620225, which differs from other common types like 33620481 or 35652097. How can I interpret or process this 33620225 type image data?
H1AMD328.E2E.zip
The text was updated successfully, but these errors were encountered: