Skip to content
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

Add jpeg adapter, support for image/jpeg mimetype #796

Open
wants to merge 12 commits into
base: main
Choose a base branch
from

Conversation

jwlodek
Copy link
Member

@jwlodek jwlodek commented Oct 15, 2024

Checklist

  • Add a Changelog entry
  • Add the ticket number which this PR closes to the comment section

Sister PR to bluesky/bluesky#1816. Tested in the lab with a real camera. Still needs added tests, and currently requires source install of ophyd-async branch that includes AD JPEG writer.

Edit: Tests added and all passing now.

@jwlodek
Copy link
Member Author

jwlodek commented Oct 15, 2024

In [25]: run['primary']['external']['manta-cam1'].metadata
Out[25]: 
{'data_key': 'manta-cam1',
 'mimetype': 'multipart/related;type=image/jpeg',
 'parameters': {'chunk_shape': [1, 544, 728],
                'template': 'proj_6ffba08d-9416-472c-974d-fbe5a1b1fcdd_{:06d}.jpeg'},
 'run_start': '0d1ab7fc-3e95-40ac-96df-0dd4820af8a7',
 'uid': '986d0ee3-1528-4e75-86c3-14f4feaba9fe',
 'uri': 'file://localhost/nsls2/data/tst/legacy/mock-proposals/2024-1/pass-000000/assets/'}

In [26]: run['primary']['external']['manta-cam1'][7]
Out[26]: 
array([[2, 2, 2, ..., 0, 0, 0],
       [2, 2, 2, ..., 0, 0, 0],
       [2, 2, 2, ..., 0, 0, 0],
       ...,
       [0, 0, 0, ..., 0, 0, 0],
       [0, 0, 0, ..., 0, 0, 0],
       [0, 0, 0, ..., 0, 0, 0]], dtype=uint8)

In [27]:

@jwlodek jwlodek marked this pull request as ready for review October 17, 2024 12:15
}
IMG_SEQUENCE_EMPTY_NAME_ROOT = "_unnamed"

IMG_SEQUENCE_MIMETYPES = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just out of curiosity, does anyone use .png? or maybe other more esoteric formats?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not aware of any of our beamlines writing pngs, I think a compressed format but not as compressed as jpeg is probably of limited use - if they want actual data they'd use tiff, if they want a snapshot where they don't care if data is compressed, jpeg is probably fine

from .type_alliases import JSON, NDSlice


class JPEGAdapter:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if there's a chance to define base classes, something like ImageAdapter and ImageSequenceAdapter and then subclass them for jpeg and tiff? What we will need to specify when subclassing are the supported mimetypes, and file reading functions (for a single file and for the sequence) -- otherwise the code looks almost identical.
Happy to help with restructuring it!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think the two can easily be combined, and probably should. Maybe just passing a callable that accepts a filepath to an image and returns an np array would be enough?

Copy link
Contributor

@genematx genematx Oct 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that was what I thought too, first; for tiffs and jpegs alone, just passing a callable should be enough, but this may not extend to any other formats (or if there's need for some custom logic) in the future (this is partly why I was asking about pngs). I think, I'd be in favor of keeping seperate JPEGAdapter and TiffAdapter classes (subclassed from ImageAdapter), even if they are very short.

self._provided_metadata = metadata or {}
self.access_policy = access_policy
if structure is None:
shape = (len(self._seq), *self.read(slice=0).shape)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ran into this problem yesterday, and it took me some time to figure out what was going on... During the init time, read() method may still be partially undefined, for example if it accesses self.structure(). I know it's not the case right now, but this limits our ability to extend it later (unfortunately, in a very non-obvious way).

-------

"""
return {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return {}
return self._provided_metadata.copy()

shape = (len(self._seq), *self.read(slice=0).shape)
structure = ArrayStructure(
shape=shape,
# one chunks per underlying TIFF file
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# one chunks per underlying TIFF file
# one chunks per underlying JPEG file

(although, unnecessary if we move this part to FileSequenceAdapter)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants