def __init__(self, defaultFilename=None): super(MainWindow, self).__init__() self.setWindowTitle(__appname__) # Save as Pascal voc xml self.defaultSaveDir = None self.usingPascalVocFormat = True if self.usingPascalVocFormat: LabelFile.suffix = '.xml' # For loading all image under a directory self.mImgList = [] self.dirname = None self.labelHist = [] self.lastOpenDir = None # Whether we need to save or not. self.dirty = False # Enble auto saving if pressing next self.autoSaving = True self._noSelectionSlot = False self._beginner = True self.screencastViewer = "firefox" self.screencast = "https://youtu.be/p0nR2YsCY_U" self.loadPredefinedClasses() # Main widgets and related state. self.labelDialog = LabelDialog(parent=self, listItem=self.labelHist) self.labelList = QListWidget() self.itemsToShapes = {} self.shapesToItems = {} self.labelList.itemActivated.connect(self.labelSelectionChanged) self.labelList.itemSelectionChanged.connect(self.labelSelectionChanged) self.labelList.itemDoubleClicked.connect(self.editLabel) # Connect to itemChanged to detect checkbox changes. self.labelList.itemChanged.connect(self.labelItemChanged) listLayout = QVBoxLayout() listLayout.setContentsMargins(0, 0, 0, 0) listLayout.addWidget(self.labelList) self.editButton = QToolButton() self.editButton.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) self.labelListContainer = QWidget() self.labelListContainer.setLayout(listLayout) listLayout.addWidget(self.editButton) #, 0, Qt.AlignCenter) listLayout.addWidget(self.labelList) self.dock = QDockWidget(u'Box Labels', self) self.dock.setObjectName(u'Labels') self.dock.setWidget(self.labelListContainer) # Tzutalin 20160906 : Add file list and dock to move faster self.fileListWidget = QListWidget() self.fileListWidget.itemDoubleClicked.connect( self.fileitemDoubleClicked) filelistLayout = QVBoxLayout() filelistLayout.setContentsMargins(0, 0, 0, 0) filelistLayout.addWidget(self.fileListWidget) self.fileListContainer = QWidget() self.fileListContainer.setLayout(filelistLayout) self.filedock = QDockWidget(u'File List', self) self.filedock.setObjectName(u'Files') self.filedock.setWidget(self.fileListContainer) self.zoomWidget = ZoomWidget() self.colorDialog = ColorDialog(parent=self) self.canvas = Canvas() self.canvas.zoomRequest.connect(self.zoomRequest) scroll = QScrollArea() scroll.setWidget(self.canvas) scroll.setWidgetResizable(True) self.scrollBars = { Qt.Vertical: scroll.verticalScrollBar(), Qt.Horizontal: scroll.horizontalScrollBar() } self.canvas.scrollRequest.connect(self.scrollRequest) self.canvas.newShape.connect(self.newShape) self.canvas.shapeMoved.connect(self.setDirty) self.canvas.selectionChanged.connect(self.shapeSelectionChanged) self.canvas.drawingPolygon.connect(self.toggleDrawingSensitive) self.setCentralWidget(scroll) self.addDockWidget(Qt.RightDockWidgetArea, self.dock) # Tzutalin 20160906 : Add file list and dock to move faster self.addDockWidget(Qt.RightDockWidgetArea, self.filedock) self.dockFeatures = QDockWidget.DockWidgetClosable\ | QDockWidget.DockWidgetFloatable self.dock.setFeatures(self.dock.features() ^ self.dockFeatures) # Actions action = partial(newAction, self) quit = action('&Quit', self.close, 'Ctrl+Q', 'quit', u'Quit application') open = action('&Open', self.openFile, 'Ctrl+O', 'open', u'Open image or label file') opendir = action('&Open Dir', self.openDir, 'Ctrl+u', 'open', u'Open Dir') changeSavedir = action('&Change default saved Annotation dir', self.changeSavedir, 'Ctrl+r', 'open', u'Change default saved Annotation dir') openAnnotation = action('&Open Annotation', self.openAnnotation, 'Ctrl+q', 'openAnnotation', u'Open Annotation') openNextImg = action('&Next Image', self.openNextImg, 'd', 'next', u'Open Next') openPrevImg = action('&Prev Image', self.openPrevImg, 'a', 'prev', u'Open Prev') save = action('&Save', self.saveFile, 'Ctrl+S', 'save', u'Save labels to file', enabled=False) saveAs = action('&Save As', self.saveFileAs, 'Ctrl+Shift+S', 'save-as', u'Save labels to a different file', enabled=False) close = action('&Close', self.closeFile, 'Ctrl+W', 'close', u'Close current file') color1 = action('Box &Line Color', self.chooseColor1, 'Ctrl+L', 'color_line', u'Choose Box line color') color2 = action('Box &Fill Color', self.chooseColor2, 'Ctrl+Shift+L', 'color', u'Choose Box fill color') createMode = action('Create\nRectBox', self.setCreateMode, 'Ctrl+N', 'new', u'Start drawing Boxs', enabled=False) editMode = action('&Edit\nRectBox', self.setEditMode, 'Ctrl+J', 'edit', u'Move and edit Boxs', enabled=False) create = action('Create\nRectBox', self.createShape, 'w', 'new', u'Draw a new Box', enabled=False) delete = action('Delete\nRectBox', self.deleteSelectedShape, 'Delete', 'delete', u'Delete', enabled=False) copy = action('&Duplicate\nRectBox', self.copySelectedShape, 'Ctrl+D', 'copy', u'Create a duplicate of the selected Box', enabled=False) advancedMode = action('&Advanced Mode', self.toggleAdvancedMode, 'Ctrl+Shift+A', 'expert', u'Switch to advanced mode', checkable=True) hideAll = action('&Hide\nRectBox', partial(self.togglePolygons, False), 'Ctrl+H', 'hide', u'Hide all Boxs', enabled=False) showAll = action('&Show\nRectBox', partial(self.togglePolygons, True), 'Ctrl+A', 'hide', u'Show all Boxs', enabled=False) help = action('&Tutorial', self.tutorial, 'Ctrl+T', 'help', u'Show demos') zoom = QWidgetAction(self) zoom.setDefaultWidget(self.zoomWidget) self.zoomWidget.setWhatsThis( u"Zoom in or out of the image. Also accessible with"\ " %s and %s from the canvas." % (fmtShortcut("Ctrl+[-+]"), fmtShortcut("Ctrl+Wheel"))) self.zoomWidget.setEnabled(False) zoomIn = action('Zoom &In', partial(self.addZoom, 10), 'Ctrl++', 'zoom-in', u'Increase zoom level', enabled=False) zoomOut = action('&Zoom Out', partial(self.addZoom, -10), 'Ctrl+-', 'zoom-out', u'Decrease zoom level', enabled=False) zoomOrg = action('&Original size', partial(self.setZoom, 100), 'Ctrl+=', 'zoom', u'Zoom to original size', enabled=False) fitWindow = action('&Fit Window', self.setFitWindow, 'Ctrl+F', 'fit-window', u'Zoom follows window size', checkable=True, enabled=False) fitWidth = action('Fit &Width', self.setFitWidth, 'Ctrl+Shift+F', 'fit-width', u'Zoom follows window width', checkable=True, enabled=False) # Group zoom controls into a list for easier toggling. zoomActions = (self.zoomWidget, zoomIn, zoomOut, zoomOrg, fitWindow, fitWidth) self.zoomMode = self.MANUAL_ZOOM self.scalers = { self.FIT_WINDOW: self.scaleFitWindow, self.FIT_WIDTH: self.scaleFitWidth, # Set to one to scale to 100% when loading files. self.MANUAL_ZOOM: lambda: 1, } edit = action('&Edit Label', self.editLabel, 'Ctrl+E', 'edit', u'Modify the label of the selected Box', enabled=False) self.editButton.setDefaultAction(edit) shapeLineColor = action( 'Shape &Line Color', self.chshapeLineColor, icon='color_line', tip=u'Change the line color for this specific shape', enabled=False) shapeFillColor = action( 'Shape &Fill Color', self.chshapeFillColor, icon='color', tip=u'Change the fill color for this specific shape', enabled=False) labels = self.dock.toggleViewAction() labels.setText('Show/Hide Label Panel') labels.setShortcut('Ctrl+Shift+L') # Lavel list context menu. labelMenu = QMenu() addActions(labelMenu, (edit, delete)) self.labelList.setContextMenuPolicy(Qt.CustomContextMenu) self.labelList.customContextMenuRequested.connect( self.popLabelListMenu) # Store actions for further handling. self.actions = struct( save=save, saveAs=saveAs, open=open, close=close, lineColor=color1, fillColor=color2, create=create, delete=delete, edit=edit, copy=copy, createMode=createMode, editMode=editMode, advancedMode=advancedMode, shapeLineColor=shapeLineColor, shapeFillColor=shapeFillColor, zoom=zoom, zoomIn=zoomIn, zoomOut=zoomOut, zoomOrg=zoomOrg, fitWindow=fitWindow, fitWidth=fitWidth, zoomActions=zoomActions, fileMenuActions=(open, opendir, save, saveAs, close, quit), beginner=(), advanced=(), editMenu=(edit, copy, delete, None, color1, color2), beginnerContext=(create, edit, copy, delete), advancedContext=(createMode, editMode, edit, copy, delete, shapeLineColor, shapeFillColor), onLoadActive=(close, create, createMode, editMode), onShapesPresent=(saveAs, hideAll, showAll)) self.menus = struct(file=self.menu('&File'), edit=self.menu('&Edit'), view=self.menu('&View'), help=self.menu('&Help'), recentFiles=QMenu('Open &Recent'), labelList=labelMenu) addActions(self.menus.file, (open, opendir, changeSavedir, openAnnotation, self.menus.recentFiles, save, saveAs, close, None, quit)) addActions(self.menus.help, (help, )) addActions(self.menus.view, (labels, advancedMode, None, hideAll, showAll, None, zoomIn, zoomOut, zoomOrg, None, fitWindow, fitWidth)) self.menus.file.aboutToShow.connect(self.updateFileMenu) # Custom context menu for the canvas widget: addActions(self.canvas.menus[0], self.actions.beginnerContext) addActions(self.canvas.menus[1], (action('&Copy here', self.copyShape), action('&Move here', self.moveShape))) self.tools = self.toolbar('Tools') self.actions.beginner = (open, opendir, openNextImg, openPrevImg, save, None, create, copy, delete, None, zoomIn, zoom, zoomOut, fitWindow, fitWidth) self.actions.advanced = (open, save, None, createMode, editMode, None, hideAll, showAll) self.statusBar().showMessage('%s started.' % __appname__) self.statusBar().show() # Application state. self.image = QImage() self.filePath = u(defaultFilename) self.recentFiles = [] self.maxRecent = 7 self.lineColor = None self.fillColor = None self.zoom_level = 100 self.fit_window = False # XXX: Could be completely declarative. # Restore application settings. if have_qstring(): types = { 'filename': QString, 'recentFiles': QStringList, 'window/size': QSize, 'window/position': QPoint, 'window/geometry': QByteArray, 'line/color': QColor, 'fill/color': QColor, 'advanced': bool, # Docks and toolbars: 'window/state': QByteArray, 'savedir': QString, 'lastOpenDir': QString, } else: types = { 'filename': str, 'recentFiles': list, 'window/size': QSize, 'window/position': QPoint, 'window/geometry': QByteArray, 'line/color': QColor, 'fill/color': QColor, 'advanced': bool, # Docks and toolbars: 'window/state': QByteArray, 'savedir': str, 'lastOpenDir': str, } self.settings = settings = Settings(types) self.recentFiles = list(settings.get('recentFiles', [])) size = settings.get('window/size', QSize(600, 500)) position = settings.get('window/position', QPoint(0, 0)) self.resize(size) self.move(position) saveDir = u(settings.get('savedir', None)) self.lastOpenDir = u(settings.get('lastOpenDir', None)) if os.path.exists(saveDir): self.defaultSaveDir = saveDir self.statusBar().showMessage( '%s started. Annotation will be saved to %s' % (__appname__, self.defaultSaveDir)) self.statusBar().show() # or simply: #self.restoreGeometry(settings['window/geometry'] self.restoreState(settings.get('window/state', QByteArray())) self.lineColor = QColor(settings.get('line/color', Shape.line_color)) self.fillColor = QColor(settings.get('fill/color', Shape.fill_color)) Shape.line_color = self.lineColor Shape.fill_color = self.fillColor def xbool(x): if isinstance(x, QVariant): return x.toBool() return bool(x) if xbool(settings.get('advanced', False)): self.actions.advancedMode.setChecked(True) self.toggleAdvancedMode() # Populate the File menu dynamically. self.updateFileMenu() # Since loading the file may take some time, make sure it runs in the background. self.queueEvent(partial(self.loadFile, self.filePath)) # Callbacks: self.zoomWidget.valueChanged.connect(self.paintCanvas) self.populateModeActions()
def __init__(self, defaultFilename=None): super().__init__() self.dirty = True self.mImgList = [] self.dirname = None self._beginner = True self.image_out_np = None self.default_save_dir = None # Application state self.filePath = None self.mattingFile = None listLayout = QVBoxLayout() listLayout.setContentsMargins(0, 0, 0, 0) matResultShow = ResizedQWidget() matResultShow.resize(697, 800) self.pic = QLabel(matResultShow) self.pic.resize(697, 800) self.pic.setGeometry(0, 0, 697, 800) self.edit = True self.bgd = True self.slic = None # self.pic.resize(matResultShow.width(), matResultShow.height()) # self.pic.setScaledContents(True) matResultShow.setLayout(listLayout) self.resultdock = QDockWidget('Result Image', self) # self.resultdock.adjustSize() self.resultdock.setObjectName('result') self.resultdock.setWidget(matResultShow) self.resultdock.resize(697, 800) self.fileListWidget = QListWidget() self.fileListWidget.itemDoubleClicked.connect( self.fileitemDoubleClicked) fileListLayout = QVBoxLayout() fileListLayout.setContentsMargins(0, 0, 0, 0) fileListLayout.addWidget(self.fileListWidget) fileListContainer = QWidget() fileListContainer.setLayout(fileListLayout) self.filedock = QDockWidget('File List', self) self.filedock.setObjectName('Files') self.filedock.setWidget(fileListContainer) self.zoomWidget = ZoomWidget() self.canvas = Canvas() scroll = QScrollArea() scroll.setWidget(self.canvas) scroll.setWidgetResizable(True) self.scrollBars = { Qt.Vertical: scroll.verticalScrollBar(), Qt.Horizontal: scroll.horizontalScrollBar() } self.scrollArea = scroll self.canvas.scrollRequest.connect(self.scrollRequest) self.setCentralWidget(scroll) self.addDockWidget(Qt.RightDockWidgetArea, self.resultdock) self.addDockWidget(Qt.RightDockWidgetArea, self.filedock) self.filedock.setFeatures(QDockWidget.DockWidgetFloatable) self.dockFeatures = QDockWidget.DockWidgetClosable | QDockWidget.DockWidgetFloatable self.resultdock.setFeatures(self.resultdock.features() ^ self.dockFeatures) # Actions action = partial(newAction, self) open_file = action('&Open', self.openFile, 'Ctrl+O', 'Open image') open_dir = action('&Open Dir', self.openDir, 'Ctrl+D', 'Open image dir') change_save_dir = action('&Change Save Dir', self.changeSavedirDialog) # open_next_img = action('&Next Image', self.openNextImg, # 'Ctrl+N', 'Open next image') # open_pre_img = action('&Previous Image', self.openPreImg, # 'Ctrl+M', 'Open previous image') save = action('&Save', self.saveFile, 'Crl+S', 'Save output image') create = action('&Edit', self.createShape, 'w', 'Start to edit') matting = action('&GrabCut Matting', self.grabcutMatting, 'e', 'GrabcutMatting') slic = action('&SLIC Preprocessing', self.slicMatting, 's', 'SlicPreprocessing') slic_start = action('&Start SLIC Matting', self.startSlicMatting, 'm', 'startsSlicMatting') withdraw = action('&withdraw', self.withdraw, 'm', 'withdraw') repaint = action('&repaint', self.repaint, 'm', 'repaint') self.scalers = { self.FIT_WINDOW: self.scaleFitWindow, self.FIT_WIDTH: self.scaleFitWidth, # Set to one to scale to 100% when loading files. self.MANUAL_ZOOM: lambda: 1, } # store actions for further handling self.actions = struct( save=save, open_file=open_file, open_dir=open_dir, change_save_dir=change_save_dir, # open_next_img=open_next_img, open_pre_img=open_pre_img, create=create, matting=matting, slic=slic, slic_start=slic_start, withdraw=withdraw, repaint=repaint) # Auto saving: enable auto saving if pressing next # self.autoSaving = QAction('Auto Saving', self) # self.autoSaving.setCheckable(True) # self.autoSaving.setChecked() # set toolbar self.tools = self.toolbar('Tools') qw = QWidget() grid = QGridLayout() nr_superpixels = QLabel(u'K') grid.addWidget(nr_superpixels, 1, 0) self.nr_superpixelsEdit = QLineEdit() self.nr_superpixelsEdit.setText('400') grid.addWidget(self.nr_superpixelsEdit, 1, 1) nc = QLabel(u'm') grid.addWidget(nc, 2, 0) self.ncEdit = QLineEdit() self.ncEdit.setText('30') grid.addWidget(self.ncEdit, 2, 1) self.cr = QCheckBox('Create RectBox', self) self.cr.setFocusPolicy(Qt.NoFocus) self.cr.move(10, 10) self.cr.toggle() self.cr.stateChanged.connect(lambda: self.btnstate(self.cr)) grid.addWidget(self.cr, 3, 1) self.dg = QCheckBox('Draw GC_BGD', self) self.dg.setFocusPolicy(Qt.NoFocus) self.dg.move(10, 10) self.dg.toggle() self.dg.stateChanged.connect(lambda: self.btnstate(self.dg)) grid.addWidget(self.dg, 4, 1) qw.setLayout(grid) self.tools.addWidget(qw) self.actions.all = ( save, open_file, open_dir, change_save_dir, create, # open_pre_img, open_next_img, matting, slic, slic_start, withdraw, repaint) addActions(self.tools, self.actions.all) # set status self.statusBar().showMessage('{} started.'.format(__appname__)) self.showMaximized()
def __init__(self, defaultFilename=None): super().__init__() self.dirty = True self.mImgList = [] self.dirname = None self._beginner = True self.image_out_np = None self.default_save_dir = None # Application state self.filePath = None self.mattingFile = None listLayout = QVBoxLayout() listLayout.setContentsMargins(0, 0, 0, 0) matResultShow = ResizedQWidget() matResultShow.resize(150, 150) self.pic = QLabel(matResultShow) self.pic.resize(150, 150) self.pic.setGeometry(50, 20, 150, 150) # self.pic.resize(matResultShow.width(), matResultShow.height()) # self.pic.setScaledContents(True) matResultShow.setLayout(listLayout) self.resultdock = QDockWidget('Result Image', self) # self.resultdock.adjustSize() self.resultdock.setObjectName('result') self.resultdock.setWidget(matResultShow) self.resultdock.resize(150, 150) self.fileListWidget = QListWidget() self.fileListWidget.itemDoubleClicked.connect( self.fileitemDoubleClicked) fileListLayout = QVBoxLayout() fileListLayout.setContentsMargins(0, 0, 0, 0) fileListLayout.addWidget(self.fileListWidget) fileListContainer = QWidget() fileListContainer.setLayout(fileListLayout) self.filedock = QDockWidget('File List', self) self.filedock.setObjectName('Files') self.filedock.setWidget(fileListContainer) self.zoomWidget = ZoomWidget() self.canvas = Canvas(parent=self) scroll = QScrollArea() scroll.setWidget(self.canvas) scroll.setWidgetResizable(True) self.scrollBars = { Qt.Vertical: scroll.verticalScrollBar(), Qt.Horizontal: scroll.horizontalScrollBar() } self.scrollArea = scroll self.canvas.scrollRequest.connect(self.scrollRequest) self.setCentralWidget(scroll) self.addDockWidget(Qt.RightDockWidgetArea, self.resultdock) self.addDockWidget(Qt.RightDockWidgetArea, self.filedock) self.filedock.setFeatures(QDockWidget.DockWidgetFloatable) self.dockFeatures = QDockWidget.DockWidgetClosable | QDockWidget.DockWidgetFloatable self.resultdock.setFeatures( self.resultdock.features() ^ self.dockFeatures) # Actions action = partial(newAction, self) open_file = action('&Open', self.openFile, 'Ctrl+O', 'Open image') open_dir = action('&Open Dir', self.openDir, 'Ctrl+D', 'Open image dir') change_save_dir = action('&Change Save Dir', self.changeSavedirDialog) # open_next_img = action('&Next Image', self.openNextImg, # 'Ctrl+N', 'Open next image') # open_pre_img = action('&Previous Image', self.openPreImg, # 'Ctrl+M', 'Open previous image') save = action('&Save', self.saveFile, 'Crl+S', 'Save output image') create = action('Create\nRectBox', self.createShape, 'w', 'Draw a new Box') matting = action('&Create\nMatting', self.grabcutMatting, 'e', 'GrabcutMatting') self.scalers = { self.FIT_WINDOW: self.scaleFitWindow, self.FIT_WIDTH: self.scaleFitWidth, # Set to one to scale to 100% when loading files. self.MANUAL_ZOOM: lambda: 1, } # store actions for further handling self.actions = struct(save=save, open_file=open_file, open_dir=open_dir, change_save_dir=change_save_dir, # open_next_img=open_next_img, open_pre_img=open_pre_img, create=create, matting=matting) # Auto saving: enable auto saving if pressing next # self.autoSaving = QAction('Auto Saving', self) # self.autoSaving.setCheckable(True) # self.autoSaving.setChecked() # set toolbar self.tools = self.toolbar('Tools') self.actions.all = (save, open_file, open_dir, change_save_dir, create, # open_pre_img, open_next_img, matting) addActions(self.tools, self.actions.all) # set status self.statusBar().showMessage('{} started.'.format(__appname__))
def __init__(self, filename=None, output=None): super(MainWindow, self).__init__() self.setWindowTitle(__appname__) # Whether we need to save or not. self.dirty = False self._noSelectionSlot = False self._beginner = True self.screencastViewer = "firefox" self.screencast = "screencast.ogv" # Main widgets and related state. self.labelDialog = LabelDialog(parent=self) self.labelList = QListWidget() self.itemsToShapes = [] self.labelList.itemActivated.connect(self.labelSelectionChanged) self.labelList.itemSelectionChanged.connect(self.labelSelectionChanged) self.labelList.itemDoubleClicked.connect(self.editLabel) # Connect to itemChanged to detect checkbox changes. self.labelList.itemChanged.connect(self.labelItemChanged) listLayout = QVBoxLayout() listLayout.setContentsMargins(0, 0, 0, 0) listLayout.addWidget(self.labelList) self.editButton = QToolButton() self.editButton.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) self.labelListContainer = QWidget() self.labelListContainer.setLayout(listLayout) listLayout.addWidget(self.editButton)#, 0, Qt.AlignCenter) listLayout.addWidget(self.labelList) #define table view self.table_view = QTableView(self) self.table_view.setSelectionBehavior(QAbstractItemView.SelectRows) self.table_view.show() self.table_view.doubleClicked.connect(self.openCurrentData) listLayout.addWidget(self.table_view) self.dock = QDockWidget('Polygon Labels', self) self.dock.setObjectName('Labels') self.dock.setWidget(self.labelListContainer) #self.dock.setWidget(self.infoLayout) self.zoomWidget = ZoomWidget() self.colorDialog = ColorDialog(parent=self) self.canvas = Canvas() self.canvas.zoomRequest.connect(self.zoomRequest) scroll = QScrollArea() scroll.setWidget(self.canvas) scroll.setWidgetResizable(True) self.scrollBars = { Qt.Vertical: scroll.verticalScrollBar(), Qt.Horizontal: scroll.horizontalScrollBar() } self.canvas.scrollRequest.connect(self.scrollRequest) self.canvas.newShape.connect(self.newShape) self.canvas.shapeMoved.connect(self.setDirty) self.canvas.selectionChanged.connect(self.shapeSelectionChanged) self.canvas.drawingPolygon.connect(self.toggleDrawingSensitive) self.setCentralWidget(scroll) self.addDockWidget(Qt.RightDockWidgetArea, self.dock) self.dockFeatures = QDockWidget.DockWidgetClosable\ | QDockWidget.DockWidgetFloatable self.dock.setFeatures(self.dock.features() ^ self.dockFeatures) # Actions action = partial(newAction, self) quit = action('&Quit', self.close, 'Ctrl+Q', 'quit', 'Quit application') open = action('&Open', self.openFile, 'Ctrl+O', 'open', 'Open image or label file') save = action('&Save', self.saveFile, 'Ctrl+S', 'save', 'Save labels to file', enabled=False) saveAs = action('&Save As', self.saveFileAs, 'Ctrl+Shift+S', 'save-as', 'Save labels to a different file', enabled=False) close = action('&Close', self.closeFile, 'Ctrl+W', 'close', 'Close current file') color1 = action('Polygon &Line Color', self.chooseColor1, 'Ctrl+L', 'color_line', 'Choose polygon line color') color2 = action('Polygon &Fill Color', self.chooseColor2, 'Ctrl+Shift+L', 'color', 'Choose polygon fill color') createMode = action('Create\nPolygo&ns', self.setCreateMode, 'Ctrl+N', 'new', 'Start drawing polygons', enabled=False) editMode = action('&Edit\nPolygons', self.setEditMode, 'Ctrl+J', 'edit', 'Move and edit polygons', enabled=False) create = action('Create\nPolygo&n', self.createShape, 'Ctrl+N', 'new', 'Draw a new polygon', enabled=False) delete = action('Delete\nPolygon', self.deleteSelectedShape, 'Delete', 'delete', 'Delete', enabled=False) copy = action('&Duplicate\nPolygon', self.copySelectedShape, 'Ctrl+D', 'copy', 'Create a duplicate of the selected polygon', enabled=False) advancedMode = action('&Advanced Mode', self.toggleAdvancedMode, 'Ctrl+Shift+A', 'expert', 'Switch to advanced mode', checkable=True) hideAll = action('&Hide\nPolygons', partial(self.togglePolygons, False), 'Ctrl+H', 'hide', 'Hide all polygons', enabled=False) showAll = action('&Show\nPolygons', partial(self.togglePolygons, True), 'Ctrl+A', 'hide', 'Show all polygons', enabled=False) help = action('&Tutorial', self.tutorial, 'Ctrl+T', 'help', 'Show screencast of introductory tutorial') zoom = QWidgetAction(self) zoom.setDefaultWidget(self.zoomWidget) self.zoomWidget.setWhatsThis( "Zoom in or out of the image. Also accessible with"\ " %s and %s from the canvas." % (fmtShortcut("Ctrl+[-+]"), fmtShortcut("Ctrl+Wheel"))) self.zoomWidget.setEnabled(False) zoomIn = action('Zoom &In', partial(self.addZoom, 10), 'Ctrl++', 'zoom-in', 'Increase zoom level', enabled=False) zoomOut = action('&Zoom Out', partial(self.addZoom, -10), 'Ctrl+-', 'zoom-out', 'Decrease zoom level', enabled=False) zoomOrg = action('&Original size', partial(self.setZoom, 100), 'Ctrl+=', 'zoom', 'Zoom to original size', enabled=False) fitWindow = action('&Fit Window', self.setFitWindow, 'Ctrl+F', 'fit-window', 'Zoom follows window size', checkable=True, enabled=False) fitWidth = action('Fit &Width', self.setFitWidth, 'Ctrl+Shift+F', 'fit-width', 'Zoom follows window width', checkable=True, enabled=False) # Group zoom controls into a list for easier toggling. zoomActions = (self.zoomWidget, zoomIn, zoomOut, zoomOrg, fitWindow, fitWidth) self.zoomMode = self.MANUAL_ZOOM self.scalers = { self.FIT_WINDOW: self.scaleFitWindow, self.FIT_WIDTH: self.scaleFitWidth, # Set to one to scale to 100% when loading files. self.MANUAL_ZOOM: lambda: 1, } edit = action('&Edit Label', self.editLabel, 'Ctrl+E', 'edit', 'Modify the label of the selected polygon', enabled=False) self.editButton.setDefaultAction(edit) shapeLineColor = action('Shape &Line Color', self.chshapeLineColor, icon='color_line', tip='Change the line color for this specific shape', enabled=False) shapeFillColor = action('Shape &Fill Color', self.chshapeFillColor, icon='color', tip='Change the fill color for this specific shape', enabled=False) labels = self.dock.toggleViewAction() labels.setText('Show/Hide Label Panel') labels.setShortcut('Ctrl+Shift+L') # Lavel list context menu. labelMenu = QMenu() addActions(labelMenu, (edit, delete)) self.labelList.setContextMenuPolicy(Qt.CustomContextMenu) self.labelList.customContextMenuRequested.connect(self.popLabelListMenu) # Store actions for further handling. self.actions = struct(save=save, saveAs=saveAs, open=open, close=close, lineColor=color1, fillColor=color2, create=create, delete=delete, edit=edit, copy=copy, createMode=createMode, editMode=editMode, advancedMode=advancedMode, shapeLineColor=shapeLineColor, shapeFillColor=shapeFillColor, zoom=zoom, zoomIn=zoomIn, zoomOut=zoomOut, zoomOrg=zoomOrg, fitWindow=fitWindow, fitWidth=fitWidth, zoomActions=zoomActions, fileMenuActions=(open,save,saveAs,close,quit), beginner=(), advanced=(), editMenu=(edit, copy, delete, None, color1, color2), beginnerContext=(create, edit, copy, delete), advancedContext=(createMode, editMode, edit, copy, delete, shapeLineColor, shapeFillColor), onLoadActive=(close, create, createMode, editMode), onShapesPresent=(saveAs, hideAll, showAll)) self.menus = struct( file=self.menu('&File'), edit=self.menu('&Edit'), view=self.menu('&View'), help=self.menu('&Help'), recentFiles=QMenu('Open &Recent'), labelList=labelMenu) addActions(self.menus.file, (open, self.menus.recentFiles, save, saveAs, close, None, quit)) addActions(self.menus.help, (help,)) addActions(self.menus.view, ( labels, advancedMode, None, hideAll, showAll, None, zoomIn, zoomOut, zoomOrg, None, fitWindow, fitWidth)) self.menus.file.aboutToShow.connect(self.updateFileMenu) # Custom context menu for the canvas widget: addActions(self.canvas.menus[0], self.actions.beginnerContext) addActions(self.canvas.menus[1], ( action('&Copy here', self.copyShape), action('&Move here', self.moveShape))) self.tools = self.toolbar('Tools') self.actions.beginner = ( open, save, None, create, copy, delete, None, zoomIn, zoom, zoomOut, fitWindow, fitWidth) self.actions.advanced = ( open, save, None, createMode, editMode, None, hideAll, showAll) self.statusBar().showMessage('%s started.' % __appname__) self.statusBar().show() # Application state. self.image = QImage() self.filename = filename self.labeling_once = output is not None self.output = output self.recentFiles = [] self.maxRecent = 7 self.lineColor = None self.fillColor = None self.zoom_level = 100 self.fit_window = False # XXX: Could be completely declarative. # Restore application settings. self.settings = {} self.recentFiles = self.settings.get('recentFiles', []) size = self.settings.get('window/size', QSize(1000, 800)) position = self.settings.get('window/position', QPoint(0, 0)) self.resize(size) self.move(position) # or simply: #self.restoreGeometry(settings['window/geometry'] self.restoreState(self.settings.get('window/state', QByteArray())) self.lineColor = QColor(self.settings.get('line/color', Shape.line_color)) self.fillColor = QColor(self.settings.get('fill/color', Shape.fill_color)) Shape.line_color = self.lineColor Shape.fill_color = self.fillColor if self.settings.get('advanced', QVariant()): self.actions.advancedMode.setChecked(True) self.toggleAdvancedMode() # Populate the File menu dynamically. self.updateFileMenu() # Since loading the file may take some time, make sure it runs in the background. self.queueEvent(partial(self.loadFile, self.filename)) # Callbacks: self.zoomWidget.valueChanged.connect(self.paintCanvas) self.populateModeActions()