def edit_transform(self): sys.stderr.write('Loading Edit Transform GUI...\n') self.statusBar().showMessage('Loading Edit Transform GUI...') self.alignment_ui = Ui_AlignmentGui() self.alignment_gui = QDialog(self) self.alignment_gui.setWindowTitle("Edit transform between adjacent sections") self.alignment_ui.setupUi(self.alignment_gui) self.alignment_ui.button_anchor.clicked.connect(self.add_anchor_pair_clicked) self.alignment_ui.button_align.clicked.connect(self.align_using_elastix) self.alignment_ui.button_compute.clicked.connect(self.compute_custom_transform) param_fps = os.listdir(DataManager.get_elastix_parameters_dir()) all_parameter_setting_names = ['_'.join(pf[:-4].split('_')[1:]) for pf in param_fps] self.alignment_ui.comboBox_parameters.addItems(all_parameter_setting_names) section_filenames = self.get_sorted_filenames(valid_only=self.show_valid_only) # Initialize gscene "current" self.curr_gscene = SimpleGraphicsScene4(id='current', gview=self.alignment_ui.curr_gview) self.alignment_ui.curr_gview.setScene(self.curr_gscene) self.curr_gscene.set_data_feeder(self.ordered_images_feeder) self.curr_gscene.set_active_i(1) self.curr_gscene.active_image_updated.connect(self.current_section_image_changed) self.curr_gscene.anchor_point_added.connect(self.anchor_point_added) # Initialize gscene "previous" self.prev_gscene = SimpleGraphicsScene4(id='previous', gview=self.alignment_ui.prev_gview) self.alignment_ui.prev_gview.setScene(self.prev_gscene) self.prev_gscene.set_data_feeder(self.ordered_images_feeder) self.prev_gscene.set_active_i(0) self.prev_gscene.active_image_updated.connect(self.previous_section_image_changed) self.prev_gscene.anchor_point_added.connect(self.anchor_point_added) # Initialize gscene "overlay" self.overlay_gscene = MultiplePixmapsGraphicsScene(id='overlay', pixmap_labels=['moving', 'fixed'], gview=self.alignment_ui.aligned_gview) self.alignment_ui.aligned_gview.setScene(self.overlay_gscene) self.transformed_images_feeder = ImageDataFeeder_v2('transformed image feeder', stack=self.stack, sections=section_filenames, resolution=self.tb_res) self.update_transformed_images_feeder() self.overlay_gscene.set_data_feeder(self.transformed_images_feeder, 'moving') self.overlay_gscene.set_data_feeder(self.ordered_images_feeder, 'fixed') self.overlay_gscene.set_active_indices({'moving': 1, 'fixed': 0}) self.overlay_gscene.set_opacity('moving', .3) self.overlay_gscene.set_opacity('fixed', .3) self.overlay_gscene.active_image_updated.connect(self.overlay_image_changed) self.alignment_gui.show()
class PreprocessGUI(QMainWindow, Ui_PreprocessGui): def __init__(self, parent=None, stack=None, tb_fmt='png', tb_res='down32', tb_version=None): """ Initialization of preprocessing tool. """ QMainWindow.__init__(self, parent) self.setupUi(self) self.stack = stack self.fileLocationManager = FileLocationManager(self.stack) self.sqlController = SqlController() self.currently_showing = 'original' self.tb_fmt = tb_fmt self.tb_res = tb_res self.tb_version = tb_version self.stack_data_dir = self.fileLocationManager.thumbnail_prep self.show_valid_only = True #_, self.section_to_filename = DataManager.load_sorted_filenames(self.stack) #self.filename_to_accept_decision = {fn: True for sec, fn in self.section_to_filename.iteritems() if not is_invalid(fn)} self.section_to_filename = self.sqlController.get_valid_sections(self.stack) # self.sorted_filenames = [f for s,f in sorted(section_to_filename.items())] self.placeholder_qimage = QImage(800, 500, QImage.Format_RGB888) painter = QPainter(self.placeholder_qimage) painter.fillRect(self.placeholder_qimage.rect(), Qt.yellow); painter.drawText(self.placeholder_qimage.rect(), Qt.AlignCenter | Qt.AlignVCenter, "Placeholder"); self.rescan_qimage = QImage(800, 500, QImage.Format_RGB888) painter = QPainter(self.rescan_qimage) painter.fillRect(self.rescan_qimage.rect(), Qt.green); painter.drawText(self.rescan_qimage.rect(), Qt.AlignCenter | Qt.AlignVCenter, "Rescan"); self.nonexisting_qimage = QImage(800, 500, QImage.Format_RGB888) painter = QPainter(self.nonexisting_qimage) painter.fillRect(self.nonexisting_qimage.rect(), Qt.white); painter.drawText(self.nonexisting_qimage.rect(), Qt.AlignCenter | Qt.AlignVCenter, "Nonexisting"); self.first_section = None self.last_section = None self.sorted_sections_gscene = SimpleGraphicsScene3(id='sorted', gview=self.sorted_sections_gview) self.sorted_sections_gview.setScene(self.sorted_sections_gscene) self.sorted_sections_gscene.active_image_updated.connect(self.sorted_sections_image_updated) self.sorted_sections_gscene.first_section_set.connect(self.set_first_section) self.sorted_sections_gscene.last_section_set.connect(self.set_last_section) self.sorted_sections_gscene.anchor_set.connect(self.set_anchor) self.sorted_sections_gscene.move_down_requested.connect(self.move_down) self.sorted_sections_gscene.move_up_requested.connect(self.move_up) ####################### self.installEventFilter(self) self.comboBox_show.activated.connect(self.show_option_changed) # self.button_sort.clicked.connect(self.sort) self.button_load_sorted_filenames.clicked.connect(self.load_sorted_filenames) # self.button_save_sorted_filenames.clicked.connect(self.save_sorted_filenames) # self.button_confirm_alignment.clicked.connect(self.compose) self.button_edit_transform.clicked.connect(self.edit_transform) # self.button_crop.clicked.connect(self.crop) self.button_save_crop.clicked.connect(self.save_crop) self.button_load_crop.clicked.connect(self.load_crop) self.button_update_order.clicked.connect(self.update_sorted_sections_gscene_from_sorted_filenames) self.button_toggle_show_hide_invalid.clicked.connect(self.toggle_show_hide_invalid) ################################ self.placeholders = set([]) self.rescans = set([]) pp_fp = os.path.join(self.fileLocationManager.brain_info, 'problematic_pairs.txt') if os.path.exists(pp_fp): sys.stderr.write("Loaded problematic pairs.\n") with open(pp_fp, 'r') as f: self.problematic_pairs = [tuple(line.split()) for line in f.readlines()] else: sys.stderr.write("Did not find problematic pairs.\n") self.problematic_pairs = [] def toggle_show_hide_invalid(self): self.show_valid_only = not self.show_valid_only print(self.show_valid_only) self.button_toggle_show_hide_invalid.setText('Show both valid and invalid' if self.show_valid_only else 'Show valid only') self.update_sorted_sections_gscene_from_sorted_filenames() def move_down(self): curr_fn = self.sorted_sections_gscene.active_section next_fn = self.sorted_sections_gscene.data_feeder.sections[self.sorted_sections_gscene.active_i + 1] filename_to_section = self.section_to_filename curr_fn_section = filename_to_section[curr_fn] next_fn_section = filename_to_section[next_fn] self.section_to_filename[curr_fn_section] = next_fn self.section_to_filename[next_fn_section] = curr_fn self.update_sorted_sections_gscene_from_sorted_filenames() self.sorted_sections_gscene.set_active_section(curr_fn) def move_up(self): curr_fn = self.sorted_sections_gscene.active_section prev_fn = self.sorted_sections_gscene.data_feeder.sections[self.sorted_sections_gscene.active_i - 1] filename_to_section = self.section_to_filename curr_fn_section = filename_to_section[curr_fn] prev_fn_section = filename_to_section[prev_fn] self.section_to_filename[curr_fn_section] = prev_fn self.section_to_filename[prev_fn_section] = curr_fn self.update_sorted_sections_gscene_from_sorted_filenames() self.sorted_sections_gscene.set_active_section(curr_fn) def load_crop(self): """ Load crop box. """ self.set_show_option('aligned') cropbox_fp = DataManager.get_cropbox_filename(stack=self.stack, anchor_fn=self.anchor_fn) with open(cropbox_fp, 'r') as f: ul_x, lr_x, ul_y, lr_y, first_section, last_section = map(int, f.readline().split()) self.first_section = self.section_to_filename[first_section] self.last_section = self.section_to_filename[last_section] self.sorted_sections_gscene.set_box(ul_x, lr_x, ul_y, lr_y) print(ul_x, lr_x, ul_y, lr_y, self.first_section, self.last_section) def save_crop(self): ul_pos = self.sorted_sections_gscene.corners['ul'].scenePos() lr_pos = self.sorted_sections_gscene.corners['lr'].scenePos() ul_x = int(ul_pos.x()) ul_y = int(ul_pos.y()) lr_x = int(lr_pos.x()) lr_y = int(lr_pos.y()) # If not set yet. if ul_x == 100 and ul_y == 100 and lr_x == 200 and lr_y == 200: return cropbox_fp = DataManager.get_cropbox_filename(stack=self.stack, anchor_fn=self.anchor_fn) filename_to_section = invert_section_to_filename_mapping(self.section_to_filename) with open(cropbox_fp, 'w') as f: f.write('%d %d %d %d %d %d' % (ul_x, lr_x, ul_y, lr_y, filename_to_section[self.first_section], filename_to_section[self.last_section])) upload_to_s3(cropbox_fp) def crop(self): pass ## Note that in cropbox, xmax, ymax are not included, so w = xmax-xmin, instead of xmax-xmin+1 # self.save_crop() # # ul_pos = self.sorted_sections_gscene.corners['ul'].scenePos() # lr_pos = self.sorted_sections_gscene.corners['lr'].scenePos() # ul_x = int(ul_pos.x()) # ul_y = int(ul_pos.y()) # lr_x = int(lr_pos.x()) # lr_y = int(lr_pos.y()) # # if self.stack in all_nissl_stacks: # pad_bg_color = 'white' # elif self.stack in all_ntb_stacks: # pad_bg_color = 'black' # elif self.stack in all_alt_nissl_ntb_stacks or self.stack in all_alt_nissl_tracing_stacks: # pad_bg_color = 'auto' # # self.web_service.convert_to_request('crop', stack=self.stack, x=ul_x, y=ul_y, w=lr_x+1-ul_x, h=lr_y+1-ul_y, # f=self.first_section, l=self.last_section, anchor_fn=self.anchor_fn, # filenames=self.get_valid_sorted_filenames(), # first_fn=self.sorted_filenames[self.first_section-1], # last_fn=self.sorted_filenames[self.last_section-1], # pad_bg_color=pad_bg_color) ################## # Edit Alignment # ################## def edit_transform(self): sys.stderr.write('Loading Edit Transform GUI...\n') self.statusBar().showMessage('Loading Edit Transform GUI...') self.alignment_ui = Ui_AlignmentGui() self.alignment_gui = QDialog(self) self.alignment_gui.setWindowTitle("Edit transform between adjacent sections") self.alignment_ui.setupUi(self.alignment_gui) self.alignment_ui.button_anchor.clicked.connect(self.add_anchor_pair_clicked) self.alignment_ui.button_align.clicked.connect(self.align_using_elastix) self.alignment_ui.button_compute.clicked.connect(self.compute_custom_transform) param_fps = os.listdir(DataManager.get_elastix_parameters_dir()) all_parameter_setting_names = ['_'.join(pf[:-4].split('_')[1:]) for pf in param_fps] self.alignment_ui.comboBox_parameters.addItems(all_parameter_setting_names) section_filenames = self.get_sorted_filenames(valid_only=self.show_valid_only) # Initialize gscene "current" self.curr_gscene = SimpleGraphicsScene4(id='current', gview=self.alignment_ui.curr_gview) self.alignment_ui.curr_gview.setScene(self.curr_gscene) self.curr_gscene.set_data_feeder(self.ordered_images_feeder) self.curr_gscene.set_active_i(1) self.curr_gscene.active_image_updated.connect(self.current_section_image_changed) self.curr_gscene.anchor_point_added.connect(self.anchor_point_added) # Initialize gscene "previous" self.prev_gscene = SimpleGraphicsScene4(id='previous', gview=self.alignment_ui.prev_gview) self.alignment_ui.prev_gview.setScene(self.prev_gscene) self.prev_gscene.set_data_feeder(self.ordered_images_feeder) self.prev_gscene.set_active_i(0) self.prev_gscene.active_image_updated.connect(self.previous_section_image_changed) self.prev_gscene.anchor_point_added.connect(self.anchor_point_added) # Initialize gscene "overlay" self.overlay_gscene = MultiplePixmapsGraphicsScene(id='overlay', pixmap_labels=['moving', 'fixed'], gview=self.alignment_ui.aligned_gview) self.alignment_ui.aligned_gview.setScene(self.overlay_gscene) self.transformed_images_feeder = ImageDataFeeder_v2('transformed image feeder', stack=self.stack, sections=section_filenames, resolution=self.tb_res) self.update_transformed_images_feeder() self.overlay_gscene.set_data_feeder(self.transformed_images_feeder, 'moving') self.overlay_gscene.set_data_feeder(self.ordered_images_feeder, 'fixed') self.overlay_gscene.set_active_indices({'moving': 1, 'fixed': 0}) self.overlay_gscene.set_opacity('moving', .3) self.overlay_gscene.set_opacity('fixed', .3) self.overlay_gscene.active_image_updated.connect(self.overlay_image_changed) self.alignment_gui.show() def update_transformed_images_feeder(self): section_filenames = self.get_sorted_filenames(valid_only=self.show_valid_only) transformed_image_filenames = [] for i in range(1, len(section_filenames)): fp = DataManager.load_image_filepath_warped_to_adjacent_section(stack=self.stack, moving_fn=section_filenames[i], fixed_fn=section_filenames[i-1]) transformed_image_filenames.append(fp) self.transformed_images_feeder.set_images(labels=section_filenames[1:], filenames=transformed_image_filenames, resolution=self.tb_res, load_with_cv2=True) def align_using_elastix(self): selected_elastix_parameter_name = str(self.alignment_ui.comboBox_parameters.currentText()) param_fn = os.path.join(UTILITY_DIR, 'preprocess', 'parameters', 'Parameters_' + selected_elastix_parameter_name + '.txt') curr_fn = self.curr_gscene.active_section prev_fn = self.prev_gscene.active_section out_dir = os.path.join(self.stack_data_dir, self.stack + '_custom_transforms', curr_fn + '_to_' + prev_fn) curr_fp = DataManager.get_image_filepath_v2(stack=self.stack, prep_id=None, fn=curr_fn, resol=self.tb_res, version=self.tb_version) prev_fp = DataManager.get_image_filepath_v2(stack=self.stack, prep_id=None, fn=prev_fn, resol=self.tb_res, version=self.tb_version ) # curr_fp = os.path.join(RAW_DATA_DIR, self.stack, curr_fn + '.' + self.tb_fmt) # prev_fp = os.path.join(RAW_DATA_DIR, self.stack, prev_fn + '.' + self.tb_fmt) execute_command('rm -rf %(out_dir)s; mkdir -p %(out_dir)s; elastix -f %(fixed_fn)s -m %(moving_fn)s -out %(out_dir)s -p %(param_fn)s' % \ dict(param_fn=param_fn, out_dir=out_dir, fixed_fn=prev_fp, moving_fn=curr_fp)) # section_filenames = self.get_sorted_filenames(valid_only=self.show_valid_only) self.update_transformed_images_feeder() def anchor_point_added(self, index): gscene_id = self.sender().id if gscene_id == 'current': self.current_section_anchor_received = True # self.curr_gscene.anchor_points.index elif gscene_id == 'previous': self.previous_section_anchor_received = True if self.current_section_anchor_received and self.previous_section_anchor_received: self.curr_gscene.set_mode('idle') self.prev_gscene.set_mode('idle') self.current_section_anchor_received = False self.previous_section_anchor_received = False self.alignment_ui.button_anchor.setEnabled(True) def compute_custom_transform(self): """ Compute transform based on added control points. """ curr_points = [] for i, c in enumerate(self.curr_gscene.anchor_circle_items): pos = c.scenePos() curr_points.append((pos.x(), pos.y())) prev_points = [] for i, c in enumerate(self.prev_gscene.anchor_circle_items): pos = c.scenePos() prev_points.append((pos.x(), pos.y())) print(self.curr_gscene.active_section, np.array(curr_points)) print(self.prev_gscene.active_section, np.array(prev_points)) curr_points = np.array(curr_points) prev_points = np.array(prev_points) curr_centroid = curr_points.mean(axis=0) prev_centroid = prev_points.mean(axis=0) curr_points0 = curr_points - curr_centroid prev_points0 = prev_points - prev_centroid H = np.dot(curr_points0.T, prev_points0) U, S, VT = np.linalg.svd(H) R = np.dot(VT.T, U.T) t = -np.dot(R, curr_centroid) + prev_centroid print(R, t) # Write to custom transform file curr_section_fn = self.curr_gscene.active_section prev_section_fn = self.prev_gscene.active_section custom_tf_dir = os.path.join(self.stack_data_dir, self.stack + '_custom_transforms', curr_section_fn + '_to_' + prev_section_fn) execute_command("rm -rf %(out_dir)s; mkdir -p %(out_dir)s" % dict(out_dir=custom_tf_dir)) custom_tf_fp = os.path.join(custom_tf_dir, '%(curr_fn)s_to_%(prev_fn)s_customTransform.txt' % \ dict(curr_fn=curr_section_fn, prev_fn=prev_section_fn)) with open(custom_tf_fp, 'w') as f: f.write('%f %f %f %f %f %f\n' % (R[0,0], R[0,1], t[0], R[1,0], R[1,1], t[1])) self.apply_custom_transform() self.update_transformed_images_feeder() def apply_custom_transform(self): # section_filenames = self.get_sorted_filenames(valid_only=self.show_valid_only) # curr_section_fn = section_filenames[self.valid_section_indices[self.curr_gscene.active_i]-1] # prev_section_fn = section_filenames[self.valid_section_indices[self.prev_gscene.active_i]-1] curr_section_fn = self.curr_gscene.active_section prev_section_fn = self.prev_gscene.active_section custom_tf_fn = os.path.join(self.stack_data_dir, self.stack+'_custom_transforms', curr_section_fn + '_to_' + prev_section_fn, curr_section_fn + '_to_' + prev_section_fn + '_customTransform.txt') with open(custom_tf_fn, 'r') as f: t11, t12, t13, t21, t22, t23 = map(float, f.readline().split()) prev_fp = DataManager.get_image_filepath_v2(stack=self.stack, prep_id=None, fn=prev_section_fn, resol=self.tb_res, version=self.tb_version ) curr_fp = DataManager.get_image_filepath_v2(stack=self.stack, prep_id=None, fn=curr_section_fn, resol=self.tb_res, version=self.tb_version ) prev_img_w, prev_img_h = identify_shape(prev_fp) output_image_fp = os.path.join(self.stack_data_dir, '%(stack)s_custom_transforms/%(curr_fn)s_to_%(prev_fn)s/%(curr_fn)s_alignedTo_%(prev_fn)s.tif' % \ dict(stack=self.stack, curr_fn=curr_section_fn, prev_fn=prev_section_fn) ) execute_command("convert %(curr_fp)s -virtual-pixel background +distort AffineProjection '%(sx)f,%(rx)f,%(ry)f,%(sy)f,%(tx)f,%(ty)f' -crop %(w)sx%(h)s%(x)s%(y)s\! -flatten -compress lzw %(output_fp)s" %\ dict(curr_fp=curr_fp, output_fp=output_image_fp, tb_fmt=self.tb_fmt, sx=t11, sy=t22, rx=t21, ry=t12, tx=t13, ty=t23, w=prev_img_w, h=prev_img_h, x='+0', y='+0', raw_data_dir=RAW_DATA_DIR)) def add_anchor_pair_clicked(self): self.curr_gscene.set_mode('add point') self.prev_gscene.set_mode('add point') self.current_section_anchor_received = False self.previous_section_anchor_received = False self.alignment_ui.button_anchor.setEnabled(False) def overlay_image_changed(self): section_filenames = self.get_sorted_filenames(valid_only=self.show_valid_only) curr_section_fn = self.overlay_gscene.active_sections['moving'] prev_section_fn = self.overlay_gscene.active_sections['fixed'] print("Problematic pairs:", self.problematic_pairs) if (prev_section_fn, curr_section_fn) in self.problematic_pairs: self.alignment_ui.label_current_filename.setText('(CHECK)' + str(curr_section_fn)) self.alignment_ui.label_current_index.setText('(CHECK)' + str(curr_section_fn)) else: self.alignment_ui.label_current_filename.setText(str(curr_section_fn)) self.alignment_ui.label_current_index.setText(str(curr_section_fn)) self.curr_gscene.set_active_section(curr_section_fn) self.prev_gscene.set_active_section(prev_section_fn) def current_section_image_changed(self): section_filenames = self.get_sorted_filenames(valid_only=self.show_valid_only) curr_section_fn = self.curr_gscene.active_section prev_section_fn = section_filenames[section_filenames.index(curr_section_fn) - 1] print("Problematic pairs:", self.problematic_pairs) if (prev_section_fn, curr_section_fn) in self.problematic_pairs: self.alignment_ui.label_current_filename.setText('(CHECK)' + str(curr_section_fn)) self.alignment_ui.label_current_index.setText('(CHECK)' + str(curr_section_fn)) else: self.alignment_ui.label_current_filename.setText(str(curr_section_fn)) self.alignment_ui.label_current_index.setText(str(curr_section_fn)) self.prev_gscene.set_active_section(prev_section_fn) self.overlay_gscene.set_active_sections({'moving': curr_section_fn, 'fixed': prev_section_fn}) def previous_section_image_changed(self): section_filenames = self.get_sorted_filenames(valid_only=self.show_valid_only) prev_section_fn = self.prev_gscene.active_section curr_section_fn = section_filenames[section_filenames.index(prev_section_fn) + 1] self.alignment_ui.label_previous_filename.setText(prev_section_fn) self.alignment_ui.label_previous_index.setText(str(prev_section_fn)) self.curr_gscene.set_active_section(curr_section_fn) self.overlay_gscene.set_active_sections({'moving': curr_section_fn, 'fixed': prev_section_fn}, emit_changed_signal=False) ########################## END OF EDIT TRANSFORM ######################################3 def save_everything(self): # Dump preprocessing info placeholder_indices = [idx+1 for idx, fn in enumerate(self.sorted_filenames) if fn == 'Placeholder'] placeholder_slide_positions = [(slide_name, pos) for slide_name, x in self.slide_position_to_fn.iteritems() for pos, fn in x.iteritems() if fn == 'Placeholder'] rescan_indices = [idx+1 for idx, fn in enumerate(self.sorted_filenames) if fn == 'Rescan'] rescan_slide_positions = [(slide_name, pos) for slide_name, x in self.slide_position_to_fn.iteritems() for pos, fn in x.iteritems() if fn == 'Rescan'] ul_pos = self.sorted_sections_gscene.corners['ul'].scenePos() lr_pos = self.sorted_sections_gscene.corners['lr'].scenePos() ul_x = int(ul_pos.x()) ul_y = int(ul_pos.y()) lr_x = int(lr_pos.x()) lr_y = int(lr_pos.y()) info = {'placeholder_indices': placeholder_indices, 'placeholder_slide_positions': placeholder_slide_positions, 'rescan_indices': rescan_indices, 'rescan_slide_positions': rescan_slide_positions, 'sorted_filenames': self.sorted_filenames, 'slide_position_to_fn': self.slide_position_to_fn, 'first_section': self.first_section, 'last_section': self.last_section, 'anchor_fn': self.anchor_fn, # 'bbox': (ul_x, lr_x, ul_y, lr_y) #xmin,xmax,ymin,ymax 'bbox': (ul_x, ul_y, lr_x+1-ul_x, lr_y+1-ul_y) #xmin,ymin,w,h } from datetime import datetime timestamp = datetime.now().strftime("%m%d%Y%H%M%S") pickle.dump(info, open(self.stack_data_dir + '/%(stack)s_preprocessInfo_%(timestamp)s.pkl' % {'stack': self.stack, 'timestamp':timestamp}, 'w')) execute_command('cd %(stack_data_dir)s && rm -f %(stack)s_preprocessInfo.pkl && ln -s %(stack)s_preprocessInfo_%(timestamp)s.pkl %(stack)s_preprocessInfo.pkl' % {'stack': self.stack, 'timestamp':timestamp, 'stack_data_dir':self.stack_data_dir}) self.save_crop() self.save_sorted_filenames() self.save() def update_sorted_sections_gscene_from_sorted_filenames(self): if not hasattr(self, 'currently_showing'): self.currently_showing = 'original' if not hasattr(self, 'anchor_fn'): anchor_fp = DataManager.get_anchor_filename_filename(self.stack) if os.path.exists(anchor_fp): with open(anchor_fp) as f: self.set_anchor(f.readline().strip()) else: imageNames_to_load = self.get_sorted_filenames(valid_only=self.show_valid_only) shapes = \ [identify_shape(DataManager.get_image_filepath_v2(stack=self.stack, fn=fn, prep_id=None, version=self.tb_version, resol=self.tb_res)) for fn in imageNames_to_load] largest_idx = np.argmax([h*w for h, w in shapes]) print('largest section is ', imageNames_to_load[largest_idx]) self.set_anchor(imageNames_to_load[largest_idx]) print(imageNames_to_load[largest_idx]) if self.currently_showing == 'original': imageNames_to_load = self.get_sorted_filenames(valid_only=self.show_valid_only) if not hasattr(self, 'ordered_images_feeder') or self.ordered_images_feeder is None: self.ordered_images_feeder = ImageDataFeeder_v2('ordered image feeder', stack=self.stack, sections=imageNames_to_load, resolution=self.tb_res, use_thread=False, auto_load=False) self.ordered_images_feeder.set_images(labels=imageNames_to_load, filenames=[DataManager.get_image_filepath_v2(stack=self.stack, fn=fn, prep_id=None, version=self.tb_version, resol=self.tb_res) for fn in imageNames_to_load], resolution=self.tb_res, load_with_cv2=False) self.ordered_images_feeder.set_images(labels=['Placeholder'], filenames=[self.placeholder_qimage], resolution=self.tb_res, load_with_cv2=False) else: self.ordered_images_feeder.set_sections(imageNames_to_load) self.sorted_sections_gscene.set_data_feeder(self.ordered_images_feeder) if self.sorted_sections_gscene.active_i is not None: active_i = self.sorted_sections_gscene.active_i else: active_i = 1 self.sorted_sections_gscene.set_active_i(active_i) elif self.currently_showing == 'aligned': imageNames_to_load = self.get_sorted_filenames(valid_only=self.show_valid_only) if not hasattr(self, 'aligned_images_feeder') or self.aligned_images_feeder is None: self.aligned_images_feeder = ImageDataFeeder_v2('aligned image feeder', stack=self.stack, sections=imageNames_to_load, resolution=self.tb_res, use_thread=False, auto_load=False) self.aligned_images_feeder.set_images(labels=imageNames_to_load, filenames=[DataManager.get_image_filepath_v2(stack=self.stack, fn=fn, prep_id='alignedPadded', version=self.tb_version, resol=self.tb_res) for fn in imageNames_to_load], resolution=self.tb_res, load_with_cv2=False) self.aligned_images_feeder.set_images(labels=['Placeholder'], filenames=[self.placeholder_qimage], resolution=self.tb_res, load_with_cv2=False) else: self.aligned_images_feeder.set_sections(imageNames_to_load) self.sorted_sections_gscene.set_data_feeder(self.aligned_images_feeder) if self.sorted_sections_gscene.active_i is not None: active_i = self.sorted_sections_gscene.active_i else: active_i = 1 self.sorted_sections_gscene.set_active_i(active_i) # elif self.currently_showing == 'mask_contour': # # self.maskContourViz_images_feeder = ImageDataFeeder_v2('mask contoured image feeder', stack=self.stack, # sections=self.valid_section_indices, resolution=self.tb_res) # self.maskContourViz_images_dir = self.stack_data_dir + '/%(stack)s_maskContourViz_unsorted' % {'stack': self.stack} # maskContourViz_image_filenames = [os.path.join(self.maskContourViz_images_dir, '%(fn)s_mask_contour_viz.tif' % {'fn': fn}) # for fn in self.valid_section_filenames] # # self.maskContourViz_images_feeder.set_images(self.valid_section_indices, maskContourViz_image_filenames, resolution=self.tb_res, load_with_cv2=False) # # self.maskContourViz_images_feeder.set_resolution(self.tb_res) # # active_i = self.sorted_sections_gscene.active_i # self.sorted_sections_gscene.set_data_feeder(self.maskContourViz_images_feeder) # self.sorted_sections_gscene.set_active_i(active_i) def save_sorted_filenames(self): sorted_filenames = self.get_sorted_filenames(valid_only=False) out_sorted_image_names_fp = DataManager.get_sorted_filenames_filename(stack=self.stack) with open(out_sorted_image_names_fp, 'w') as f: for i, fn in enumerate(sorted_filenames): f.write('%s %03d\n' % (fn, i+1)) # index starts from 1 upload_to_s3(out_sorted_image_names_fp) sys.stderr.write('Sorted filename list saved.\n') self.statusBar().showMessage('Sorted filename list saved.') def load_sorted_filenames(self): # filename_to_section, section_to_filename = DataManager.load_sorted_filenames(self.stack) # self.sorted_filenames = [f for s,f in sorted(section_to_filename.items())] sys.stderr.write('Sorted filename list is loaded.\n') self.statusBar().showMessage('Sorted filename list is loaded.') # self.fn_to_slide_position = {fn: (slide, pos) for slide, pos_to_fn in self.slide_position_to_fn.iteritems() for pos, fn in pos_to_fn.iteritems()} # self.sorted_slide_positions = [self.fn_to_slide_position[fn] for fn in self.sorted_filenames] self.update_sorted_sections_gscene_from_sorted_filenames() def load_slide_position_map(self): fn = self.stack_data_dir + '/%(stack)s_slide_position_to_fn.pkl' % {'stack': self.stack} if os.path.exists(fn): self.slide_position_to_fn = pickle.load(open(fn, 'r')) sys.stderr.write('Slide position to image filename mapping is loaded.\n') self.statusBar().showMessage('Slide position to image filename mapping is loaded.') else: sys.stderr.write('Cannot load slide position to image filename mapping - File does not exists.\n') self.statusBar().showMessage('Cannot load slide position to image filename mapping - File does not exists.') def save(self): pickle.dump(self.slide_position_to_fn, open(self.stack_data_dir + '/%(stack)s_slide_position_to_fn.pkl' % {'stack': self.stack}, 'w') ) def get_sorted_filenames(self, valid_only=False): return [fn for sec, fn in sorted(self.section_to_filename.items()) if (fn != 'Rescan' and fn != 'Placeholder' and self.filename_to_accept_decision[fn]) or not valid_only] def compose(self): pass def set_first_section(self, fn): self.first_section = str(fn) self.update_sorted_sections_gscene_label() def set_last_section(self, fn): self.last_section = str(fn) self.update_sorted_sections_gscene_label() def set_anchor(self, anchor): if isinstance(anchor, int): self.anchor_fn = self.sorted_filenames[anchor-1] elif isinstance(anchor, str): self.anchor_fn = anchor with open(os.path.join(THUMBNAIL_DATA_DIR, self.stack, self.stack + '_anchor.txt'), 'w') as f: f.write(self.anchor_fn) self.update_sorted_sections_gscene_label() def sorted_sections_image_updated(self): filename = self.sorted_sections_gscene.active_section self.label_sorted_sections_filename.setText(filename) self.label_sorted_sections_index.setText(str(self.sorted_sections_gscene.active_section)) if filename == 'Placeholder' or filename == 'Rescan': return assert filename != 'Unknown' and filename != 'Nonexisting' # Update slide scene # slide_name = self.filename_to_slide[filename] # position = self.slide_position_to_fn[slide_name].keys()[self.slide_position_to_fn[slide_name].values().index(filename)] # self.slide_gscene.set_active_section(slide_name) self.update_sorted_sections_gscene_label() def update_sorted_sections_gscene_label(self): """ Set the label next to sortedSectionGscene to FIRST, LAST or ANCHOR. """ # print self.sorted_sections_gscene.active_section, self.anchor_fn # if self.sorted_sections_gscene.active_section is not None: # print self.sorted_filenames[self.sorted_sections_gscene.active_section-1] if self.sorted_sections_gscene.active_section == self.first_section: self.label_sorted_sections_status.setText('FIRST') elif self.sorted_sections_gscene.active_section == self.last_section: self.label_sorted_sections_status.setText('LAST') elif hasattr(self, 'anchor_fn') and self.sorted_sections_gscene.active_section is not None and \ self.sorted_sections_gscene.active_section == self.anchor_fn: print(self.sorted_sections_gscene.active_section) self.label_sorted_sections_status.setText('ANCHOR') else: self.label_sorted_sections_status.setText('') def set_status(self, slide_name, position, fn): """ Update slide_position_to_fn variables. If active, change content and captions of the specified slide position gscene. """ # old_fn = self.slide_position_to_fn[slide_name][position] self.slide_position_to_fn[slide_name][position] = fn # # if slide_name == 'N_92': # print position # print self.slide_position_gscenes[position].data_feeder.all_sections # print self.section_image_feeders[slide_name].all_sections if slide_name == self.slide_gscene.active_section: self.slide_position_gscenes[position].set_active_section(fn) self.labels_slide_position_filename[position].setText(fn) if hasattr(self, 'sorted_filenames'): if fn == 'Placeholder' or fn == 'Rescan' or fn == 'Nonexisting': self.labels_slide_position_index[position].setText('') else: if fn in self.sorted_filenames: self.labels_slide_position_index[position].setText(str(self.sorted_filenames.index(fn)+1)) else: self.labels_slide_position_index[position].setText('Not in sorted list.') # def slide_image_updated(self): # self.setWindowTitle('Slide %(slide_index)s' % {'slide_index': self.slide_gscene.active_section}) # # slide_name = self.slide_gscene.active_section # feeder = self.section_image_feeders[slide_name] # # if slide_name not in self.slide_position_to_fn: # self.slide_position_to_fn[slide_name] = {p: 'Unknown' for p in [1,2,3]} # # for position, gscene in self.slide_position_gscenes.iteritems(): # # gscene.set_data_feeder(feeder) # # if self.slide_position_to_fn[slide_name][position] != 'Unknown': # self.set_status(slide_name, position, self.slide_position_to_fn[slide_name][position]) # else: # if position in self.thumbnail_filenames[slide_name]: # newest_fn = sorted(self.thumbnail_filenames[slide_name][position].items())[-1][1] # self.set_status(slide_name, position, newest_fn) # else: # self.set_status(slide_name, position, 'Nonexisting') def show_option_changed(self, index): show_option_text = str(self.sender().currentText()) if show_option_text == 'Original Aligned': self.set_show_option('aligned') elif show_option_text == 'Original': self.set_show_option('original') elif show_option_text == 'Mask Contoured': self.set_show_option('mask_contour') else: raise Exception('Not implemented.') def set_show_option(self, showing): if self.currently_showing == showing: return else: self.currently_showing = showing print(self.currently_showing) self.update_sorted_sections_gscene_from_sorted_filenames() def slide_position_image_updated(self): position = self.sender().id self.set_status(self.slide_gscene.active_section, position, self.slide_position_gscenes[position].active_section) def eventFilter(self, obj, event): if event.type() == QEvent.GraphicsSceneMousePress: pass elif event.type() == QEvent.KeyPress: key = event.key() return False
class PreprocessGUI(QMainWindow, Ui_PreprocessGui): def __init__(self, parent=None, stack=None, tb_fmt='png', tb_res='down32', tb_version=None): """ Initialization of preprocessing tool. """ QMainWindow.__init__(self, parent) self.setupUi(self) self.stack = stack self.currently_showing = 'original' self.tb_fmt = tb_fmt self.tb_res = tb_res self.tb_version = tb_version self.stack_data_dir = os.path.join(THUMBNAIL_DATA_DIR, stack) self.show_valid_only = True _, self.section_to_filename = DataManager.load_sorted_filenames(self.stack) self.filename_to_accept_decision = {fn: True for sec, fn in self.section_to_filename.iteritems() if not is_invalid(fn)} # self.sorted_filenames = [f for s,f in sorted(section_to_filename.items())] self.placeholder_qimage = QImage(800, 500, QImage.Format_RGB888) painter = QPainter(self.placeholder_qimage) painter.fillRect(self.placeholder_qimage.rect(), Qt.yellow); painter.drawText(self.placeholder_qimage.rect(), Qt.AlignCenter | Qt.AlignVCenter, "Placeholder"); self.rescan_qimage = QImage(800, 500, QImage.Format_RGB888) painter = QPainter(self.rescan_qimage) painter.fillRect(self.rescan_qimage.rect(), Qt.green); painter.drawText(self.rescan_qimage.rect(), Qt.AlignCenter | Qt.AlignVCenter, "Rescan"); self.nonexisting_qimage = QImage(800, 500, QImage.Format_RGB888) painter = QPainter(self.nonexisting_qimage) painter.fillRect(self.nonexisting_qimage.rect(), Qt.white); painter.drawText(self.nonexisting_qimage.rect(), Qt.AlignCenter | Qt.AlignVCenter, "Nonexisting"); self.first_section = None self.last_section = None self.sorted_sections_gscene = SimpleGraphicsScene3(id='sorted', gview=self.sorted_sections_gview) self.sorted_sections_gview.setScene(self.sorted_sections_gscene) self.sorted_sections_gscene.active_image_updated.connect(self.sorted_sections_image_updated) self.sorted_sections_gscene.first_section_set.connect(self.set_first_section) self.sorted_sections_gscene.last_section_set.connect(self.set_last_section) self.sorted_sections_gscene.anchor_set.connect(self.set_anchor) self.sorted_sections_gscene.move_down_requested.connect(self.move_down) self.sorted_sections_gscene.move_up_requested.connect(self.move_up) ####################### self.installEventFilter(self) self.comboBox_show.activated.connect(self.show_option_changed) # self.button_sort.clicked.connect(self.sort) self.button_load_sorted_filenames.clicked.connect(self.load_sorted_filenames) # self.button_save_sorted_filenames.clicked.connect(self.save_sorted_filenames) # self.button_confirm_alignment.clicked.connect(self.compose) self.button_edit_transform.clicked.connect(self.edit_transform) # self.button_crop.clicked.connect(self.crop) self.button_save_crop.clicked.connect(self.save_crop) self.button_load_crop.clicked.connect(self.load_crop) self.button_update_order.clicked.connect(self.update_sorted_sections_gscene_from_sorted_filenames) self.button_toggle_show_hide_invalid.clicked.connect(self.toggle_show_hide_invalid) ################################ self.placeholders = set([]) self.rescans = set([]) pp_fp = os.path.join(THUMBNAIL_DATA_DIR, stack, stack + '_problematic_pairs.txt') if os.path.exists(pp_fp): sys.stderr.write("Loaded problematic pairs.\n") with open(pp_fp, 'r') as f: self.problematic_pairs = [tuple(line.split()) for line in f.readlines()] else: sys.stderr.write("Did not find problematic pairs.\n") self.problematic_pairs = [] def toggle_show_hide_invalid(self): self.show_valid_only = not self.show_valid_only print self.show_valid_only self.button_toggle_show_hide_invalid.setText('Show both valid and invalid' if self.show_valid_only else 'Show valid only') self.update_sorted_sections_gscene_from_sorted_filenames() def move_down(self): curr_fn = self.sorted_sections_gscene.active_section next_fn = self.sorted_sections_gscene.data_feeder.sections[self.sorted_sections_gscene.active_i + 1] filename_to_section = invert_section_to_filename_mapping(self.section_to_filename) curr_fn_section = filename_to_section[curr_fn] next_fn_section = filename_to_section[next_fn] self.section_to_filename[curr_fn_section] = next_fn self.section_to_filename[next_fn_section] = curr_fn self.update_sorted_sections_gscene_from_sorted_filenames() self.sorted_sections_gscene.set_active_section(curr_fn) def move_up(self): curr_fn = self.sorted_sections_gscene.active_section prev_fn = self.sorted_sections_gscene.data_feeder.sections[self.sorted_sections_gscene.active_i - 1] filename_to_section = invert_section_to_filename_mapping(self.section_to_filename) curr_fn_section = filename_to_section[curr_fn] prev_fn_section = filename_to_section[prev_fn] self.section_to_filename[curr_fn_section] = prev_fn self.section_to_filename[prev_fn_section] = curr_fn self.update_sorted_sections_gscene_from_sorted_filenames() self.sorted_sections_gscene.set_active_section(curr_fn) def load_crop(self): """ Load crop box. """ self.set_show_option('aligned') cropbox_fp = DataManager.get_cropbox_filename(stack=self.stack, anchor_fn=self.anchor_fn) with open(cropbox_fp, 'r') as f: ul_x, lr_x, ul_y, lr_y, first_section, last_section = map(int, f.readline().split()) self.first_section = self.section_to_filename[first_section] self.last_section = self.section_to_filename[last_section] self.sorted_sections_gscene.set_box(ul_x, lr_x, ul_y, lr_y) print ul_x, lr_x, ul_y, lr_y, self.first_section, self.last_section def save_crop(self): ul_pos = self.sorted_sections_gscene.corners['ul'].scenePos() lr_pos = self.sorted_sections_gscene.corners['lr'].scenePos() ul_x = int(ul_pos.x()) ul_y = int(ul_pos.y()) lr_x = int(lr_pos.x()) lr_y = int(lr_pos.y()) # If not set yet. if ul_x == 100 and ul_y == 100 and lr_x == 200 and lr_y == 200: return cropbox_fp = DataManager.get_cropbox_filename(stack=self.stack, anchor_fn=self.anchor_fn) filename_to_section = invert_section_to_filename_mapping(self.section_to_filename) with open(cropbox_fp, 'w') as f: f.write('%d %d %d %d %d %d' % (ul_x, lr_x, ul_y, lr_y, filename_to_section[self.first_section], filename_to_section[self.last_section])) upload_to_s3(cropbox_fp) def crop(self): pass ## Note that in cropbox, xmax, ymax are not included, so w = xmax-xmin, instead of xmax-xmin+1 # self.save_crop() # # ul_pos = self.sorted_sections_gscene.corners['ul'].scenePos() # lr_pos = self.sorted_sections_gscene.corners['lr'].scenePos() # ul_x = int(ul_pos.x()) # ul_y = int(ul_pos.y()) # lr_x = int(lr_pos.x()) # lr_y = int(lr_pos.y()) # # if self.stack in all_nissl_stacks: # pad_bg_color = 'white' # elif self.stack in all_ntb_stacks: # pad_bg_color = 'black' # elif self.stack in all_alt_nissl_ntb_stacks or self.stack in all_alt_nissl_tracing_stacks: # pad_bg_color = 'auto' # # self.web_service.convert_to_request('crop', stack=self.stack, x=ul_x, y=ul_y, w=lr_x+1-ul_x, h=lr_y+1-ul_y, # f=self.first_section, l=self.last_section, anchor_fn=self.anchor_fn, # filenames=self.get_valid_sorted_filenames(), # first_fn=self.sorted_filenames[self.first_section-1], # last_fn=self.sorted_filenames[self.last_section-1], # pad_bg_color=pad_bg_color) ################## # Edit Alignment # ################## def edit_transform(self): sys.stderr.write('Loading Edit Transform GUI...\n') self.statusBar().showMessage('Loading Edit Transform GUI...') self.alignment_ui = Ui_AlignmentGui() self.alignment_gui = QDialog(self) self.alignment_gui.setWindowTitle("Edit transform between adjacent sections") self.alignment_ui.setupUi(self.alignment_gui) self.alignment_ui.button_anchor.clicked.connect(self.add_anchor_pair_clicked) self.alignment_ui.button_align.clicked.connect(self.align_using_elastix) self.alignment_ui.button_compute.clicked.connect(self.compute_custom_transform) param_fps = os.listdir(DataManager.get_elastix_parameters_dir()) all_parameter_setting_names = ['_'.join(pf[:-4].split('_')[1:]) for pf in param_fps] self.alignment_ui.comboBox_parameters.addItems(all_parameter_setting_names) section_filenames = self.get_sorted_filenames(valid_only=self.show_valid_only) # Initialize gscene "current" self.curr_gscene = SimpleGraphicsScene4(id='current', gview=self.alignment_ui.curr_gview) self.alignment_ui.curr_gview.setScene(self.curr_gscene) self.curr_gscene.set_data_feeder(self.ordered_images_feeder) self.curr_gscene.set_active_i(1) self.curr_gscene.active_image_updated.connect(self.current_section_image_changed) self.curr_gscene.anchor_point_added.connect(self.anchor_point_added) # Initialize gscene "previous" self.prev_gscene = SimpleGraphicsScene4(id='previous', gview=self.alignment_ui.prev_gview) self.alignment_ui.prev_gview.setScene(self.prev_gscene) self.prev_gscene.set_data_feeder(self.ordered_images_feeder) self.prev_gscene.set_active_i(0) self.prev_gscene.active_image_updated.connect(self.previous_section_image_changed) self.prev_gscene.anchor_point_added.connect(self.anchor_point_added) # Initialize gscene "overlay" self.overlay_gscene = MultiplePixmapsGraphicsScene(id='overlay', pixmap_labels=['moving', 'fixed'], gview=self.alignment_ui.aligned_gview) self.alignment_ui.aligned_gview.setScene(self.overlay_gscene) self.transformed_images_feeder = ImageDataFeeder_v2('transformed image feeder', stack=self.stack, sections=section_filenames, resolution=self.tb_res) self.update_transformed_images_feeder() self.overlay_gscene.set_data_feeder(self.transformed_images_feeder, 'moving') self.overlay_gscene.set_data_feeder(self.ordered_images_feeder, 'fixed') self.overlay_gscene.set_active_indices({'moving': 1, 'fixed': 0}) self.overlay_gscene.set_opacity('moving', .3) self.overlay_gscene.set_opacity('fixed', .3) self.overlay_gscene.active_image_updated.connect(self.overlay_image_changed) self.alignment_gui.show() def update_transformed_images_feeder(self): section_filenames = self.get_sorted_filenames(valid_only=self.show_valid_only) transformed_image_filenames = [] for i in range(1, len(section_filenames)): fp = DataManager.load_image_filepath_warped_to_adjacent_section(stack=self.stack, moving_fn=section_filenames[i], fixed_fn=section_filenames[i-1]) transformed_image_filenames.append(fp) self.transformed_images_feeder.set_images(labels=section_filenames[1:], filenames=transformed_image_filenames, resolution=self.tb_res, load_with_cv2=True) def align_using_elastix(self): selected_elastix_parameter_name = str(self.alignment_ui.comboBox_parameters.currentText()) param_fn = os.path.join(REPO_DIR, 'preprocess', 'parameters', 'Parameters_' + selected_elastix_parameter_name + '.txt') curr_fn = self.curr_gscene.active_section prev_fn = self.prev_gscene.active_section out_dir = os.path.join(self.stack_data_dir, self.stack + '_custom_transforms', curr_fn + '_to_' + prev_fn) curr_fp = DataManager.get_image_filepath_v2(stack=self.stack, prep_id=None, fn=curr_fn, resol=self.tb_res, version=self.tb_version) prev_fp = DataManager.get_image_filepath_v2(stack=self.stack, prep_id=None, fn=prev_fn, resol=self.tb_res, version=self.tb_version ) # curr_fp = os.path.join(RAW_DATA_DIR, self.stack, curr_fn + '.' + self.tb_fmt) # prev_fp = os.path.join(RAW_DATA_DIR, self.stack, prev_fn + '.' + self.tb_fmt) execute_command('rm -rf %(out_dir)s; mkdir -p %(out_dir)s; elastix -f %(fixed_fn)s -m %(moving_fn)s -out %(out_dir)s -p %(param_fn)s' % \ dict(param_fn=param_fn, out_dir=out_dir, fixed_fn=prev_fp, moving_fn=curr_fp)) # section_filenames = self.get_sorted_filenames(valid_only=self.show_valid_only) self.update_transformed_images_feeder() def anchor_point_added(self, index): gscene_id = self.sender().id if gscene_id == 'current': self.current_section_anchor_received = True # self.curr_gscene.anchor_points.index elif gscene_id == 'previous': self.previous_section_anchor_received = True if self.current_section_anchor_received and self.previous_section_anchor_received: self.curr_gscene.set_mode('idle') self.prev_gscene.set_mode('idle') self.current_section_anchor_received = False self.previous_section_anchor_received = False self.alignment_ui.button_anchor.setEnabled(True) def compute_custom_transform(self): """ Compute transform based on added control points. """ curr_points = [] for i, c in enumerate(self.curr_gscene.anchor_circle_items): pos = c.scenePos() curr_points.append((pos.x(), pos.y())) prev_points = [] for i, c in enumerate(self.prev_gscene.anchor_circle_items): pos = c.scenePos() prev_points.append((pos.x(), pos.y())) print self.curr_gscene.active_section, np.array(curr_points) print self.prev_gscene.active_section, np.array(prev_points) curr_points = np.array(curr_points) prev_points = np.array(prev_points) curr_centroid = curr_points.mean(axis=0) prev_centroid = prev_points.mean(axis=0) curr_points0 = curr_points - curr_centroid prev_points0 = prev_points - prev_centroid H = np.dot(curr_points0.T, prev_points0) U, S, VT = np.linalg.svd(H) R = np.dot(VT.T, U.T) t = -np.dot(R, curr_centroid) + prev_centroid print R, t # Write to custom transform file curr_section_fn = self.curr_gscene.active_section prev_section_fn = self.prev_gscene.active_section custom_tf_dir = os.path.join(self.stack_data_dir, self.stack + '_custom_transforms', curr_section_fn + '_to_' + prev_section_fn) execute_command("rm -rf %(out_dir)s; mkdir -p %(out_dir)s" % dict(out_dir=custom_tf_dir)) custom_tf_fp = os.path.join(custom_tf_dir, '%(curr_fn)s_to_%(prev_fn)s_customTransform.txt' % \ dict(curr_fn=curr_section_fn, prev_fn=prev_section_fn)) with open(custom_tf_fp, 'w') as f: f.write('%f %f %f %f %f %f\n' % (R[0,0], R[0,1], t[0], R[1,0], R[1,1], t[1])) self.apply_custom_transform() self.update_transformed_images_feeder() def apply_custom_transform(self): # section_filenames = self.get_sorted_filenames(valid_only=self.show_valid_only) # curr_section_fn = section_filenames[self.valid_section_indices[self.curr_gscene.active_i]-1] # prev_section_fn = section_filenames[self.valid_section_indices[self.prev_gscene.active_i]-1] curr_section_fn = self.curr_gscene.active_section prev_section_fn = self.prev_gscene.active_section custom_tf_fn = os.path.join(self.stack_data_dir, self.stack+'_custom_transforms', curr_section_fn + '_to_' + prev_section_fn, curr_section_fn + '_to_' + prev_section_fn + '_customTransform.txt') with open(custom_tf_fn, 'r') as f: t11, t12, t13, t21, t22, t23 = map(float, f.readline().split()) prev_fp = DataManager.get_image_filepath_v2(stack=self.stack, prep_id=None, fn=prev_section_fn, resol=self.tb_res, version=self.tb_version ) curr_fp = DataManager.get_image_filepath_v2(stack=self.stack, prep_id=None, fn=curr_section_fn, resol=self.tb_res, version=self.tb_version ) prev_img_w, prev_img_h = identify_shape(prev_fp) output_image_fp = os.path.join(self.stack_data_dir, '%(stack)s_custom_transforms/%(curr_fn)s_to_%(prev_fn)s/%(curr_fn)s_alignedTo_%(prev_fn)s.tif' % \ dict(stack=self.stack, curr_fn=curr_section_fn, prev_fn=prev_section_fn) ) execute_command("convert %(curr_fp)s -virtual-pixel background +distort AffineProjection '%(sx)f,%(rx)f,%(ry)f,%(sy)f,%(tx)f,%(ty)f' -crop %(w)sx%(h)s%(x)s%(y)s\! -flatten -compress lzw %(output_fp)s" %\ dict(curr_fp=curr_fp, output_fp=output_image_fp, tb_fmt=self.tb_fmt, sx=t11, sy=t22, rx=t21, ry=t12, tx=t13, ty=t23, w=prev_img_w, h=prev_img_h, x='+0', y='+0', raw_data_dir=RAW_DATA_DIR)) def add_anchor_pair_clicked(self): self.curr_gscene.set_mode('add point') self.prev_gscene.set_mode('add point') self.current_section_anchor_received = False self.previous_section_anchor_received = False self.alignment_ui.button_anchor.setEnabled(False) def overlay_image_changed(self): section_filenames = self.get_sorted_filenames(valid_only=self.show_valid_only) curr_section_fn = self.overlay_gscene.active_sections['moving'] prev_section_fn = self.overlay_gscene.active_sections['fixed'] print "Problematic pairs:", self.problematic_pairs if (prev_section_fn, curr_section_fn) in self.problematic_pairs: self.alignment_ui.label_current_filename.setText('(CHECK)' + str(curr_section_fn)) self.alignment_ui.label_current_index.setText('(CHECK)' + str(curr_section_fn)) else: self.alignment_ui.label_current_filename.setText(str(curr_section_fn)) self.alignment_ui.label_current_index.setText(str(curr_section_fn)) self.curr_gscene.set_active_section(curr_section_fn) self.prev_gscene.set_active_section(prev_section_fn) def current_section_image_changed(self): section_filenames = self.get_sorted_filenames(valid_only=self.show_valid_only) curr_section_fn = self.curr_gscene.active_section prev_section_fn = section_filenames[section_filenames.index(curr_section_fn) - 1] print "Problematic pairs:", self.problematic_pairs if (prev_section_fn, curr_section_fn) in self.problematic_pairs: self.alignment_ui.label_current_filename.setText('(CHECK)' + str(curr_section_fn)) self.alignment_ui.label_current_index.setText('(CHECK)' + str(curr_section_fn)) else: self.alignment_ui.label_current_filename.setText(str(curr_section_fn)) self.alignment_ui.label_current_index.setText(str(curr_section_fn)) self.prev_gscene.set_active_section(prev_section_fn) self.overlay_gscene.set_active_sections({'moving': curr_section_fn, 'fixed': prev_section_fn}) def previous_section_image_changed(self): section_filenames = self.get_sorted_filenames(valid_only=self.show_valid_only) prev_section_fn = self.prev_gscene.active_section curr_section_fn = section_filenames[section_filenames.index(prev_section_fn) + 1] self.alignment_ui.label_previous_filename.setText(prev_section_fn) self.alignment_ui.label_previous_index.setText(str(prev_section_fn)) self.curr_gscene.set_active_section(curr_section_fn) self.overlay_gscene.set_active_sections({'moving': curr_section_fn, 'fixed': prev_section_fn}, emit_changed_signal=False) ########################## END OF EDIT TRANSFORM ######################################3 def save_everything(self): # Dump preprocessing info placeholder_indices = [idx+1 for idx, fn in enumerate(self.sorted_filenames) if fn == 'Placeholder'] placeholder_slide_positions = [(slide_name, pos) for slide_name, x in self.slide_position_to_fn.iteritems() for pos, fn in x.iteritems() if fn == 'Placeholder'] rescan_indices = [idx+1 for idx, fn in enumerate(self.sorted_filenames) if fn == 'Rescan'] rescan_slide_positions = [(slide_name, pos) for slide_name, x in self.slide_position_to_fn.iteritems() for pos, fn in x.iteritems() if fn == 'Rescan'] ul_pos = self.sorted_sections_gscene.corners['ul'].scenePos() lr_pos = self.sorted_sections_gscene.corners['lr'].scenePos() ul_x = int(ul_pos.x()) ul_y = int(ul_pos.y()) lr_x = int(lr_pos.x()) lr_y = int(lr_pos.y()) info = {'placeholder_indices': placeholder_indices, 'placeholder_slide_positions': placeholder_slide_positions, 'rescan_indices': rescan_indices, 'rescan_slide_positions': rescan_slide_positions, 'sorted_filenames': self.sorted_filenames, 'slide_position_to_fn': self.slide_position_to_fn, 'first_section': self.first_section, 'last_section': self.last_section, 'anchor_fn': self.anchor_fn, # 'bbox': (ul_x, lr_x, ul_y, lr_y) #xmin,xmax,ymin,ymax 'bbox': (ul_x, ul_y, lr_x+1-ul_x, lr_y+1-ul_y) #xmin,ymin,w,h } from datetime import datetime timestamp = datetime.now().strftime("%m%d%Y%H%M%S") pickle.dump(info, open(self.stack_data_dir + '/%(stack)s_preprocessInfo_%(timestamp)s.pkl' % {'stack': self.stack, 'timestamp':timestamp}, 'w')) execute_command('cd %(stack_data_dir)s && rm -f %(stack)s_preprocessInfo.pkl && ln -s %(stack)s_preprocessInfo_%(timestamp)s.pkl %(stack)s_preprocessInfo.pkl' % {'stack': self.stack, 'timestamp':timestamp, 'stack_data_dir':self.stack_data_dir}) self.save_crop() self.save_sorted_filenames() self.save() def update_sorted_sections_gscene_from_sorted_filenames(self): if not hasattr(self, 'currently_showing'): self.currently_showing = 'original' if not hasattr(self, 'anchor_fn'): anchor_fp = DataManager.get_anchor_filename_filename(self.stack) if os.path.exists(anchor_fp): with open(anchor_fp) as f: self.set_anchor(f.readline().strip()) else: imageNames_to_load = self.get_sorted_filenames(valid_only=self.show_valid_only) shapes = \ [identify_shape(DataManager.get_image_filepath_v2(stack=self.stack, fn=fn, prep_id=None, version=self.tb_version, resol=self.tb_res)) for fn in imageNames_to_load] largest_idx = np.argmax([h*w for h, w in shapes]) print 'largest section is ', imageNames_to_load[largest_idx] self.set_anchor(imageNames_to_load[largest_idx]) print imageNames_to_load[largest_idx] if self.currently_showing == 'original': imageNames_to_load = self.get_sorted_filenames(valid_only=self.show_valid_only) if not hasattr(self, 'ordered_images_feeder') or self.ordered_images_feeder is None: self.ordered_images_feeder = ImageDataFeeder_v2('ordered image feeder', stack=self.stack, sections=imageNames_to_load, resolution=self.tb_res, use_thread=False, auto_load=False) self.ordered_images_feeder.set_images(labels=imageNames_to_load, filenames=[DataManager.get_image_filepath_v2(stack=self.stack, fn=fn, prep_id=None, version=self.tb_version, resol=self.tb_res) for fn in imageNames_to_load], resolution=self.tb_res, load_with_cv2=False) self.ordered_images_feeder.set_images(labels=['Placeholder'], filenames=[self.placeholder_qimage], resolution=self.tb_res, load_with_cv2=False) else: self.ordered_images_feeder.set_sections(imageNames_to_load) self.sorted_sections_gscene.set_data_feeder(self.ordered_images_feeder) if self.sorted_sections_gscene.active_i is not None: active_i = self.sorted_sections_gscene.active_i else: active_i = 1 self.sorted_sections_gscene.set_active_i(active_i) elif self.currently_showing == 'aligned': imageNames_to_load = self.get_sorted_filenames(valid_only=self.show_valid_only) if not hasattr(self, 'aligned_images_feeder') or self.aligned_images_feeder is None: self.aligned_images_feeder = ImageDataFeeder_v2('aligned image feeder', stack=self.stack, sections=imageNames_to_load, resolution=self.tb_res, use_thread=False, auto_load=False) self.aligned_images_feeder.set_images(labels=imageNames_to_load, filenames=[DataManager.get_image_filepath_v2(stack=self.stack, fn=fn, prep_id='alignedPadded', version=self.tb_version, resol=self.tb_res) for fn in imageNames_to_load], resolution=self.tb_res, load_with_cv2=False) self.aligned_images_feeder.set_images(labels=['Placeholder'], filenames=[self.placeholder_qimage], resolution=self.tb_res, load_with_cv2=False) else: self.aligned_images_feeder.set_sections(imageNames_to_load) self.sorted_sections_gscene.set_data_feeder(self.aligned_images_feeder) if self.sorted_sections_gscene.active_i is not None: active_i = self.sorted_sections_gscene.active_i else: active_i = 1 self.sorted_sections_gscene.set_active_i(active_i) # elif self.currently_showing == 'mask_contour': # # self.maskContourViz_images_feeder = ImageDataFeeder_v2('mask contoured image feeder', stack=self.stack, # sections=self.valid_section_indices, resolution=self.tb_res) # self.maskContourViz_images_dir = self.stack_data_dir + '/%(stack)s_maskContourViz_unsorted' % {'stack': self.stack} # maskContourViz_image_filenames = [os.path.join(self.maskContourViz_images_dir, '%(fn)s_mask_contour_viz.tif' % {'fn': fn}) # for fn in self.valid_section_filenames] # # self.maskContourViz_images_feeder.set_images(self.valid_section_indices, maskContourViz_image_filenames, resolution=self.tb_res, load_with_cv2=False) # # self.maskContourViz_images_feeder.set_resolution(self.tb_res) # # active_i = self.sorted_sections_gscene.active_i # self.sorted_sections_gscene.set_data_feeder(self.maskContourViz_images_feeder) # self.sorted_sections_gscene.set_active_i(active_i) def save_sorted_filenames(self): sorted_filenames = self.get_sorted_filenames(valid_only=False) out_sorted_image_names_fp = DataManager.get_sorted_filenames_filename(stack=self.stack) with open(out_sorted_image_names_fp, 'w') as f: for i, fn in enumerate(sorted_filenames): f.write('%s %03d\n' % (fn, i+1)) # index starts from 1 upload_to_s3(out_sorted_image_names_fp) sys.stderr.write('Sorted filename list saved.\n') self.statusBar().showMessage('Sorted filename list saved.') def load_sorted_filenames(self): # filename_to_section, section_to_filename = DataManager.load_sorted_filenames(self.stack) # self.sorted_filenames = [f for s,f in sorted(section_to_filename.items())] sys.stderr.write('Sorted filename list is loaded.\n') self.statusBar().showMessage('Sorted filename list is loaded.') # self.fn_to_slide_position = {fn: (slide, pos) for slide, pos_to_fn in self.slide_position_to_fn.iteritems() for pos, fn in pos_to_fn.iteritems()} # self.sorted_slide_positions = [self.fn_to_slide_position[fn] for fn in self.sorted_filenames] self.update_sorted_sections_gscene_from_sorted_filenames() def load_slide_position_map(self): fn = self.stack_data_dir + '/%(stack)s_slide_position_to_fn.pkl' % {'stack': self.stack} if os.path.exists(fn): self.slide_position_to_fn = pickle.load(open(fn, 'r')) sys.stderr.write('Slide position to image filename mapping is loaded.\n') self.statusBar().showMessage('Slide position to image filename mapping is loaded.') else: sys.stderr.write('Cannot load slide position to image filename mapping - File does not exists.\n') self.statusBar().showMessage('Cannot load slide position to image filename mapping - File does not exists.') def save(self): pickle.dump(self.slide_position_to_fn, open(self.stack_data_dir + '/%(stack)s_slide_position_to_fn.pkl' % {'stack': self.stack}, 'w') ) def get_sorted_filenames(self, valid_only=False): return [fn for sec, fn in sorted(self.section_to_filename.items()) if (fn != 'Rescan' and fn != 'Placeholder' and self.filename_to_accept_decision[fn]) or not valid_only] def compose(self): pass def set_first_section(self, fn): self.first_section = str(fn) self.update_sorted_sections_gscene_label() def set_last_section(self, fn): self.last_section = str(fn) self.update_sorted_sections_gscene_label() def set_anchor(self, anchor): if isinstance(anchor, int): self.anchor_fn = self.sorted_filenames[anchor-1] elif isinstance(anchor, str): self.anchor_fn = anchor with open(os.path.join(THUMBNAIL_DATA_DIR, self.stack, self.stack + '_anchor.txt'), 'w') as f: f.write(self.anchor_fn) self.update_sorted_sections_gscene_label() def sorted_sections_image_updated(self): filename = self.sorted_sections_gscene.active_section self.label_sorted_sections_filename.setText(filename) self.label_sorted_sections_index.setText(str(self.sorted_sections_gscene.active_section)) if filename == 'Placeholder' or filename == 'Rescan': return assert filename != 'Unknown' and filename != 'Nonexisting' # Update slide scene # slide_name = self.filename_to_slide[filename] # position = self.slide_position_to_fn[slide_name].keys()[self.slide_position_to_fn[slide_name].values().index(filename)] # self.slide_gscene.set_active_section(slide_name) self.update_sorted_sections_gscene_label() def update_sorted_sections_gscene_label(self): """ Set the label next to sortedSectionGscene to FIRST, LAST or ANCHOR. """ # print self.sorted_sections_gscene.active_section, self.anchor_fn # if self.sorted_sections_gscene.active_section is not None: # print self.sorted_filenames[self.sorted_sections_gscene.active_section-1] if self.sorted_sections_gscene.active_section == self.first_section: self.label_sorted_sections_status.setText('FIRST') elif self.sorted_sections_gscene.active_section == self.last_section: self.label_sorted_sections_status.setText('LAST') elif hasattr(self, 'anchor_fn') and self.sorted_sections_gscene.active_section is not None and \ self.sorted_sections_gscene.active_section == self.anchor_fn: print self.sorted_sections_gscene.active_section self.label_sorted_sections_status.setText('ANCHOR') else: self.label_sorted_sections_status.setText('') def set_status(self, slide_name, position, fn): """ Update slide_position_to_fn variables. If active, change content and captions of the specified slide position gscene. """ # old_fn = self.slide_position_to_fn[slide_name][position] self.slide_position_to_fn[slide_name][position] = fn # # if slide_name == 'N_92': # print position # print self.slide_position_gscenes[position].data_feeder.all_sections # print self.section_image_feeders[slide_name].all_sections if slide_name == self.slide_gscene.active_section: self.slide_position_gscenes[position].set_active_section(fn) self.labels_slide_position_filename[position].setText(fn) if hasattr(self, 'sorted_filenames'): if fn == 'Placeholder' or fn == 'Rescan' or fn == 'Nonexisting': self.labels_slide_position_index[position].setText('') else: if fn in self.sorted_filenames: self.labels_slide_position_index[position].setText(str(self.sorted_filenames.index(fn)+1)) else: self.labels_slide_position_index[position].setText('Not in sorted list.') # def slide_image_updated(self): # self.setWindowTitle('Slide %(slide_index)s' % {'slide_index': self.slide_gscene.active_section}) # # slide_name = self.slide_gscene.active_section # feeder = self.section_image_feeders[slide_name] # # if slide_name not in self.slide_position_to_fn: # self.slide_position_to_fn[slide_name] = {p: 'Unknown' for p in [1,2,3]} # # for position, gscene in self.slide_position_gscenes.iteritems(): # # gscene.set_data_feeder(feeder) # # if self.slide_position_to_fn[slide_name][position] != 'Unknown': # self.set_status(slide_name, position, self.slide_position_to_fn[slide_name][position]) # else: # if position in self.thumbnail_filenames[slide_name]: # newest_fn = sorted(self.thumbnail_filenames[slide_name][position].items())[-1][1] # self.set_status(slide_name, position, newest_fn) # else: # self.set_status(slide_name, position, 'Nonexisting') def show_option_changed(self, index): show_option_text = str(self.sender().currentText()) if show_option_text == 'Original Aligned': self.set_show_option('aligned') elif show_option_text == 'Original': self.set_show_option('original') elif show_option_text == 'Mask Contoured': self.set_show_option('mask_contour') else: raise Exception('Not implemented.') def set_show_option(self, showing): if self.currently_showing == showing: return else: self.currently_showing = showing print self.currently_showing self.update_sorted_sections_gscene_from_sorted_filenames() def slide_position_image_updated(self): position = self.sender().id self.set_status(self.slide_gscene.active_section, position, self.slide_position_gscenes[position].active_section) def eventFilter(self, obj, event): if event.type() == QEvent.GraphicsSceneMousePress: pass elif event.type() == QEvent.KeyPress: key = event.key() return False