def padder(animal, bgcolor): fileLocationManager = FileLocationManager(animal) sqlController = SqlController() sqlController.get_animal_info(animal) INPUT = os.path.join(fileLocationManager.prep, 'thumbnail_masked') OUTPUT = '/net/birdstore/Active_Atlas_Data/data_root/brains_info/masks/{}/prealigned'.format(animal) files = sorted(os.listdir(INPUT)) width = sqlController.scan_run.width height = sqlController.scan_run.height max_width = int(width * SCALING_FACTOR) max_height = int(height * SCALING_FACTOR) for i, file in enumerate(tqdm(files)): infile = os.path.join(INPUT, file) try: img = io.imread(infile) except: print('Could not open', infile) continue fixed = place_image(img, file, max_width, max_height, bgcolor) outpath = os.path.join(OUTPUT, file) cv2.imwrite(outpath, fixed.astype('uint8')) print('Finished')
class GUICropBrainStem(QWidget): def __init__(self, stack, parent=None): super(GUICropBrainStem, self).__init__(parent) self.stack = stack self.fileLocationManager = FileLocationManager(self.stack) self.sqlController = SqlController() self.sqlController.get_animal_info(self.stack) self.valid_sections = self.sqlController.get_valid_sections(stack) self.valid_section_keys = sorted(list(self.valid_sections)) self.curr_section_index = 0 self.curr_section = None self.active_selection = '' self.img_width = 2001 self.img_height = 1001 self.rostral = -1 self.caudal = -1 self.ventral = -1 self.dorsal = -1 self.first_slice = -1 self.last_slice = -1 self.init_ui() self.b_rostral.clicked.connect( lambda: self.click_button(self.b_rostral)) self.b_caudal.clicked.connect(lambda: self.click_button(self.b_caudal)) self.b_dorsal.clicked.connect(lambda: self.click_button(self.b_dorsal)) self.b_ventral.clicked.connect( lambda: self.click_button(self.b_ventral)) self.b_first_slice.clicked.connect( lambda: self.click_button(self.b_first_slice)) self.b_last_slice.clicked.connect( lambda: self.click_button(self.b_last_slice)) self.b_done.clicked.connect(lambda: self.click_button(self.b_done)) self.viewer.click.connect(self.click_photo) def init_ui(self): self.font_h1 = QFont("Arial", 32) self.font_p1 = QFont("Arial", 16) self.grid_top = QGridLayout() self.grid_body_upper = QGridLayout() self.grid_body = QGridLayout() self.grid_body_lower = QGridLayout() self.resize(1600, 1100) # Grid Top self.e_title = QLineEdit() self.e_title.setAlignment(Qt.AlignCenter) self.e_title.setFont(self.font_h1) self.e_title.setReadOnly(True) self.e_title.setText("Setup Sorted Filenames") self.e_title.setFrame(False) self.grid_top.addWidget(self.e_title, 0, 0) self.b_help = QPushButton("HELP") self.b_help.setDefault(True) self.b_help.setEnabled(True) self.grid_top.addWidget(self.b_help, 0, 1) # Grid BODY UPPER self.e_filename = QLineEdit() self.e_filename.setAlignment(Qt.AlignCenter) self.e_filename.setFont(self.font_p1) self.e_filename.setReadOnly(True) self.e_filename.setText("Filename: ") self.grid_body_upper.addWidget(self.e_filename, 0, 2) self.e_section = QLineEdit() self.e_section.setAlignment(Qt.AlignCenter) self.e_section.setFont(self.font_p1) self.e_section.setReadOnly(True) self.e_section.setText("Section: ") self.grid_body_upper.addWidget(self.e_section, 0, 3) # Grid BODY self.viewer = ImageViewer(self) self.grid_body.addWidget(self.viewer, 0, 0) # Grid BODY LOWER self.b_rostral = QPushButton("Rostral Limit:") self.grid_body_lower.addWidget(self.b_rostral, 0, 0) self.e_rostral = QLineEdit() self.e_rostral.setAlignment(Qt.AlignCenter) self.e_rostral.setFont(self.font_p1) self.grid_body_lower.addWidget(self.e_rostral, 0, 1) self.b_caudal = QPushButton("Caudal Limit:") self.grid_body_lower.addWidget(self.b_caudal, 1, 0) self.e_caudal = QLineEdit() self.e_caudal.setAlignment(Qt.AlignCenter) self.e_caudal.setFont(self.font_p1) self.grid_body_lower.addWidget(self.e_caudal, 1, 1) self.b_dorsal = QPushButton("Dorsal Limit:") self.grid_body_lower.addWidget(self.b_dorsal, 0, 2) self.e_dorsal = QLineEdit() self.e_dorsal.setAlignment(Qt.AlignCenter) self.e_dorsal.setFont(self.font_p1) self.grid_body_lower.addWidget(self.e_dorsal, 0, 3) self.b_ventral = QPushButton("Ventral Limit:") self.grid_body_lower.addWidget(self.b_ventral, 1, 2) self.e_ventral = QLineEdit() self.e_ventral.setAlignment(Qt.AlignCenter) self.e_ventral.setFont(self.font_p1) self.grid_body_lower.addWidget(self.e_ventral, 1, 3) self.b_first_slice = QPushButton("Mark as FIRST Slice With Brainstem:") self.grid_body_lower.addWidget(self.b_first_slice, 0, 4) self.e_first_slice = QLineEdit() self.e_first_slice.setAlignment(Qt.AlignCenter) self.e_first_slice.setFont(self.font_p1) self.grid_body_lower.addWidget(self.e_first_slice, 0, 5) self.b_last_slice = QPushButton("Mark as LAST Slice With Brainstem:") self.grid_body_lower.addWidget(self.b_last_slice, 1, 4) self.e_last_slice = QLineEdit() self.e_last_slice.setAlignment(Qt.AlignCenter) self.e_last_slice.setFont(self.font_p1) self.grid_body_lower.addWidget(self.e_last_slice, 1, 5) self.b_done = QPushButton("DONE") self.grid_body_lower.addWidget(self.b_done, 1, 6) # Super grid self.supergrid = QGridLayout() self.supergrid.addLayout(self.grid_top, 0, 0) self.supergrid.addLayout(self.grid_body_upper, 1, 0) self.supergrid.addLayout(self.grid_body, 2, 0) self.supergrid.addLayout(self.grid_body_lower, 3, 0) # Set layout and window title self.setLayout(self.supergrid) self.setWindowTitle("Q") def set_curr_section(self, section_index=-1): """ Sets the current section to the section passed in. Will automatically update curr_section, prev_section, and next_section. Updates the header fields and loads the current section image. """ if section_index == -1: section_index = self.curr_section_index # Update curr, prev, and next section self.curr_section_index = section_index self.curr_section = self.valid_sections[self.valid_section_keys[ self.curr_section_index]] # Update the section and filename at the top self.e_filename.setText(self.curr_section['destination']) self.e_section.setText(str(self.curr_section['section_number'])) # Get filepath of "curr_section" and set it as viewer's photo img_fp = os.path.join(self.fileLocationManager.thumbnail_prep, self.curr_section['destination']) if os.path.isfile(img_fp): img = cv2.imread(img_fp) * 3 self.img_height, self.img_width, channel = img.shape if self.rostral != -1: x_coordinate = int(self.rostral) img[:, x_coordinate - 2:x_coordinate + 2, :] = np.ones( (self.img_height, 4, 3)) * 255 if self.caudal != -1: x_coordinate = int(self.caudal) img[:, x_coordinate - 2:x_coordinate + 2, :] = np.ones( (self.img_height, 4, 3)) * 255 if self.dorsal != -1: y_coordinate = int(self.dorsal) img[y_coordinate - 2:y_coordinate + 2, :, :] = np.ones( (4, self.img_width, 3)) * 255 if self.ventral != -1: y_coordinate = int(self.ventral) img[y_coordinate - 2:y_coordinate + 2, :, :] = np.ones( (4, self.img_width, 3)) * 255 qImg = QImage(img.data, self.img_width, self.img_height, 3 * self.img_width, QImage.Format_RGB888) self.viewer.set_photo(QPixmap(qImg)) # Update the internal crop values based on text boxes #self.updateCropVals() def get_valid_section_index(self, section_index): if section_index >= len(self.valid_sections): return 0 elif section_index < 0: return len(self.valid_sections) - 1 else: return section_index def click_button(self, button): if button in [ self.b_rostral, self.b_caudal, self.b_dorsal, self.b_ventral ]: self.viewer.set_drag_mode(0) if button == self.b_rostral: self.active_selection = 'rostral' elif button == self.b_caudal: self.active_selection = 'caudal' elif button == self.b_dorsal: self.active_selection = 'dorsal' elif button == self.b_ventral: self.active_selection = 'ventral' # Prep2 section limits elif button in [self.b_first_slice, self.b_last_slice]: if button == self.b_first_slice: self.first_slice = int(self.curr_section) self.e_first_slice.setText(str(self.curr_section)) elif button == self.b_last_slice: self.last_slice = int(self.curr_section) self.e_last_slice.setText(str(self.curr_section)) elif button == self.b_done: if -1 in [ self.rostral, self.caudal, self.dorsal, self.ventral, self.first_slice, self.last_slice ]: QMessageBox.about(self, "Popup Message", "Make sure all six fields have values!") return elif self.rostral >= self.caudal: QMessageBox.about( self, "Popup Message", "Rostral Limit must be smaller than caudal limit!") return elif self.dorsal >= self.ventral: QMessageBox.about( self, "Popup Message", "Dorsal Limit must be smaller than Ventral limit!") return elif self.first_slice >= self.last_slice: QMessageBox.about(self, "Popup Message", "Last slice must be after the first slice!") return try: QMessageBox.about( self, "Popup Message", "This operation will take roughly 1.5 minutes per image.") self.setCurrSection(self.curr_section) stain = stack_metadata[stack]['stain'] os.subprocess.call([ 'python', 'a_script_preprocess_6.py', stack, stain, '-l', str(self.rostral), str(self.caudal), str(self.dorsal), str(self.ventral), str(self.first_slice), str(self.last_slice) ]) sys.exit(app.exec_()) except Exception as e: sys.stderr.write('\n ********************************\n') sys.stderr.write(str(e)) sys.stderr.write('\n ********************************\n') def click_photo(self, pos): if self.viewer.dragMode() == QGraphicsView.NoDrag: x = pos.x() y = pos.y() print('%d, %d' % (pos.x(), pos.y())) scale_factor = 1.0 / self.viewer.scale_factor if self.active_selection == '': pass elif self.active_selection == 'rostral': self.rostral = int(x * scale_factor) self.rostral = min(self.rostral, self.img_width - 5) self.rostral = max(self.rostral, 5) self.e_rostral.setText(str(self.rostral)) elif self.active_selection == 'caudal': self.caudal = int(x * scale_factor) self.caudal = min(self.caudal, self.img_width - 5) self.caudal = max(self.caudal, 5) self.e_caudal.setText(str(self.caudal)) elif self.active_selection == 'dorsal': self.dorsal = int(y * scale_factor) self.dorsal = min(self.dorsal, self.img_height - 5) self.dorsal = max(self.dorsal, 5) self.e_dorsal.setText(str(self.dorsal)) elif self.active_selection == 'ventral': self.ventral = int(y * scale_factor) self.ventral = min(self.ventral, self.img_height - 5) self.ventral = max(self.ventral, 5) self.e_ventral.setText(str(self.ventral)) self.active_selection = '' self.viewer.set_drag_mode(1) def updateCropVals(self): if self.e_rostral.text() != '': try: self.rostral = int(self.e_rostral.text()) except: self.rostral = -1 self.e_rostral.setText("") if self.e_caudal.text() != '': try: self.caudal = int(self.e_caudal.text()) except: self.caudal = -1 self.e_caudal.setText("") if self.e_dorsal.text() != '': try: self.dorsal = int(self.e_dorsal.text()) except: self.dorsal = -1 self.e_dorsal.setText("") if self.e_ventral.text() != '': try: self.ventral = int(self.e_ventral.text()) except: self.ventral = -1 self.e_ventral.setText("") if self.e_first_slice.text() != '': try: self.first_slice = int(self.e_first_slice.text()) except: self.first_slice = -1 self.e_first_slice.setText("") if self.e_last_slice.text() != '': try: self.last_slice = int(self.e_last_slice.text()) except: self.last_slice = -1 self.e_last_slice.setText("") def keyPressEvent(self, event): try: key = event.key() except AttributeError: key = event if key == 91: # [ index = self.get_valid_section_index(self.curr_section_index - 1) self.set_curr_section(index) elif key == 93: # ] index = self.get_valid_section_index(self.curr_section_index + 1) self.set_curr_section(index) elif key == 16777220: # Enter index = self.get_valid_section_index(self.curr_section_index) self.set_curr_section(index) else: print(key) def closeEvent(self, event): sys.exit(app.exec_())
class GUISetupMain(QWidget): def __init__(self, stack, parent=None): super(GUISetupMain, self).__init__(parent) # Stack specific info, determined from dropdown menu selection self.stack = stack self.fileLocationManager = FileLocationManager(self.stack) self.sqlController = SqlController() self.sqlController.get_animal_info(self.stack) self.stain = self.sqlController.histology.counterstain self.curr_step = self.sqlController.get_current_step_from_progress_ini(self.stack) # Init UI self.init_ui() # Set buttons functionality self.b_1_4.clicked.connect(lambda: self.click_button(self.b_1_4)) self.b_1_6.clicked.connect(lambda: self.click_button(self.b_1_6)) self.b_exit.clicked.connect(lambda: self.click_button(self.b_exit)) # Update buttons self.update_buttons() # Center the GUI self.center() def init_ui(self): self.grid_buttons = QGridLayout() self.grid_bottom = QGridLayout() # Grid buttons self.b_1_4 = QPushButton("Setup Sorted Filenames") self.grid_buttons.addWidget(self.b_1_4) self.b_1_6 = QPushButton("Run automatic setup scripts") self.grid_buttons.addWidget(self.b_1_6) # Grid bottom self.progress = QProgressBar(self) self.progress.hide() self.grid_bottom.addWidget(self.progress) self.b_exit = QPushButton("Exit") self.b_exit.setDefault(True) self.grid_bottom.addWidget(self.b_exit) # Super grid self.super_grid = QGridLayout() self.super_grid.addLayout(self.grid_buttons, 1, 0) self.super_grid.addLayout(self.grid_bottom, 2, 0) self.setLayout(self.super_grid) self.setWindowTitle("Align to Active Brainstem Atlas - Setup Page") self.resize(1000, 450) def update_buttons(self): """ Locates where you are in the pipeline by reading the brains_info/STACK_progress.ini Buttons corresponding to previous steps are marked as "completed", buttons corresponding to future steps are marked as "unpressable" and are grayed out. """ self.stain = self.sqlController.histology.counterstain try: self.curr_step = self.sqlController.get_current_step_from_progress_ini(self.stack) print('format grid buttons current step is', self.curr_step) curr_step_index = ['1-4', '1-5', '1-6'].index(self.curr_step[:3]) for index, button in enumerate([self.b_1_4, self.b_1_6]): if index <= curr_step_index + 1: button.setEnabled(True) else: button.setEnabled(False) # If there are no stacks/brains that have been started except KeyError: for button in [self.b_1_4, self.b_1_6]: button.setEnabled(False) def click_button(self, button): """ If any of the "grid" buttons are pressed, this is the callback function. In this case, "grid" buttons have a one-to_one correspondance to the steps in the pipeline. The completion of each step means you move onto the next one. """ # Setup/Create sorted filenames if button == self.b_1_4: try: subprocess.call(['python', 'a_GUI_setup_sorted_filenames.py', self.stack]) self.update_buttons() except Exception as e: sys.stderr.write(str(e)) # Run automatic scripts elif button == self.b_1_6: message = "This operation will take a long time." message += " Several minutes per image." QMessageBox.about(self, "Popup Message", message) preprocess_setup(self.stack, self.stain) #subprocess.call(['python', 'utilities/a_script_preprocess_1.py', self.stack, self.stain]) subprocess.call(['python', 'a_script_preprocess_2.py', self.stack, self.stain]) self.sqlController.set_step_completed_in_progress_ini(self.stack, '1-6_setup_scripts') """ pipeline_status = get_pipeline_status(self.stack) if not 'preprocess_1' in pipeline_status and \ not 'preprocess_2' in pipeline_status and not 'setup' in pipeline_status: self.sqlController.set_step_completed_in_progress_ini(self.stack, '1-6_setup_scripts') sys.exit(app.exec_()) pipeline_status = get_pipeline_status(self.stack) if pipeline_status == 'a_script_preprocess_3': self.sqlController.set_step_completed_in_progress_ini(self.stack, '1-6_setup_scripts') sys.exit(app.exec_()) # else: # print '\n\n\n\n' # print 'pipeline_status:' ## print pipeline_status # print '\n\n\n\n' # #set_step_completed_in_progress_ini( self.stack, '1-6_setup_scripts') print('finished in button 4') """ elif button == self.b_exit: self.closeEvent(None) self.update_buttons() def center(self): """ This function simply aligns the GUI to the center of your monitor. """ frameGm = self.frameGeometry() screen = QApplication.desktop().screenNumber(QApplication.desktop().cursor().pos()) centerPoint = QApplication.desktop().screenGeometry(screen).center() frameGm.moveCenter(centerPoint) self.move(frameGm.topLeft()) def closeEvent(self, event): sys.exit(app.exec_())
class init_GUI(QWidget): def __init__(self, stack, parent=None): super(init_GUI, self).__init__(parent) self.font_h1 = QFont("Arial", 32) self.font_p1 = QFont("Arial", 16) self.stack = stack self.fileLocationManager = FileLocationManager(self.stack) self.sqlController = SqlController() self.sqlController.get_animal_info(self.stack) self.valid_sections = self.sqlController.get_valid_sections(stack) self.valid_section_keys = sorted(list(self.valid_sections)) section_length = len(self.valid_section_keys) self.curr_section_index = section_length // 2 self.prev_section_index = self.curr_section_index self.next_section_index = self.curr_section_index self.curr_section = self.valid_sections[self.valid_section_keys[ self.curr_section_index]]['destination'] self.prev_section = self.getPrevValidSection(self.curr_section_index) self.next_section = self.getNextValidSection(self.curr_section_index) self.curr_T = None self.mode = 'view' # self.mode = 'align' self.transform_type = 'pairwise' # Can toggle to 'anchor' # Increasing this number will brighten the images self.curr_img_multiplier = 1 self.prev_img_multiplier = 1 self.initUI() def initUI(self): # Set Layout and Geometry of Window self.grid_top = QGridLayout() self.grid_body_upper = QGridLayout() self.grid_body = QGridLayout() self.grid_body_lower_align_mode = QGridLayout() self.grid_bottom = QGridLayout() self.grid_blank = QGridLayout() # self.setFixedSize(1600, 1100) self.resize(1600, 1100) ### VIEWER ### (Grid Body) self.viewer = ImageViewer(self) self.viewer.photoClicked.connect(self.photoClicked) ### Grid TOP ### # Static Text Field (Title) self.e1 = QLineEdit() self.e1.setValidator(QIntValidator()) self.e1.setAlignment(Qt.AlignCenter) self.e1.setFont(self.font_h1) self.e1.setReadOnly(True) self.e1.setText("Quality Checker") self.e1.setFrame(False) self.grid_top.addWidget(self.e1, 0, 0) # Button Text Field self.b_help = QPushButton("HELP") self.b_help.setDefault(True) self.b_help.setEnabled(True) self.b_help.clicked.connect( lambda: self.help_button_press(self.b_help)) self.b_help.setStyleSheet( "color: rgb(0,0,0); background-color: rgb(250,250,250);") self.grid_top.addWidget(self.b_help, 0, 1) ### Grid BODY UPPER ### # Static Text Field self.e2 = QLineEdit() self.e2.setAlignment(Qt.AlignCenter) self.e2.setFont(self.font_p1) self.e2.setReadOnly(True) self.e2.setText("Filename: ") self.e2.setStyleSheet( "color: rgb(50,50,250); background-color: rgb(250,250,250);") self.grid_body_upper.addWidget(self.e2, 0, 0) # Static Text Field self.e3 = QLineEdit() self.e3.setAlignment(Qt.AlignCenter) self.e3.setFont(self.font_p1) self.e3.setReadOnly(True) self.e3.setText("Section: ") self.e3.setStyleSheet( "color: rgb(50,50,250); background-color: rgb(250,250,250);") self.grid_body_upper.addWidget(self.e3, 0, 1) # Static Text Field self.e4 = QLineEdit() self.e4.setAlignment(Qt.AlignCenter) self.e4.setFont(self.font_p1) self.e4.setReadOnly(True) self.e4.setText("Filename: ") self.e4.setStyleSheet( "color: rgb(250,50,50); background-color: rgb(250,250,250);") self.grid_body_upper.addWidget(self.e4, 0, 2) # Static Text Field self.e5 = QLineEdit() self.e5.setAlignment(Qt.AlignCenter) self.e5.setFont(self.font_p1) self.e5.setReadOnly(True) self.e5.setText("Section: ") self.e5.setStyleSheet( "color: rgb(250,50,50); background-color: rgb(250,250,250);") self.grid_body_upper.addWidget(self.e5, 0, 3) ### Grid BODY ### # Custom VIEWER self.grid_body.addWidget(self.viewer, 0, 0) ### Grid BODY LOWER (align mode only) ### # Button Text Field self.b1 = QPushButton("Brighten blue image") self.b1.setDefault(True) self.b1.setEnabled(False) self.b1.clicked.connect(lambda: self.buttonPress(self.b1)) self.b1.setStyleSheet( "color: rgb(50,50,250); background-color: rgb(250,250,250);") self.grid_body_lower_align_mode.addWidget(self.b1, 0, 0) # Button Text Field self.b2 = QPushButton("Brighten red image") self.b2.setDefault(True) self.b2.setEnabled(False) self.b2.clicked.connect(lambda: self.buttonPress(self.b2)) self.b2.setStyleSheet( "color: rgb(250,50,50); background-color: rgb(250,250,250);") self.grid_body_lower_align_mode.addWidget(self.b2, 1, 0) # Button Text Field self.b_up = QPushButton("/\\") self.b_up.setDefault(True) self.b_up.setEnabled(False) self.b_up.clicked.connect(lambda: self.buttonPress(self.b_up)) self.b_up.setStyleSheet( "color: rgb(250,50,50); background-color: rgb(250,250,250);") self.grid_body_lower_align_mode.addWidget(self.b_up, 0, 3) # Button Text Field self.b_left = QPushButton("<=") self.b_left.setDefault(True) self.b_left.setEnabled(False) self.b_left.clicked.connect(lambda: self.buttonPress(self.b_left)) self.b_left.setStyleSheet( "color: rgb(250,50,50); background-color: rgb(250,250,250);") self.grid_body_lower_align_mode.addWidget(self.b_left, 1, 2) # Button Text Field self.b_down = QPushButton("\/") self.b_down.setDefault(True) self.b_down.setEnabled(False) self.b_down.clicked.connect(lambda: self.buttonPress(self.b_down)) self.b_down.setStyleSheet( "color: rgb(250,50,50); background-color: rgb(250,250,250);") self.grid_body_lower_align_mode.addWidget(self.b_down, 1, 3) # Button Text Field self.b_right = QPushButton("=>") self.b_right.setDefault(True) self.b_right.setEnabled(False) self.b_right.clicked.connect(lambda: self.buttonPress(self.b_right)) self.b_right.setStyleSheet( "color: rgb(250,50,50); background-color: rgb(250,250,250);") self.grid_body_lower_align_mode.addWidget(self.b_right, 1, 4) # Button Text Field self.b_clockwise = QPushButton("^--'") self.b_clockwise.setDefault(True) self.b_clockwise.setEnabled(False) self.b_clockwise.clicked.connect( lambda: self.buttonPress(self.b_clockwise)) self.b_clockwise.setStyleSheet( "color: rgb(250,50,50); background-color: rgb(250,250,250);") self.grid_body_lower_align_mode.addWidget(self.b_clockwise, 0, 6) # Button Text Field self.b_cclockwise = QPushButton("'--^") self.b_cclockwise.setDefault(True) self.b_cclockwise.setEnabled(False) self.b_cclockwise.clicked.connect( lambda: self.buttonPress(self.b_cclockwise)) self.b_cclockwise.setStyleSheet( "color: rgb(250,50,50); background-color: rgb(250,250,250);") self.grid_body_lower_align_mode.addWidget(self.b_cclockwise, 0, 7) # Button Text Field self.b_save_transform = QPushButton("Save Transformation") self.b_save_transform.setDefault(True) self.b_save_transform.setEnabled(False) self.b_save_transform.clicked.connect( lambda: self.buttonPress(self.b_save_transform)) self.b_save_transform.setStyleSheet( "color: rgb(0,0,0); background-color: rgb(250,200,250);") self.grid_body_lower_align_mode.addWidget(self.b_save_transform, 1, 9) # Button Text Field self.b_done = QPushButton("DONE") self.b_done.setDefault(True) self.b_done.setEnabled(True) self.b_done.clicked.connect(lambda: self.buttonPress(self.b_done)) self.b_done.setStyleSheet( "color: rgb(0,0,0); background-color: rgb(200,250,250);") self.grid_body_lower_align_mode.addWidget(self.b_done, 1, 10) # Grid stretching self.grid_body_upper.setColumnStretch(0, 2) self.grid_body_upper.setColumnStretch(2, 2) ### SUPERGRID ### self.supergrid = QGridLayout() self.supergrid.addLayout(self.grid_top, 0, 0) self.supergrid.addLayout(self.grid_body_upper, 1, 0) self.supergrid.addLayout(self.grid_body, 2, 0) self.supergrid.addLayout(self.grid_body_lower_align_mode, 3, 0) self.supergrid.addLayout(self.grid_bottom, 4, 0) # Set layout and window title self.setLayout(self.supergrid) self.setWindowTitle("Q") # Loads self.curr_section as the current image and sets all fields appropriatly self.setCurrSection(self.curr_section_index) def help_button_press(self, button): info_text = "This GUI is used to align slices to each other. The shortcut commands are as follows: \n\n\ - `m`: Toggle between view mode (grayscale) and alignment mode (red & blue).\n\ - `[`: Go back one section. \n\ - `]`: Go forward one section. \n\n\ \ All changes must be done in alignment mode. Alignment mode will display the pairwise alignment between the current \ active section (red) and the previous section (blue). Using the buttons at the foot of the GUI, you can translate and \ rotate the active section (red) as well as brighten either the active or previous section. Adjust the red slice such \ that it is aligned to the blue slice as well as possible and press \"Save Transformation\".\n\n\ \ The grayscale images should all be aligned to one another. Please verify that all sections are aligned properly \ before you finish this step." QMessageBox.information(self, "Empty Field", info_text) def loadImage(self): # Get filepath of "curr_section" and set it as viewer's photo #fp = get_fp(self.curr_section, prep_id=1) input_tif = os.path.join(self.fileLocationManager.thumbnail_prep, self.curr_section) print('input_tif', input_tif) #fp = io.imread(input_tif) self.viewer.setPhoto(QPixmap(input_tif)) self.curr_T = None # # img, T = get_transformed_image( self.curr_section, # transformation='anchor', # prev_section=self.prev_section ) # T = get_comulative_pairwise_transform( stack, # DataManager.metadata_cache['sections_to_filenames'][stack][self.curr_section] ) # img = apply_transform( stack, T, # DataManager.metadata_cache['sections_to_filenames'][stack][self.curr_section]) # height, width, channel = img.shape # bytesPerLine = 3 * width # qImg = QImage(img.data, width, height, bytesPerLine, QImage.Format_RGB888) # # self.viewer.setPhoto( QPixmap( qImg ) ) def loadImageThenNormalize(self): # Get filepath of "curr_section" and set it as viewer's photo input_tif = os.path.join(self.fileLocationManager.oriented, self.curr_section) #fp = imread(input_tif) img = io.imread(input_tif) * 3 height, width, channel = img.shape bytesPerLine = 3 * width qImg = QImage(img.data, width, height, bytesPerLine, QImage.Format_RGB888) self.viewer.setPhoto(QPixmap(qImg)) def loadImagesColored(self): # we want to load RED (current section) and BLUE (previous section) channels overlayed curr_tif = os.path.join(self.fileLocationManager.oriented, self.curr_section) img_curr_red = io.imread(curr_tif) prev_tif = os.path.join(self.fileLocationManager.oriented, self.prev_section) img_prev_blue = io.imread(prev_tif) # Load the untransformed images # img_curr_red = cv2.imread( fp_curr_red ) # img_prev_blue = cv2.imread( fp_prev_blue ) if self.transform_type == 'anchor': # Load anchor-transformed images img_curr_red, T = get_transformed_image(self.curr_section, transformation='anchor') img_prev_blue, Tb = get_transformed_image(self.prev_section, transformation='anchor') self.curr_T = T elif self.transform_type == 'pairwise' and self.curr_section > self.prev_section: # Load pairwise-transformed images # The current red image is transformed to the previous blue image img_curr_red, T = get_transformed_image( self.curr_section, transformation='pairwise', prev_section=self.prev_section) self.curr_T = T # Blue image does not change prev_tif = os.path.join(self.fileLocationManager.oriented, self.prev_section) img_prev_blue = io.imread(prev_tif) elif self.transform_type == 'pairwise' and self.curr_section < self.prev_section: # In the case of wrapping (prev_section wrapps to the last section when curr_section is 0) # We just load the red ad blue channels of curr_section making it appear purple self.curr_T = None curr_tif = os.path.join(self.fileLocationManager.oriented, self.curr_section) img_curr_red = io.imread(curr_tif) prev_tif = os.path.join(self.fileLocationManager.oriented, self.prev_section) img_prev_blue = io.imread(prev_tif) height_r, width_r, _ = img_curr_red.shape height_b, width_b, _ = img_prev_blue.shape new_height = max(height_r, height_b) new_width = max(width_r, width_b) img_combined = np.ones((new_height, new_width, 3)) img_combined[0:height_r, 0:width_r, 0] += img_curr_red[:, :, 0] img_combined[0:height_b, 0:width_b, 2] += img_prev_blue[:, :, 0] img_combined = np.array( img_combined, dtype=np.uint8) # This line only change the type, not values # Create a "qImg" which allows you to create a QPixmap from a matrix bytesPerLine = 3 * new_width qImg = QImage(img_combined.data * 2, new_width, new_height, bytesPerLine, QImage.Format_RGB888) pixmap = QPixmap(qImg) # pixmap = pixmap.scaled(640,400, Qt.KeepAspectRatio) self.viewer.setPhoto(pixmap) def transformImagesColored(self): # we want to load RED (current section) and BLUE (previous section) channels overlayed #fp_curr_red = get_fp(self.curr_section) #fp_prev_blue = get_fp(self.prev_section) curr_tif = os.path.join(self.fileLocationManager.oriented, self.curr_section) fp_curr_red = io.imread(curr_tif) prev_tif = os.path.join(self.fileLocationManager.oriented, self.prev_section) fp_prev_blue = io.imread(prev_tif) if self.transform_type == 'anchor': # Load anchor-transformed images img_curr_red = apply_transform(stack, self.curr_T, self.curr_section) img_prev_blue, Tb = get_transformed_image(self.prev_section, transformation='anchor') elif self.transform_type == 'pairwise': # Load pairwise-transformed images # The current red image is transformed to the previous blue image img_curr_red = apply_transform(stack, self.curr_T, self.curr_section) # Blue image does not change img_prev_blue = io.imread(fp_prev_blue) height_r, width_r, _ = img_curr_red.shape height_b, width_b, _ = img_prev_blue.shape new_height = max(height_r, height_b) new_width = max(width_r, width_b) img_combined = np.ones((new_height, new_width, 3)) img_combined[0:height_r, 0:width_r, 0] += img_curr_red[:, :, 0] * self.curr_img_multiplier img_combined[0:height_b, 0:width_b, 2] += img_prev_blue[:, :, 0] * self.prev_img_multiplier img_combined = np.array( img_combined, dtype=np.uint8) # This line only change the type, not values # Create a "qImg" which allows you to create a QPixmap from a matrix bytesPerLine = 3 * new_width qImg = QImage(img_combined.data * 2, new_width, new_height, bytesPerLine, QImage.Format_RGB888) pixmap = QPixmap(qImg) # pixmap = pixmap.scaled(640,400, Qt.KeepAspectRatio) self.viewer.setPhoto(pixmap) def photoClicked(self, pos): if self.viewer.dragMode() == QGraphicsView.NoDrag: print('%d, %d' % (pos.x(), pos.y())) def pixInfo(self): self.viewer.toggleDragMode() def keyPressEvent(self, event): try: key = event.key() except AttributeError: key = event if key == 91: # [ self.getPrevValidSection(self.curr_section_index) self.setCurrSection(self.prev_section_index) elif key == 93: # ] self.getNextValidSection(self.curr_section_index) self.setCurrSection(self.next_section_index) elif key == 81: # Q self.pixInfo() elif key == 77: # M self.toggleMode() else: print(key) def setCurrSection(self, section_index=-1): """ Sets the current section to the section passed in. Will automatically update curr_section, prev_section, and next_section. Updates the header fields and loads the current section image. """ if section_index == -1: section_index = self.curr_section_index # Update curr, prev, and next section self.curr_section_index = section_index self.curr_section = self.valid_sections[self.valid_section_keys[ self.curr_section_index]]['destination'] self.prev_section = self.getPrevValidSection(self.curr_section_index) self.next_section = self.getNextValidSection(self.curr_section_index) self.updateCurrHeaderFields() self.updatePrevHeaderFields() self.curr_img_multiplier = 1 self.prev_img_multiplier = 1 if self.mode == 'view': self.loadImage() self.toggle_align_buttons(enabled=False) elif self.mode == 'align': self.loadImagesColored() self.toggle_align_buttons(enabled=True) def toggleMode(self): if self.mode == 'view': self.mode = 'align' elif self.mode == 'align': self.mode = 'view' self.setCurrSection() def buttonPress(self, button): # Brighten an image if button in [self.b1, self.b2]: if button == self.b1: self.prev_img_multiplier += 1 if self.prev_img_multiplier > 5: self.prev_img_multiplier = 1 if button == self.b2: self.curr_img_multiplier += 1 if self.curr_img_multiplier > 5: self.curr_img_multiplier = 1 # Translate the red image and update T matrix if button in [self.b_right, self.b_left, self.b_up, self.b_down]: if button == self.b_right: self.curr_T[0, 2] += 3 if button == self.b_left: self.curr_T[0, 2] -= 3 if button == self.b_up: self.curr_T[1, 2] -= 3 if button == self.b_down: self.curr_T[1, 2] += 3 # self.transformImagesColored() # Rotate the red image and update T matrix if button in [self.b_clockwise, self.b_cclockwise]: if button == self.b_clockwise: degrees = 0.3 if button == self.b_cclockwise: degrees = -0.3 # Update matrix's rotation fields self.curr_T[0, 0] = math.cos( math.acos(self.curr_T[0, 0]) + degrees * (math.pi / 180)) self.curr_T[1, 1] = math.cos( math.acos(self.curr_T[1, 1]) + degrees * (math.pi / 180)) self.curr_T[0, 1] = -math.sin( math.asin(-self.curr_T[0, 1]) + degrees * (math.pi / 180)) self.curr_T[1, 0] = math.sin( math.asin(self.curr_T[1, 0]) + degrees * (math.pi / 180)) if button == self.b_save_transform: self.saveCurrTransform() self.update_prep1_images() if button == self.b_done: sys.exit(app.exec_()) self.transformImagesColored() def getNextValidSection(self, section_index): self.next_section_index = section_index + 1 if self.next_section_index > len(self.valid_sections) - 1: self.next_section_index = 0 self.next_section = self.valid_sections[self.valid_section_keys[ self.next_section_index]]['destination'] return self.next_section def getPrevValidSection(self, section_index): self.prev_section_index = int(section_index) - 1 if self.prev_section_index < 0: self.prev_section_index = len(self.valid_sections) - 1 self.prev_section = self.valid_sections[self.valid_section_keys[ self.prev_section_index]]['destination'] return self.prev_section def toggle_align_buttons(self, enabled): self.b1.setEnabled(enabled) self.b2.setEnabled(enabled) self.b_right.setEnabled(enabled) self.b_left.setEnabled(enabled) self.b_up.setEnabled(enabled) self.b_down.setEnabled(enabled) self.b_clockwise.setEnabled(enabled) self.b_cclockwise.setEnabled(enabled) self.b_save_transform.setEnabled(enabled) def updateCurrHeaderFields(self): label = self.valid_sections[self.valid_section_keys[ self.curr_section_index]]['source'] self.e4.setText(label) self.e5.setText(self.curr_section) def updatePrevHeaderFields(self): label = self.valid_sections[self.valid_section_keys[ self.prev_section_index]]['source'] self.e2.setText(label) self.e3.setText(self.prev_section) def update_prep1_images(self): version = stain_to_metainfo[self.stain]['img_version_1'] create_input_spec_ini_all(name='input_spec.ini', \ stack=stack, prep_id='None', version=version, resol='thumbnail') # Call "compose" to regenerate the csv file command = [ 'python', 'compose_v3.py', 'input_spec.ini', '--op', 'from_none_to_aligned' ] completion_message = 'Finished creating transforms to anchor csv file.' call_and_time(command, completion_message=completion_message) # Apply transformations from csv and save as prep1 images command = [ 'python', 'warp_crop_v3.py', '--input_spec', 'input_spec.ini', '--op_id', 'from_none_to_padded', '--njobs', '8', '--pad_color', get_padding_color(stack) ] completion_message = 'Finished transformation to padded (prep1).' call_and_time(command, completion_message=completion_message) def saveCurrTransform(self): if self.transform_type == 'pairwise': curr_section_fn = self.sections_to_filenames[self.curr_section] prev_section_fn = self.sections_to_filenames[self.prev_section] custom_transform_txt_name = '{}_to_{}.txt'.format( curr_section_fn, prev_section_fn) custom_transform_txt_file = os.path.join( self.fileLocationManager.custom_transform, custom_transform_txt_name) custom_transform_img_name = '{}_{}.txt'.format( curr_section_fn, prev_section_fn) custom_transform_img_file = os.path.join( self.fileLocationManager.aligned_to, custom_transform_img_name) T = self.curr_T # Saves the transformed image since we gave a specific output_fp apply_transform(stack, self.curr_T, self.curr_section, custom_transform_img_file) with open(custom_transform_txt_file, 'w') as file: file.write(str(T[0, 0]) + ' ' + str(T[0, 1]) + ' ' + str(T[0, 2]) + ' ' + \ str(T[1, 0]) + ' ' + str(T[1, 1]) + ' ' + str(T[1, 2])) else: pass
class init_GUI(QWidget): def __init__(self, stack, parent=None): super(init_GUI, self).__init__(parent) self.font_h1 = QFont("Arial", 32) self.font_p1 = QFont("Arial", 16) self.queued_transformations = [] # create a dataManager object self.sqlController = SqlController() self.stack = stack self.fileLocationManager = FileLocationManager(self.stack) self.sqlController.get_animal_info(self.stack) self.valid_sections = self.sqlController.get_valid_sections(stack) self.valid_section_keys = sorted(list(self.valid_sections)) section_length = len(self.valid_section_keys) self.curr_section_index = section_length // 2 self.prev_section_index = self.curr_section_index self.next_section_index = self.curr_section_index self.curr_section = self.valid_sections[self.valid_section_keys[ self.curr_section_index]]['destination'] self.prev_section = self.getPrevValidSection(self.curr_section_index) self.next_section = self.getNextValidSection(self.curr_section_index) self.initUI() def initUI(self): # Set Layout and Geometry of Window self.grid_top = QGridLayout() self.grid_body_upper = QGridLayout() self.grid_body = QGridLayout() self.grid_body_lower = QGridLayout() self.grid_bottom = QGridLayout() self.grid_blank = QGridLayout() # self.setFixedSize(1600, 1000) self.resize(1600, 1000) ### VIEWER ### (Grid Body) self.viewer = ImageViewer(self) self.viewer.photoClicked.connect(self.photoClicked) ### Grid TOP ### # Static Text Field (Title) self.e1 = QLineEdit() self.e1.setValidator(QIntValidator()) self.e1.setAlignment(Qt.AlignCenter) self.e1.setFont(self.font_h1) self.e1.setReadOnly(True) self.e1.setText("Orient Images") self.e1.setFrame(False) self.grid_top.addWidget(self.e1, 0, 0) # Button Text Field self.b_help = QPushButton("HELP") self.b_help.setDefault(True) self.b_help.setEnabled(True) self.b_help.clicked.connect( lambda: self.help_button_press(self.b_help)) self.b_help.setStyleSheet( "color: rgb(0,0,0); background-color: rgb(250,250,250);") self.grid_top.addWidget(self.b_help, 0, 1) ### Grid BODY UPPER ### # Static Text Field self.e4 = QLineEdit() self.e4.setAlignment(Qt.AlignCenter) self.e4.setFont(self.font_p1) self.e4.setReadOnly(True) self.e4.setText("Filename: ") # self.e4.setStyleSheet("color: rgb(250,50,50); background-color: rgb(250,250,250);") self.grid_body_upper.addWidget(self.e4, 0, 2) # Static Text Field self.e5 = QLineEdit() self.e5.setAlignment(Qt.AlignCenter) self.e5.setFont(self.font_p1) self.e5.setReadOnly(True) self.e5.setText("Section: ") # self.e5.setStyleSheet("color: rgb(250,50,50); background-color: rgb(250,250,250);") self.grid_body_upper.addWidget(self.e5, 0, 3) ### Grid BODY ### # Custom VIEWER self.grid_body.addWidget(self.viewer, 0, 0) ### Grid BODY LOWER ### # Button Text Field self.b1 = QPushButton("Flip image(s) across central vertical line") self.b1.setDefault(True) self.b1.setEnabled(True) self.b1.clicked.connect(lambda: self.buttonPress(self.b1)) self.b1.setStyleSheet( "color: rgb(0,0,0); background-color: rgb(250,250,200);") self.grid_body_lower.addWidget(self.b1, 0, 0) # Button Text Field self.b2 = QPushButton("Flop image(s) across central horozontal line") self.b2.setDefault(True) self.b2.setEnabled(True) self.b2.clicked.connect(lambda: self.buttonPress(self.b2)) self.b2.setStyleSheet( "color: rgb(0,0,0); background-color: rgb(250,250,200);") self.grid_body_lower.addWidget(self.b2, 1, 0) # Button Text Field self.b3 = QPushButton("Rotate Image(s)") self.b3.setDefault(True) self.b3.setEnabled(True) self.b3.clicked.connect(lambda: self.buttonPress(self.b3)) self.b3.setStyleSheet( "color: rgb(0,0,0); background-color: rgb(250,200,250);") self.grid_body_lower.addWidget(self.b3, 0, 1, 1, 2) # Checkbox self.cb_1 = QCheckBox("Apply transformation to ALL images") self.cb_1.setChecked(True) self.cb_1.setEnabled(False) self.grid_body_lower.addWidget(self.cb_1, 0, 3) # Static Text Field self.e6 = QLineEdit() self.e6.setMaximumWidth(250) self.e6.setAlignment(Qt.AlignRight) self.e6.setReadOnly(True) self.e6.setText("Degrees to rotate (clockwise!): ") self.grid_body_lower.addWidget(self.e6, 1, 1) # Dropbown Menu (ComboBox) for selecting Stack self.cb = QComboBox() self.cb.addItems(['90', '180', '270']) # self.cb.addItems( ['Rotate by 90 degrees', 'Rotate by 180 degrees', 'Rotate by 270 degrees'] ) # self.cb.addItems( ['45', '90', '135', '180', '225', '270', '315'] ) self.grid_body_lower.addWidget(self.cb, 1, 2) # Button Text Field self.b_done = QPushButton("Done orienting") self.b_done.setDefault(True) self.b_done.setEnabled(True) self.b_done.clicked.connect(lambda: self.buttonPress(self.b_done)) self.b_done.setStyleSheet( "color: rgb(0,0,0); background-color: #dfbb19;") self.grid_body_lower.addWidget(self.b_done, 1, 3) # Grid stretching # self.grid_body_upper.setColumnStretch(0, 2) self.grid_body_upper.setColumnStretch(2, 2) # self.grid_body_lower.setColumnStretch(3, 1) ### SUPERGRID ### self.supergrid = QGridLayout() self.supergrid.addLayout(self.grid_top, 0, 0) self.supergrid.addLayout(self.grid_body_upper, 1, 0) self.supergrid.addLayout(self.grid_body, 2, 0) # self.supergrid.addLayout( self.grid_body_lower, 4, 0) self.supergrid.addWidget(QHLine(), 6, 0, 1, 2) # self.supergrid.addLayout( self.grid_bottom, 6, 0) self.supergrid.addLayout(self.grid_body_lower, 7, 0) self.supergrid.addWidget(QHLine(), 8, 0, 1, 2) # Set layout and window title self.setLayout(self.supergrid) self.setWindowTitle("Q") # Loads self.curr_section as the current image and sets all fields appropriatly self.setCurrSection(self.curr_section_index) def help_button_press(self, button): info_text = "This GUI is used to align slices to each other. The shortcut commands are as follows: \n\n\ - `[`: Go back one section. \n\ - `]`: Go forward one section." QMessageBox.information(self, "Empty Field", info_text) def loadImage(self): curr_fn = self.valid_sections[self.valid_section_keys[ self.curr_section_index]]['destination'] # Get filepath of "curr_section" and set it as viewer's photo img_fp = os.path.join(self.fileLocationManager.thumbnail_prep, curr_fn) self.viewer.setPhoto(QPixmap(img_fp)) def photoClicked(self, pos): if self.viewer.dragMode() == QGraphicsView.NoDrag: print('%d, %d' % (pos.x(), pos.y())) def pixInfo(self): self.viewer.toggleDragMode() def keyPressEvent(self, event): try: key = event.key() except AttributeError: key = event if key == 91: # [ self.getPrevValidSection(self.curr_section_index) self.setCurrSection(self.prev_section_index) elif key == 93: # ] self.getNextValidSection(self.curr_section_index) self.setCurrSection(self.next_section_index) else: print(key) def setCurrSection(self, section_index=-1): """ Sets the current section to the section passed in. Will automatically update curr_section, prev_section, and next_section. Updates the header fields and loads the current section image. """ if section_index == -1: section_index = self.curr_section_index # Update curr, prev, and next section self.curr_section_index = section_index self.curr_section = self.valid_sections[self.valid_section_keys[ self.curr_section_index]]['destination'] self.prev_section = self.getPrevValidSection(self.curr_section_index) self.next_section = self.getNextValidSection(self.curr_section_index) # Update the section and filename at the top self.updateCurrHeaderFields() # Update the quality selection in the bottom left self.loadImage() def getNextValidSection(self, section_index): self.next_section_index = section_index + 1 if self.next_section_index > len(self.valid_sections) - 1: self.next_section_index = 0 self.next_section = self.valid_sections[self.valid_section_keys[ self.next_section_index]]['destination'] return self.next_section def getPrevValidSection(self, section_index): self.prev_section_index = int(section_index) - 1 if self.prev_section_index < 0: self.prev_section_index = len(self.valid_sections) - 1 self.prev_section = self.valid_sections[self.valid_section_keys[ self.prev_section_index]]['destination'] return self.prev_section def buttonPress(self, button): # Brighten an image if button in [self.b1, self.b2, self.b3]: # "Flip image(s) across central vertical line" if button == self.b1: self.transform_thumbnails('flip') # "Flop image(s) across central horozontal line" elif button == self.b2: self.transform_thumbnails('flop') # "Rotate Image(s)" elif button == self.b3: self.transform_thumbnails('rotate', degrees=str(self.cb.currentText())) # Update the Viewer info and displayed image self.setCurrSection(self.curr_section_index) elif button == self.b_done: QMessageBox.about( self, "Popup Message", "All selected operations will now be performed on the\ full sized raw images. This may take an hour or two, depending on how many operations are queued." ) self.apply_queued_transformations() self.finished() def updateCurrHeaderFields(self): label = self.valid_sections[self.valid_section_keys[ self.curr_section_index]]['source'] self.e4.setText(label) self.e5.setText(str(self.curr_section)) def transform_thumbnails(self, transform_type, degrees=0): """ Transform_type must be "rotate", "flip", or "flop". These transformations get applied to all the active sections. The actual conversions take place on the thumbnails and the raw files. The transformed raw files get placed in the preps/oriented dir. """ if transform_type == 'rotate': base_cmd = ['convert', '-' + transform_type, str(degrees)] else: base_cmd = ['convert', '-' + transform_type] self.queued_transformations.append(base_cmd) # Apply transforms to just the thumbnails THUMBNAIL = self.fileLocationManager.prep_thumbnail for k, v in self.valid_sections.items(): thumbnail = os.path.join(THUMBNAIL, v['destination']) subprocess.call(base_cmd + [thumbnail, thumbnail]) def finished(self): self.sqlController.set_step_completed_in_progress_ini( self.stack, '1-5_setup_orientations') # close_main_gui( ex ) sys.exit(app.exec_()) def apply_queued_transformations(self): print('queued_transformations', self.queued_transformations) if self.queued_transformations == []: print('No transformations to do. Exit stage left ...') else: # Apply to "raw" images RAW = self.fileLocationManager.tif ORIENTED = self.fileLocationManager.oriented for base_cmd in tqdm(self.queued_transformations): for k, v in self.valid_sections.items(): raw = os.path.join(RAW, v['source']) oriented = os.path.join(ORIENTED, v['destination']) subprocess.call(base_cmd + [raw, oriented]) #print(base_cmd + [raw, oriented]) # Clear the queued transformations self.queued_transformations = []
class GUISortedFilenames(QWidget): def __init__(self, stack, parent=None): super(GUISortedFilenames, self).__init__(parent) self.stack = stack self.fileLocationManager = FileLocationManager(self.stack) self.sqlController = SqlController() self.sqlController.get_animal_info(self.stack) self.valid_sections = self.sqlController.get_valid_sections(stack) self.valid_section_keys = sorted(list(self.valid_sections)) self.curr_section_index = 0 self.curr_section = None self.init_ui() self.b_rotate_left.clicked.connect( lambda: self.click_button(self.b_rotate_left)) self.b_rotate_right.clicked.connect( lambda: self.click_button(self.b_rotate_right)) self.b_flip_vertical.clicked.connect( lambda: self.click_button(self.b_flip_vertical)) self.b_flip_horozontal.clicked.connect( lambda: self.click_button(self.b_flip_horozontal)) self.b_move_left.clicked.connect( lambda: self.click_button(self.b_move_left)) self.b_move_right.clicked.connect( lambda: self.click_button(self.b_move_right)) self.b_quality.currentIndexChanged.connect( lambda: self.click_button(self.b_quality)) self.b_remove.clicked.connect(lambda: self.click_button(self.b_remove)) self.b_help.clicked.connect(lambda: self.click_button(self.b_help)) self.b_done.clicked.connect(lambda: self.click_button(self.b_done)) self.set_curr_section(self.curr_section_index) def init_ui(self): self.font_h1 = QFont("Arial", 32) self.font_p1 = QFont("Arial", 16) self.grid_top = QGridLayout() self.grid_body_upper = QGridLayout() self.grid_body = QGridLayout() self.grid_body_lower = QGridLayout() self.resize(1600, 1100) # Grid Top self.e_title = QLineEdit() self.e_title.setAlignment(Qt.AlignCenter) self.e_title.setFont(self.font_h1) self.e_title.setReadOnly(True) self.e_title.setText("Setup Sorted Filenames") self.e_title.setFrame(False) self.grid_top.addWidget(self.e_title, 0, 0) self.b_help = QPushButton("HELP") self.b_help.setDefault(True) self.b_help.setEnabled(True) self.grid_top.addWidget(self.b_help, 0, 1) # Grid BODY UPPER self.e_filename = QLineEdit() self.e_filename.setAlignment(Qt.AlignCenter) self.e_filename.setFont(self.font_p1) self.e_filename.setReadOnly(True) self.e_filename.setText("Filename: ") self.grid_body_upper.addWidget(self.e_filename, 0, 2) self.e_section = QLineEdit() self.e_section.setAlignment(Qt.AlignCenter) self.e_section.setFont(self.font_p1) self.e_section.setReadOnly(True) self.e_section.setText("Section: ") self.grid_body_upper.addWidget(self.e_section, 0, 3) # Grid BODY self.viewer = ImageViewer(self) self.grid_body.addWidget(self.viewer, 0, 0) # Grid BODY LOWER self.b_flip_vertical = QPushButton("Flip vertically") self.grid_body_lower.addWidget(self.b_flip_vertical, 0, 0) self.b_flip_horozontal = QPushButton("Flop horizontally") self.grid_body_lower.addWidget(self.b_flip_horozontal, 0, 1) self.b_rotate_left = QPushButton("Rotate Left") self.grid_body_lower.addWidget(self.b_rotate_left, 0, 2) self.b_rotate_right = QPushButton("Rotate Right") self.grid_body_lower.addWidget(self.b_rotate_right, 0, 3) self.b_move_left = QPushButton("<-- Move Section Left <--") #self.grid_body_lower.addWidget(self.b_move_left, 1, 0) self.b_move_right = QPushButton("--> Move Section Right -->") #self.grid_body_lower.addWidget(self.b_move_right, 1, 1) self.b_quality = QComboBox() self.b_quality.addItems([ 'Section quality: unusable', 'Section quality: blurry', 'Section quality: good' ]) #self.grid_body_lower.addWidget(self.b_quality, 1, 2) self.b_remove = QPushButton("Remove section") #self.grid_body_lower.addWidget(self.b_remove, 1, 3) self.progress = QProgressBar(self) self.grid_body_lower.addWidget(self.progress, 2, 0, 1, 3) self.progress.hide() self.b_done = QPushButton("Finished") self.grid_body_lower.addWidget(self.b_done, 2, 3) # Super grid self.supergrid = QGridLayout() self.supergrid.addLayout(self.grid_top, 0, 0) self.supergrid.addLayout(self.grid_body_upper, 1, 0) self.supergrid.addLayout(self.grid_body, 2, 0) self.supergrid.addLayout(self.grid_body_lower, 3, 0) # Set layout and window title self.setLayout(self.supergrid) self.setWindowTitle("Q") def set_curr_section(self, section_index=-1): """ Sets the current section to the section passed in. Will automatically update curr_section, prev_section, and next_section. Updates the header fields and loads the current section image. """ if section_index == -1: section_index = self.curr_section_index # Update curr, prev, and next section self.curr_section_index = section_index self.curr_section = self.valid_sections[self.valid_section_keys[ self.curr_section_index]] # Update the section and filename at the top self.e_filename.setText(self.curr_section['destination']) self.e_section.setText(str(self.curr_section['section_number'])) # Get filepath of "curr_section" and set it as viewer's photo img_fp = os.path.join(self.fileLocationManager.thumbnail_prep, self.curr_section['destination']) self.viewer.set_photo(img_fp) # Update the quality selection in the bottom left index = self.b_quality.findText(self.curr_section['quality'], Qt.MatchFixedString) if index >= 0: self.b_quality.setCurrentIndex(index) def get_valid_section_index(self, section_index): if section_index >= len(self.valid_sections): return 0 elif section_index < 0: return len(self.valid_sections) - 1 else: return section_index def click_button(self, button): if button == self.b_quality: curr_section = self.valid_sections[self.valid_section_keys[ self.curr_section_index]] curr_section['quality'] = self.b_quality.currentText() self.sqlController.save_valid_sections(self.valid_sections) elif button in [self.b_move_left, self.b_move_right, self.b_remove]: if button == self.b_move_left: self.sqlController.move_section( self.stack, self.curr_section['section_number'], -1) elif button == self.b_move_right: self.sqlController.move_section( self.stack, self.curr_section['section_number'], 1) elif button == self.b_remove: result = self.message_box( 'Are you sure you want to totally remove this section from this brain?\n\n' + 'Warning: The image will be marked as irrelevant to the current brain!', True) # The answer is Yes if result == 2: # Remove the current section from "self.valid_sections self.sqlController.inactivate_section( self.stack, self.curr_section['section_number']) self.valid_sections = self.sqlController.get_valid_sections( self.stack) self.valid_section_keys = sorted(list(self.valid_sections)) if self.curr_section_index == 0: self.curr_section_index = len( self.valid_section_keys) - 1 else: self.curr_section_index = self.curr_section_index - 1 else: pass # Update the Viewer info and displayed image self.valid_sections = self.sqlController.get_valid_sections( self.stack) self.valid_section_keys = sorted(list(self.valid_sections)) self.set_curr_section(self.curr_section_index) elif button in [ self.b_flip_vertical, self.b_flip_horozontal, self.b_rotate_right, self.b_rotate_left ]: """ Transform_type must be "rotate", "flip", or "flop". These transformations get applied to all the active sections. The actual conversions take place on the thumbnails and the raw files. The transformed raw files get placed in the preps/oriented dir. """ index = [ self.b_flip_vertical, self.b_flip_horozontal, self.b_rotate_right, self.b_rotate_left ].index(button) op = ['flip', 'flop', 'right', 'left'][index] size = len(self.valid_sections.values()) - 1 self.progress_bar(True, size) for index, section in enumerate(self.valid_sections.values()): thumbnail_path = os.path.join( self.fileLocationManager.thumbnail_prep, section['destination']) if os.path.isfile(thumbnail_path): self.transform_image(thumbnail_path, op) self.progress.setValue(index) self.progress_bar(False, size) self.set_curr_section(section_index=-1) elif button == self.b_help: self.message_box( 'This GUI is used to align slices to each other. The shortcut commands are as follows: \n\n' + '- `[`: Go back one section. \n' + '- `]`: Go forward one section. \n\n' + 'Use the buttons on the bottom panel to move', False) elif button == self.b_done: self.message_box( "All selected operations will now be performed on the full sized raw images" + "This may take an hour or two, depending on how many operations are queued.", False) # Apply the transformations to the real images self.apply_queued_transformations() self.sqlController.set_step_completed_in_progress_ini( self.stack, '1-4_setup_sorted_filenames') self.sqlController.set_step_completed_in_progress_ini( self.stack, '1-5_setup_orientations') sys.exit(app.exec_()) def transform_image(self, filename, op): def get_last_2d(data): if data.ndim <= 2: return data m, n = data.shape[-2:] return data.flat[:m * n].reshape(m, n) img = io.imread(filename) img = get_last_2d(img) # Rotating a multidimensional image has to be done backwards. # To rotate right, do np.rot(img, 3), to rotate left, do np.rot(img, 1) if op == 'left': img = np.rot90(img, 3) elif op == 'right': img = np.rot90(img, 1) elif op == 'flip': img = np.flipud(img) elif op == 'flop': img = np.fliplr(img) os.unlink(filename) io.imsave(filename, img) self.save_to_web_thumbnail(filename, img) def save_to_web_thumbnail(self, filename, img): filename = os.path.basename(filename) png_file = os.path.splitext(filename)[0] + '.png' png_path = os.path.join(self.fileLocationManager.thumbnail_web, png_file) if os.path.exists(png_path): os.unlink(png_path) io.imsave(png_path, img) def apply_queued_transformations(self): pass def progress_bar(self, show, max_value): if show: self.progress.setMaximum(max_value) self.progress.show() else: self.progress.hide() self.b_quality.setDisabled(show) self.b_move_left.setDisabled(show) self.b_move_right.setDisabled(show) self.b_flip_vertical.setDisabled(show) self.b_flip_horozontal.setDisabled(show) self.b_rotate_right.setDisabled(show) self.b_rotate_left.setDisabled(show) self.b_remove.setDisabled(show) self.b_done.setDisabled(show) def message_box(self, text, is_warn): msg_box = QMessageBox() msg_box.setText(text) if is_warn: msg_box.addButton(QPushButton('Cancel'), QMessageBox.RejectRole) msg_box.addButton(QPushButton('No'), QMessageBox.NoRole) msg_box.addButton(QPushButton('Yes'), QMessageBox.YesRole) return msg_box.exec_() def keyPressEvent(self, event): try: key = event.key() except AttributeError: key = event if key == 91: # [ index = self.get_valid_section_index(self.curr_section_index - 1) self.set_curr_section(index) elif key == 93: # ] index = self.get_valid_section_index(self.curr_section_index + 1) self.set_curr_section(index) else: print(key) def closeEvent(self, event): sys.exit(app.exec_())
class init_GUI(QWidget): def __init__(self, stack, parent = None): super(init_GUI, self).__init__(parent) self.font1 = QFont("Arial",16) self.font2 = QFont("Arial",12) # Stack specific info, determined from dropdown menu selection self.stack = stack self.curr_step = "" self.sqlController = SqlController() self.sqlController.get_animal_info(self.stack) self.initUI() def initUI(self): # Set Layout and Geometry of Window self.grid_top = QGridLayout() self.grid_buttons = QGridLayout() self.grid_bottom = QGridLayout() #self.setFixedSize(1000, 450) self.resize(1000, 450) ### Grid Top (1 row) ### # Static Text Field self.e1 = QLineEdit() self.e1.setValidator( QIntValidator() ) self.e1.setAlignment(Qt.AlignCenter) self.e1.setFont( self.font1 ) self.e1.setReadOnly( True ) self.e1.setText( "Align Step: Main Page" ) self.e1.setFrame( False ) self.grid_top.addWidget( self.e1, 0, 0) ### Grid Buttons ### # Button self.b_1 = QPushButton("1) Correct automatic alignments") format_grid_button_initial( self.b_1 ) self.b_1.clicked.connect( lambda:self.button_grid_push(self.b_1) ) self.grid_buttons.addWidget( self.b_1, 0, 0) ### Grid Bottom ### # Button Text Field self.b_exit = QPushButton("Exit") self.b_exit.setDefault(True) self.b_exit.clicked.connect(lambda:self.button_push(self.b_exit)) self.grid_bottom.addWidget(self.b_exit, 0, 4) #self.grid_buttons.setColumnStretch(1, 3) #self.grid_buttons.setRowStretch(1, 2) ### SUPERGRID ### self.supergrid = QGridLayout() self.supergrid.addLayout( self.grid_top, 0, 0) self.supergrid.addLayout( self.grid_buttons, 1, 0) self.supergrid.addLayout( self.grid_bottom, 2, 0) # Set layout and window title self.setLayout( self.supergrid ) self.setWindowTitle("Align to Active Brainstem Atlas - Aligning Slices Page") # Update interactive windows self.updateFields() # Center the GUI self.center() def updateFields(self): # Set stack-specific variables try: self.stain = self.sqlController.histology.counterstain # Check the brains_info/STACK_progress.ini file for which step we're on self.curr_step = self.sqlController.get_current_step_from_progress_ini(self.stack) # Disable all grid buttons except for the one corresponding to our current step self.format_grid_buttons() # If there are no stacks/brains that have been started except KeyError: for grid_button in [self.b_1]: format_grid_button_cantStart( grid_button ) def format_grid_buttons(self): """ Locates where you are in the pipeline by reading the brains_info/STACK_progress.ini Buttons corresponding to previous steps are marked as "completed", buttons corresponding to future steps are marked as "unpressable" and are grayed out. """ curr_step = self.curr_step if '2_align' in curr_step: active_button = self.b_1 else: active_button = None print(curr_step) passed_curr_step = False for grid_button in [self.b_1]: if not passed_curr_step and grid_button != active_button: format_grid_button_completed( grid_button ) elif grid_button == active_button: passed_curr_step = True format_grid_button_initial(active_button) elif passed_curr_step and grid_button != active_button: format_grid_button_cantStart( grid_button ) def button_grid_push(self, button): """ If any of the "grid" buttons are pressed, this is the callback function. In this case, "grid" buttons have a one-to_one correspondance to the steps in the pipeline. The completion of each step means you move onto the next one. """ # Alignment Correction GUI if button == self.b_1: subprocess.call(['python','a_GUI_correct_alignments.py', self.stack]) self.sqlController.set_step_completed_in_progress_ini(self.stack, '2_align') self.updateFields() def button_push(self, button): """ Secondary button callback function """ if button == self.b_exit: sys.exit( app.exec_() ) def center(self): """ This function simply aligns the GUI to the center of your monitor. """ frameGm = self.frameGeometry() screen = QApplication.desktop().screenNumber( QApplication.desktop().cursor().pos()) centerPoint = QApplication.desktop().screenGeometry(screen).center() frameGm.moveCenter(centerPoint) self.move(frameGm.topLeft()) def closeEvent(self, event): sys.exit( app.exec_() )
class init_GUI(QWidget): def __init__(self, parent=None): super(init_GUI, self).__init__(parent) self.font1 = QFont("Arial", 16) self.font2 = QFont("Arial", 12) self.stack = stack self.fileLocationManager = FileLocationManager(self.stack) self.sqlController = SqlController() self.sqlController.get_animal_info(self.stack) self.stain = self.sqlController.histology.counterstain self.curr_step = self.sqlController.get_current_step_from_progress_ini( self.stack) self.initUI() def initUI(self): # Set Layout and Geometry of Window self.grid_top = QGridLayout() self.grid_buttons = QGridLayout() self.grid_bottom = QGridLayout() #self.setFixedSize(1000, 450) self.resize(1000, 450) ### Grid Top (1 row) ### # Static Text Field self.e1 = QLineEdit() self.e1.setValidator(QIntValidator()) self.e1.setAlignment(Qt.AlignCenter) self.e1.setFont(self.font1) self.e1.setReadOnly(True) self.e1.setText("Global Atlas Fit Step: Main Page") self.e1.setFrame(False) self.grid_top.addWidget(self.e1, 0, 0) ### Grid Buttons ### # Button self.b_1 = QPushButton("1) Select centers of 12N and 3N") format_grid_button_initial(self.b_1) self.b_1.clicked.connect(lambda: self.button_grid_push(self.b_1)) self.grid_buttons.addWidget(self.b_1, 0, 0) ### Grid Bottom ### # Button Text Field self.b_exit = QPushButton("Exit") self.b_exit.setDefault(True) self.b_exit.clicked.connect(lambda: self.button_push(self.b_exit)) self.grid_bottom.addWidget(self.b_exit, 0, 4) #self.grid_buttons.setColumnStretch(1, 3) #self.grid_buttons.setRowStretch(1, 2) ### SUPERGRID ### self.supergrid = QGridLayout() self.supergrid.addLayout(self.grid_top, 0, 0) self.supergrid.addLayout(self.grid_buttons, 1, 0) self.supergrid.addLayout(self.grid_bottom, 2, 0) # Set layout and window title self.setLayout(self.supergrid) self.setWindowTitle("Global Atlas fit") # Update interactive windows self.updateFields() # Center the GUI self.center() def updateFields(self): self.stain = self.sqlController.histology.counterstain try: self.curr_step = self.sqlController.get_current_step_from_progress_ini( self.stack) # Disable all grid buttons except for the one corresponding to our current step self.format_grid_buttons() # Disable all grid buttons except for the one corresponding to our current step self.format_grid_buttons() # If there are no stacks/brains that have been started except KeyError: for grid_button in [self.b_1]: format_grid_button_cantStart(grid_button) def format_grid_buttons(self): """ Locates where you are in the pipeline by reading the brains_info/STACK_progress.ini Buttons corresponding to previous steps are marked as "completed", buttons corresponding to future steps are marked as "unpressable" and are grayed out. """ curr_step = self.curr_step if '5_fit_atlas_global' in curr_step: active_button = self.b_1 else: active_button = None print(curr_step) passed_curr_step = False for grid_button in [self.b_1]: if not passed_curr_step and grid_button != active_button: format_grid_button_completed(grid_button) elif grid_button == active_button: passed_curr_step = True format_grid_button_initial(active_button) elif passed_curr_step and grid_button != active_button: format_grid_button_cantStart(grid_button) def button_grid_push(self, button): """ If any of the "grid" buttons are pressed, this is the callback function. In this case, "grid" buttons have a one-to_one correspondance to the steps in the pipeline. The completion of each step means you move onto the next one. """ # Alignment Correction GUI if button == self.b_1: subprocess.call( ['python', 'a_GUI_atlas_global_select_centers.py', self.stack]) """ TODO, fix this get_pipelinestatus progress = get_pipeline_status( self.stack ) if not progress=='a_script_preprocess_7': fp1 = os.path.join(os.environ['ROOT_DIR'], 'CSHL_simple_global_registration', self.stack+'_T_atlas_wrt_canonicalAtlasSpace_subject_wrt_wholebrain_atlasResol.txt') #fp2 = os.path.join(os.environ['ROOT_DIR'], 'CSHL_simple_global_registration', # self.stack+'_T_atlas_wrt_canonicalAtlasSpace_subject_wrt_wholebrain_atlasResol.bp') #fp2_v2 = os.path.join(os.environ['ROOT_DIR'], 'CSHL_simple_global_registration', # self.stack+'_T_atlas_wrt_canonicalAtlasSpace_subject_wrt_wholebrain_atlasResol.npy') if os.path.exists( fp1 ):# and ( os.path.exists( fp2 ) or os.path.exists( fp2_v2 ) ): set_step_completed_in_progress_ini( self.stack, '5_fit_atlas_global') """ self.updateFields() def button_push(self, button): """ Secondary button callback function """ if button == self.b_exit: sys.exit(app.exec_()) def center(self): """ This function simply aligns the GUI to the center of your monitor. """ frameGm = self.frameGeometry() screen = QApplication.desktop().screenNumber( QApplication.desktop().cursor().pos()) centerPoint = QApplication.desktop().screenGeometry(screen).center() frameGm.moveCenter(centerPoint) self.move(frameGm.topLeft()) def closeEvent(self, event): sys.exit(app.exec_())