smooth image update: use monitor callbacks to avoid block of ui when waiting for frame

This commit is contained in:
2022-07-18 13:08:51 +02:00
parent c056f3f329
commit 1696328a53
2 changed files with 63 additions and 42 deletions

View File

@@ -107,6 +107,7 @@ class epics_cam(object):
print('camera.new_frame_pv_cb') print('camera.new_frame_pv_cb')
def get_image(self): def get_image(self):
_log.warning('this can be very slow. Use callbacks if possible.')
try: try:
pv_pic=self.getPv('FPICTURE') pv_pic=self.getPv('FPICTURE')
except AttributeError: except AttributeError:
@@ -120,13 +121,7 @@ class epics_cam(object):
pv_pic=self.getPv('FPICTURE') pv_pic=self.getPv('FPICTURE')
sz=self._sz sz=self._sz
pic = pv_pic.get(count=sz[0]*sz[1], as_numpy=True).reshape(sz[::-1]) pic = pv_pic.get(count=sz[0]*sz[1], as_numpy=True).reshape(sz[::-1])
f=np.array(((0, 0, 0, 0, 0), epics_cam.set_fiducial(pic,255)
(0, 1, 1, 1, 0),
(0, 1, 0, 0, 0),
(0, 1, 1, 0, 0),
(0, 1, 0, 0, 0),
(0, 0, 0, 0, 0),), pic.dtype)
pic[0:6, 0:5]=f*255
except AttributeError as e: except AttributeError as e:
_log.warning("failed to fetch image") _log.warning("failed to fetch image")
@@ -219,6 +214,16 @@ class epics_cam(object):
pv_cam.put(CameraStatus.RUNNING, wait=True) pv_cam.put(CameraStatus.RUNNING, wait=True)
self.update_size() self.update_size()
@staticmethod
def set_fiducial(pic,val):
# fiducial test
f=np.array(((0, 0, 0, 0, 0),
(0, 1, 1, 1, 0),
(0, 1, 0, 0, 0),
(0, 1, 1, 0, 0),
(0, 1, 0, 0, 0),
(0, 0, 0, 0, 0),), pic.dtype)
pic[0:6, 0:5]=f*pic.max()
def sim_gen(self,sz=(1500,1000),t=100,mode=0): def sim_gen(self,sz=(1500,1000),t=100,mode=0):
'generate simulation data' 'generate simulation data'
@@ -257,15 +262,8 @@ class epics_cam(object):
assert(img.mode=='L') # 8 bit grayscale assert(img.mode=='L') # 8 bit grayscale
assert(sz==img.size) assert(sz==img.size)
imgSeq[i,:,:]=np.array(img.getdata()).reshape(sz[::-1]) imgSeq[i,:,:]=np.array(img.getdata()).reshape(sz[::-1])
f=np.array(((0,0,0,0,0), pic=imgSeq[i]
(0,1,1,1,0), epics_cam.set_fiducial(pic, 255)
(0,1,0,0,0),
(0,1,1,0,0),
(0,1,0,0,0),
(0,0,0,0,0),),imgSeq.dtype)
imgSeq[i,0:6,0:5]=f*255
self._sim['imgSeq']=imgSeq self._sim['imgSeq']=imgSeq
self._sim['imgIdx']=0 self._sim['imgIdx']=0

View File

@@ -395,12 +395,32 @@ class Main(QMainWindow, Ui_MainWindow):
app=QApplication.instance() app=QApplication.instance()
app._camera.pause() app._camera.pause()
def updateImage(self, pause=False): def new_frame_sim_cb(self, **kwargs):
#if not sample_camera.is_paused(): #ZAC: orig. code
app=QApplication.instance() app=QApplication.instance()
img = app._camera.get_image() sim=app._camera._sim
if img is not None: imgSeq=sim['imgSeq']
self.img.setImage(img) idx=sim['imgIdx']
sim['imgIdx']=(idx+1)%imgSeq.shape[0]
# _log.info('simulated idx:{}'.format(idx))
pic=imgSeq[idx]
self.img.setImage(pic)
delay=500 # ms -> 2fps
QtCore.QTimer.singleShot(delay, self.new_frame_sim_cb)
def new_frame_pv_cb(self, **kwargs):
app=QApplication.instance()
sz=app._camera._sz
if kwargs['count']==sz[0]*sz[1]:
pic=kwargs['value'].reshape(sz[::-1])
else:
sz=self.update_size()
pic=kwargs['value'].reshape(sz[::-1])
_log.debug('new_frame_pv_cb count {}'.format(kwargs['count']))
if pic.dtype==np.int16:
pic.dtype=np.uint16
camera.epics_cam.set_fiducial(pic, 255)
self.img.setImage(pic)
def init_settings_tracker(self): def init_settings_tracker(self):
_log.info("configuring widget persistence") _log.info("configuring widget persistence")
@@ -527,15 +547,13 @@ class Main(QMainWindow, Ui_MainWindow):
self.timer.timeout.connect(self.check_zescape) self.timer.timeout.connect(self.check_zescape)
self.timer.start(20) self.timer.start(20)
else: else:
#zescape.stop_listening() #ZAC: orig. code app=QApplication.instance()
_log.warning("re-starting timer on camera update")
try: try:
self.timer.stop() self.new_frame_sim_cb()
except: except AttributeError:
pass app._camera.run(self.new_frame_pv_cb)
self.timer = QtCore.QTimer(self)
self.timer.timeout.connect(self.updateImage)
self.timer.start(10)
def check_zescape(self): def check_zescape(self):
msg = zescape.check() msg = zescape.check()
@@ -3156,28 +3174,31 @@ class Main(QMainWindow, Ui_MainWindow):
def really_quit(self): def really_quit(self):
"""called when user Ctrl-Q the app""" """called when user Ctrl-Q the app"""
global user, just_quit if QMessageBox.question(self, "", "Are you sure you want to quit?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No,) == QMessageBox.Yes:
if (just_quit
or QMessageBox.question(self, "", "Are you sure you want to quit?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No,) == QMessageBox.Yes
):
self._do_quit = True self._do_quit = True
self.close() self.close()
def closeEvent(self, event): def closeEvent(self, event):
"""this is called when the user clicks the window's cross icon""" """this is called when the user clicks the window's cross icon"""
global user, just_quit
if ( if (
just_quit self._do_quit
or self._do_quit
or QMessageBox.question( self, "", "Are you sure you want to quit?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No,) == QMessageBox.Yes or QMessageBox.question( self, "", "Are you sure you want to quit?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No,) == QMessageBox.Yes
): ):
sample_camera.disconnect() app=QApplication.instance()
try:
pv=app._camera._pv['pic']
pv.clear_auto_monitor() # disconnect PV monitor callback -> program exit faster.
except AttributeError:
_log.warning('disconnect PV callback failed.')
_log.info('disconnect PV callback')
settings.setValue("window/geometry", self.saveGeometry()) settings.setValue("window/geometry", self.saveGeometry())
settings.setValue("window/windowState", self.saveState()) settings.setValue("window/windowState", self.saveState())
settings.setValue("window/main_splitter", self._main_splitter.sizes()) settings.setValue("window/main_splitter", self._main_splitter.sizes())
settings.setValue("last_active", time.time()) settings.setValue("last_active", time.time())
_log.info('save settings')
QMainWindow.closeEvent(self, event) #QMainWindow.closeEvent(self, event)
_log.info('closeEvent done')
else: else:
event.ignore() event.ignore()
@@ -3220,7 +3241,10 @@ def sigint_handler(*args):
def main(): def main():
import argparse import argparse
parser = argparse.ArgumentParser() #(h, t)=os.path.split(sys.argv[0]);cmd='\n '+(t if len(h)>20 else sys.argv[0])+' '
#exampleCmd=('', '-m0xf -v0')
epilog=__doc__ #+'\nExamples:'+''.join(map(lambda s:cmd+s, exampleCmd))+'\n'
parser=argparse.ArgumentParser(epilog=epilog, formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument("--sim", "-s", type=lambda x: int(x,0), help="simulate devices (see bitmasks) default=0x%(default)x", default=0) parser.add_argument("--sim", "-s", type=lambda x: int(x,0), help="simulate devices (see bitmasks) default=0x%(default)x", default=0)
args = parser.parse_args() args = parser.parse_args()
_log.info('Arguments:{}'.format(args.__dict__)) _log.info('Arguments:{}'.format(args.__dict__))
@@ -3250,10 +3274,9 @@ def main():
if args.sim&0x08: if args.sim&0x08:
app._camera = camera.epics_cam(None) app._camera = camera.epics_cam(None)
app._camera.sim_gen(mode=1) app._camera.sim_gen(mode=1)
app._camera.run()
else: else:
app._camera = camera.epics_cam() app._camera = camera.epics_cam()
app._camera.run() #app._camera.run() is called in center_piece_update
app_icon = QtGui.QIcon() app_icon = QtGui.QIcon()
app_icon.addFile("artwork/logo/16x16.png", QtCore.QSize(16, 16)) app_icon.addFile("artwork/logo/16x16.png", QtCore.QSize(16, 16))