Distorted image after threading display function.

99 views
Skip to first unread message

aishwarya selvaraj

unread,
Jun 20, 2018, 5:51:08 AM6/20/18
to pyqtgraph
I am trying to acquire images from camera and display images on the GUI created using PyQt. In order to prevent the GUI from hanging and to make the display faster I have used threading. A new thread is created for images acquisition and once the image is available  signal is created to display them on the GUI panel.
I have 2 classes defined in 2 separate file, one a python code and another cython.
File 1 : This file has the GUI defined.

data_acquired = pyqtSignal(np.ndarray)
self.data_acquired.connect(self.RepeatPlot)
# the above 2 lines are defined immediately after class is defined and within __init__(),and not at this location as pasted here
self.acq_thread = Thread(target = self.camera.LiveAquisition,args =(self.data_acquired.emit,))
self.acq_thread.start()

The display region on the GUI is defined as :
self.Display = GraphicsView(self.centralwidget)
self.Display.setGeometry(QtCore.QRect(30, 130, 461, 541))
font
= QtGui.QFont()
font
.setPointSize(10)
font
.setBold(True)
font
.setWeight(75)
self.Display.setFont(font)
self.Display.setMouseTracking(True)
self.Display.setAutoFillBackground(False)
self.Display.setObjectName("Display")
self.l = GraphicsLayout()
self.vb = self.l.addViewBox()
self.Display.setCentralItem(self.l)
self.img = ImageItem(border='w')
self.vb.addItem(self.img)


Function RepeatPlot():
@pyqtSlot(np.ndarray)
def RepeatPlot(self,image):
   
self.I = image
   
self.img.setImage(self.I)



File 2: Where the camera functionalities is written

def LiveAquisition(self,callback):

   
# Initialisation and declaration of variables/paramters
   image
= np.zeros(((self.aoiWidth-self.AOILeft)/self.hbin, (self.aoiHeight-self.AOITop)/self.vbin), dtype=np.uint16)
   image
= np.zeros(((self.aoiWidth)/self.hbin, (self.aoiHeight)/self.vbin), dtype=np.uint16)


   
self.i = 0
   start
= time.time()
   
while self.i <self.framecount:
      pBuf
= <unsigned char *>calloc(sizeInBytes, sizeof(unsigned char))
      AT_QueueBuffer
(<AT_H>self.cameraHandle, pBuf, sizeInBytes)

     
#print "Frame number is :",
     
#print self.i



      timeOut
= <unsigned int>(3 * self.exposureTime * 1000)
     
if timeOut < 500:
         timeOut
= 500
      response_code
= AT_WaitBuffer(<AT_H>self.cameraHandle, &returnBuffer, &BufSize, timeOut)


     
Py_INCREF(dtype)

      image
= PyArray_NewFromDescr(<PyTypeObject *> np.ndarray, np.dtype('<H'), 2,dims, strides,pBuf, np.NPY_C_CONTIGUOUS,None)
      callback
(image)
      time
.sleep(0.01)


      free
(pBuf)
     
self.i = self.i+1

   copy2WCStr
("AcquisitionStop",string3)
   AT_Command
(<AT_H>self.cameraHandle, string3)
   AT_Flush
(<AT_H>self.cameraHandle)
   stop
= time.time()
   
print "Time:",
   
print stop-start

Im trying to display a fixed number of images using this method.
when Im trying to display, for certain image size the images appears as shown in the image attached.
Any idea why that happens?Kindly  help.
Screenshot from 2018-06-20 18-39-41.png
Screenshot from 2018-06-20 18-48-46.png

Patrick

unread,
Jun 20, 2018, 11:34:37 PM6/20/18
to pyqtgraph
Hi,

I'm only familiar with the Andor SDK2 and not the SDK3, so don't know exactly how image acquisition works, but it looks like your plumbing between getting the image data (image = PyArray_NewFromDescr... and the callback) and displaying it is working fine.

I would be checking the length of data returned by the camera (AT_WaitBuffer command), ensure it matches your expected image dimensions and that you're correctly converting the camera byte data into the numpy array (shape, dtype etc). You're obviously getting a lot of zeros from somewhere into your image array.

Another thought, if you are collecting a kinetic series of 500 images, check the documentation on the AT_QueueBuffer and AT_WaitBuffer commands. I know in the Andor SDK2 the WaitForAcquisition command returns after each individual frame is captured in a kinetic series (or during continuous readout), rather than after all frames have been captured. On each acquisition event I then need to check the camera status to determine if/which new images are available and their indices and then retreive the appropriate frame(s) from the camera (or if  acquisition failed/cancelled etc).

Patrick

aishwarya selvaraj

unread,
Jun 21, 2018, 4:16:54 AM6/21/18
to pyqt...@googlegroups.com
​​
​​
Hi, 
I checked the values returned by  ImageSizeBytes (expected value)  and BufSize (actual value) from the code I sent in my previous email. For all the image dimension they return the same values, but I observed the following:

1. For images of size(128x128) and (512x512) the value returned from ImageSizeBytes and  BufSize  is :
128 x 128 -------- 128*128*2+(128*8)  =  33792
512 x 512 --------512*512*2+(512*8)   =  528384
These values are correct and are true to the logic. Also notice that these image display without any issue.

2. For images of size (1040 x 1392), (1080 x 1920) the values returned from ImageSizeBytes  and  BufSize  are 2895360 and 4147200 respectively.But as per theory it should be, 
(1040 x 1392) --------  1040*1392*2+(1040*8)  =  2903680
(1080 x 1920) --------- 1080*1920*2+(1080*8)  =  4155840

While displaying these images there is a blank display as in the image attached

3.   For images (2048 x 2048), (2160 x2560) even though ImageSizeBytes  and  BufSize   returned value as expected I get segmentation fault.

PS: I use pixel encoding  Mono16 and preamp gain 16-bit (low noise & high well capacity). Hence 1 pixel = 2bytes


I didn't completely understand the last part of your mail. As far I perceive, I'm trying to acquire N images and for each image, a buffer is kept ready (pBuf) to store the data. With the same setup code I have previously acquired images of all the standard sizes without any issues. It's only the display method I have changed this time.


--
You received this message because you are subscribed to the Google Groups "pyqtgraph" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pyqtgraph+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/pyqtgraph/9369949e-3198-4b8c-ad35-d9d012f52094%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Regards,
Aishwarya Selvaraj

Luke Campagnola

unread,
Jun 21, 2018, 12:09:22 PM6/21/18
to pyqt...@googlegroups.com
I'm guessing the issue is that you create an ndarray from pBuf, and then immediately delete pBuf after emitting the signal. This frees up the memory in use by the ndarray, causing it to be partially overwritten by the time it is displayed in the gui thread. An easy way to check this might be to send a copy of the array: `callback(image.copy())`.

However if you want to avoid the performance overhead of copying (and also avoid memory leaks), then you need to understand how to transfer "ownership" of the memory held in pBuf to numpy. I am not familiar enough with the numpy C API or cython to make a suggestion there.

Side question: is there a reason you are using cython instead of ctypes? For camera acquisition, I would imagine the latter is easier and just as fast.

--
You received this message because you are subscribed to the Google Groups "pyqtgraph" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pyqtgraph+unsubscribe@googlegroups.com.

aishwarya selvaraj

unread,
Jun 22, 2018, 2:47:04 AM6/22/18
to pyqt...@googlegroups.com
@Luke,
Yes clearing the memory free(pBuf) was indeed the root of the problem. Thank you 
I had done benchmarking in cython which showed improvement in speed compared to python.
I was not aware of the usability of ctypes for camera-related functions. 

On Thu, Jun 21, 2018 at 9:38 PM, Luke Campagnola <luke.ca...@gmail.com> wrote:
I'm guessing the issue is that you create an ndarray from pBuf, and then immediately delete pBuf after emitting the signal. This frees up the memory in use by the ndarray, causing it to be partially overwritten by the time it is displayed in the gui thread. An easy way to check this might be to send a copy of the array: `callback(image.copy())`.

However if you want to avoid the performance overhead of copying (and also avoid memory leaks), then you need to understand how to transfer "ownership" of the memory held in pBuf to numpy. I am not familiar enough with the numpy C API or cython to make a suggestion there.

Side question: is there a reason you are using cython instead of ctypes? For camera acquisition, I would imagine the latter is easier and just as fast.

For more options, visit https://groups.google.com/d/optout.



--
Regards,
Aishwarya Selvaraj
Reply all
Reply to author
Forward
0 new messages