Best practice for displaying high resolution camera images captured on server

Hi, reviving this zombie-thread 40 years later.
I have so far not been able to reproduce the problem without using the camera, which is weird.

Here is a little too much code:

import asyncio
import PySpin
import numpy as np
import holoviews as hv
import panel as pn
import param

hv.extension('bokeh')


class Camera(param.Parameterized):
    camera = None
    system = None
    cam_list = None
    latest = param.Parameter(default=(np.ones(shape=(50, 50), dtype=np.uint16) * 2000))
    task: None = None
    livefeed = param.Boolean()

    async def get_frames(self):
        while self.livefeed:
            frame = await asyncio.to_thread(self.camera.GetNextImage, 2000)
            self.latest = frame.GetNDArray()  # This makes the program leak memory like crazy.
            # self.latest = (np.random.random((3200, 2200)) * 16000).astype(np.uint16) # If i use this line instead of previous, no leak.
            frame.Release()

    @pn.depends("livefeed", watch=True)
    async def main(self):
        print("In main")
        self.system = PySpin.System.GetInstance()
        self.cam_list = self.system.GetCameras()
        self.camera = self.cam_list.GetByIndex(0)
        self.camera.Init()
        self.camera.AcquisitionMode.SetValue(PySpin.AcquisitionMode_Continuous)
        self.camera.TLStream.StreamBufferHandlingMode.SetValue(PySpin.StreamBufferHandlingMode_NewestOnly)  # Make sure no old frames are sent
        self.camera.BeginAcquisition()

        self.task = asyncio.create_task(self.get_frames())
        print("Waiting for task...")
        await self.task

        if self.camera:
            if self.camera.IsStreaming():
                self.camera.EndAcquisition()
            self.camera.DeInit()
            self.camera = None
        self.cam_list.Clear()
        self.system.ReleaseInstance()


cam = Camera()


@pn.depends(image=cam.param.latest, watch=False)
def img0(image):
    plot = hv.Image(image)
    return plot


pn.serve(
    pn.Row(hv.DynamicMap(img0, cache_size=1), cam.param.livefeed)
)

It seems like the DynamicMap keeps a reference to the ndarray if it comes from the camera, but not if it is a random ndarray. If I create an hv.Image of the camera image but do not return it, there is no leak, but as soon as img0 returns it, there is like 13.5MB memory leak per frame.

I tried with an all black ndarray of same size too, but no leak.
If I do GetNDArray() * 0 it also does not leak.

The images that the camera produce at the moment are almost completely black with just some hot pixels. It has a lid on and is sitting on my desk at the moment.

I’d be very grateful if someone could shed some light here… :slight_smile:

Python 3.10.6
Panel: 0.14.2
Bokeh: 2.4.3
Param: 1.12.3
Holoviews: 1.15.4

1 Like