basler / pypylon

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

Delay in loop grabResult.GetArray() #306

Open comelaine opened 3 years ago

comelaine commented 3 years ago

Hello everyone, I am working on the synch between a sensor of rotation on a wheel and the basler camera ace 2 a2A1920 160UC BAS. My goal is to synch both so that when the sensor detect a movement of 20mm the camera take a snapshot with the distance in the title of the image.

Despite I am running the program on high performance computer under windows 10, the fps average is 60fps thus the distance between two frames are higher than the 20 mm required : ( Yaxis are the distance in mm, and Xaxis are the frames ) Figure 2020-12-16 150202

I have 4 threads :

So I am trying to find where is the delay in my loop. Did I reach the limit of the basler camera ? ( supposed to be 150 fps ) How to optimize the code ? Thanks

run of the videostream thread

def run(self):

        # conecting to the first available camera
        camera = pylon.InstantCamera(pylon.TlFactory.GetInstance().CreateFirstDevice())
        camera.Open()  #Need to open camera before can use camera.ExposureTime
        camera.ExposureTime.SetValue(5000)

        # Grabing Continusely (video) with minimal delay
        camera.StartGrabbing(pylon.GrabStrategy_LatestImageOnly) 
        camera.AcquisitionFrameRateEnable.SetValue(True)

        camera.AcquisitionFrameRate.SetValue(150) # fps at 150 fps 
        camera.IsGrabbing()

        flag_exept = False 

        while self._run_flag : # loop grabbing 

            grabResult = camera.RetrieveResult(1000, pylon.TimeoutHandling_ThrowException)

            if grabResult.GrabSucceeded():

                self.frame_compteur += 1
                times.append(time.time())

                distance = self.get_distance() # get distance from the sensor in a separate thread 

                if distance > self.distance_prec + 20 : # to see if distance is 20mm more than the previous one                 

                    positions.append(distance)
                    self.distance_prec = distance
                    a = grabResult.GetArray() #this is where i think i have a delay 
                    frames.append(a.copy()) #this is where i think i have a delay too
                    self.bmp_compteur += 1

                    if self.frame_compteur % 5 == 0 :
                        flag_exept = True 

                else:
                    if (self.frame_compteur % 5 == 0 ) or flag_exept :
                        # modulo 5 to send image to a pyqt GUI at 25 fps
                        image_affichee = grabResult.GetArray() # pointeur 
                        self.change_pixmap_signal.emit(image_affichee) # envoi du signal video vers le gui  
                        self.change_text_signal.emit(str(distance)) # envoi du signal text  vers le gui  
                        flag_exept = False 

            grabResult.Release()
        camera.StopGrabbing()

run of the saving thread

def run(self):

        i = 0

        while self.flag_save :
            n = len(frames[i:])

            if n!= 0 :
                for j in range(i,i+n):
                    #print(len(frames),j)
                    cv2.imwrite( "Frame_{}.bmp".format(positions[j]), frames[j])
                    frames[j]=0
                    i+=1
                    self.pourcent = round((i / len(frames))*100)
            else:
                time.sleep(0.02)`
zoldaten commented 2 years ago

1. a = grabResult.GetArray() #this is where i think i have a delay have a look at grabResult by print(dir(grabResult)) and see it shape. try to reduce it. if it has something like 1920,1080,3 try to convert it to mono to get 1920,1080. 2. frames.append(a.copy()) try not to use append if you can. it is a slow python method. better use function that operates frame at place or lambda. 3.check out what you really get at start - print('fps: ',camera.ResultingFrameRate.Value)

4.try to change grab strategies:

camera.StartGrabbing(pylon.GrabStrategy_LatestImageOnly)

camera.StartGrabbing(pylon.GrabStrategy_OneByOne)

camera.StartGrabbing(pylon.GrabStrategy_LatestImages)

5.decrease image size camera.Width.SetValue(640) camera.Height.SetValue(1440)

  1. try to change- camera.PixelFormat.SetValue("Mono12") #Mono8

7.use converter converter = pylon.ImageFormatConverter() //converting to opencv bgr format converter.OutputPixelFormat = pylon.PixelType_BGR8packed converter.OutputBitAlignment = pylon.OutputBitAlignment_MsbAligned ... in your grabbing cycle: image = converter.Convert(grabResult)