morefigs / pymba

Python wrapper for Allied Vision's Vimba C API
MIT License
105 stars 84 forks source link

fps low #123

Open skywo1f opened 4 years ago

skywo1f commented 4 years ago

When I am testing the camera (1800U500c) using the vimba viewer, I get 100+ fps for full resolution. When I test the same camera using pymba, I only get ~10 fps. I know it is not an exposure time issue as I have varied that from 40 to 40k with minimal effect on the fps. What does help with the fps is asking the camera for less pixels (e.g. 1200x1200 is returned at 30fps). Any idea how to speed up the fps?

skywo1f commented 4 years ago

`from time import sleep from pymba import Vimba from _display_frame import display_frame import time import cv2

import threading

def camCapture(camera): try: camera.arm('SingleFrame') while (True): start_time = time.time() # start time of the loop frame = camera.acquire_frame() image = frame.buffer_data_numpy()

        cv2.imshow('ImageWindow', image)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
        print("FPS: ", 1.0 / (time.time() - start_time))

except: 
    camera.disarm()
    camera.close()

if name == 'main':

with Vimba() as vimba:
    camera = vimba.camera(0)
    camera.open()
    featureAM = camera.feature('DeviceLinkThroughputLimitMode')
    value = featureAM.value
    featureAM.value = 'Off'

    feature = camera.feature('PixelFormat')
    value = feature.value
    feature.value = 'BGR8'

    featureH = camera.feature('Height')
    value = featureH.value
    featureH.value = 1944                           #default 1944   small 1146

    featureW = camera.feature('Width')
    value = featureW.value
    featureW.value = 2592                           #default 2592   small 2200

    featureGA = camera.feature('GainAuto')
    value = featureGA.value
    featureGA.value = 'Continuous'

    featureBWA = camera.feature('BalanceWhiteAuto')
    value = featureBWA.value
    featureBWA.value = 'Once'

    featureET = camera.feature('ExposureTime')
    value = featureET.value
    featureET.value = 4000                                           #default 4000

    capture_thread = threading.Thread(target=camCapture,args=(camera,))
    capture_thread.daemon = True
    capture_thread.start()

    try:
        while(True):
            time.sleep(4)
    except:
        camera.disarm()
        camera.close()`
jakove commented 4 years ago

I think the problem is in camCapture. The camera is armed in "SingleFrame"-mode. SingleFrame is only for shooting one frame. If you want to reach high fps-rates you have to use "Continous" with a proper callback function. In the examples is shown how to use the callback function. I achieve in full resolution 395 fps with my usb camera, which is the frame-rate limit of the camera. For me it is possible to achive round about 1100 fps.

skywo1f commented 4 years ago

would you mind posting your code? I tried using continuous frames, but 1, it was hard getting them into an object which opencv could interact with, and 2, even the continuous frames example was working a little janky(20 fps, only showing the top fifth of the image) for me on my xavier.

jakove commented 4 years ago

Im am working with a nvidia jetson xavier too. So the hardware should be no problem. At first you should follow the instructions from allied vision. There ist a document for jetson: https://cdn.alliedvision.com/fileadmin/content/documents/products/software/software/embedded/Optimizing-Performance-Jetson_appnote.pdf

Forfirst steps try to use the examples: callback function: https://github.com/morefigs/pymba/blob/master/examples/camera/_display_frame.py

streaming images: https://github.com/morefigs/pymba/blob/master/examples/camera/opencv_acquire_streaming_images.py

The callback function should be fast enough for 100+ fps. At first you should try to implement it by yourself.

To fix the highest framerate:

camera.feature("ExposureTime").value = 200
#is needed for editing framerate
camera.feature("AcquisitionFrameRateMode").value = 'Basic'
#get the max fps with settings (depends on image size and on exposure time)
max_fps = camera.feature("AcquisitionFrameRate").range[-1]
camera.feature("AcquisitionFrameRate").value = max_fps

My code ist to complex for posting it here. Cause i copy the images to gpu and run a cnn.
But i try to help if there are further questions.

skywo1f commented 4 years ago

I tried your suggestion but I am getting `Traceback (most recent call last): File "fast_color_video.py", line 55, in featureAFR.value = max_fps
File "/usr/local/lib/python3.6/dist-packages/pymba/feature.py", line 40, in value self._access_func('set', self.info.featureDataType)(value) File "/usr/local/lib/python3.6/dist-packages/pymba/feature.py", line 142, in _set_float raise VimbaException(error) pymba.vimba_exception.VimbaException: Operation is invalid with the current access mode.

` when I try to change those camera values

But even if I did have access, it wouldn't matter as those values are already at "basic" and max_fps by default (I printed them out).

Increasing the exposure time makes the fps go down, but lowering the exposure time didnt help much with the fps in my case.

skywo1f commented 4 years ago

in my implementation of _display_frame, I am only getting 15 fps: ` from pymba import Vimba, VimbaException from _display_frame_fast import display_frame import time

if name == 'main':

with Vimba() as vimba:
    camera = vimba.camera(0)
    camera.open()

    camera.arm('SingleFrame')

    # capture a single frame, more than once if desired
    for i in range(100):
        start_time = time.time() # start time of the loop
        try:
            frame = camera.acquire_frame()
            display_frame(frame, 0)
            print("FPS: ", 1.0 / (time.time() - start_time))

        except VimbaException as e:
            # rearm camera upon frame timeout
            if e.error_code == VimbaException.ERR_TIMEOUT:
                print(e)
                camera.disarm()
                camera.arm('SingleFrame')

            else:
                raise

    camera.disarm()

    camera.close()

`

jakove commented 4 years ago

Are you able to change the values with the VimbaViewer?

you are still using: camera.arm('SingleFrame') To achive high framerates it is necessary to use the 'Continuous' mode.

The following example shows how to stream images: https://github.com/morefigs/pymba/blob/master/examples/camera/opencv_acquire_streaming_images.py

skywo1f commented 4 years ago

The problem with the Continuous mode example is that it doesn't include a line like frame = camera.acquire_frame() so that I can load the frame and send it out for processing

I can somewhat change the values with the vimba viewer, though at the moment it is just giving me one frame at a time (whenever I press play).

jakove commented 4 years ago

In https://github.com/morefigs/pymba/blob/master/examples/camera/_display_frame.py line 21: image = frame.buffer_data_numpy()

This is the line you need for processing. Then there are several ways to continue. If your algorthm is fast you can handle all in the callback function. But you can also use Queues or sth. similar to process your image in another thread or send it direct to gpu with PyCUDA.

So you are not able to view a live stream in VimbaViewer?

skywo1f commented 4 years ago

I tried grabbing the frame using the method you suggested, then sending it over to another thread via Queue, but I am not getting anything on the other side: ' from time import sleep from pymba import Vimba from _display_frame import display_frame import time import cv2 from queue import Queue import threading

def camCapture(camera,imageHolder): try: camera.arm('Continuous',display_frame) camera.start_frame_acquisition() while (True): start_time = time.time() # start time of the loop imageHolder.put(frame.buffer_data_numpy())

except: 
    camera.stop_frame_acquisition()
    camera.disarm()
    camera.close()

def camShow(imageHolder): time.sleep(1) #wait for camera to start up while True: image = imageHolder.get() cv2.imshow('ImageWindow', image) if cv2.waitKey(1) & 0xFF == ord('q'): break print("FPS: ", 1.0 / (time.time() - start_time))

if name == 'main':

with Vimba() as vimba:
    camera = vimba.camera(0)
    camera.open()
    featureAM = camera.feature('DeviceLinkThroughputLimitMode')
    value = featureAM.value
    featureAM.value = 'Off'

    feature = camera.feature('PixelFormat')
    value = feature.value
    feature.value = 'BGR8'

    featureH = camera.feature('Height')
    value = featureH.value
    featureH.value = 1944                           #default 1944   small 1146

    featureW = camera.feature('Width')
    value = featureW.value
    featureW.value = 2592                           #default 2592   small 2200

    featureGA = camera.feature('GainAuto')
    value = featureGA.value
    featureGA.value = 'Continuous'

    featureBWA = camera.feature('BalanceWhiteAuto')
    value = featureBWA.value
    featureBWA.value = 'Once'

    featureET = camera.feature('ExposureTime')
    value = featureET.value
    featureET.value = 4000                                           #default 4000

    imageHolder = Queue()

    capture_thread = threading.Thread(target=camCapture,args=(camera,imageHolder))
    capture_thread.daemon = True
    capture_thread.start()

    show_thread = threading.Thread(target=camShow,args=(imageHolder, ))
    show_thread.daemon = True
    show_thread.start()

    try:
        while(True):
            time.sleep(4)
    except:
        camera.stop_frame_acquisition()
        camera.disarm()
        camera.close()

'

mvalvaa commented 4 years ago

Did you resolve this problem? I am using an Alvium 1800U and have the same problem.

My camera have 29 max fps but in Vimba Viewer and using python acquire image example I only get 5fps. In Vimba viewer if I change from SingleFrame to Continuous, fps maintain equal (5fps). In python if I use Continous mode I get the same error as @skywo1f, VimbaException: Operation is invalid with the current access mode