Streaming and acquisition#
pyFlir supports two acquisition styles: manual stream control (start, read in a
loop, stop) and the convenience wrappers (grab for a single frame,
acquire for a fixed batch).
Convenience acquisition#
For one-shot or batch acquisition the simplest path is:
frame = cam.grab() # single frame → numpy (H, W) uint16
frames = cam.acquire(20) # list of 20 (H, W) arrays
Both wrap the start/read/stop cycle automatically. grab() starts the stream,
reads one frame, and stops. acquire(n) does the same for n frames.
Live streaming#
For continuous display or processing loops, control the stream manually:
cam.start_stream()
try:
while True:
frame = cam.read(timeout=2.0, latest=True)
process_and_display(frame)
finally:
cam.stop_stream()
Pass latest=True to read() in display loops. Without
it, if your processing loop falls behind the camera frame rate, frames
accumulate in the internal queue and the displayed image drifts further behind
real time each second. latest=True drains the queue and always returns the
most recent frame, keeping end-to-end latency bounded to one frame period.
ROI and frame rate#
Reducing the sensor window (ROI) increases the maximum achievable frame rate. Query the camera’s constraints first:
limits = cam.get_roi_limits()
# {'width_min': 16, 'width_inc': 16, 'height_min': 5, 'height_inc': 4,
# 'sensor_width': 640, 'sensor_height': 512}
print(cam.get_roi())
# {'width': 640, 'height': 512, 'offset_x': 0, 'offset_y': 0}
# Switch to a smaller window (stop the stream first)
cam.set_roi(320, 256)
print(f"Max FPS at new ROI: {cam.frame_rate_max:.1f} Hz")
Width must be a multiple of width_inc; height must satisfy
(height - height_min) % height_inc == 0. Heights are reported in usable
image rows — the driver adds any camera-appended metadata rows internally and
they do not appear in the returned arrays.
Metadata rows#
Some FLIR cameras (including the A6751sc) append one or more telemetry rows to
each frame. pyFlir detects these automatically during load_xml() by reading
the SensorHeight register and comparing it to the frame height. The extra
rows are stripped from every returned frame; the stripped data is accessible on
cam.last_metadata_rows if needed.
NUC and flag#
Non-Uniformity Correction improves image uniformity. The workflow is to move the physical flag in front of the detector, apply NUC, then stow the flag:
cam.flag_move_in_fov() # physical flag blocks the detector
cam.trigger_nuc() # apply NUC coefficients
cam.flag_move_stowed() # stow flag, resume imaging
The camera must be streaming or in a suitable state for the NUC command to be accepted; refer to the camera’s hardware manual for timing requirements.
Calibration blocks#
FLIR A-series cameras store multiple calibration presets, each covering a different temperature range. List and select them:
for b in cam.get_calibration_blocks():
active = " ← active" if b["index"] == cam.get_calibration_block() else ""
print(f"[{b['index']}] {b.get('name', '')} "
f"{b['tmin']:.0f}–{b['tmax']:.0f} °C{active}")
cam.set_calibration_block(0) # select the first (coldest) range
Radiometric object parameters#
These values affect the accuracy of temperature measurements derived from raw digital counts. Set them to match your measurement scenario:
cam.set_object_params(
emissivity = 0.95, # surface emissivity (0–1)
distance_m = 1.0, # object-to-camera distance in metres
atm_temp_K = 293.15, # atmospheric temperature in Kelvin
refl_temp_K = 293.15, # reflected apparent temperature in Kelvin
humidity = 0.50, # relative humidity (0–1)
)
print(cam.get_object_params())
Temperature sensors#
Read all on-board thermistors:
for name, celsius in cam.get_temperatures().items():
print(f"{name}: {celsius:.1f} °C")
The FPA (focal-plane array) temperature is also available as a property:
print(f"FPA: {cam.detector_temperature:.1f} °C")
Raw GenICam feature access#
Features not exposed as properties can be read and written by GenICam name:
cam.read_int("Width")
cam.write_int("Height", 256)
cam.read_float("AcquisitionFrameRate")
cam.read_enum("PixelFormat")
cam.execute_command("AcquisitionStart")
Use list_features() to see every feature node loaded from
the XML.