Probably the second most common complaint relating to Raspberry Pi cameras, after "Help! My camera is not detected!", is this - so here are some tips and advice. The symptom is that the image received from the camera is not the full field of view (FoV) - that is, it appears "cropped" or "zoomed in". To fix this, we need to understand camera modes.
Camera Modes
A camera usually has several readout modes. There's always a full resolution mode where you receive an image that is the full sensor resolution. Depending on the sensor this may be quite large, and it may only support lower framerates than other modes.
In addition to this, there can be cropped modes, where only a portion of the full resolution image is returned, and binned modes. Binned modes amalgamate several of the sensors pixels, usually a 2x2 group of them, into a single output pixel. This reduces both the image width and height by half, and normally results in higher achievable framerates. Besides this 2x2 binned mode, some sensors may support higher binning factors, modes using both binning and cropping, or even asymmetric binning factors, though this is more rare.
Camera modes cause difficulties because applications normally ask for a particular output resolution, and it's impossible from this to know for sure which is the most appropriate camera mode. Should we be prioritising resolution for a higher quality output, or is framerate more important? The only general solution is to let users discover the available camera modes and choose the one that they want.
Discovering the Camera Modes
In rpicam-apps
The easiest way to discover the available camera modes is to open a terminal window and enterFor an HQ cam (using the IMX477 sensor) this outputs:This is telling us that camera 0 has an imx477 sensor, with a native full resolution of 4056x3040 pixels at 12 bits per sample. The native Bayer order is RGGB (see, for example, here if you are not familiar with Bayer sensors), though flipping or rotating the output from the sensor will normally change the order.
The final mode in the list is clearly the full resolution mode for this sensor, and the one just above (2028x1520) is a 2x2 binned version of the full sensor image. Note that each line specifies a crop as (x,y)/wxh, where x and y are the offsets of the top left output pixel in the full resolution sensor image, and w and h are the width and height of the output (again, in full resolution pixel units).
The other two modes are not full FoV. The 2028x1080 mode is applying some letter-boxing (only the y offset is non-zero), whereas the 1332x990 mode is taking just a central portion from the sensor array. Both of these modes are 2x2 binned, which you can tell by the output dimensions (for example, 1332x990) being half the listed crop width/height (2664x1980).
In Python
In Python you can list the sensor modes too. You should do this as the first thing after opening the camera because doing so will reconfigure the camera several times and require you to stop any active camera session. RunningyieldsWe have exactly the same camera modes as before, indicating the same crop, the same bit depth, Bayer order and framerate. Additionally we obtain the min/max/default exposure times for the mode (in microseconds), as well the pixel format for both the packed and unpacked versions of the mode that we can supply when configuring the camera (more on this later).
Packed Modes and Unpacked Modes
Besides the use of binned or cropped sensor modes, we also have a choice of how the pixels are stored in memory - either "packed" or "unpacked". An "unpacked" mode will store every single pixel sample into a 16-bit word in memory. This makes them easy to manipulate with the CPU, and is the obvious choice for anyone wanting to process the raw pixel data for themselves.
The "packed" version stores pixels in a packed or compressed format. This is more efficient as it uses less memory and less memory bandwidth so should normally be the default unless your application has a particular reason to prefer unpacked data.
Pi 5 vs. earlier Pis
On a Pi 4 (or earlier):
In rpicam-apps
Here it's very easy to choose the camera mode. You can add the "--mode" or "--viewfinder-mode" parameter to the command line to force the choice of a particular camera mode as follows:Here, we've given the width, height and bit depth of the camera mode (separated by a colon), plus an extra "P" to denote "packed". You would use "U" for "unpacked". It's best to supply all these parameters to be 100% sure you get what you want. You could leave off the "P" and it would default to the same thing, but if you left off the the 10 (bit-depth), it would go for a 12 bit camera mode giving you something altogether different.
Use "--viewfinder-mode" for rpicam-hello and the preview mode of rpicam-still. For the capture mode in rpicam-still, and rpicam-vid, use "--mode". In all cases, you should be able to verify the chosen camera modes from the console messages.
In Python
Use the "sensor" parameter when creating your camera configuration. You can specify the output size (from the sensor), and the bit depth. So to choose the 1332x990 mode of the HQ cam, you could useBy default this will give you a packed (Pi 4 or earlier) or compressed (Pi 5) format in the raw sensor stream buffer. To force an unpacked pixel format, ask for an unpacked format for the raw streamWhen you do this, the precise Bayer order is ignored - there is only one the sensor can supply, and that is what you will get. The bit depth in the format here will also be ignored in favour of the sensor bit depth - it really only is the fact that it's an unpacked format that matters. Recall that the "picam2.sensor_modes" lists what format to ask for depending on whether you want unpacked or packed/compressed output.
In all cases, after applying the configuration to the camera ("picam2.configure(config)"), check the camera configuration to verify what actually happened. So afteron a Pi 5 we obtain"SBGGR16" confirms that we have 16-bit pixels using the full 16-bit output range, and that it's unpacked. The Bayer order is also corrected to the one that the sensor will produce. The remaining sensor part of the configuration confirms that we have the 10-bit camera mode that we wanted. On a Pi 4 you'd see "SBGGR10" rather than "SBGGR16" - these are still one pixel per 16-bit word, but using only a 10-bit range.
Had you wanted a packed/compressed format, you could ask for "SBGGR10_CSI2P" in place of "SBGGR10". Again, it's only the "CSI2P" part, indicating packing, that matters, giving a a packed output (Pi 4 or earlier) or compressed output (Pi 5). Note that on a Pi 5, after configuration, the format will actually be reported as "BGGR_PISP_COMP1" indicating that the format is in reality compressed, not just packed. The distinction between packed/compressed and unpacked, and packing on ealier Pis vs. compression on Pi 5, can be tricky, so it's well worth experimenting a bit in an interactive Python shell to verify how things behave.
More information on this can be found in section 4.2.2 of the Picamera2 manual. Configuring the sensor and raw streams is a complex topic, so it's well worth familiarising yourself with all the available information!
Anything incorrect or unclear?
If anything is unclear, or you have further questions, please ask in a separate thread. We'll edit and update the text here to reflect any improvements. Thanks!
Camera Modes
A camera usually has several readout modes. There's always a full resolution mode where you receive an image that is the full sensor resolution. Depending on the sensor this may be quite large, and it may only support lower framerates than other modes.
In addition to this, there can be cropped modes, where only a portion of the full resolution image is returned, and binned modes. Binned modes amalgamate several of the sensors pixels, usually a 2x2 group of them, into a single output pixel. This reduces both the image width and height by half, and normally results in higher achievable framerates. Besides this 2x2 binned mode, some sensors may support higher binning factors, modes using both binning and cropping, or even asymmetric binning factors, though this is more rare.
Camera modes cause difficulties because applications normally ask for a particular output resolution, and it's impossible from this to know for sure which is the most appropriate camera mode. Should we be prioritising resolution for a higher quality output, or is framerate more important? The only general solution is to let users discover the available camera modes and choose the one that they want.
Discovering the Camera Modes
In rpicam-apps
The easiest way to discover the available camera modes is to open a terminal window and enter
Code:
rpicam-hello --list-camerasCode:
Available cameras-----------------0 : imx477 [4056x3040 12-bit RGGB] (/base/axi/pcie@1000120000/rp1/i2c@88000/imx477@1a) Modes: 'SRGGB10_CSI2P' : 1332x990 [120.05 fps - (696, 528)/2664x1980 crop] 'SRGGB12_CSI2P' : 2028x1080 [50.03 fps - (0, 440)/4056x2160 crop] 2028x1520 [40.01 fps - (0, 0)/4056x3040 crop] 4056x3040 [10.00 fps - (0, 0)/4056x3040 crop]The final mode in the list is clearly the full resolution mode for this sensor, and the one just above (2028x1520) is a 2x2 binned version of the full sensor image. Note that each line specifies a crop as (x,y)/wxh, where x and y are the offsets of the top left output pixel in the full resolution sensor image, and w and h are the width and height of the output (again, in full resolution pixel units).
The other two modes are not full FoV. The 2028x1080 mode is applying some letter-boxing (only the y offset is non-zero), whereas the 1332x990 mode is taking just a central portion from the sensor array. Both of these modes are 2x2 binned, which you can tell by the output dimensions (for example, 1332x990) being half the listed crop width/height (2664x1980).
In Python
In Python you can list the sensor modes too. You should do this as the first thing after opening the camera because doing so will reconfigure the camera several times and require you to stop any active camera session. Running
Code:
from picamera2 import Picamera2from pprint import pprintpicam2 = Picamera2()pprint(picam2.sensor_modes)Code:
[{'bit_depth': 10, 'crop_limits': (696, 528, 2664, 1980), 'exposure_limits': (31, 667234896, 20000), 'format': SRGGB10_CSI2P, 'fps': 120.05, 'size': (1332, 990), 'unpacked': 'SRGGB10'}, {'bit_depth': 12, 'crop_limits': (0, 440, 4056, 2160), 'exposure_limits': (60, 674181621, 20000), 'format': SRGGB12_CSI2P, 'fps': 50.03, 'size': (2028, 1080), 'unpacked': 'SRGGB12'}, {'bit_depth': 12, 'crop_limits': (0, 0, 4056, 3040), 'exposure_limits': (60, 674181621, 20000), 'format': SRGGB12_CSI2P, 'fps': 40.01, 'size': (2028, 1520), 'unpacked': 'SRGGB12'}, {'bit_depth': 12, 'crop_limits': (0, 0, 4056, 3040), 'exposure_limits': (114, 694422939, 20000), 'format': SRGGB12_CSI2P, 'fps': 10.0, 'size': (4056, 3040), 'unpacked': 'SRGGB12'}]Packed Modes and Unpacked Modes
Besides the use of binned or cropped sensor modes, we also have a choice of how the pixels are stored in memory - either "packed" or "unpacked". An "unpacked" mode will store every single pixel sample into a 16-bit word in memory. This makes them easy to manipulate with the CPU, and is the obvious choice for anyone wanting to process the raw pixel data for themselves.
The "packed" version stores pixels in a packed or compressed format. This is more efficient as it uses less memory and less memory bandwidth so should normally be the default unless your application has a particular reason to prefer unpacked data.
Pi 5 vs. earlier Pis
On a Pi 4 (or earlier):
- Unpacked pixels are stored directly into 16-bit words so that the most significant bits (beyond the sample bit-depth) are zero.
- Packed pixels are stored using standard CSI2 packing. For 10-bit pixels, 4 samples are stored in 5 bytes. For 12-bit pixels, it's 2 samples in 3 bytes. The precise format is beyond the scope of this document, but it's not too hard to unpack using the CPU if required.
- Unpacked pixels are left-shifted up to the full 16 bits before being stored into 16-bit words. All the zero bits are therefore at the least significant end. The camera configuration can be inspected to verify the actual bit-depth of the camera samples (see later).
- Pi 5 uses compression rather than packing. This uses a 1-byte per sample visually lossless scheme. It can be decompressed but the process is relatively slow, so unpacked formats should usually be preferred over decompression.
- The Pi 5 compression format is lossy. If your application needs to preserve exact values from the sensor, ask for an unpacked format as these bypass the compression process entirely.
In rpicam-apps
Here it's very easy to choose the camera mode. You can add the "--mode" or "--viewfinder-mode" parameter to the command line to force the choice of a particular camera mode as follows:
Code:
rpicam-hello --viewfinder-mode 1332:990:10:PUse "--viewfinder-mode" for rpicam-hello and the preview mode of rpicam-still. For the capture mode in rpicam-still, and rpicam-vid, use "--mode". In all cases, you should be able to verify the chosen camera modes from the console messages.
In Python
Use the "sensor" parameter when creating your camera configuration. You can specify the output size (from the sensor), and the bit depth. So to choose the 1332x990 mode of the HQ cam, you could use
Code:
config = picam2.create_preview_configuration(sensor={'output_size': (1332, 990), 'bit_depth': 10})Code:
sensor = {'output_size': (1332, 990), 'bit_depth': 10}config = picam2.create_preview_configuration(raw={'format': 'SRGGB10'}, sensor=sensor)In all cases, after applying the configuration to the camera ("picam2.configure(config)"), check the camera configuration to verify what actually happened. So after
Code:
from picamera2 import Picamera2picam2 = Picamera2()config = picam2.create_preview_configuration(raw={"format": "SRGGB12"}, sensor={"output_size": (1332, 990), "bit_depth": 10})picam2.configure(config)Code:
>>> picam2.camera_configuration()['sensor']{'bit_depth': 10, 'output_size': (1332, 990)}>>> picam2.camera_configuration()['raw']{'format': 'SBGGR16', 'size': (1332, 990), 'stride': 2688, 'framesize': 2661120}Had you wanted a packed/compressed format, you could ask for "SBGGR10_CSI2P" in place of "SBGGR10". Again, it's only the "CSI2P" part, indicating packing, that matters, giving a a packed output (Pi 4 or earlier) or compressed output (Pi 5). Note that on a Pi 5, after configuration, the format will actually be reported as "BGGR_PISP_COMP1" indicating that the format is in reality compressed, not just packed. The distinction between packed/compressed and unpacked, and packing on ealier Pis vs. compression on Pi 5, can be tricky, so it's well worth experimenting a bit in an interactive Python shell to verify how things behave.
More information on this can be found in section 4.2.2 of the Picamera2 manual. Configuring the sensor and raw streams is a complex topic, so it's well worth familiarising yourself with all the available information!
Anything incorrect or unclear?
If anything is unclear, or you have further questions, please ask in a separate thread. We'll edit and update the text here to reflect any improvements. Thanks!
Statistics: Posted by therealdavidp — Mon Dec 08, 2025 12:13 pm