waveform80 / picamera

A pure Python interface to the Raspberry Pi camera module
https://picamera.readthedocs.io/
BSD 3-Clause "New" or "Revised" License
1.57k stars 357 forks source link

Problem updating overlay #448

Open sithdaddy opened 6 years ago

sithdaddy commented 6 years ago

hello.

I am trying to modify an overlay consisting of images using the "update" function but i get constantly this message in the terminal ...

Traceback (most recent call last): File "_ctypes/callbacks.c", line 314, in 'calling callback function' File "/usr/lib/python2.7/dist-packages/picamera/mmalobj.py", line 1227, in wrapper self._pool.send_buffer(block=False) File "/usr/lib/python2.7/dist-packages/picamera/mmalobj.py", line 1931, in send_buffer super(MMALPortPool, self).send_buffer(port, block, timeout) File "/usr/lib/python2.7/dist-packages/picamera/mmalobj.py", line 1881, in send_buffer raise PiCameraMMALError(mmal.MMAL_EAGAIN, 'no buffers available') picamera.exc.PiCameraMMALError: no buffers available: Resource temporarily unavailable; try again later

The only way to avoid that would be to remove the overlay each time and then recreating it with a new content. the problem with that is overlay flicker , even if one removes an overlay from a lower layer.

here is the code i use ...

===========================================================

import picamera from PIL import Image, ImageDraw, ImageFont import time

camera = picamera.PiCamera() camera.resolution = (1280, 800) camera.framerate = 30 camera.start_preview()

overlay_renderer = None file_name = "ANIMATIONS/NOFLIP/LABELS/overlay0.png" file_name2 = "ANIMATIONS/NOFLIP/LABELS/overlay1.png"

def OSD_render() :

global overlay_renderer global file_name2

img = Image.new("RGBA", (1280, 800),(255,255,255,0)) #create new image img1= Image.open(file_name2) #load overlay1.png img.paste(img1, (0,0) ,img1) #paste overlay1.png into img1

overlay_renderer.update(img.tostring()) #update "img" to layer 3

if name == 'main':

imgDtmp= Image.open(file_name)
imgD = Image.new("RGBA", (1280, 800),(255,255,255,0))    #DUMMY BLANK IMAGE
imgD.paste(imgDtmp, (0,0) ,imgDtmp)
overlay_renderer = camera.add_overlay(imgD.tostring(),layer=3,size=imgD.size,alpha=0)

while True:
  OSD_render()
  time.sleep(2)

=============================================================

How can i fix this issue ?

AStinch commented 6 years ago

Hey, have just come accross this problem as well and although the program still works it absolutely kills my frame rate due to print statements and im guessing other background processing. Will upload code when I have simplified a bit to help with debugging. I will also be trying to find a fix but is a little bit above my skills so if anyone else can help would be very grateful. Cheers

AStinch commented 6 years ago

import numpy as np import picamera

camera = picamera.PiCamera(resolution = (1024,768)) img = np.zeros((768,1024,3), dtype=np.uint8) layer1 = camera.add_overlay(img, layer = 1)

for down in range (0, 768, 10):

img[down:down+10, 502:522] = [255,255,255] 
layer1.update(img)

camera.remove_overlay(layer1)

anxuae commented 6 years ago

Same error for me. To avoid it, I put the call to camera.add_overlay and camera.remove_overlay inside the for loop. I don't see any performance issue (but my loop is slow due to processing between the 2 calls).

Billwilliams1952 commented 6 years ago

Same problem for me too. It seems the exceptions don’t corrupt the picamera settibgs though the print statements are a pain.

I work around it by using layers instead. Just move each overlay around. No flicker

oveddan commented 5 years ago

@Billwilliams1952 I have the same issue. What do you mean by using layers instead? Can you provide some sample code?

o0Zz commented 5 years ago

Hi,

I also fixed this issue by using layers (Like done by Billwilliams1952). OFC, this is a workaround, but the idea here is to use 2 overlays and 2 layers in order to display each one after each other and avoid blinking.

Here is a quick sample code:

    def OnOverlayUpdated(self, anOverlayImg):
        theTmpOverlay = self.mCamera.add_overlay(anOverlayImg.tobytes(), size=anOverlayImg.size, layer=self.mCurrentOverlayLayer)

        self.mCurrentOverlayLayer = self.mCurrentOverlayLayer + 1
        if self.mCurrentOverlayLayer > 4:
            self.mCurrentOverlayLayer = 3

        if self.mOverlay != None:
            self.mCamera.remove_overlay(self.mOverlay)

        self.mOverlay = theTmpOverlay

I hope it can help other peoples.