basler / pypylon

The official python wrapper for the pylon Camera Software Suite
http://www.baslerweb.com
BSD 3-Clause "New" or "Revised" License
578 stars 208 forks source link

Get max transfer size got error #486

Open kimdonggyun opened 2 years ago

kimdonggyun commented 2 years ago

Hello I am using a USB camera and I was trying to change the setting of maximum transfer size but I got the error below.

cam.GetStreamGrabberParams().MaxTransferSize.SetValue(transfersize)

File "/Users/dkim/opt/anaconda3/envs/camera/lib/python3.10/site-packages/pypylon/pylon.py", line 4266, in getattr return self.GetNodeMap().GetNode(attribute) File "/Users/dkim/opt/anaconda3/envs/camera/lib/python3.10/site-packages/pypylon/genicam.py", line 1357, in GetNode return _genicam.INodeMap_GetNode(self, Name) _genicam.LogicalErrorException: Node not existing (file 'genicam_wrap.cpp', line 16181)

I could see the maximum transfer size on the pylon viewer and I could adjust the value there. So there should be a command to change the value but I could not. Could you please let me know the proper function to change the maximum transfer size?

Many thanks.

thiesmoeller commented 2 years ago

syntax would be for e.g. 4MB max transfer size

cam.StreamGrabber.MaxTransferSize = 4 * 1024 * 1024

increasing max transfer size will decrease the system load and could help with your issue of loosing frames.

These settings are system dependent ( windows/linux ) so also check https://github.com/basler/pypylon/issues/466#issuecomment-1029814337 for more settings required on linux system

This is documented in the pylon SDK

kimdonggyun commented 2 years ago

Thank you. I've tried the code above and I haven't got an error. However, the recorded video length between the two cameras is different and shorter than the time which the video was recorded for. Thus, frame dropping is still here. I am suspecting the set value for max transfer size was not applied to the camera, as I could see the default value (262144) through Pylon viewer. The other parameters, such as height, width, and exposure time, were changed with the value I set. Are there other parameters to help solve this issue? by the way I am using Mac.

thiesmoeller commented 2 years ago

If you suspect, that you drop frames. Please use Basler pylon viewer application to assist in finding good settings.

Can you show the inner grab loop, that you use for your camera and the camera model?

kimdonggyun commented 2 years ago

I am using two cameras and recording the video simultaneously. I tried recording via the pylon viewer but I got an error message while I was recording two cameras. But the error message did not appear when I recorded through only one camera. The error message is: "An error occurred during recording.Frame could not be written from buffer to disk. The recording was stopped."

Could it be because I am using one hub for connecting two USB cameras? Would it be better to use separate line for each camera?

The camera I am using is acA4024-29uc

Below is the script for two camera multi recording.

class multi_video_recording_start:
    def __init__(self, cams, video_format = "FFMPEG", video_codec="h264",
                        writing_mode="I", macro_block_size= 2, quality=5, bitrate=None):

        # check OS
        if platform.system() == "Windows":
            recording_dir = "C:/Users/awiadm/Desktop/Dong_camera/recording"
        elif platform.system() == "Darwin":
            recording_dir = "/Users/dkim/Desktop/work/basler_camera/recording"

        # check number of connected camera

        # input filepath
        filename_cam1 = input("type the file name for Cam1 :")
        filename_cam2 = input("type the file name for Cam2 :")
        filepath_cam1 = os.path.join(recording_dir, filename_cam1+str(".mp4"))
        filepath_cam2 = os.path.join(recording_dir, filename_cam2+str(".mp4"))

        filepaths = (filepath_cam1, filepath_cam2)

        # check fps of camera and set this value as viedeo writer's fps. Both Camera's set FPS and video writer's FPS value should have to be same!!
        cams[0].Open()
        cams[1].Open()

        while int(cams[0].AcquisitionFrameRate.GetValue()) != int(cams[1].AcquisitionFrameRate.GetValue()):
            print("cameras' FPS value is different. Set new FPS ")
            break

        cams[0].Close()
        cams[1].Close()

        # run multi_recording function
        self.multi_recording(filepaths=filepaths, cams=cams, video_format=video_format, video_codec=video_codec,
                                writing_mode=writing_mode, macro_block_size=macro_block_size, quality=quality,
                                bitrate=bitrate)

    def multi_recording(self, filepaths, cams, video_format = "FFMPEG", video_codec="h264",
                        writing_mode="I", macro_block_size= 2, quality=5, bitrate=None):
        """
        recording cameras at the same time.
        filepaths (in tuple or list form with full file path and file name e.g. user/desktop/camer/video.mp4)
        cams (array of camera instaces)
        """

        cam1 = Thread(name="cam1", target= self.video_recording_start, 
                        args=(filepaths[0] , cams[0], video_format, video_codec,
                        writing_mode, macro_block_size, quality, bitrate)
                        )
        cam2 = Thread(name="cam2", target= self.video_recording_start, 
                        args=(filepaths[1] , cams[1], video_format, video_codec,
                        writing_mode, macro_block_size, quality, bitrate)
                        )
        cam1.start()
        cam2.start()

        print("recording start with %s at %s" % (cams[0].DeviceInfo.GetFriendlyName(), datetime.now()))
        print("recording start with %s at %s" % (cams[1].DeviceInfo.GetFriendlyName(), datetime.now()))

    def video_recording_start(self, filepath, cam, video_format = "FFMPEG", video_codec="h264",
                    writing_mode="I", macro_block_size= 2, quality=5, bitrate=None):
        """
        recording through camera and writing the video into as a video file
        video_format = e.g. FFMPEG
        filename should contain video_container = video container type e.g. filename.mp4
        video_codec = video codec e.g. h264
        writing_mode = "I" # imageio writing mode "I" for video recording
        macro_block_size = 1 # integer, width and height should be divisable with this number
        quality = 10  # float 0 - 10, default 5. better resolution with higher number
        bitrate = None  # integer, if None, quality parameter will be used. Otherwise, quality parameter will be ignored
        """
        cam.Open() # open camera instance
        writer_fps = int(cam.AcquisitionFrameRate.GetValue()) # get fps value from camera to apply on writer's fps

        with get_writer(filepath, format=video_format, codec=video_codec, 
                macro_block_size=macro_block_size, mode= writing_mode, quality=quality, bitrate=bitrate, fps=writer_fps) as writer:

            print("recording value: ", "Height:",cam.Height.GetValue(), "Width:", cam.Width.GetValue(), 
                "Exposuretime:", cam.ExposureTime.GetValue(), "AcquisitionFrameRate:", cam.AcquisitionFrameRate.GetValue(), "MaxTransferSize:", cam.StreamGrabber.MaxTransferSize.GetValue())       
            cam.StartGrabbing()

            while cam.IsGrabbing():
                try :
                    res = cam.RetrieveResult(10000)
                except:
                    print("something wrong while recording")
                writer.append_data(res.Array)
                res.Release()

Thanks for your help.

thiesmoeller commented 2 years ago

For max performance on USB don't use a HUB. Always go to direct connection. To stabilize a system first check that you can acquire ( without compression and writing to disk etc. ) the video data from the cameras without any issues. And after this is checked... optimize the recording side of it.

kimdonggyun commented 2 years ago

@thiesmoeller Thanks for the information. I just checked the Frame Rate in real-time, from both of the cameras. It turns out the frame rate dropped suddenly while the video was recording.

Basler acA4024-29uc (24258110) 25.156113740096323
Basler acA4024-29uc (24258109) 25.086600515571824
Basler acA4024-29uc (24258110) 24.962529162500594
Basler acA4024-29uc (24258109) 24.678037902813
Basler acA4024-29uc (24258110) 26.09810034035828
Basler acA4024-29uc (24258109) 25.734610358135512
Basler acA4024-29uc (24258110) 25.265826139861574
Basler acA4024-29uc (24258109) 25.4497927879277
Basler acA4024-29uc (24258110) 25.5814197451802
Basler acA4024-29uc (24258109) 26.17121749113962
Basler acA4024-29uc (24258110) 25.600312503814745
Basler acA4024-29uc (24258109) 25.77699658912823
Basler acA4024-29uc (24258110) 0.8994196226099506
Basler acA4024-29uc (24258109) 0.8911362800030255
Basler acA4024-29uc (24258110) 21.577302775419913
Basler acA4024-29uc (24258109) 15.775592106005499
Basler acA4024-29uc (24258110) 1.5281872545886928
Basler acA4024-29uc (24258109) 1.539511069985417
Basler acA4024-29uc (24258110) 1.797020007857644
Basler acA4024-29uc (24258109) 1.7254645128857433
Basler acA4024-29uc (24258110) 2.058316709483814
Basler acA4024-29uc (24258109) 1.9405792722846236
Basler acA4024-29uc (24258110) 8.171459631745982
Basler acA4024-29uc (24258109) 9.63735917814955
Basler acA4024-29uc (24258110) 8.305091994899293
Basler acA4024-29uc (24258109) 6.8725620476587626
Basler acA4024-29uc (24258110) 6.533814792082724
Basler acA4024-29uc (24258109) 6.558847077662129
Basler acA4024-29uc (24258110) 6.022137000147886
Basler acA4024-29uc (24258109) 5.216069403267206
Basler acA4024-29uc (24258110) 4.833929559284529
Basler acA4024-29uc (24258109) 4.747915720982252
Basler acA4024-29uc (24258110) 4.469876346647143
Basler acA4024-29uc (24258109) 4.105240800826079
Basler acA4024-29uc (24258110) 4.06933867852129
Basler acA4024-29uc (24258109) 4.01714393530894
Basler acA4024-29uc (24258110) 3.800720399073902
Basler acA4024-29uc (24258109) 3.5484535227735154
Basler acA4024-29uc (24258110) 3.4051004610434896
Basler acA4024-29uc (24258109) 3.470715375627646
Basler acA4024-29uc (24258110) 3.5700549088101785
Basler acA4024-29uc (24258109) 3.5901499724809356
Basler acA4024-29uc (24258110) 3.709567407700907
Basler acA4024-29uc (24258109) 3.56685194130173
Basler acA4024-29uc (24258110) 3.647452403500396

I am not an expert on video recording from a machine vision camera, but it seems while the video was recording, computational power reached a limit and slowed down the Fram rate, I guess. Considering the FPS dropping happens almost beginning of the video recording, it might be because of some RAM or buffer issue? Do you think I can solve this issue or should I upgrade my computer. I am using Macbook pro with i5 CPU and 16gb Ram.

And below is the short code to check the Frame rate in real time.

                new_time = time.time()
                fps = 1/(new_time-prev_time)
                prev_time = new_time
                print(cam.DeviceInfo.GetFriendlyName(), fps)
thiesmoeller commented 2 years ago

hi @kimdonggyun ... your system is too slow for your task:

just looking at your numbers: you have two acA4024-29uc -> this is 12mpix... and it seems you want to run it at ~25fps

you want to encode in total 12Mpix @ 50 fps

I did just a quick look at one of the encoding benchmarks: https://www.guru3d.com/articles-pages/core-i5-12400-processor-review,15.html

where core i5 is mentioned to encode ~ 1080p50

12Mpix is ~ 6 times 1080P ... so your system is by a factor of 6 too slow to encode this amount of data.

kimdonggyun commented 2 years ago

Thank you. I know that I can not use the full camera sensor. And even I do not need a full camera sensor, so I set the width and height smaller than the actual full sensor size. But it seems even though I set smaller width and height, my computer can not handle the amount of data.

One question is, when I set the new values (width, height, FPS and exposure time etc) I checked whether I can apply the set FPS with the below code.

 # Check whether maximum FPS with current setting is more than set FPS
    if float(cam.ResultingFrameRate.GetValue()) >= FPS:
        print("You can apply set FPS (%s)" %(FPS ,))
    else:
        print("maximum FPS is %s. Set lower FPS or change the setting" %(float(cam.ResultingFrameRate.GetValue())  ,))

I considered cam.ResultingFrameRate.GetValue() returns the availability of using the set FPS with the current setting. And my script only runs when the cam.ResultingFrameRate.GetValue() is greater than the set FPS.

Am I using the function in the wrong way?

Also, if my computer can not handle the current setting, are there other ways to cope with this issue except replacing the computer? Such as altering the type of video encoding with lower quality.

Thanks in advance