class FramePainter(QtGui.QPainter): ''' A QPainter for a blank frame, which can be converted into a Pillow image with finalize() ''' def __init__(self, width, height): image = BlankFrame(width, height) log.debug("Creating QImage from PIL image object") self.image = ImageQt(image) super().__init__(self.image) def setPen(self, penStyle): if type(penStyle) is tuple: super().setPen(PaintColor(*penStyle)) else: super().setPen(penStyle) def finalize(self): log.verbose("Finalizing FramePainter") imBytes = self.image.bits().asstring(self.image.byteCount()) frame = Image.frombytes('RGBA', (self.image.width(), self.image.height()), imBytes) self.end() return frame
class EMBLXrayImaging(QtGraphicsManager, AbstractCollect): def __init__(self, *args): QtGraphicsManager.__init__(self, *args) AbstractCollect.__init__(self, *args) self.ff_apply = False self.ff_ssim = None self.qimage = None self.qpixmap = None self.image_count = 0 self.image_reading_thread = None self.ff_corrected_list = [] self.config_dict = {} self.collect_omega_start = 0 self.omega_start = 0 self.omega_move_enabled = False self.reference_distance = None self.reference_angle = None self.motor_positions = None self.image_dimension = (0, 0) self.graphics_camera_frame = None self.image_polling = None self.repeat_image_play = None self.current_image_index = None self.mouse_hold = False self.mouse_coord = [0, 0] self.centering_started = 0 self._previous_collect_status = None self._actual_collect_status = None self._failed = False self._number_of_images = 0 self.printed_warnings = [] self.printed_errors = [] self.chan_collect_status = None self.chan_collect_frame = None self.chan_collect_error = None self.chan_camera_error = None self.chan_camera_warning = None self.chan_ff_ssim = None self.cmd_collect_compression = None self.cmd_collect_detector = None self.cmd_collect_directory = None self.cmd_collect_exposure_time = None self.cmd_collect_in_queue = None self.cmd_collect_num_images = None self.cmd_collect_overlap = None self.cmd_collect_range = None self.cmd_collect_scan_type = None self.cmd_collect_shutter = None self.cmd_collect_start_angle = None self.cmd_collect_template = None self.cmd_collect_start = None self.cmd_collect_abort = None self.cmd_collect_ff_num_images = None self.cmd_collect_ff_offset = None self.cmd_collect_ff_pre = None self.cmd_collect_ff_post = None self.cmd_camera_trigger = None self.cmd_camera_live_view = None self.cmd_camera_write_data = None self.cmd_camera_ff_ssim = None self.beam_focusing_hwobj = None def init(self): AbstractCollect.init(self) self.ready_event = gevent.event.Event() self.image_dimension = (2048, 2048) self.reference_distance = self.getProperty("reference_distance") self.reference_angle = self.getProperty("reference_angle") QtGraphicsManager.init(self) self.disconnect(HWR.beamline.sample_view.camera, "imageReceived", self.camera_image_received) self.disconnect( HWR.beamline.diffractometer, "minidiffStateChanged", self.diffractometer_state_changed, ) self.disconnect( HWR.beamline.diffractometer, "centringStarted", self.diffractometer_centring_started, ) self.disconnect( HWR.beamline.diffractometer, "centringAccepted", self.create_centring_point, ) self.disconnect( HWR.beamline.diffractometer, "centringSuccessful", self.diffractometer_centring_successful, ) self.disconnect( HWR.beamline.diffractometer, "centringFailed", self.diffractometer_centring_failed, ) self.disconnect( HWR.beamline.diffractometer, "pixelsPerMmChanged", self.diffractometer_pixels_per_mm_changed, ) self.disconnect( HWR.beamline.diffractometer, "omegaReferenceChanged", self.diffractometer_omega_reference_changed, ) self.disconnect( HWR.beamline.diffractometer, "minidiffPhaseChanged", self.diffractometer_phase_changed, ) self.diffractometer_pixels_per_mm_changed((20., 20.)) self.graphics_manager_hwobj = self.getObjectByRole("graphics_manager") self.graphics_scale_item.set_start_position( 20, self.image_dimension[1] - 20) self.graphics_scale_item.set_custom_pen_color(Colors.BLUE) self.graphics_omega_reference_item.set_custom_pen_color( Colors.DARK_BLUE) self.graphics_measure_distance_item.set_custom_pen_color( Colors.DARK_BLUE) self.graphics_beam_item.hide() self.graphics_view.scene().measureItemChanged.connect( self.measure_item_changed) self.graphics_view.scene().setSceneRect(0, 0, self.image_dimension[0], self.image_dimension[1]) self.qimage = QtImport.QImage() self.qpixmap = QtImport.QPixmap() self.chan_frame = self.get_channel_object("chanFrame") self.chan_frame.connectSignal("update", self.frame_changed) self.chan_ff_ssim = self.get_channel_object("chanFFSSIM") self.chan_ff_ssim.connectSignal("update", self.ff_ssim_changed) self.chan_collect_status = self.get_channel_object("collectStatus") #self._actual_collect_status = self.chan_collect_status.getValue() self.chan_collect_status.connectSignal("update", self.collect_status_update) self.chan_collect_frame = self.get_channel_object("chanFrameCount") self.chan_collect_frame.connectSignal("update", self.collect_frame_update) self.chan_collect_error = self.get_channel_object("collectError") self.chan_collect_error.connectSignal("update", self.collect_error_update) self.chan_camera_warning = self.get_channel_object("cameraWarning") self.chan_camera_warning.connectSignal("update", self.camera_warning_update) self.chan_camera_error = self.get_channel_object("cameraError") self.chan_camera_error.connectSignal("update", self.camera_error_update) self.cmd_collect_detector = self.get_command_object("collectDetector") self.cmd_collect_directory = self.get_command_object( "collectDirectory") self.cmd_collect_exposure_time = self.get_command_object( "collectExposureTime") self.cmd_collect_in_queue = self.get_command_object("collectInQueue") self.cmd_collect_num_images = self.get_command_object( "collectNumImages") self.cmd_collect_range = self.get_command_object("collectRange") self.cmd_collect_scan_type = self.get_command_object("collectScanType") self.cmd_collect_shutter = self.get_command_object("collectShutter") self.cmd_collect_shutterless = self.get_command_object( "collectShutterless") self.cmd_collect_start_angle = self.get_command_object( "collectStartAngle") self.cmd_collect_template = self.get_command_object("collectTemplate") self.cmd_collect_ff_num_images = self.get_command_object( "collectFFNumImages") self.cmd_collect_ff_offset = self.get_command_object("collectFFOffset") self.cmd_collect_ff_pre = self.get_command_object("collectFFPre") self.cmd_collect_ff_post = self.get_command_object("collectFFPost") self.cmd_camera_trigger = self.get_command_object("cameraTrigger") self.cmd_camera_live_view = self.get_command_object("cameraLiveView") self.cmd_camera_write_data = self.get_command_object("cameraWriteData") self.cmd_camera_ff_ssim = self.get_command_object("cameraFFSSIM") self.cmd_collect_start = self.get_command_object("collectStart") self.cmd_collect_abort = self.get_command_object("collectAbort") self.beam_focusing_hwobj = self.getObjectByRole("beam_focusing") def frame_changed(self, data): if self._collecting: jpgdata = StringIO(data) im = Image.open(jpgdata) self.qimage = ImageQt(im) self.graphics_camera_frame.setPixmap( self.qpixmap.fromImage(self.qimage, QtImport.Qt.MonoOnly)) def ff_ssim_changed(self, value): if self._collecting: self.ff_ssim = list(value) self.ff_ssim.sort() def mouse_clicked(self, pos_x, pos_y, left_click): QtGraphicsManager.mouse_clicked(self, pos_x, pos_y, left_click) if self.centering_started: self.motor_positions["phi"] = self.omega_angle HWR.beamline.diffractometer.set_static_positions( self.motor_positions) HWR.beamline.diffractometer.image_clicked(pos_x, pos_y) self.centering_started -= 1 if not self.centering_started: self.set_centring_state(False) def mouse_released(self, pos_x, pos_y): QtGraphicsManager.mouse_released(self, pos_x, pos_y) self.mouse_hold = False def mouse_moved(self, pos_x, pos_y): QtGraphicsManager.mouse_moved(self, pos_x, pos_y) if self.mouse_hold: if self.mouse_coord[0] - pos_x > 0: index = self.current_image_index + 1 elif self.mouse_coord[0] - pos_x < 0: index = self.current_image_index - 1 else: return if index < 0: index = self.image_count - 1 elif index >= self.image_count: index = 0 self.mouse_coord[0] = pos_x self.display_image(index) def measure_item_changed(self, measured_points, measured_pix_num): start_x = measured_points[0].x() start_y = measured_points[0].y() end_x = measured_points[1].x() end_y = measured_points[1].y() if self.image_reading_thread is None: im = np.array(self.qimage.bits()).reshape(self.qimage.width(), self.qimage.height()) else: im = self.image_reading_thread.get_raw_image( self.current_image_index) #im_slice = im[start_x:start_y,end_x,end_y] #print im_slice.size, im_slice x = np.linspace(start_x, end_x, measured_pix_num) y = np.linspace(start_y, end_y, measured_pix_num) zi = ndimage.map_coordinates(im, np.vstack((x, y))) self.emit("measureItemChanged", zi) def get_graphics_view(self): return self.graphics_view def set_repeate_image_play(self, value): self.repeat_image_play = value def set_graphics_scene_size(self, size, fixed): pass def stop_move_beam_mark(self): """Stops to move beam mark :emits: infoMsg as str """ self.set_cursor_busy(False) self.in_move_beam_mark_state = False self.graphics_move_beam_mark_item.hide() self.graphics_view.graphics_scene.update() pos_x = self.graphics_move_beam_mark_item.end_coord[0] pos_y = self.graphics_move_beam_mark_item.end_coord[1] HWR.beamline.diffractometer.set_imaging_beam_position(pos_x, pos_y) logging.getLogger("GUI").info("Imaging beam position set to %d, %d" % (pos_x, pos_y)) self.emit("infoMsg", "") def diffractometer_phi_motor_moved(self, position): """Method when phi motor changed. Updates omega reference by redrawing phi angle :param position: phi rotation value :type position: float """ QtGraphicsManager.diffractometer_phi_motor_moved(self, position) #logging.getLogger("GUI").info(str(position)) self.display_image_by_angle(position) def pre_execute(self, data_model): self._failed = False """ if self.beam_focusing_hwobj.get_focus_mode() != "imaging": self._error_msg = "Beamline is not in Imaging mode" self.emit("collectFailed", self._error_msg) logging.getLogger("GUI").error("Imaging: Error during acquisition (%s)" % self._error_msg) self.ready_event.set() self._collecting = False self._failed = True return """ self.emit("progressInit", ("Image acquisition", 100, False)) self._collect_frame = 0 self.printed_warnings = [] self.printed_errors = [] self.ff_ssim = None self.config_dict = {} path_template = data_model.acquisitions[0].path_template acq_params = data_model.acquisitions[0].acquisition_parameters im_params = data_model.xray_imaging_parameters self._number_of_images = acq_params.num_images if im_params.detector_distance is not None: logging.getLogger("GUI").warning( "Imaging: Setting detector distance to %d mm" % int(im_params.detector_distance)) delta = (im_params.detector_distance - self.reference_distance) * self.reference_angle for motor in self.beam_focusing_hwobj.get_focus_motors(): if motor["motorName"] == "P14DetHor1": target = motor["focusingModes"]["Imaging"] + delta tine.set("/P14/P14DetTrans/P14detHor1", "Move.START", target) elif motor["motorName"] == "P14DetHor2": target = motor["focusingModes"]["Imaging"] + delta tine.set("/P14/P14DetTrans/P14detHor2", "Move.START", target) #TODO add later wait time.sleep(3) HWR.beamline.detector.distance.set_value( im_params.detector_distance, timeout=30) logging.getLogger("GUI").info("Imaging: Detector distance set") self.cmd_collect_detector("pco") self.cmd_collect_directory(str(path_template.directory)) self.cmd_collect_template(str(path_template.get_image_file_name())) self.cmd_collect_scan_type("xrimg") self.cmd_collect_exposure_time(acq_params.exp_time) self.cmd_collect_num_images(acq_params.num_images) self.cmd_collect_start_angle(acq_params.osc_start) self.cmd_collect_range(acq_params.osc_range) self.cmd_collect_in_queue(acq_params.in_queue != False) shutter_name = HWR.beamline.detector.get_shutter_name() self.cmd_collect_shutter(shutter_name) self.cmd_collect_ff_num_images(im_params.ff_num_images) self.cmd_collect_ff_offset([ im_params.sample_offset_a, im_params.sample_offset_b, im_params.sample_offset_c, ]) self.cmd_collect_ff_pre(im_params.ff_pre) self.cmd_collect_ff_post(im_params.ff_post) if acq_params.osc_range == 0: self.cmd_camera_trigger(False) else: self.cmd_camera_trigger(True) self.cmd_camera_live_view(im_params.ff_apply) self.cmd_camera_write_data(im_params.camera_write_data) self.cmd_camera_ff_ssim(im_params.ff_ssim_enabled) self.set_osc_start(acq_params.osc_start) self.current_dc_parameters = qmo.to_collect_dict( data_model, HWR.beamline.session, qmo.Sample())[0] self.current_dc_parameters["status"] = "Running" self.current_dc_parameters["comments"] = "" self.motor_positions = HWR.beamline.diffractometer.get_positions() self.take_crystal_snapshots() self.store_data_collection_in_lims() def execute(self, data_model): if not self._failed: self._collecting = True self.ready_event.clear() gevent.spawn(self.cmd_collect_start) #self.cmd_collect_start() #if data_model.xray_imaging_parameters.camera_write_data: # self.read_images_task = gevent.spawn(self.load_images, None, None, None, data_model) self.ready_event.wait() self.ready_event.clear() def post_execute(self, data_model): self.emit("progressStop", ()) self._collecting = False acq_params = data_model.acquisitions[0].acquisition_parameters path_template = data_model.acquisitions[0].path_template filename_template = "%s_%d_%" + str(path_template.precision) + "d" config_filename = filename_template % ( path_template.base_prefix, path_template.run_number, path_template.start_num) + ".json" config_file_path = os.path.join(path_template.directory, config_filename) archive_config_path = os.path.join( path_template.get_archive_directory(), config_filename) self.config_dict = { "motor_pos": self.motor_positions, "collect": self.current_dc_parameters, "imaging": data_model.xray_imaging_parameters.as_dict(), "ff_ssim": None } if data_model.xray_imaging_parameters.ff_pre: self.config_dict["ff_ssim"] = self.ff_ssim try: if not os.path.exists(path_template.get_archive_directory()): os.makedirs(path_template.get_archive_directory()) with open(archive_config_path, 'w') as outfile: json.dump(self.config_dict, outfile) logging.getLogger("GUI").info( "Imaging: Acquisition parameters saved in %s" % archive_config_path) except: logging.getLogger("GUI").error( "Imaging: Unable to save acquisition parameters in %s" % archive_config_path) #self.current_dc_parameters["status"] = "Data collection successful" self.update_data_collection_in_lims() #Copy first and last image to ispyb if data_model.xray_imaging_parameters.camera_write_data: image_filename = filename_template % ( path_template.base_prefix, path_template.run_number, path_template.start_num) + ".jpeg" image_filename = os.path.join( path_template.get_archive_directory(), image_filename) raw_image = read_image(path_template.get_image_path() % path_template.start_num, timeout=3) if raw_image is not None: misc.imsave(image_filename, raw_image) #Scale image from 2048x2048 to 256x256 misc.imsave(image_filename.replace(".jpeg", ".thumb.jpeg"), misc.imresize(raw_image, (256, 256))) self.store_image_in_lims(path_template.start_num) if acq_params.num_images > 1: image_filename = filename_template % ( path_template.base_prefix, path_template.run_number, acq_params.num_images - 1) + ".jpeg" image_filename = os.path.join( path_template.get_archive_directory(), image_filename) raw_image = read_image(path_template.get_image_path() % acq_params.num_images, timeout=3) if raw_image is not None: misc.imsave(image_filename, raw_image) misc.imsave( image_filename.replace(".jpeg", ".thumb.jpeg"), misc.imresize(raw_image, (256, 256))) self.store_image_in_lims(acq_params.num_images - path_template.start_num) @task def _take_crystal_snapshot(self, filename): """Saves crystal snapshot""" self.graphics_manager_hwobj.save_scene_snapshot(filename) def data_collection_hook(self): pass @task def move_motors(self, motor_position_dict): """Move to centred position""" if motor_position_dict: HWR.beamline.diffractometer.move_motors(motor_position_dict) def trigger_auto_processing(self, process_event, frame_number): pass def collect_status_update(self, status): """Status event that controls execution :param status: collection status :type status: string """ if status != self._actual_collect_status: self._previous_collect_status = self._actual_collect_status self._actual_collect_status = status if self._collecting: if self._actual_collect_status == "error": #self.emit("collectFailed", self._error_msg) error_msg = "Error during the acquisition (%s)" % self._error_msg logging.getLogger("GUI").error("Imaging: %s" % error_msg) self.collection_failed(error_msg) if self._previous_collect_status is None: if self._actual_collect_status == "busy": self.print_log("GUI", "info", "Imaging: Preparing acquisition...") elif self._previous_collect_status == "busy": if self._actual_collect_status == "collecting": self.emit("collectStarted", (None, 1)) self.print_log("GUI", "info", "Imaging: Acquisition started") elif self._actual_collect_status == "ready": self.ready_event.set() self._collecting = False elif self._previous_collect_status == "collecting": if self._actual_collect_status == "ready": self.ready_event.set() self._collecting = False #if self.ff_ssim is None: # self.ff_ssim_changed(self.chan_ff_ssim.getValue()) logging.getLogger("GUI").info( "Imaging: Acquisition done") elif self._actual_collect_status == "aborting": self.print_log("HWR", "info", "Imaging: Aborting...") self.ready_event.set() self._collecting = False def collect_error_update(self, error_msg): """Collect error behaviour :param error_msg: error message :type error_msg: string """ if self._collecting and len(error_msg) > 0: self._error_msg = error_msg.replace("\n", "") logging.getLogger("GUI").error( "Imaging: Error from detector server: %s" % error_msg) def collect_frame_update(self, frame): """Image frame update :param frame: frame num :type frame: int """ if self._collecting: if self._collect_frame != frame: self._collect_frame = frame self.emit("progressStep", (int(float(frame) / self._number_of_images * 100))) self.emit("collectImageTaken", frame) def camera_warning_update(self, warning_str): if self._collecting: if warning_str.endswith("\n"): warning_str = warning_str[:-1] if warning_str.startswith("\n"): warning_str = warning_str[1:] warning_list = warning_str.split("\n") for warning in warning_list: if warning and warning not in self.printed_warnings: logging.getLogger("GUI").warning( "Imaging: PCO camera warning: %s" % warning) self.printed_warnings.append(warning) def camera_error_update(self, error_str): if self._collecting: if error_str.endswith("\n"): error_str = error_str[:-1] if error_str.startswith("\n"): error_str = error_str[1:] error_list = error_str.split("\n") for error in error_list: if error and error not in self.printed_errors: logging.getLogger("GUI").error( "Imaging: PCO camera error: %s" % error) self.printed_errors.append(error) def set_ff_apply(self, state): self.ff_apply = state self.display_image(self.current_image_index) def display_image_by_angle(self, angle=None): if self.config_dict: if not angle: angle = self.omega_angle osc_seq = self.config_dict["collect"]["oscillation_sequence"][0] index = int(osc_seq["range"] * (angle - osc_seq["start"])) self.display_image(index) def display_image(self, index): if self.image_reading_thread is None: return #osc_seq = self.config_dict["collect"]["oscillation_sequence"][0] #angle = osc_seq["start"] + index * osc_seq["range"] #self.motor_positions["phi"] = angle #HWR.beamline.diffractometer.set_static_positions(self.motor_positions) #self.graphics_omega_reference_item.set_phi_position(angle) self.current_image_index = index raw_image = self.image_reading_thread.get_raw_image(index) if self.ff_apply: if self.ff_corrected_list[index] is None: corrected_im_min_max = self.image_reading_thread.get_corrected_im_min_max( ) ff_image = self.image_reading_thread.get_ff_image( index).astype(float) ff_corrected_image = np.divide(raw_image.astype(float), ff_image, out=np.ones_like( raw_image.astype(float)), where=ff_image != 0) im = 255. * (ff_corrected_image - corrected_im_min_max[0]) / ( corrected_im_min_max[1] - corrected_im_min_max[0]) self.ff_corrected_list[index] = im.astype(np.uint16) else: im = self.ff_corrected_list[index] else: raw_im_min_max = self.image_reading_thread.get_raw_im_min_max() im = 255. * (raw_image - raw_im_min_max[0]) / (raw_im_min_max[1] - raw_im_min_max[0]) if im is not None: self.qimage = QtImport.QImage(im.astype(np.uint8), im.shape[1], im.shape[0], im.shape[1], QtImport.QImage.Format_Indexed8) self.graphics_camera_frame.setPixmap( self.qpixmap.fromImage(self.qimage)) self.emit("imageLoaded", index) def display_image_relative(self, relative_index): self.display_image(self.current_image_index + relative_index) def play_image_relative(self, relative_angle): self.play_images(0.04, relative_angle, False) def set_osc_start(self, osc_start): self.collect_omega_start = osc_start def set_omega_move_enabled(self, state): self.omega_move_enabled = state def get_ff_and_config_path(self, raw_image_path): directory = os.path.dirname(raw_image_path) filename = os.path.basename(raw_image_path) ff_path = os.path.join(directory, "ff_%s_00001.tiff" % filename[:-11]) if not os.path.exists(ff_path): ff_path = None config_path = os.path.join( directory.replace("mnt/beegfs/P14", "data/ispyb/p14"), "%s_00001.json" % filename[:-11]) if not os.path.exists(config_path): config_path = None return ff_path, config_path def load_images(self, data_path=None, flat_field_path=None, config_path=None, data_model=None, load_all=True): ff_ssim = None raw_filename_list = [] ff_filename_list = [] self.config_dict = {} self.omega_start = HWR.beamline.diffractometer.get_omega_position() self.motor_positions = None self.image_reading_thread = None if not data_model: if data_path.endswith("tiff"): ext_len = 4 else: ext_len = 3 base_name_list = os.path.splitext(os.path.basename(data_path)) prefix = base_name_list[0][:-(ext_len + 1)] # Reading config json -------------------------------------------- if config_path is None: config_path = data_path[:-ext_len] + "json" if os.path.exists(config_path): with open(config_path) as f: self.config_dict = json.load(f) ff_ssim = self.config_dict["ff_ssim"] self.motor_positions = deepcopy(self.config_dict["motor_pos"]) HWR.beamline.diffractometer.set_static_positions( self.motor_positions) else: logging.getLogger("user_level_log").error( "Imaging: Unable to open config file %s" % config_path) if data_model: if data_model.xray_imaging_parameters.ff_pre: acq_params = data_model.acquisitions[0].acquisition_parameters path_template = data_model.acquisitions[0].path_template for index in range( data_model.xray_imaging_parameters.ff_num_images): ff_filename_list.append( os.path.join( path_template.directory, "ff_" + path_template.get_image_file_name() % (index + 1))) elif os.path.exists(flat_field_path): base_name_list = os.path.splitext(os.path.basename(data_path)) ff_prefix = base_name_list[0][:-(ext_len + 1)] os.chdir(os.path.dirname(flat_field_path)) ff_filename_list = [ os.path.join(os.path.dirname(flat_field_path), f) for f in os.listdir(os.path.dirname(flat_field_path)) if f.startswith("ff_" + prefix) ] ff_filename_list.sort() # Reading raw images ------------------------------------------------- if data_model: acq_params = data_model.acquisitions[0].acquisition_parameters path_template = data_model.acquisitions[0].path_template for index in range(acq_params.num_images): raw_filename_list.append( os.path.join( path_template.directory, path_template.get_image_file_name() % (index + 1))) elif os.path.exists(data_path): os.chdir(os.path.dirname(data_path)) raw_filename_list = sorted([ os.path.join(os.path.dirname(data_path), f) for f in os.listdir(os.path.dirname(data_path)) if f.startswith(prefix) ]) else: acq_params = data_model.acquisitions[0].acquisition_parameters path_template = data_model.acquisitions[0].path_template for index in range(acq_params.num_images): raw_filename_list.append( os.path.join( path_template.directory, path_template.get_image_file_name() % (index + 1))) self.image_count = len(raw_filename_list) if self.image_reading_thread is not None: self.image_reading_thread.set_stop() self.ff_corrected_list = [None] * self.image_count self.image_reading_thread = ImageReadingThread(raw_filename_list, ff_filename_list, ff_ssim) self.image_reading_thread.start() self.current_image_index = 0 self.emit('imageInit', self.image_count) gevent.sleep(2) self.last_image_index = 0 self.display_image_by_angle() def play_images(self, exp_time=0.04, relative_angle=None, repeat=True): self.image_polling = gevent.spawn(self.do_image_polling, exp_time, relative_angle, repeat) def do_image_polling(self, exp_time=0.04, relative_angle=0, repeat=False): self.repeat_image_play = repeat direction = 1 if relative_angle < 0: direction = -1 rotate_in_sec = 2 step = int(self.image_count / (rotate_in_sec / exp_time)) start_index = self.current_image_index index = 0 while self.current_image_index < self.image_count: if relative_angle: if index >= abs(self.image_count / 360. * relative_angle): break logging.getLogger("HWR").debug("display: " + str(self.current_image_index)) self.display_image(self.current_image_index) self.current_image_index += direction * step if self.repeat_image_play and self.current_image_index >= self.image_count: self.current_image_index = 0 gevent.sleep(exp_time) index += step if relative_angle: self.display_image( int(start_index + self.image_count / 360. * relative_angle)) def stop_image_play(self): self.image_polling.kill() def stop_collect(self): self.cmd_collect_abort() def mouse_wheel_scrolled(self, delta): if self.image_reading_thread is None or \ self.image_reading_thread.get_raw_image(self.current_image_index) is None: return if delta > 0: self.current_image_index -= 1 if self.current_image_index < 0: self.current_image_index = self.image_count - 1 else: self.current_image_index += 1 if self.current_image_index == self.image_count: self.current_image_index = 0 self.display_image(self.current_image_index) def start_centering(self): self.centering_started = 3 self.set_centring_state(True) #osc_seq = self.config_dict["collect"]["oscillation_sequence"][0] #angle = osc_seq["start"] + index * osc_seq["range"] self.motor_positions["phi"] = self.omega_angle HWR.beamline.diffractometer.set_static_positions(self.motor_positions) HWR.beamline.diffractometer.start_centring_method( HWR.beamline.diffractometer.CENTRING_METHOD_IMAGING) def start_n_centering(self): self.centering_started = 100 self.set_centring_state(True) HWR.beamline.diffractometer.start_centring_method( HWR.beamline.diffractometer.CENTRING_METHOD_IMAGING_N)
class EMBLXrayImaging(QtGraphicsManager, AbstractCollect): """ Based on the collection and graphics """ def __init__(self, *args): QtGraphicsManager.__init__(self, *args) AbstractCollect.__init__(self, *args) self.ff_apply = False self.ff_ssim = None self.qimage = None self.qpixmap = None self.image_count = 0 self.image_reading_thread = None self.image_processing_thread = None self.ff_corrected_list = [] self.config_dict = {} self.collect_omega_start = 0 self.omega_start = 0 self.omega_move_enabled = False self.last_image_index = None self.image_dimension = (0, 0) self.graphics_camera_frame = None self.image_polling = None self.repeat_image_play = None self.current_image_index = None self.mouse_hold = False self.mouse_coord = [0, 0] self.centering_started = 0 self.current_dc_parameters = None self._previous_collect_status = None self._actual_collect_status = None self._failed = False self._number_of_images = 0 self._collect_frame = 0 self.printed_warnings = [] self.printed_errors = [] self.chan_collect_status = None self.chan_collect_frame = None self.chan_collect_error = None self.chan_camera_error = None self.chan_camera_warning = None self.chan_frame = None self.chan_ff_ssim = None self.cmd_collect_compression = None self.cmd_collect_detector = None self.cmd_collect_directory = None self.cmd_collect_exposure_time = None self.cmd_collect_in_queue = None self.cmd_collect_num_images = None self.cmd_collect_overlap = None self.cmd_collect_range = None self.cmd_collect_scan_type = None self.cmd_collect_shutter = None self.cmd_collect_start_angle = None self.cmd_collect_template = None self.cmd_collect_start = None self.cmd_collect_shutterless = None self.cmd_collect_abort = None self.cmd_collect_ff_num_images = None self.cmd_collect_ff_offset = None self.cmd_collect_ff_pre = None self.cmd_collect_ff_post = None self.cmd_camera_trigger = None self.cmd_camera_live_view = None self.cmd_camera_write_data = None self.cmd_camera_ff_ssim = None self.beam_focusing_hwobj = None self.session_hwobj = None def init(self): AbstractCollect.init(self) self.ready_event = gevent.event.Event() self.image_dimension = (2048, 2048) QtGraphicsManager.init(self) self.disconnect(self.camera_hwobj, "imageReceived", self.camera_image_received) self.disconnect( self.diffractometer_hwobj, "minidiffStateChanged", self.diffractometer_state_changed, ) self.disconnect( self.diffractometer_hwobj, "centringStarted", self.diffractometer_centring_started, ) self.disconnect( self.diffractometer_hwobj, "centringAccepted", self.create_centring_point ) self.disconnect( self.diffractometer_hwobj, "centringSuccessful", self.diffractometer_centring_successful, ) self.disconnect( self.diffractometer_hwobj, "centringFailed", self.diffractometer_centring_failed, ) self.disconnect( self.diffractometer_hwobj, "pixelsPerMmChanged", self.diffractometer_pixels_per_mm_changed, ) self.disconnect( self.diffractometer_hwobj, "omegaReferenceChanged", self.diffractometer_omega_reference_changed, ) self.disconnect( self.diffractometer_hwobj, "minidiffPhaseChanged", self.diffractometer_phase_changed, ) self.diffractometer_pixels_per_mm_changed((20.0, 20.0)) self.camera_hwobj = None self.graphics_scale_item.set_start_position(20, self.image_dimension[1] - 20) self.graphics_scale_item.set_custom_pen_color(Colors.BLUE) self.graphics_omega_reference_item.set_custom_pen_color(Colors.DARK_BLUE) self.graphics_measure_distance_item.set_custom_pen_color(Colors.DARK_BLUE) self.graphics_beam_item.hide() self.graphics_view.scene().measureItemChanged.connect(self.measure_item_changed) self.graphics_view.scene().setSceneRect( 0, 0, self.image_dimension[0], self.image_dimension[1] ) self.qimage = QtImport.QImage() self.qpixmap = QtImport.QPixmap() self.chan_frame = self.getChannelObject("chanFrame") self.chan_frame.connectSignal("update", self.frame_changed) self.chan_ff_ssim = self.getChannelObject("chanFFSSIM") self.chan_ff_ssim.connectSignal("update", self.ff_ssim_changed) self.chan_collect_status = self.getChannelObject("collectStatus") self._actual_collect_status = self.chan_collect_status.getValue() self.chan_collect_status.connectSignal("update", self.collect_status_update) self.chan_collect_frame = self.getChannelObject("chanFrameCount") self.chan_collect_frame.connectSignal("update", self.collect_frame_update) self.chan_collect_error = self.getChannelObject("collectError") self.chan_collect_error.connectSignal("update", self.collect_error_update) self.chan_camera_warning = self.getChannelObject("cameraWarning") self.chan_camera_warning.connectSignal("update", self.camera_warning_update) self.chan_camera_error = self.getChannelObject("cameraError") self.chan_camera_error.connectSignal("update", self.camera_error_update) self.cmd_collect_detector = self.getCommandObject("collectDetector") self.cmd_collect_directory = self.getCommandObject("collectDirectory") self.cmd_collect_exposure_time = self.getCommandObject("collectExposureTime") self.cmd_collect_in_queue = self.getCommandObject("collectInQueue") self.cmd_collect_num_images = self.getCommandObject("collectNumImages") self.cmd_collect_range = self.getCommandObject("collectRange") self.cmd_collect_scan_type = self.getCommandObject("collectScanType") self.cmd_collect_shutter = self.getCommandObject("collectShutter") self.cmd_collect_shutterless = self.getCommandObject("collectShutterless") self.cmd_collect_start_angle = self.getCommandObject("collectStartAngle") self.cmd_collect_template = self.getCommandObject("collectTemplate") self.cmd_collect_ff_num_images = self.getCommandObject("collectFFNumImages") self.cmd_collect_ff_offset = self.getCommandObject("collectFFOffset") self.cmd_collect_ff_pre = self.getCommandObject("collectFFPre") self.cmd_collect_ff_post = self.getCommandObject("collectFFPost") self.cmd_camera_trigger = self.getCommandObject("cameraTrigger") self.cmd_camera_live_view = self.getCommandObject("cameraLiveView") self.cmd_camera_write_data = self.getCommandObject("cameraWriteData") self.cmd_camera_ff_ssim = self.getCommandObject("cameraFFSSIM") self.cmd_collect_start = self.getCommandObject("collectStart") self.cmd_collect_abort = self.getCommandObject("collectAbort") self.beam_focusing_hwobj = self.getObjectByRole("beam_focusing") self.session_hwobj = self.getObjectByRole("session") def frame_changed(self, data): """ Displays frame comming from camera :param data: :return: """ if self._collecting: jpgdata = StringIO(data) im = Image.open(jpgdata) self.qimage = ImageQt(im) self.graphics_camera_frame.setPixmap( self.qpixmap.fromImage(self.qimage, QtImport.Qt.MonoOnly) ) def ff_ssim_changed(self, value): """ Updates ff ssim :param value: list of lists :return: """ if self._collecting: self.ff_ssim = list(value) self.ff_ssim.sort() def mouse_clicked(self, pos_x, pos_y, left_click): """ Mouse click event for centering :param pos_x: int :param pos_y: int :param left_click: boolean :return: """ QtGraphicsManager.mouse_clicked(self, pos_x, pos_y, left_click) # self.mouse_hold = True # self.mouse_coord = [pos_x, pos_y] if self.centering_started: self.diffractometer_hwobj.image_clicked(pos_x, pos_y) self.play_image_relative(90) # self.diffractometer_hwobj.move_omega_relative(90, timeout=5) self.centering_started -= 1 def mouse_released(self, pos_x, pos_y): """ Mouse release event :param pos_x: :param pos_y: :return: """ QtGraphicsManager.mouse_released(self, pos_x, pos_y) self.mouse_hold = False def mouse_moved(self, pos_x, pos_y): """ Mouse move event :param pos_x: :param pos_y: :return: """ QtGraphicsManager.mouse_moved(self, pos_x, pos_y) if self.mouse_hold: if self.mouse_coord[0] - pos_x > 0: index = self.current_image_index + 1 elif self.mouse_coord[0] - pos_x < 0: index = self.current_image_index - 1 else: return if index < 0: index = self.image_count - 1 elif index >= self.image_count: index = 0 self.mouse_coord[0] = pos_x self.display_image(index) def measure_item_changed(self, measured_points, measured_pix_num): """ Updates image measurement item :param measured_points: :param measured_pix_num: :return: """ start_x = measured_points[0].x() start_y = measured_points[0].y() end_x = measured_points[1].x() end_y = measured_points[1].y() if self.image_reading_thread is None: im = np.array(self.qimage.bits()).reshape( self.qimage.width(), self.qimage.height() ) else: im = self.image_reading_thread.get_raw_image(self.current_image_index) # im_slice = im[start_x:start_y,end_x,end_y] # print im_slice.size, im_slice x = np.linspace(start_x, end_x, measured_pix_num) y = np.linspace(start_y, end_y, measured_pix_num) zi = ndimage.map_coordinates(im, np.vstack((x, y))) self.emit("measureItemChanged", zi) def get_graphics_view(self): """ Returns graphics view :return: """ return self.graphics_view def set_repeate_image_play(self, value): """ Sets repeat the image play :param value: :return: """ self.repeat_image_play = value def set_graphics_scene_size(self, size, fixed): pass def pre_execute(self, data_model): """ Pre execute method :param data_model: :return: """ self._failed = False """ if self.beam_focusing_hwobj.get_focus_mode() != "imaging": self._error_msg = "Beamline is not in Imaging mode" self.emit("collectFailed", self._error_msg) logging.getLogger("GUI").error("Imaging: Error during acquisition (%s)" % self._error_msg) self.ready_event.set() self._collecting = False self._failed = True return """ self.emit("progressInit", ("Image acquisition", 100, False)) self._collect_frame = 0 self.printed_warnings = [] self.printed_errors = [] self.ff_ssim = None self.config_dict = {} path_template = data_model.acquisitions[0].path_template acq_params = data_model.acquisitions[0].acquisition_parameters im_params = data_model.xray_imaging_parameters self._number_of_images = acq_params.num_images if im_params.detector_distance: delta = im_params.detector_distance - self.detector_hwobj.get_distance() if abs(delta) > 0.0001: tine.set( "/P14/P14DetTrans/ComHorTrans", "IncrementMove.START", -0.003482 * delta, ) self.detector_hwobj.set_distance( im_params.detector_distance, wait=True, timeout=30 ) self.cmd_collect_detector("pco") self.cmd_collect_directory(str(path_template.directory)) self.cmd_collect_template(str(path_template.get_image_file_name())) self.cmd_collect_scan_type("xrimg") self.cmd_collect_exposure_time(acq_params.exp_time) self.cmd_collect_num_images(acq_params.num_images) self.cmd_collect_start_angle(acq_params.osc_start) self.cmd_collect_range(acq_params.osc_range) self.cmd_collect_in_queue(acq_params.in_queue != False) shutter_name = self.detector_hwobj.get_shutter_name() self.cmd_collect_shutter(shutter_name) self.cmd_collect_ff_num_images(im_params.ff_num_images) self.cmd_collect_ff_offset( [ im_params.sample_offset_a, im_params.sample_offset_b, im_params.sample_offset_c, ] ) self.cmd_collect_ff_pre(im_params.ff_pre) self.cmd_collect_ff_post(im_params.ff_post) if acq_params.osc_range == 0: self.cmd_camera_trigger(False) else: self.cmd_camera_trigger(True) self.cmd_camera_live_view(im_params.ff_apply) self.cmd_camera_write_data(im_params.camera_write_data) self.cmd_camera_ff_ssim(im_params.ff_ssim_enabled) self.set_osc_start(acq_params.osc_start) self.current_dc_parameters = qmo.to_collect_dict( data_model, self.session_hwobj, qmo.Sample() )[0] self.current_dc_parameters["status"] = "Running" self.current_dc_parameters["comments"] = "" self.store_data_collection_in_lims() def execute(self, data_model): """ Main execute method :param data_model: :return: """ if not self._failed: self._collecting = True self.ready_event.clear() gevent.spawn(self.cmd_collect_start) # self.cmd_collect_start() # if data_model.xray_imaging_parameters.camera_write_data: # self.read_images_task = gevent.spawn(self.load_images, None, None, None, data_model) self.ready_event.wait() self.ready_event.clear() def post_execute(self, data_model): """ Stores results in ispyb :param data_model: :return: """ self.emit("progressStop", ()) self._collecting = False acq_params = data_model.acquisitions[0].acquisition_parameters path_template = data_model.acquisitions[0].path_template filename_template = "%s_%d_%" + str(path_template.precision) + "d" config_filename = ( filename_template % ( path_template.base_prefix, path_template.run_number, path_template.start_num, ) + ".json" ) #config_file_path = os.path.join(path_template.directory, config_filename) archive_config_path = os.path.join( path_template.get_archive_directory(), config_filename ) self.config_dict = { "collect": acq_params.as_dict(), "path": path_template.as_dict(), "imaging": data_model.xray_imaging_parameters.as_dict(), "ff_ssim": None, } if data_model.xray_imaging_parameters.ff_pre: self.config_dict["ff_ssim"] = self.ff_ssim try: if not os.path.exists(path_template.get_archive_directory()): os.makedirs(path_template.get_archive_directory()) with open(archive_config_path, "w") as outfile: json.dump(self.config_dict, outfile) logging.getLogger("GUI").info( "Imaging: Acquisition parameters saved in %s" % archive_config_path ) except BaseException: logging.getLogger("GUI").error( "Imaging: Unable to save acquisition parameters in %s" % archive_config_path ) self.current_dc_parameters["status"] = "Data collection successful" self.update_data_collection_in_lims() # Copy first and last image to ispyb if self.image_reading_thread is not None: image_filename = ( filename_template % ( path_template.base_prefix, path_template.run_number, path_template.start_num, ) + ".jpeg" ) image_filename = os.path.join( path_template.get_archive_directory(), image_filename ) # misc.imsave(image_filename, self.image_reading_thread.get_raw_image(0)) self.store_image_in_lims(0) if acq_params.num_images > 1: image_filename = ( filename_template % ( path_template.base_prefix, path_template.run_number, acq_params.num_images - 1, ) + ".jpeg" ) image_filename = os.path.join( path_template.get_archive_directory(), image_filename ) # misc.imsave(image_filename, self.image_reading_thread.get_raw_image(0)) self.store_image_in_lims(acq_params.num_images - 1) @task def _take_crystal_snapshot(self, filename): """Saves crystal snapshot""" self.graphics_manager_hwobj.save_scene_snapshot(filename) def data_collection_hook(self): """ Not implemented :return: """ pass def move_motors(self, motor_position_dict): """ Not implemented :param motor_position_dict: :return: """ pass def trigger_auto_processing(self, process_event, frame_number): """ Not implemented :param process_event: :param frame_number: :return: """ pass def collect_status_update(self, status): """Status event that controls execution :param status: collection status :type status: string """ if status != self._actual_collect_status: self._previous_collect_status = self._actual_collect_status self._actual_collect_status = status if self._collecting: if self._actual_collect_status == "error": self.emit("collectFailed", self._error_msg) logging.getLogger("GUI").error( "Imaging: Error during the acquisition (%s)" % self._error_msg ) self.ready_event.set() self._collecting = False if self._previous_collect_status is None: if self._actual_collect_status == "busy": self.print_log( "GUI", "info", "Imaging: Preparing acquisition..." ) elif self._previous_collect_status == "busy": if self._actual_collect_status == "collecting": self.emit("collectStarted", (None, 1)) self.print_log("GUI", "info", "Imaging: Acquisition started") elif self._actual_collect_status == "ready": self.ready_event.set() self._collecting = False elif self._previous_collect_status == "collecting": if self._actual_collect_status == "ready": self.ready_event.set() self._collecting = False if self.ff_ssim is None: self.ff_ssim_changed(self.chan_ff_ssim.getValue()) logging.getLogger("GUI").info("Imaging: Acquisition done") elif self._actual_collect_status == "aborting": self.print_log("HWR", "info", "Imaging: Aborting...") self.ready_event.set() self._collecting = False def collect_error_update(self, error_msg): """Collect error behaviour :param error_msg: error message :type error_msg: string """ if self._collecting and len(error_msg) > 0: self._error_msg = error_msg.replace("\n", "") logging.getLogger("GUI").error( "Imaging: Error from detector server: %s" % error_msg ) def collect_frame_update(self, frame): """Image frame update :param frame: frame num :type frame: int """ if self._collecting: if self._collect_frame != frame: self._collect_frame = frame self.emit( "progressStep", (int(float(frame) / self._number_of_images * 100)) ) self.emit("collectImageTaken", frame) def camera_warning_update(self, warning_str): """ Displays camera warnings :param warning_str: :return: """ if self._collecting: if warning_str.endswith("\n"): warning_str = warning_str[:-1] if warning_str.startswith("\n"): warning_str = warning_str[1:] warning_list = warning_str.split("\n") for warning in warning_list: if warning and warning not in self.printed_warnings: logging.getLogger("GUI").warning( "Imaging: PCO camera warning: %s" % warning ) self.printed_warnings.append(warning) def camera_error_update(self, error_str): """ Displays camera errors :param error_str: :return: """ if self._collecting: if error_str.endswith("\n"): error_str = error_str[:-1] if error_str.startswith("\n"): error_str = error_str[1:] error_list = error_str.split("\n") for error in error_list: if error and error not in self.printed_errors: logging.getLogger("GUI").error( "Imaging: PCO camera error: %s" % error ) self.printed_errors.append(error) def set_ff_apply(self, state): """ Apply ff to live view :param state: :return: """ self.ff_apply = state self.display_image(self.current_image_index) def display_image(self, index): """ Displays image on the canvas :param index: int :return: """ angle = self.collect_omega_start + index * self.image_count / 360.0 if angle > 360: angle -= 360 elif angle < 0: angle += 360 self.graphics_omega_reference_item.set_phi_position(angle) self.current_image_index = index im = self.image_reading_thread.get_raw_image(index) if self.ff_apply and self.image_processing_thread: if self.ff_corrected_list[index] is None: im_min, im_max = self.image_processing_thread.get_im_min_max() im = self.image_reading_thread.get_raw_image(index).astype(float) ff_image = self.image_reading_thread.get_ff_image(index).astype(float) ff_corrected_image = np.divide( im, ff_image, out=np.ones_like(im), where=ff_image != 0 ) im = 255.0 * (ff_corrected_image - im_min) / (im_max - im_min) self.ff_corrected_list[index] = im.astype(np.uint16) else: im = self.ff_corrected_list[index] # sx = ndimage.sobel(im, axis=0, mode='constant') # sy = ndimage.sobel(im, axis=1, mode='constant') # im = np.hypot(sx, sy) if im is not None: self.qimage = QtImport.QImage( im.astype(np.uint8), im.shape[1], im.shape[0], im.shape[1], QtImport.QImage.Format_Indexed8, ) self.graphics_camera_frame.setPixmap(self.qpixmap.fromImage(self.qimage)) self.emit("imageLoaded", index) def display_image_relative(self, relative_index): """ Displays relative image :param relative_index: :return: """ self.display_image(self.current_image_index + relative_index) def play_image_relative(self, relative_angle): """ Starts image video :param relative_angle: :return: """ self.play_images(0.04, relative_angle, False) def set_osc_start(self, osc_start): """ Defines osc start :param osc_start: float :return: """ self.collect_omega_start = osc_start def set_omega_move_enabled(self, state): """ Move omega if the image has been displayed :param state: :return: """ self.omega_move_enabled = state def load_images( self, data_path=None, flat_field_path=None, config_path=None, data_model=None, load_all=True, ): """ Load and process images via threads :param data_path: str :param flat_field_path: str :param config_path: str :param data_model: :param load_all: boolean :return: """ ff_ssim = None self.config_dict = {} self.omega_start = self.diffractometer_hwobj.get_omega_position() self.image_reading_thread = None self.image_processing_thread = None ff_filename_list = [] raw_filename_list = [] if not data_model: if data_path.endswith("tiff"): ext_len = 4 else: ext_len = 3 base_name_list = os.path.splitext(os.path.basename(data_path)) prefix = base_name_list[0][: -(ext_len + 1)] # Reading config json -------------------------------------------- if config_path is None: config_path = data_path[:-ext_len] + "json" if os.path.exists(config_path): with open(config_path) as f: self.config_dict = json.load(f) ff_ssim = self.config_dict["ff_ssim"] self.set_osc_start(self.config_dict["collect"]["osc_start"]) else: logging.getLogger("user_level_log").error( "Imaging: Unable to open config file %s" % config_path ) if data_model: if data_model.xray_imaging_parameters.ff_pre: path_template = data_model.acquisitions[0].path_template for index in range(data_model.xray_imaging_parameters.ff_num_images): ff_filename_list.append( os.path.join( path_template.directory, "ff_" + path_template.get_image_file_name() % (index + 1), ) ) elif os.path.exists(flat_field_path): base_name_list = os.path.splitext(os.path.basename(data_path)) os.chdir(os.path.dirname(flat_field_path)) ff_filename_list = sorted( [ os.path.join(os.path.dirname(flat_field_path), f) for f in os.listdir(os.path.dirname(flat_field_path)) if f.startswith("ff_" + prefix) ] ) # Reading raw images ------------------------------------------------- if data_model: acq_params = data_model.acquisitions[0].acquisition_parameters path_template = data_model.acquisitions[0].path_template for index in range(acq_params.num_images): raw_filename_list.append( os.path.join( path_template.directory, path_template.get_image_file_name() % (index + 1), ) ) elif os.path.exists(data_path): os.chdir(os.path.dirname(data_path)) raw_filename_list = sorted( [ os.path.join(os.path.dirname(data_path), f) for f in os.listdir(os.path.dirname(data_path)) if f.startswith(prefix) ] ) else: acq_params = data_model.acquisitions[0].acquisition_parameters path_template = data_model.acquisitions[0].path_template for index in range(acq_params.num_images): raw_filename_list.append( os.path.join( path_template.directory, path_template.get_image_file_name() % (index + 1), ) ) self.image_count = len(raw_filename_list) if self.image_reading_thread is not None: self.image_reading_thread.set_stop() if self.image_processing_thread is not None: image_processing_queue.queue.clear() self.image_processing_thread.set_stop() self.ff_corrected_list = [None] * self.image_count self.image_reading_thread = ImageReadingThread( raw_filename_list, ff_filename_list, ff_ssim ) self.image_reading_thread.start() if ff_filename_list: self.image_processing_thread = ImageProcessingThread(self.image_count) self.image_processing_thread.start() self.current_image_index = 0 self.emit("imageInit", self.image_count) # gevent.sleep(5) self.last_image_index = 0 # self.display_image(0) def play_images(self, exp_time=0.04, relative_index=None, repeat=True): """ Play image video :param exp_time: :param relative_index: :param repeat: :return: """ self.image_polling = gevent.spawn( self.do_image_polling, exp_time, relative_index, repeat ) def do_image_polling(self, exp_time=0.04, relative_index=1, repeat=False): """ Image polling task :param exp_time: :param relative_index: :param repeat: :return: """ self.repeat_image_play = repeat direction = 1 if relative_index > 0 else -1 rotate_in_sec = 10 step = int(self.image_count / (rotate_in_sec / exp_time)) index = 0 while self.current_image_index < self.image_count: if index >= abs(relative_index): break self.display_image(self.current_image_index) self.current_image_index += direction * step if self.repeat_image_play and self.current_image_index >= self.image_count: self.current_image_index -= self.image_count gevent.sleep(exp_time) index += step def stop_image_play(self): """ Stop image video :return: """ self.image_polling.kill() def stop_collect(self): """ Stops image collection :return: """ self.cmd_collect_abort() def mouse_wheel_scrolled(self, delta): """ Handles mouse scroll :param delta: :return: """ if ( self.image_reading_thread is None or self.image_reading_thread.get_raw_image(self.current_image_index) is None ): return if delta > 0: self.current_image_index -= 1 if self.current_image_index < 0: self.current_image_index = self.image_count - 1 else: self.current_image_index += 1 if self.current_image_index == self.image_count: self.current_image_index = 0 self.display_image(self.current_image_index) def start_centering(self): """ Starts 3 click centering :return: """ self.centering_started = 3 self.diffractometer_hwobj.start_centring_method( self.diffractometer_hwobj.CENTRING_METHOD_IMAGING ) def start_n_centering(self): """ Starts n click centering :return: """ self.centering_started = 100 self.diffractometer_hwobj.start_centring_method( self.diffractometer_hwobj.CENTRING_METHOD_IMAGING_N ) def move_omega(self, image_index): """ Rotates omega :param image_index: :return: """ if image_index != self.last_image_index: if self.config_dict: omega_relative = self.config_dict["collect"]["osc_range"] * image_index else: omega_relative = self.image_count / 360.0 * image_index if self.last_image_index > image_index: omega_relative *= -1 self.diffractometer_hwobj.move_omega_relative(omega_relative) self.last_image_index = image_index def move_omega_relative(self, relative_index): """ Rotates omega relative :param relative_index: :return: """ self.move_omega(self.last_image_index + relative_index)