raspberrypi / picamera2

New libcamera based python library
BSD 2-Clause "Simplified" License
891 stars 188 forks source link

[BUG?] Setting overlay after camera.start() raises an exception #661

Open dev-zzo opened 1 year ago

dev-zzo commented 1 year ago

Please only report one bug per issue!

Describe the bug Calling set_overlay() after start() is called results in an exception getting raised. Doing the same before start() is called works properly but precludes updating the overlay at a later point. I do believe this is a bug, however it might be me misusing the API in some way.

To Reproduce

I tried piecing together the code for you to reproduce the issue while sticking as close to what I have as I could:

def create_camera(screen_width=1920, screen_height=1080):
  from picamera2 import Picamera2, Preview
  # grab a camera
  camera = Picamera2()
  # adjust the preview to preserve camera aspect ratio
  array_size = camera.camera_properties["PixelArraySize"]
  preview_width = int(float(array_size[0]) / float(array_size[1]) * screen_height)
  preview_height = screen_height
  # create the configuration
  config = camera.create_still_configuration(
    main={'size': (array_size[0] // 2, array_size[1] // 2)},
    lores={'size': (preview_width, preview_height)},
    display='lores')
  camera.configure(config)
  # start the camera
  camera.start_preview(Preview.DRM, x=(screen_width - preview_width) // 2, y=0, width=preview_width, height=preview_height)
  camera.start()
  # create the overlay
  from PIL import Image, ImageDraw
  from tempfile import mkstemp
  from os import unlink, close
  img = Image.new('RGBA', (preview_width, preview_height))
  # skipping the actual drawing...
  tempfile, tempname = mkstemp(suffix=".png")
  close(tempfile)
  img.save(tempname)
  camera.set_overlay(cv2.imread(tempname, cv2.IMREAD_UNCHANGED))
  unlink(tempname)

  return camera

Expected behaviour I would expect to be able to set/update overlay images at any point while the camera is running.

Console Output, Screenshots

...
INFO:picamera2.picamera2:Camera started
Traceback (most recent call last):
  File "/home/pi/ps.py", line 381, in <module>
    do_capture(args)
  File "/home/pi/ps.py", line 312, in do_capture
    camera = create_camera()
  File "/home/pi/ps.py", line 170, in create_camera
    set_preview_overlay(camera)
  File "/home/pi/ps.py", line 192, in set_preview_overlay
    camera.set_overlay(cv2.imread(tempname, cv2.IMREAD_UNCHANGED))
  File "/usr/lib/python3/dist-packages/picamera2/picamera2.py", line 1528, in set_overlay
    self._preview.set_overlay(overlay)
  File "/usr/lib/python3/dist-packages/picamera2/previews/drm_preview.py", line 107, in set_overlay
    self.render_drm(self.picam2, self.current)
  File "/usr/lib/python3/dist-packages/picamera2/previews/drm_preview.py", line 111, in render_drm
    display_stream_name = completed_request.config['display']
TypeError: 'NoneType' object is not subscriptable

Hardware : Pi 3B with HQ camera attached.

Additional context Add any other context about the problem here.

davidplowman commented 1 year ago

Thanks for reporting that. I think the problem is that the preview thinks it has acquired a "handle" on the request currently being displayed, only when you're running with only a single buffer it can't actually do that. So I'll patch that up but in the meantime you should find it works ok if you add buffer_count=2 to your configuration. (Actually it may run better too with two buffers, maybe even increase the buffer count by more.)

dev-zzo commented 1 year ago

Thanks for having a look, David. Increasing buffer count did fix the issue indeed!