Skip to content

Instantly share code, notes, and snippets.

@rwb27
Last active April 27, 2023 15:09
Show Gist options
  • Save rwb27/a23808e9f4008b48de95692a38ddaa08 to your computer and use it in GitHub Desktop.
Save rwb27/a23808e9f4008b48de95692a38ddaa08 to your computer and use it in GitHub Desktop.
Manually setting gain of raspberry pi camera from within python
from __future__ import print_function
import picamera
from picamera import mmal, mmalobj, exc
from picamera.mmalobj import to_rational
import time
MMAL_PARAMETER_ANALOG_GAIN = mmal.MMAL_PARAMETER_GROUP_CAMERA + 0x59
MMAL_PARAMETER_DIGITAL_GAIN = mmal.MMAL_PARAMETER_GROUP_CAMERA + 0x5A
def set_gain(camera, gain, value):
"""Set the analog gain of a PiCamera.
camera: the picamera.PiCamera() instance you are configuring
gain: either MMAL_PARAMETER_ANALOG_GAIN or MMAL_PARAMETER_DIGITAL_GAIN
value: a numeric value that can be converted to a rational number.
"""
if gain not in [MMAL_PARAMETER_ANALOG_GAIN, MMAL_PARAMETER_DIGITAL_GAIN]:
raise ValueError("The gain parameter was not valid")
ret = mmal.mmal_port_parameter_set_rational(cam._camera.control._port,
gain,
to_rational(value))
if ret == 4:
raise exc.PiCameraMMALError(ret, "Are you running the latest version of the userland libraries? Gain setting was introduced in late 2017.")
elif ret != 0:
raise exc.PiCameraMMALError(ret)
def set_analog_gain(camera, value):
"""Set the gain of a PiCamera object to a given value."""
set_gain(camera, MMAL_PARAMETER_ANALOG_GAIN, value)
def set_digital_gain(camera, value):
"""Set the digital gain of a PiCamera object to a given value."""
set_gain(camera, MMAL_PARAMETER_DIGITAL_GAIN, value)
if __name__ == "__main__":
with picamera.PiCamera() as cam:
cam.start_preview(fullscreen=False, window=(0,50,640,480))
time.sleep(2)
# fix the auto white balance gains at their current values
g = cam.awb_gains
cam.awb_mode = "off"
cam.awb_gains = g
# fix the shutter speed
cam.shutter_speed = cam.exposure_speed
print("Current a/d gains: {}, {}".format(cam.analog_gain, cam.digital_gain))
print("Attempting to set analogue gain to 1")
set_analog_gain(cam, 1)
print("Attempting to set digital gain to 1")
set_digital_gain(cam, 1)
# The old code is left in here in case it is a useful example...
#ret = mmal.mmal_port_parameter_set_rational(cam._camera.control._port,
# MMAL_PARAMETER_DIGITAL_GAIN,
# to_rational(1))
#print("Return code: {}".format(ret))
try:
while True:
print("Current a/d gains: {}, {}".format(cam.analog_gain, cam.digital_gain))
time.sleep(1)
except KeyboardInterrupt:
print("Stopping...")

Setting Pi camera analogue/digital gain from Python

This gist contains a very minimal Python script that shows how to set the analogue and digital gains of the Raspberry Pi camera module from within Python. It is a trivial thing, all the actual work was done by the developers of userland in particular 6by9, and of course the developers of picamera. It does require the latest version of the userland libraries in order to be able to send the gain-setting commands. These are not yet (as of January 2018) in the main Raspbian distribution, but it is not scary to build this yourself:

sudo apt-get install cmake
git clone https://github.com/raspberrypi/userland.git
cd userland
./buildme
sudo shutdown -r now

After you've got the latest version of the userland libraries, you should be able to run

python set_gain.py

This will open a preview window and then freeze the analogue and digital gains at 1. Look at the code to see how it's done - it is not complicated. To use this in your own code, just do:

import picamera
from set_picamera_gain import set_analog_gain, set_digital_gain

with picamera.PiCamera() as cam:
    set_analog_gain(cam, 2)
    set_digital_gain(cam, 1)

Hopefully I will get round to making a pull request to picamera - but of course that's only really useful once the userland code is updated in the distribution.

@jhihn
Copy link

jhihn commented Mar 25, 2021

I am trying to reverse engineer this for a project using the C++ raspicam library. I'm setting the gains, I think appropriately, but it is not working.
What is the significance of line 49? cam.shutter_speed = cam.exposure_speed

In the C++ I set shutter speed to a value I like, and exposure to off. I think this should do the same thing?

@oferbentovim
Copy link

oferbentovim commented Aug 7, 2022

to capture stable images use this code in python
you do not have to use opencv as it is not installed easily


from picamerax import PiCamera #https://gist.github.com/rwb27/a23808e9f4008b48de95692a38ddaa08/ 
from picamerax.array import PiRGBArray

def InitCamera():
	iso = 120
	awbR = 1.25
	awbB = 1.8
	shutter = 35500
	angain = 1
	dggain = 1

	#camera.resolution = (2592, 1944) # this gets an image with a bluish line on the bottom of the image
	camera.resolution = (2592, 1440) #v4l2-ctl --list-formats-ext 
	camera.framerate = 10
	camera.vflip = True
	camera.hflip = True
	#camera.start_preview(fullscreen=False, window = (35, 35, 60, 60))

	camera.exposure_mode = 'off'
	camera.awb_mode = 'off'
	camera.drc_strength = 'off'
	camera.iso = iso	
	camera.shutter_speed = shutter 
	camera.analog_gain = angain
	camera.digital_gain = dggain
	camera.awb_gains = (awbR,awbB) # (red, blue) 

def GetImageAndShow():
	# grab an image from the camera
	rawCapture = PiRGBArray(camera)
	camera.capture(rawCapture, format="bgr")
	image = rawCapture.array
	cv2.imshow("output", image)
	k = cv2.waitKeyEx(5) & 0xFF
	#if k == 27: #Esc - this will only work if thre is a cv2.window working
	#	Exit = True
	filename = PixDir + "/test.png"
	cv2.imwrite(filename, image)

it does capture a stable image however the maximum image size available is not achived even if you set gpu memory to 256 in sudo raspi-config

@rwb27
Copy link
Author

rwb27 commented Aug 19, 2022

@oferbentovim I've never found a definitive answer, but raw RGB captures don't often work at full resolution. I've had better success with JPEG captures at full resolution, or JPEG plus Bayer data (if you want the full uncompressed pixel data). The latter requires a bit more work to process the image and is slow, but seems way more reliable.

@rwb27
Copy link
Author

rwb27 commented Aug 19, 2022

@jhihn that line sets the shutter speed to the last value used by the auto exposure - it means the exposure doesn't change when we switch from auto to manual. If you already have a sensible value for shutter speed, you can safely ignore it.

@TheAllKnowingSeaweed
Copy link

TheAllKnowingSeaweed commented Apr 27, 2023

Did anyone get this to work without getting errors or find another way of setting the analog gain high consitently? @dogadogan @vijayashri91 did you manage to find a solution to this problem around the error wit userland download?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment