LJMUAstroecology / flirpy

Python library to interact with FLIR camera cores
Other
199 stars 53 forks source link

Lepton Flir UW 160 FOV | AGC cant be enabled (non-radiometric) #104

Open Bra1nsen opened 3 weeks ago

Bra1nsen commented 3 weeks ago

Version 0.3.0

Describe the bug AGC (Automatic Gain Control) settings cannot be enabled on non-radiometric FLIR Lepton cameras when using flirpy. The camera.set_agc(True) command has no effect, and AGC-related settings are unresponsive. In the GetThermal application, we confirmed that AGC control is dependent on radiometry support, as AGC settings are disabled when supportsRadiometry is false. Commenting out this radiometry dependency line in GetThermal was necessary to enable AGC settings.

To Reproduce 1Set up a non-radiometric FLIR Lepton camera with flirpy. 2Attempt to enable AGC using camera.set_agc(True) and configure AGC parameters like set_agc_mode and set_agc_max_gain. 3Verify that AGC settings do not apply, and the image output remains unaffected. 4Confirm AGC dependency on radiometry in GetThermal by opening ~/GetThermal/qml/lepton/AgcControls.qml and observing that 5AGC settings are disabled when supportsRadiometry is false. Comment out or remove enabled: !acq.cci.supportsRadiometry in AgcControls.qml to manually override the dependency.

Expected behavior AGC should be configurable independently of radiometry support, particularly for non-radiometric Lepton cameras, as AGC primarily affects image contrast and should ideally not require radiometric capabilities.

Screenshots If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

Additional context expected image:

image

current image:

image

script used:

import time
from datetime import datetime
from flirpy.camera.lepton import Lepton
from PIL import Image
import numpy as np
import os

def setup_camera(camera):
    """Configure camera settings for capturing."""

    # **Automatic Gain Control (AGC) Settings**
    try:
        camera.set_agc(True)  # Enable AGC
        print("AGC enabled.")

        # AGC Advanced Settings
        camera.set_agc_mode("HEQ")                # Options: "Linear", "HEQ"
        camera.set_agc_max_gain(4)                # Max gain for AGC
        camera.set_agc_clip_limit_high(255)       # High clip limit
        camera.set_agc_clip_limit_low(0)          # Low clip limit
        camera.set_agc_damping_factor(0.1)        # Low damping factor for quick AGC adjustment
        print("AGC configured with mode HEQ, max gain 4, high contrast, and low damping.")

    except AttributeError:
        print("AGC settings not supported by this library or camera.")

    # **Flat-Field Correction (FFC) Settings**
    try:
        camera.set_ffc_mode("manual")  # Options: "automatic", "manual"
        camera.set_ffc_period(10)      # Set FFC period if in automatic mode (in seconds)
        camera.perform_ffc()           # Manually perform FFC
        print("FFC configured to manual mode and performed.")

    except AttributeError:
        print("FFC settings not supported by this library or camera.")

    # **Radiometry Settings**
    try:
        camera.set_radiometry(True)         # Enable radiometric mode
        camera.set_emissivity(0.98)         # Set emissivity
        camera.set_radiometry_units("Celsius")  # Temperature units: "Celsius", "Fahrenheit", "Kelvin"
        print("Radiometry enabled with emissivity set to 0.98 and units in Celsius.")

    except AttributeError:
        print("Radiometry settings not supported by this library or camera.")

    # **Resolution and Frame Rate Settings**
    try:
        camera.set_resolution((160, 120))   # Max resolution for Lepton 3.x models
        camera.set_frame_rate(9)            # Frame rate in Hz
        print("Resolution set to 160x120, frame rate set to 9 Hz.")

    except AttributeError:
        print("Resolution or frame rate settings not supported by this library or camera.")

    # **Gain and Contrast Settings**
    try:
        camera.set_gain(0.1)        # Set low gain
        camera.set_contrast(4.0)    # Set high contrast
        print("Gain set to 0.1 (low), contrast set to 4.0 (high).")

    except AttributeError:
        print("Gain or contrast settings not supported by this library or camera.")

    # **Color Palette Setting (Iron Black)**
    try:
        camera.set_color_map("Iron Black")  # Set color map to Iron Black
        print("Color palette set to Iron Black.")

    except AttributeError:
        print("Color map setting not supported by this library or camera.")

def capture_image(camera):
    """Capture a thermal image, normalize, and save with a timestamp."""
    # Capture an image as a numpy array
    image = camera.grab()

    # Normalize the array to 8-bit grayscale for display purposes
    image = (image / np.max(image) * 255).astype(np.uint8)
    pil_image = Image.fromarray(image)

    # Generate a filename with the current timestamp
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    filename = f"thermal_images/thermal_image_{timestamp}.png"

    # Save the image
    pil_image.save(filename)
    print(f"Image saved as {filename}")

def main():
    # Ensure output directory exists
    os.makedirs("thermal_images", exist_ok=True)

    # Open the Lepton camera and set it up
    with Lepton() as camera:
        setup_camera(camera)
        print("Starting image capture every 30 seconds. Press Ctrl+C to stop.")

        try:
            while True:
                capture_image(camera)
                time.sleep(30)  # Wait 30 seconds before the next capture
        except KeyboardInterrupt:
            print("\nImage capture stopped by user.")

if __name__ == "__main__":
    main()
jveitchmichaelis commented 2 weeks ago

Hi,

This isn't exactly a bug. None of the control functions (like flat fielding/AGC request) are currently implemented in Flirpy because the way they're communicated to the PureThermal board is not trivial (in Python, anyway). It's unclear to me where most of your code comes from - none of those methods exist in Flirpy so it's not surprising that they don't work. The only methods available for the Lepton beyond core are some setup functions and a telemetry decoder. This allows for some basic functionality with PureThermal boards, but you don't get control.

The way that the GroupGets library works, is it provides a custom version of libuvc that sends camera commands via UVC extension. In some respect, this is a logical way to add this sort of control, but just implementing a normal serial interface would have made life a lot easier (i.e. as FLIR does with its other camera cores). Their fork of libuvc is now years old and doesn't seem to be maintained.

GetThermal uses a modified version of libuvc for camera image download and control. Even if you have libuvc on your system already, you will have to build the fork.

We might be able to do workaround via this approach: https://github.com/groupgets/purethermal1-uvc-capture, calling v4l2-ctl via subprocess. That would be fine I think.

Could you check if those V4L commands work on your Pi via a terminal? If they do then it should be straightforward to add support, assuming the later boards work in the same way.

Otherwise you are correct, AGC has no dependence on radiometry. It's just a flat field correction. For example, the Boson was non-radiometric for a long time.

The other option is to use the OEM breakout board which I think works fine on a full size Pi (but not a Zero) and implement the commands over serial. That's a... "on the list" feature, but I haven't had any time to devote to it.

Best Josh