Make get_movie setup eager, acquisition lazy; optimize serval - #166
Draft
Baharis wants to merge 128 commits into
Draft
Make get_movie setup eager, acquisition lazy; optimize serval#166Baharis wants to merge 128 commits into
get_movie setup eager, acquisition lazy; optimize serval#166Baharis wants to merge 128 commits into
Conversation
…. TODO: investigate why.
…s (up to a few hundred)
…d up to ~70 if diffraction
…nd up to ~70 if diffraction
…dexed, plot correctly
# Conflicts: # src/instamatic/camera/camera_serval.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR is work in progress. It contains irrelevant history from a branch with multiple other features that should be ignored here.
Eager setup – lazy acquisition
Instamatic has two methods to get camera feed,
get_imageandget_movie. The latter is underutilized to the degree where many cameras implement it as loop overget_image. In my work, I strive to flesh outget_movieas a distinct alternative that allows receives images as they are collected, minimizes dead time, and in general allows collecting short burst-series in contrast to the more generalget_image. For this reason, I modifiedget_movieto return iterator in #121 and updated/supported it since (#137, #154, #160). Here I suggest another improvement toget_moviethat will make it more responsive.In python, every callable can have two exit points,
returnoryield. When called, methods thatreturnrun immediately, but methods thatyielddo not; instead they return aGeneratorthat executes only once it is iterated usingnext. This creates lazy iterables, executed only when demanded, which is very useful e.g. for demanding or infinite loops.The lazy/eager distinction of return/yield can be used to minimize
get_movie's dead time. Becauseget_moviealways returns an iterable, it can receive two unique signals to start: one when it is called, and one when it is iterated over. From my experience working with Instamatic I realized that this can be used to create really fine control over timing.Here I suggest utilizing the double-start mechanism of
get_moviein the following way:get_movieis called: videostream is blocked, camera is configured for a movie, and ageneratoris created.generatoris iterated: camera immediately starts collecting images.get_imageand videostream is unblocked.This behavior allows for a really fine control over timing. When writing multi-threaded code I noticed that I often want to start camera and some TEM change concurrently. With proposed mechanism, this can be done the following way:
In order to get this behavior, two changes are required. Firstly,
LiveVideoStreamandMediaGrabberresponsible for streaming need a separate callable withyieldthat is called it as late as possible. Secondly, individual implementations of cameras need to do the same. This allows cameras to "prepare" for movie acquisition, and then start it quickly, which makes synchronizing camera and TEM much easier.Finally, suggested change is non-invasive. If any existing script already uses
get_movie, it will behave just as expected. Ultimately, most persons interested in movies will callget_movieimmediately before iterating them (for i, h in ctrl.get_movie(n, e)), in which case separating startup and iteration will have little to no effect. No changes to other implementations are also strictly needed, unless someone desired to reap benefits of this eager setup / lazy acquisition mechanism.Serval optimization
The current implementation of
get_moviein serval is nice and easy but falls off at high data rates. Serval client first asks camera for N frames, and thenget_requests every one individually. In my tests I noticed that this introduces delays, to the degree where I could not get more than 8 images per second. To counter it, I implemented a custom TCP stream reader that circumvents ASI package. With it in place, all movie data is streamed by the server continuously and read in milliseconds. The mechanism is completely optional and can be switched on by settingSTREAM_MOVIES_VIA_TCP = Truein camera_serval.py orstream_movies_via_tcp = trueincamera.yaml.