Open Manuel-Angel-Es opened 1 year ago
A short test program which shows the issue is the following code:
import os
import picamera2 as pc2
import time
useNewConfig = True
class PicameraTest:
def __init__(self):
self.picamera2 = pc2.Picamera2()
self.rawModes = [
{"size":(1332, 990),"format":"SRGGB10"},
{"size":(2028, 1080),"format":"SRGGB12"},
{"size":(2028, 1520),"format":"SRGGB12"},
{"size":(4056, 3040),"format":"SRGGB12"}
]
config = self.picamera2.create_still_configuration()
self.mode = 3
config['buffer_count'] = 4
config['queue'] = True
config['raw'] = self.rawModes[self.mode]
config['main'] = {"size":self.rawModes[self.mode]['size'],'format':'RGB888'}
self.picamera2.configure(config)
def setMode(self, para):
# stop the camera
self.picamera2.stop()
time.sleep(0.2)
if useNewConfig:
config = self.picamera2.create_still_configuration(raw={})
else:
config = self.picamera2.camera_configuration()
config['raw'] = self.rawModes[int(para)]
config['main'] = {"size":self.rawModes[int(para)]['size'], 'format':'RGB888'}
self.picamera2.configure(config)
self.picamera2.start()
print('Video mode is now: %d' % int(para))
request = self.picamera2.capture_request()
request.save_dng(str(int(para)) + ".dng")
request.release()
def stop(self):
self.picamera2.stop()
def main():
# Print OS version
os_version = os.popen('cat /etc/os-release').read()
print(os_version)
cam_test = PicameraTest()
time.sleep(2)
for i in range(len(cam_test.rawModes)):
cam_test.setMode(i)
time.sleep(0.1)
# Test modes in reverse order
for i in reversed(range(len(cam_test.rawModes))):
cam_test.setMode(i)
time.sleep(0.1)
cam_test.stop()
print("Test completed!")
if __name__ == "__main__":
main()
With the global flag useNewConfig = True
, the program runs as expected; with the flag useNewConfig = False
, the resolution stays at the 4k res. Tests were done on a RP3 with the orignal HQ sensor and CMA=320MB. The same program runs flawlessly on earlier OS-versions.
That bug is still there today, after upgrading the RP3 to the latest version of Bookworm, that is, with picamera2 version 0.3.14.
With useNewConfig = True
I get the following line (as expected):
[0:41:36.315546877] [7482] INFO Camera camera.cpp:1181 configuring streams: (0) 1332x990-RGB888 (1) 1332x990-SBGGR10
[0:41:36.317038680] [7498] INFO RPI vc4.cpp:608 Sensor: /base/soc/i2c0mux/i2c@1/imx477@1a - Selected sensor format: 1332x990-SBGGR10_1X10 - Selected unicam format: 1332x990-BG10
with the selected sensor format as requested, namely 1332x990-SBGGR10_1X10
.
But with useNewConfig = False
, the selected sensor format is always 4056x3040-BG12
, which is wrong:
[0:43:15.344342869] [7702] INFO Camera camera.cpp:1181 configuring streams: (0) 1332x990-RGB888 (1) 4056x3040-SBGGR12
[0:43:15.345149893] [7718] INFO RPI vc4.cpp:608 Sensor: /base/soc/i2c0mux/i2c@1/imx477@1a - Selected sensor format: 4056x3040-SBGGR12_1X12 - Selected unicam format: 4056x3040-BG12
One way to circumvent this is to start always with a new base config. In this case however, all the other parameters of a config need to be buffered externally and set again for each mode switch. There are use cases where the selected transform
, buffer_count
and NoiseReductionMode
for example should stay as they are, even if the camera performs a mode switch - that used to work flawlessly in the previous OS-version, but fails now.
Hi, thanks for reporting this.
Would it be possible to submit a test script in the form
from picamera2 import Picamera2
picam2 = Picamera2()
config = picam2.create_preview_configuration(...stuff...)
picam2.configure(config)
print(picam2.camera_configuration())
as that would make it easy to see the problem and saves me from having to understand longer bits of code.
I should add that there have been changes in libcamera as to how configuration happens. The way we used the raw stream to force the sensor configuration was regarded as a bit of a "bodge", and so you now have to configure the sensor directly. Picamera2 will normally figure out the sensor configuration from the raw stream that you specify, so as to maintain backward compatibility. But it's possible you're falling into a difference in the new way of doing things.
As I said in the forum post, there is updated documentation coming but unfortunately that's a bit of a 1000-mile journey at the moment. I also said I'd try and post some abbreviated guidance shortly, and I am trying to get back to that. In the meantime, anything that makes test cases really easy to follow is a big help. Thanks!
@davidplowman,
Thanks for your attention.
I have prepared a small python script to highlight the problem:
from picamera2 import Picamera2
picam2 = Picamera2()
config = picam2.create_still_configuration()
picam2.configure(config)
picam2.still_configuration.main.size=(2028, 1520)
picam2.still_configuration.raw.size=(2028, 1520)
picam2.configure("still")
print(picam2.camera_configuration())
picam2.still_configuration.main.size=(4056, 3040)
picam2.still_configuration.raw.size=(4056, 3040)
picam2.configure("still")
print(picam2.camera_configuration())
picam2.close()
Look at the output of the first configuration. Both the size of the main stream and the raw stream are correct at the resolution of 2028 x 1520 px
After the second resolution change, the resolution of the main stream has changed, which is correct at 4056 x 3040 px, but the resolution of the raw stream has not changed, which remains at 2028 x 1520 px.
Script output results:
[20:27:51.377945844] [235416] INFO Camera camera_manager.cpp:284 libcamera v0.1.0+99-4a23664b
[20:27:51.441276356] [235426] WARN RPiSdn sdn.cpp:39 Using legacy SDN tuning - please consider moving SDN inside rpi.denoise
[20:27:51.444275165] [235426] INFO RPI vc4.cpp:444 Registered camera /base/soc/i2c0mux/i2c@1/imx477@1a to Unicam device /dev/media1 and ISP device /dev/media2
[20:27:51.444360590] [235426] INFO RPI pipeline_base.cpp:1142 Using configuration file '/usr/share/libcamera/pipeline/rpi/vc4/rpi_apps.yaml'
[20:27:51.461632142] [235416] INFO Camera camera_manager.cpp:284 libcamera v0.1.0+99-4a23664b
[20:27:51.509979292] [235429] WARN RPiSdn sdn.cpp:39 Using legacy SDN tuning - please consider moving SDN inside rpi.denoise
[20:27:51.512743160] [235429] INFO RPI vc4.cpp:444 Registered camera /base/soc/i2c0mux/i2c@1/imx477@1a to Unicam device /dev/media1 and ISP device /dev/media2
[20:27:51.512868621] [235429] INFO RPI pipeline_base.cpp:1142 Using configuration file '/usr/share/libcamera/pipeline/rpi/vc4/rpi_apps.yaml'
[20:27:51.520676048] [235416] INFO Camera camera.cpp:1181 configuring streams: (0) 4056x3040-BGR888 (1) 4056x3040-SBGGR12_CSI2P
[20:27:51.521241873] [235429] INFO RPI vc4.cpp:608 Sensor: /base/soc/i2c0mux/i2c@1/imx477@1a - Selected sensor format: 4056x3040-SBGGR12_1X12 - Selected unicam format: 4056x3040-pBCC
[20:27:51.557560304] [235416] INFO Camera camera.cpp:1181 configuring streams: (0) 2028x1520-BGR888 (1) 2028x1520-SBGGR12_CSI2P
[20:27:51.558109722] [235429] INFO RPI vc4.cpp:608 Sensor: /base/soc/i2c0mux/i2c@1/imx477@1a - Selected sensor format: 2028x1520-SBGGR12_1X12 - Selected unicam format: 2028x1520-pBCC
{'use_case': 'still', 'buffer_count': 1, 'transform': <libcamera.Transform 'identity'>, 'display': None, 'encode': None, 'colour_space': <libcamera.ColorSpace 'sYCC'>, 'controls': <Controls: {'NoiseReductionMode': <NoiseReductionModeEnum.HighQuality: 2>, 'FrameDurationLimits': (100, 1000000000)}>, 'main': {'size': (2028, 1520), 'format': 'BGR888', 'stride': 6144, 'framesize': 9338880}, 'lores': None, 'raw': {'size': (2028, 1520), 'format': 'SBGGR12_CSI2P', 'stride': 3072, 'framesize': 4669440}, 'queue': True, 'sensor': {'bit_depth': 12, 'output_size': (2028, 1520)}}
[20:27:51.577172545] [235416] INFO Camera camera.cpp:1181 configuring streams: (0) 4056x3040-BGR888 (1) 2028x1520-SBGGR12_CSI2P
[20:27:51.577701722] [235429] INFO RPI vc4.cpp:608 Sensor: /base/soc/i2c0mux/i2c@1/imx477@1a - Selected sensor format: 2028x1520-SBGGR12_1X12 - Selected unicam format: 2028x1520-pBCC
{'use_case': 'still', 'buffer_count': 1, 'transform': <libcamera.Transform 'identity'>, 'display': None, 'encode': None, 'colour_space': <libcamera.ColorSpace 'sYCC'>, 'controls': <Controls: {'NoiseReductionMode': <NoiseReductionModeEnum.HighQuality: 2>, 'FrameDurationLimits': (100, 1000000000)}>, 'main': {'size': (4056, 3040), 'format': 'BGR888', 'stride': 12192, 'framesize': 37063680}, 'lores': None, 'raw': {'size': (2028, 1520), 'format': 'SBGGR12_CSI2P', 'stride': 3072, 'framesize': 4669440}, 'queue': True, 'sensor': {'bit_depth': 12, 'output_size': (2028, 1520)}}
In previous versions of picamera2 the resolution change worked normally.
Regards
Hi, thanks for the simple test case, that's very helpful.
There have indeed been some changes in how libcamera configures the sensor, and I talk about this a bit in the release notes on the forum. Mostly I've tried to hide the change from users, but I haven't done it properly for people using the picam2.still_configuration
idiom for setting up the camera configuration.
I'll fix this shortly, but for now the best workaround is to put
picam2.still_configuration = picam2.create_still_configuration()
at the top when you start changing the configuration.
Once I have fixed the code, the correct procedure will be to do
picam2.still_configuration.sensor.output_size = (4056, 3040)
instead of
picam2.still_configuration.raw.size = (4056, 3040)
(you can do both, though setting raw.size
would be unnecessary).
Hi @davidplowman,
Thank you very much for your attention and your kind response.
I hope it doesn't take you too much work to modify the code.
Best regards
I have a very similar problem while trying to flip the image, and the posted workaround fixes the issue. I hope that since the solution is the same that means the necessary code changes are the same!
picam2 = Picamera2(camera)
transform = libcamera.Transform(hflip=True, vflip=True)
still_config = picam2.create_still_configuration(transform=transform)
picam2.configure(still_config)
print(picam2.camera_configuration())
output:
{'use_case': 'still', 'transform': <libcamera.Transform 'hvflip'>, 'colour_space': <libcamera.ColorSpace 'sYCC'>, 'buffer_count': 1, 'queue': True, 'main': {'format': 'BGR888', 'size': (4608, 2592), 'stride': 13824, 'framesize': 35831808}, 'lores': None, 'raw': {'format': 'SRGGB10_CSI2P', 'size': (4608, 2592), 'stride': 5760, 'framesize': 14929920}, 'controls': {'NoiseReductionMode': <NoiseReductionModeEnum.HighQuality: 2>, 'FrameDurationLimits': (100, 1000000000)}, 'sensor': {'bit_depth': 10, 'output_size': (4608, 2592)}, 'display': None, 'encode': None}
However after capturing an image it is not flipped, even though the 'transform' member in the output would indicate otherwise.
Applying the workaround in this thread and adding the line
picam2.still_configuration = still_config
results in a properly flipped image.
I am thankful that @Manuel-Angel-Es opened this issue and that @davidplowman posted the workaround! Thanks everyone, hope this issue can be fixed soon.
@cdcformatc There has been some stuff in libcamera to do with transforms that got broken. I think maybe this release might be the first one to pick up that broken stuff even though it happened quite some time ago? I think it might be principally the reporting that's got messed up, libcamera is confused about what rotation it reports back to us. I believe it to be fixed in mainline libcamera now, but unfortunately those fixes break Picamera2 so there's some integration work to do. Sigh. I'll look into it, but maybe let's not discuss it in this issue as it is not the same thing. Thanks!
Back to the original problem, the proposed fix is here: https://github.com/raspberrypi/picamera2/pull/850
Discussed in https://github.com/raspberrypi/picamera2/discussions/838