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

View File

@@ -395,12 +395,32 @@ class Main(QMainWindow, Ui_MainWindow):
app=QApplication.instance()
app._camera.pause()
def updateImage(self, pause=False):
#if not sample_camera.is_paused(): #ZAC: orig. code
def new_frame_sim_cb(self, **kwargs):
app=QApplication.instance()
img = app._camera.get_image()
if img is not None:
self.img.setImage(img)
sim=app._camera._sim
imgSeq=sim['imgSeq']
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):
_log.info("configuring widget persistence")
@@ -527,15 +547,13 @@ class Main(QMainWindow, Ui_MainWindow):
self.timer.timeout.connect(self.check_zescape)
self.timer.start(20)
else:
#zescape.stop_listening() #ZAC: orig. code
_log.warning("re-starting timer on camera update")
app=QApplication.instance()
try:
self.timer.stop()
except:
pass
self.timer = QtCore.QTimer(self)
self.timer.timeout.connect(self.updateImage)
self.timer.start(10)
self.new_frame_sim_cb()
except AttributeError:
app._camera.run(self.new_frame_pv_cb)
def check_zescape(self):
msg = zescape.check()
@@ -3156,28 +3174,31 @@ class Main(QMainWindow, Ui_MainWindow):
def really_quit(self):
"""called when user Ctrl-Q the app"""
global user, just_quit
if (just_quit
or QMessageBox.question(self, "", "Are you sure you want to quit?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No,) == QMessageBox.Yes
):
if QMessageBox.question(self, "", "Are you sure you want to quit?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No,) == QMessageBox.Yes:
self._do_quit = True
self.close()
def closeEvent(self, event):
"""this is called when the user clicks the window's cross icon"""
global user, just_quit
if (
just_quit
or self._do_quit
self._do_quit
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/windowState", self.saveState())
settings.setValue("window/main_splitter", self._main_splitter.sizes())
settings.setValue("last_active", time.time())
QMainWindow.closeEvent(self, event)
_log.info('save settings')
#QMainWindow.closeEvent(self, event)
_log.info('closeEvent done')
else:
event.ignore()
@@ -3220,7 +3241,10 @@ def sigint_handler(*args):
def main():
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)
args = parser.parse_args()
_log.info('Arguments:{}'.format(args.__dict__))
@@ -3250,10 +3274,9 @@ def main():
if args.sim&0x08:
app._camera = camera.epics_cam(None)
app._camera.sim_gen(mode=1)
app._camera.run()
else:
app._camera = camera.epics_cam()
app._camera.run()
#app._camera.run() is called in center_piece_update
app_icon = QtGui.QIcon()
app_icon.addFile("artwork/logo/16x16.png", QtCore.QSize(16, 16))