Repository navigation
Aravis: add the capabilities a camera is usually asked for - #1001
Merged
marktsuchida merged 11 commits intoOct 5, 2026
Merged
Conversation
The layout in a Bayer format's name says which pixel of the 2x2 cell is red. That matters to whatever demosaics the image later; to this adapter, which hands the mosaic to Micro-Manager as it arrives, all four layouts are the same buffer: one component, of the depth the format names. Only the RG layout was listed as supported, so a camera offering BayerBG8 and BayerBG12 -- which is how plenty of colour cameras ship -- had both dropped from the PixelFormat property, and a camera with nothing else could not be opened at all. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The adapter's only use of the camera's frame rate was to switch the limit off at every exposure change, so that the exposure paced the camera. A user who wanted a fixed rate -- to pace an experiment, or to stay inside a link's bandwidth -- had no way to ask for one. AcquisitionFrameRate is now a property wherever the camera has the feature, with the camera's own bounds, and AcquisitionFrameRateEnable alongside it on cameras that have that too. SetExposure() leaves the limit alone while it is switched on, rather than taking away a rate the user just set at the next exposure change. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Cameras that have a temperature sensor report it through the GenICam DeviceTemperature feature, and the adapter never read it. It is a read-only property now, under Micro-Manager's own name for it, CCDTemperature, whatever the sensor is made of -- which is the name the rest of Micro-Manager looks for. Which sensor the camera reports is its DeviceTemperatureSelector to say, and this does not touch it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ReverseX and ReverseY are ordinary features, and on a microscope they matter: the image's handedness depends on how many mirrors the light met on the way to the camera, and a camera that can undo that costs nothing to ask. Micro-Manager's own TransposeMirror properties turn the image over for the screen; these turn it over in the camera, so the data itself arrives the right way round. Both are Boolean features, so one handler serves both -- each property is named after the feature it reads -- and neither property exists on a camera without them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A pattern the camera generates is how a user tells a dark image apart from a broken link, and it is the only image available when nothing is connected to the lens mount. The feature is not called the same thing everywhere: the standard name is TestPattern, and Basler's cameras have TestImageSelector and no TestPattern at all. Both are looked for, and the property is TestPattern either way, with the entries the camera itself offers rather than a list written here. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A packet larger than the path allows is dropped by the network rather than refused by the camera, so the stream fails on large frames and works on small ones, with nothing in the log to say why. The delay between packets is what keeps a camera from overrunning a switch, or a host that cannot take the data at line rate. Aravis reads both and never negotiates them, and the adapter offered no way to see or change either. Both appear only on a GigE camera, and only where the camera has the feature. On USB3 there are no packets to size and the properties do not exist. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Packet loss on a marginal link shows up as frames that never arrive, and nothing else: Micro-Manager simply receives fewer images than it asked for. A user had no way to tell a slow camera from a lossy cable. Aravis counts completed buffers, failures and underruns per stream, so the three are read-only properties now. They are taken from the stream before it is released rather than only while it runs, because the end of a sequence that went wrong is exactly when someone goes looking for them -- and a stream that has been released cannot be asked at all. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Initialize() switches auto exposure off, because Micro-Manager is what sets the exposure and a camera adjusting it underneath makes SetExposure() a refusal on some cameras and a polite fiction on others. That is the right default. But the mode was then never offered, so a camera that ships in auto -- the FLIR Blackfly S does -- had it switched off at every open with no way to ask for it back. ExposureAuto is a property now, in the camera's own vocabulary of Off, Once and Continuous, which is what arv-tool and the vendors' software show. GainAuto keeps its older AUTO_OFF/AUTO_ONCE/AUTO_CONTINUOUS values: changing those would break configurations people have already saved. Like GainAuto, it declines to change mode mid-sequence. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ReverseX, ReverseY and AcquisitionFrameRateEnable are Boolean features in the standard, but a node can carry one of those names and be something else -- an integer holding 0 or 1. Aravis's boolean calls refuse such a node, with "Not a ArvGcBoolean", and a property that reads it at every refresh turns that refusal into a log line per poll: a camera here produced 40 lines over 20 property refreshes. Asking whether the feature is available is not enough, so the three properties are now offered only where the node really is a Boolean. A camera that models them some other way is left without those properties rather than with a property that cannot work and a log that fills up. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Two ways a property can misreport a camera, both found by setting a frame rate on an Alvium. Its limits were read once, at startup. The rate a camera can reach depends on what else it has been asked for -- that camera manages 15.97 Hz at a 5 ms exposure and 5.00 Hz at 200 ms, and the region and binning move it too -- so limits from startup soon describe a camera that no longer exists. Micro-Manager refuses a value outside a property's limits before the adapter is called at all, which turned a rate the camera would have taken into "Cannot set property". The limits are re-read whenever the exposure or the geometry changes, and a rate that arrives anyway is clamped to what the camera can do now, as SetExposure() has always clamped the exposure. The properties also started from values written here rather than from the camera: a frame rate of "0.0", which is not even within its own limits, a temperature of 0 degrees, and mirroring reported as off on a camera that was mirroring. Micro-Manager shows a property from its own cache until something refreshes it, so that placeholder is what the user saw. Each one now starts from what the camera reports. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
AravisCamera.cpp says "These are in alphabetical order" above its method definitions, and they had stopped being so. Most of the drift is from the commits before this one, which put each new method next to a related one rather than in its alphabetical place; three were already out of order before that, including IsExposureSequenceable ahead of IsCapturing. Nothing but position changes: every definition is byte for byte what it was. The header's property and internal blocks are sorted the same way, and GetImageHeight now precedes GetImageWidth there as it does in the definitions. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Member
|
Thanks, @HazenBabcock. These look like useful features. |
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.
I read through the changes that Claude code made and did some manual
testing with a Basler camera and Micro-Manager. I believe that these
capabilities work as described below.
Claude code:
Follow-up to #995. Eleven commits: ten are a capability the adapter did not
have, or a bug found while adding one, and the last only moves code. Tested
against three real cameras — a Basler acA1440-220uc, an Allied Vision 1800
U-1240m and a FLIR Blackfly S BFS-U3-19S4M, all USB3 Vision — and against
emulated GigE cameras for what hardware here cannot show.
Every Bayer layout, not just RG
The layout in a Bayer format's name says which pixel of the 2x2 cell is red.
That matters to whatever demosaics the image; to this adapter, which hands the
mosaic over as it arrives, all four layouts are one component of the format's
depth. Only RG was listed, so a camera offering BayerBG8 and BayerBG12 had
both dropped from
PixelFormat, and a camera with nothing else could not beopened at all.
A frame rate the user can set
The adapter's only use of the camera's rate was to switch the limit off at
every exposure change, so that exposure paced the camera. Anyone who wanted a
fixed rate — to pace an experiment, or to stay inside a link's bandwidth — had
no way to ask for one.
AcquisitionFrameRateis now a property wherever the camera has it, with thecamera's own bounds, and
AcquisitionFrameRateEnablealongside it where thatexists.
SetExposure()leaves the limit alone while it is switched on, ratherthan taking away a rate the user just set at the next exposure change.
Auto exposure, back again
Initialize()switches auto exposure off, because Micro-Manager is what setsthe exposure and a camera adjusting it underneath makes
SetExposure()arefusal on some cameras and a polite fiction on others. That is the right
default — but the mode was never offered afterwards, so a camera that ships in
auto, as the Blackfly S does, had it switched off at every open with no way to
ask for it back.
ExposureAutois a property now, in the camera's vocabularyof Off, Once and Continuous.
GainAutokeeps its olderAUTO_*values:changing those would break saved configurations.
Temperature, mirroring, test pattern
CCDTemperature, read-only, from the camera'sDeviceTemperature. Whichsensor it reports is the camera's
DeviceTemperatureSelectorto say, and thisdoes not touch it.
ReverseXandReverseY, where the camera has them. On a microscope theimage's handedness depends on how many mirrors the light met on the way, and a
camera that can undo that costs nothing to ask. Micro-Manager's own
TransposeMirrorproperties turn the image over for the screen; these turn itover in the camera.
A test pattern, under whichever name the camera uses: the standard
TestPattern, or Basler'sTestImageSelector, which is all a Basler has. Theproperty is
TestPatterneither way, carrying the entries the camera itselfoffers.
GigE packet size and delay
A packet larger than the path allows is dropped by the network rather than
refused by the camera, so the stream fails on large frames and works on small
ones, with nothing in the log to say why. The delay between packets is what
keeps a camera from overrunning a switch or a host. Aravis reads both and
never negotiates them. Both appear only on a GigE camera, and only where the
camera has the feature.
What the stream did
Packet loss shows up as frames that never arrive and nothing else:
Micro-Manager simply receives fewer images than it asked for. Completed,
failed and underrun frame counts are read-only properties now. They are taken
from the stream before it is released, because the end of a sequence that went
wrong is exactly when someone goes looking for them — and a released stream
cannot be asked at all.
A Boolean that is not one
Found while testing the above.
ReverseX,ReverseYandAcquisitionFrameRateEnableare Boolean features in the standard, but a nodecan carry one of those names and be something else — an integer holding 0 or
then refuse the node, and a property that reads it at every refresh turns that
refusal into a log line per poll. One camera here produced 40 lines over 20
property refreshes. The three properties are now offered only where the node
really is a Boolean.
A property that describes the camera
Also found while testing. The frame rate a camera can reach moves with the
exposure, the region and the binning: an Alvium manages 15.97 Hz at a 5 ms
exposure and 5.00 Hz at 200 ms. Limits read once at startup go stale, and
Micro-Manager refuses a value outside a property's limits before the adapter
is called at all -- so a rate the camera would have accepted came back as
"Cannot set property". The limits are re-read whenever the exposure or
geometry changes, and a rate that arrives anyway is clamped to what the camera
can do now, as
SetExposure()has always clamped the exposure.The new properties also started from values written in the adapter rather than
read from the camera: a frame rate of "0.0", outside its own limits, a
temperature of 0, mirroring reported as off on a camera that was mirroring.
Micro-Manager shows a property from its cache until something refreshes it, so
that placeholder is what the user saw. Each now starts from what the camera
reports.
The last commit only moves code
AravisCamera.cppsays "These are in alphabetical order" above its methoddefinitions, and the commits above had put each new method next to a related
one instead. The final commit sorts them, which is about 300 lines of movement
and no change to any of them: every definition is byte for byte what it was,
and three that were already out of place before this branch are sorted too.
Nothing to read there.
Testing
Basler acA1440-220uc, colour, USB3. The frame rate holds 5 Hz across an
exposure change, with the enable flag still set afterwards.
CCDTemperaturereads 61 C, matching
arv-tool.ReverseXandReverseYmirror the scene'sown pixels. The test pattern appears under Basler's
TestImageSelectorspelling, offering Testimage1 to Testimage6, and frames are bit-identical with
one on where the lens sees noise with it off. The stream counters report 5
completed after the stream has been released.
ExposureAutogoes Off ->Continuous -> Off. No packet properties, because USB3 has no packets to size.
No Aravis log line for the whole run, and all 33 recorded settings as found
afterwards.
Allied Vision 1800 U-1240m, mono, USB3. The same, with the test pattern
under the standard
TestPatternname instead, mirroring verified on thescene, temperature 43 C, and 30 settings as found. One difference: this camera
refuses to let Aravis write its frame rate at all, answering
USB3Vision write_memory error (write-protect). That is not the adapter --arv-toolcannot write it either, nor can Aravis with the enable flag set, with
AcquisitionFrameRateModeat its only value, after a delay, or with a streamopen. The property is offered, the camera declines, and the refusal is logged
once per attempt.
FLIR Blackfly S BFS-U3-19S4M, mono, USB3, and the only camera here that
ships with auto exposure and auto gain switched on -- which is what the
ExposureAuto commit is for. The frame rate holds 5 Hz across an exposure
change. The test pattern is
SensorTestPattern.ReverseXandReverseYboth mirror the scene's own pixels. With no lens fitted, where the sensor sees
a flat field,
ReverseXstill turns that test pattern into exactly its mirrorimage byte for byte, while
ReverseYcannot be judged from it -- the patternis vertical bars, identical flipped top to bottom. Temperature 51.5 C, no
Aravis log line, 37 settings as found.
On emulated GigE cameras, new checks covering a frame rate that survives an
exposure change, a GigE camera's packet size, and stream counters that outlive
the stream they describe. The check that a frame rate reaches the camera was
confirmed to fail when the property's write is dropped.
Each camera's settings are recorded before the test and restored afterwards,
and checked against a record of the camera as first found.
🤖 Generated with Claude Code