From 43878b36e2af9c5cef6d21a855ddd1b45be7a5a6 Mon Sep 17 00:00:00 2001 From: yair Date: Sun, 16 Nov 2025 04:05:26 +0200 Subject: [PATCH] add auto gain --- scripts/camera_control.py | 23 +++++++++++++++- scripts/launch-ids.py | 44 ++++++++++++++++++++++++++++--- sys/idsueye/gstidsueyesrc.c | 52 ++++++++++++++++++++++++++++++++----- sys/idsueye/gstidsueyesrc.h | 1 + 4 files changed, 108 insertions(+), 12 deletions(-) diff --git a/scripts/camera_control.py b/scripts/camera_control.py index 21881e5..ce0883a 100644 --- a/scripts/camera_control.py +++ b/scripts/camera_control.py @@ -17,6 +17,8 @@ Usage: uv run scripts/camera_control.py set-gain 50 # Set gain to 50 uv run scripts/camera_control.py get-auto-exposure # Get auto-exposure status uv run scripts/camera_control.py set-auto-exposure 1 # Enable auto-exposure + uv run scripts/camera_control.py get-auto-gain # Get auto-gain status + uv run scripts/camera_control.py set-auto-gain 1 # Enable auto-gain uv run scripts/camera_control.py status # Get pipeline status This script provides both individual control commands and full test suite functionality @@ -186,6 +188,8 @@ Examples: %(prog)s set-gain 50 # Set gain to 50 %(prog)s get-auto-exposure # Get auto-exposure status %(prog)s set-auto-exposure 1 # Enable auto-exposure + %(prog)s get-auto-gain # Get auto-gain status + %(prog)s set-auto-gain 1 # Enable auto-gain %(prog)s status # Get pipeline status """, formatter_class=argparse.RawDescriptionHelpFormatter @@ -194,7 +198,8 @@ Examples: parser.add_argument('command', nargs='?', choices=['test', 'get-exposure', 'set-exposure', 'get-framerate', 'set-framerate', - 'get-gain', 'set-gain', 'get-auto-exposure', 'set-auto-exposure', 'status'], + 'get-gain', 'set-gain', 'get-auto-exposure', 'set-auto-exposure', + 'get-auto-gain', 'set-auto-gain', 'status'], help='Command to execute') parser.add_argument('value', @@ -279,6 +284,22 @@ Examples: success = simple_command(f"SET_AUTO_EXPOSURE {ae_value}", f"{'Enabling' if ae_value else 'Disabling'} auto-exposure") + elif args.command == 'get-auto-gain': + success = simple_command("GET_AUTO_GAIN", "Getting auto-gain status") + + elif args.command == 'set-auto-gain': + if args.value is None: + print("Error: set-auto-gain requires a value (0=off, 1=on)") + parser.print_help() + sys.exit(1) + # Convert to int + ag_value = int(args.value) + if ag_value not in [0, 1]: + print("Error: Auto-gain must be 0 (off) or 1 (on)") + sys.exit(1) + success = simple_command(f"SET_AUTO_GAIN {ag_value}", + f"{'Enabling' if ag_value else 'Disabling'} auto-gain") + elif args.command == 'status': success = simple_command("STATUS", "Getting pipeline status") diff --git a/scripts/launch-ids.py b/scripts/launch-ids.py index 3a63407..3462cb5 100644 --- a/scripts/launch-ids.py +++ b/scripts/launch-ids.py @@ -28,7 +28,8 @@ # - Dynamic exposure control (0.015-30000 milliseconds, default: 10ms) # - Auto-exposure mode support (--auto-exposure flag) # - Dynamic framerate control (1-20000 fps, default: 750fps) -# - Dynamic gain control (0-100, 0 for auto, default: 0) +# - Dynamic gain control (0-100, default: 0) +# - Auto-gain mode support (--auto-gain flag) # - Dynamic camera ID selection (0-254, default: 0 for first found) # - Dynamic device ID selection (0-254, system enumeration ID) # - Configurable video cropping (default: crop 3 pixels from bottom) @@ -44,10 +45,12 @@ # GET_CAMERA_ID - Get current camera ID # SET_DEVICE_ID - Set device ID (0-254, system enumeration) # GET_DEVICE_ID - Get current device ID -# SET_GAIN - Set master gain (0-100, 0 for auto) +# SET_GAIN - Set master gain (0-100) # GET_GAIN - Get current gain value # SET_AUTO_EXPOSURE <0|1> - Enable (1) or disable (0) auto-exposure # GET_AUTO_EXPOSURE - Get auto-exposure status +# SET_AUTO_GAIN <0|1> - Enable (1) or disable (0) auto-gain +# GET_AUTO_GAIN - Get auto-gain status # STATUS - Get pipeline status and current settings # # Example Control Usage: @@ -138,7 +141,8 @@ class ControlServer: print(f"Control server listening on UDP port {self.port}") print(" Commands: SET_EXPOSURE , GET_EXPOSURE, SET_FRAMERATE , GET_FRAMERATE,") print(" SET_CAMERA_ID , GET_CAMERA_ID, SET_DEVICE_ID , GET_DEVICE_ID,") - print(" SET_GAIN , GET_GAIN, SET_AUTO_EXPOSURE <0|1>, GET_AUTO_EXPOSURE, STATUS") + print(" SET_GAIN , GET_GAIN, SET_AUTO_EXPOSURE <0|1>, GET_AUTO_EXPOSURE,") + print(" SET_AUTO_GAIN <0|1>, GET_AUTO_GAIN, STATUS") while self.running: try: @@ -200,6 +204,10 @@ class ControlServer: return self.handle_set_auto_exposure(parts) elif cmd == "GET_AUTO_EXPOSURE": return self.handle_get_auto_exposure() + elif cmd == "SET_AUTO_GAIN": + return self.handle_set_auto_gain(parts) + elif cmd == "GET_AUTO_GAIN": + return self.handle_get_auto_gain() elif cmd == "STATUS": return self.handle_status() else: @@ -371,6 +379,33 @@ class ControlServer: except Exception as e: return f"ERROR: {str(e)}" + def handle_set_auto_gain(self, parts): + """Handle SET_AUTO_GAIN command""" + if len(parts) != 2: + return "ERROR INVALID_SYNTAX: Usage: SET_AUTO_GAIN <0|1>" + + try: + value = int(parts[1]) + if value not in [0, 1]: + return "ERROR OUT_OF_RANGE: Auto-gain must be 0 (off) or 1 (on)" + + self.src.set_property("auto-gain", bool(value)) + actual = self.src.get_property("auto-gain") + return f"OK {int(actual)}" + + except ValueError: + return "ERROR INVALID_SYNTAX: Auto-gain must be 0 or 1" + except Exception as e: + return f"ERROR: {str(e)}" + + def handle_get_auto_gain(self): + """Handle GET_AUTO_GAIN command""" + try: + value = self.src.get_property("auto-gain") + return f"OK {int(value)}" + except Exception as e: + return f"ERROR: {str(e)}" + def handle_status(self): """Handle STATUS command""" try: @@ -380,6 +415,7 @@ class ControlServer: device_id = self.src.get_property("device-id") gain = self.src.get_property("gain") auto_exposure = int(self.src.get_property("auto-exposure")) + auto_gain = int(self.src.get_property("auto-gain")) # Get pipeline state state = "UNKNOWN" @@ -387,7 +423,7 @@ class ControlServer: _, current_state, _ = self.pipeline.get_state(0) state = current_state.value_nick.upper() - return f"OK exposure={exposure} framerate={framerate} camera_id={camera_id} device_id={device_id} gain={gain} auto_exposure={auto_exposure} state={state}" + return f"OK exposure={exposure} framerate={framerate} camera_id={camera_id} device_id={device_id} gain={gain} auto_exposure={auto_exposure} auto_gain={auto_gain} state={state}" except Exception as e: return f"ERROR: {str(e)}" diff --git a/sys/idsueye/gstidsueyesrc.c b/sys/idsueye/gstidsueyesrc.c index a28db70..b81348c 100644 --- a/sys/idsueye/gstidsueyesrc.c +++ b/sys/idsueye/gstidsueyesrc.c @@ -75,7 +75,8 @@ enum PROP_EXPOSURE, PROP_FRAMERATE, PROP_GAIN, - PROP_AUTO_EXPOSURE + PROP_AUTO_EXPOSURE, + PROP_AUTO_GAIN }; #define DEFAULT_PROP_CAMERA_ID 0 @@ -87,6 +88,7 @@ enum #define DEFAULT_PROP_FRAMERATE 0 #define DEFAULT_PROP_GAIN 0 #define DEFAULT_PROP_AUTO_EXPOSURE FALSE +#define DEFAULT_PROP_AUTO_GAIN FALSE /* pad templates */ @@ -175,6 +177,10 @@ gst_idsueyesrc_class_init (GstIdsueyeSrcClass * klass) g_param_spec_boolean ("auto-exposure", "Auto Exposure", "Enable automatic exposure control", DEFAULT_PROP_AUTO_EXPOSURE, (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + g_object_class_install_property (gobject_class, PROP_AUTO_GAIN, + g_param_spec_boolean ("auto-gain", "Auto Gain", + "Enable automatic gain control", DEFAULT_PROP_AUTO_GAIN, + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); } static void @@ -211,6 +217,7 @@ gst_idsueyesrc_init (GstIdsueyeSrc * src) src->framerate = DEFAULT_PROP_FRAMERATE; src->gain = DEFAULT_PROP_GAIN; src->auto_exposure = DEFAULT_PROP_AUTO_EXPOSURE; + src->auto_gain = DEFAULT_PROP_AUTO_GAIN; src->stop_requested = FALSE; src->caps = NULL; @@ -272,6 +279,12 @@ gst_idsueyesrc_set_property (GObject * object, guint property_id, gst_idsueyesrc_set_framerate_exposure (src); } break; + case PROP_AUTO_GAIN: + src->auto_gain = g_value_get_boolean (value); + if (src->is_started) { + gst_idsueyesrc_set_framerate_exposure (src); + } + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -315,6 +328,9 @@ gst_idsueyesrc_get_property (GObject * object, guint property_id, case PROP_AUTO_EXPOSURE: g_value_set_boolean (value, src->auto_exposure); break; + case PROP_AUTO_GAIN: + g_value_set_boolean (value, src->auto_gain); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -971,14 +987,36 @@ gst_idsueyesrc_set_framerate_exposure (GstIdsueyeSrc * src) } } - /* Set gain if specified (0 means use default/auto) */ - if (src->gain > 0) { - ret = is_SetHardwareGain (src->hCam, src->gain, IS_IGNORE_PARAMETER, - IS_IGNORE_PARAMETER, IS_IGNORE_PARAMETER); + /* Handle auto-gain */ + if (src->auto_gain) { + /* Enable auto gain */ + double enable = 1.0; + ret = is_SetAutoParameter (src->hCam, IS_SET_ENABLE_AUTO_GAIN, + &enable, NULL); if (ret != IS_SUCCESS) { - GST_WARNING_OBJECT (src, "Failed to set gain to %d (error %d)", - src->gain, ret); + GST_WARNING_OBJECT (src, "Failed to enable auto gain (error %d)", ret); success = FALSE; + } else { + GST_DEBUG_OBJECT (src, "Auto gain enabled"); + } + } else { + /* Disable auto gain */ + double disable = 0.0; + ret = is_SetAutoParameter (src->hCam, IS_SET_ENABLE_AUTO_GAIN, + &disable, NULL); + if (ret != IS_SUCCESS) { + GST_WARNING_OBJECT (src, "Failed to disable auto gain (error %d)", ret); + } + + /* Set manual gain if specified (0 means use default) */ + if (src->gain > 0) { + ret = is_SetHardwareGain (src->hCam, src->gain, IS_IGNORE_PARAMETER, + IS_IGNORE_PARAMETER, IS_IGNORE_PARAMETER); + if (ret != IS_SUCCESS) { + GST_WARNING_OBJECT (src, "Failed to set gain to %d (error %d)", + src->gain, ret); + success = FALSE; + } } } diff --git a/sys/idsueye/gstidsueyesrc.h b/sys/idsueye/gstidsueyesrc.h index 7a62049..abb108f 100644 --- a/sys/idsueye/gstidsueyesrc.h +++ b/sys/idsueye/gstidsueyesrc.h @@ -59,6 +59,7 @@ struct _GstIdsueyeSrc gdouble framerate; gint gain; gboolean auto_exposure; + gboolean auto_gain; GstClockTime acq_start_time; guint32 last_frame_count;