Example #1
0
    def __init__(self):
        super(MainWindow, self).__init__()
        self.ui = Ui_mainWindow()
        self.ui.setupUi(self)
        self.fill_list_view()
        self.ui.insert.clicked.connect(self.insert_line)
        self.ui.delete_2.clicked.connect(self.delete_selected)
        self.ui.update.clicked.connect(self.show_update_form)
        self.ui.update_button.clicked.connect(self.update_selected)

        # hide form for updating on start
        self.hide_update_form()
Example #2
0
    def __init__(self, parent=None, **kwargs):
        super(MainWindow, self).__init__(parent, **kwargs)
        QMainWindow.__init__(self)
        Ui_mainWindow.__init__(self)
        self.setupUi(self)

        # Thread Management
        self.thread = QThread()
        self.serial_connection = SerialThread(result=self.display)
        self.request_signal.connect(
            self.serial_connection.main_thread_function)
        self.thread.started.connect(self.serial_connection.start)
        self.serial_connection.moveToThread(self.thread)
        qApp.aboutToQuit.connect(self.thread.quit)
        self.thread.start()

        # UI initial values
        self.serial_port_path, self.serial_port_name = self.get_port()
        self.serial_port_QLineEdit.setText(self.serial_port_path)

        self.connect_pushButton.clicked.connect(self.start_thread)
Example #3
0
    def __init__(self):
        global pointWidth
        QtGui.QMainWindow.__init__(self)

        # Set up the user interface from Designer.
        self.ui = Ui_mainWindow()
        self.ui.setupUi(self)
        self.setCentralWidget(self.ui.scrollArea)
		
        self.pModeButtonGroup = QtGui.QButtonGroup(self)
        self.pModeButtonGroup.addButton(self.ui.dotClickButton)
        self.pModeButtonGroup.addButton(self.ui.dotDragButton)
		
        self.rModeButtonGroup = QtGui.QButtonGroup(self)
        self.rModeButtonGroup.addButton(self.ui.rectClickButton)
        self.rModeButtonGroup.addButton(self.ui.rectDragButton)
		
        self.toolButtonGroup = QtGui.QButtonGroup(self)
        self.toolButtonGroup.addButton(self.ui.dotButton)
        self.toolButtonGroup.addButton(self.ui.rectangleButton)
		
        self.undoStacks = []
        self.connectSignals()

        if currentTool=="point":
			self.ui.rectClickButton.hide()
			self.ui.rectDragButton.hide()
        else:
			self.ui.dotClickButton.hide()
			self.ui.dotDragButton.hide()
        
        self.ui.saveAction.setEnabled(False)

        self.dragIsActive = False
        self.drawingRectangle = False
        self.resizeReady = False
        self.resizeIsActive = False
        self.resizeType = ""
		
        self.ui.indicesAction.setChecked(indicesVisible)
        self.ui.pointsAction.setChecked(pointsVisible)
        self.ui.rectanglesAction.setChecked(rectanglesVisible)

            
        # Force pointwidth to be odd
        if pointWidth % 2 == 0:
            pointWidth += 1

        self.ui.zoomImage.paint = QtGui.QPainter()
        self.ui.zoomImage.pen = QtGui.QPen(penColor)
        self.ui.zoomImage.pen.setWidth(pointWidth*zoomAmount)
        self.ui.zoomImage.crossPen = QtGui.QPen(QtCore.Qt.black)
        self.ui.zoomImage.crossPen.setWidth(1)

        self.ui.image.paint = QtGui.QPainter()
        self.ui.image.pen = QtGui.QPen(penColor)
		
        self.rectPen = QtGui.QPen(penColor)
        self.rectPen.setDashPattern(dashPattern)
        #self.rectPen.setWidth(pointWidth-1)
        
        self.ui.coo = QtGui.QLabel()
        self.ui.statusBar.addPermanentWidget(self.ui.coo)
        self.ui.coord = QtGui.QLabel()
        self.ui.statusBar.addPermanentWidget(self.ui.coord)
        
        self.keyPressEvent = self.mainKeyPressEvent
        self.keyReleaseEvent = self.mainKeyReleaseEvent
        self.ui.zoomImage.paintEvent = self.zoomImagePaintEvent
        self.ui.image.paintEvent = self.imagePaintEvent
        self.ui.image.mousePressEvent = self.imageMousePressEvent
        self.ui.image.mouseReleaseEvent = self.imageMouseReleaseEvent
        self.ui.image.mouseMoveEvent = self.imageMouseMoveEvent
Example #4
0
class MainWindow(QtGui.QMainWindow):
    def __init__(self):
        global pointWidth
        QtGui.QMainWindow.__init__(self)

        # Set up the user interface from Designer.
        self.ui = Ui_mainWindow()
        self.ui.setupUi(self)
        self.setCentralWidget(self.ui.scrollArea)
		
        self.pModeButtonGroup = QtGui.QButtonGroup(self)
        self.pModeButtonGroup.addButton(self.ui.dotClickButton)
        self.pModeButtonGroup.addButton(self.ui.dotDragButton)
		
        self.rModeButtonGroup = QtGui.QButtonGroup(self)
        self.rModeButtonGroup.addButton(self.ui.rectClickButton)
        self.rModeButtonGroup.addButton(self.ui.rectDragButton)
		
        self.toolButtonGroup = QtGui.QButtonGroup(self)
        self.toolButtonGroup.addButton(self.ui.dotButton)
        self.toolButtonGroup.addButton(self.ui.rectangleButton)
		
        self.undoStacks = []
        self.connectSignals()

        if currentTool=="point":
			self.ui.rectClickButton.hide()
			self.ui.rectDragButton.hide()
        else:
			self.ui.dotClickButton.hide()
			self.ui.dotDragButton.hide()
        
        self.ui.saveAction.setEnabled(False)

        self.dragIsActive = False
        self.drawingRectangle = False
        self.resizeReady = False
        self.resizeIsActive = False
        self.resizeType = ""
		
        self.ui.indicesAction.setChecked(indicesVisible)
        self.ui.pointsAction.setChecked(pointsVisible)
        self.ui.rectanglesAction.setChecked(rectanglesVisible)

            
        # Force pointwidth to be odd
        if pointWidth % 2 == 0:
            pointWidth += 1

        self.ui.zoomImage.paint = QtGui.QPainter()
        self.ui.zoomImage.pen = QtGui.QPen(penColor)
        self.ui.zoomImage.pen.setWidth(pointWidth*zoomAmount)
        self.ui.zoomImage.crossPen = QtGui.QPen(QtCore.Qt.black)
        self.ui.zoomImage.crossPen.setWidth(1)

        self.ui.image.paint = QtGui.QPainter()
        self.ui.image.pen = QtGui.QPen(penColor)
		
        self.rectPen = QtGui.QPen(penColor)
        self.rectPen.setDashPattern(dashPattern)
        #self.rectPen.setWidth(pointWidth-1)
        
        self.ui.coo = QtGui.QLabel()
        self.ui.statusBar.addPermanentWidget(self.ui.coo)
        self.ui.coord = QtGui.QLabel()
        self.ui.statusBar.addPermanentWidget(self.ui.coord)
        
        self.keyPressEvent = self.mainKeyPressEvent
        self.keyReleaseEvent = self.mainKeyReleaseEvent
        self.ui.zoomImage.paintEvent = self.zoomImagePaintEvent
        self.ui.image.paintEvent = self.imagePaintEvent
        self.ui.image.mousePressEvent = self.imageMousePressEvent
        self.ui.image.mouseReleaseEvent = self.imageMouseReleaseEvent
        self.ui.image.mouseMoveEvent = self.imageMouseMoveEvent

    def mainKeyPressEvent(self, event):
        if event.key() == QtCore.Qt.Key_Shift and modes[currentTool] != "drag":
            if currentTool == "point":
                self.ui.dotDragButton.setChecked(True)
            if currentTool == "rectangle":
                self.ui.rectDragButton.setChecked(True)
            modes[currentTool] = "tempDrag"
            self.ui.image.setCursor(QtGui.QCursor(QtCore.Qt.SizeAllCursor))

    def mainKeyReleaseEvent(self, event):
        if event.key() == QtCore.Qt.Key_Shift and modes[currentTool]=="tempDrag":
            if self.ui.image.pixmap() and (currentTool == "point" or currentTool == "rectangle"):
				if (modes[currentTool] == "drag" or modes[currentTool] == "tempDrag") and self.dragIsActive:
					annotationChanged[currentIndex] = True
					self.ui.image.repaint()
					self.dragIsActive = False
            if currentTool == "point":
                self.ui.dotClickButton.setChecked(True)
            if currentTool == "rectangle":
                self.ui.rectClickButton.setChecked(True)
            self.ui.image.setCursor(QtGui.QCursor(QtCore.Qt.CrossCursor))

    def imageMouseMoveEvent(self, event):
        global zoomPoints, points, rectangles, currentIndex
        x,y = event.pos().x(),event.pos().y()
        if self.dragIsActive:
            if currentTool == "point":
				if 0 <= x < self.ui.image.width() and 0 <= y < self.ui.image.height():
					points[currentIndex][self.pointToDrag] = (x,y)
					self.ui.image.repaint()
            elif currentTool == "rectangle":
				(i,j,k,m) = self.beforeRect
				deltaX,deltaY = x-self.rectDragPoint.x(),y-self.rectDragPoint.y()
				newX,newY = i+deltaX, j+deltaY
				if 0 <= x < self.ui.image.width() and 0 <= y < self.ui.image.height() \
					and 0 <= newX < self.ui.image.width()-k and 0 <= newY < self.ui.image.height()-m:
						rectangles[currentIndex][self.rectToDrag] = (newX,newY,k,m)
						self.ui.image.repaint()
						
        elif self.resizeIsActive:
			(i,j,w,h) = rectangles[currentIndex][self.rectToResize]
			if self.resizeType == "upleft":
				deltaX,deltaY = x-i, y-j
				newX, newY = x,y
				newWidth, newHeight = w-deltaX,h-deltaY
				#rectangles[currentIndex][self.rectToResize] = (x,y,w-deltaX,h-deltaY)
			elif self.resizeType == "downleft":
				deltaX,deltaY = x-i, y-j-h
				newX, newY = i+deltaX, j
				newWidth, newHeight = w-deltaX,h+deltaY
				#rectangles[currentIndex][self.rectToResize] = (i+deltaX,j,w-deltaX,h+deltaY)
			elif self.resizeType == "upright":
				deltaX,deltaY = x-i-w, y-j
				newX, newY = i,j+deltaY
				newWidth, newHeight = w+deltaX,h-deltaY
				#rectangles[currentIndex][self.rectToResize] = (i,j+deltaY,w+deltaX,h-deltaY)
			elif self.resizeType == "downright":
				deltaX,deltaY = x-i-w, y-j-h
				newX, newY = i,j
				newWidth, newHeight = w+deltaX,h+deltaY
				#rectangles[currentIndex][self.rectToResize] = (i,j,w+deltaX,h+deltaY)
			elif self.resizeType == "left":
				deltaX = x-i
				newX, newY = i+deltaX,j
				newWidth, newHeight = w-deltaX,h
				#rectangles[currentIndex][self.rectToResize] = (i+deltaX,j,w-deltaX,h)
			elif self.resizeType == "right":
				deltaX = x-i-w
				newX, newY = i,j
				newWidth, newHeight = w+deltaX,h
				#rectangles[currentIndex][self.rectToResize] = (i,j,w+deltaX,h)
			elif self.resizeType == "up":
				deltaY = y-j
				newX, newY = i,j+deltaY
				newWidth, newHeight = w,h-deltaY
				#rectangles[currentIndex][self.rectToResize] = (i,j+deltaY,w,h-deltaY)
			elif self.resizeType == "down":
				deltaY = y-j-h
				newX, newY = i,j
				newWidth, newHeight = w,h+deltaY
				#rectangles[currentIndex][self.rectToResize] = (i,j,w,h+deltaY)
			#if newWidth < 0:
			#	newX -= newWidth
			#	newWidth = abs(newWidth)
			#if newHeight < 0:
			#	newY += newHeight
			#	newHeight = abs(newHeight)
			rectangles[currentIndex][self.rectToResize] = (newX,newY,newWidth,newHeight)
			self.ui.image.repaint()
						
        elif currentTool == "rectangle" and modes[currentTool] != "drag" and modes[currentTool] != "tempDrag":
			self.resizeReady = False
			for (i,j,k,m) in rectangles[currentIndex]:
				if abs(x-i)<=2:
					if abs(y-j)<=2:   #upper-left corner of rectangle
						self.ui.image.setCursor(QtGui.QCursor(QtCore.Qt.SizeFDiagCursor))
						self.resizeType = "upleft"
						self.rectToResize = rectangles[currentIndex].index((i,j,k,m))
						self.resizeReady = True
						break
					elif abs(y-j-m)<=2:   #lower-left corner of rectangle
						self.ui.image.setCursor(QtGui.QCursor(QtCore.Qt.SizeBDiagCursor))
						self.resizeType = "downleft"
						self.rectToResize = rectangles[currentIndex].index((i,j,k,m))
						self.resizeReady = True
						break
					elif -2<=y-j<=m+2:   #left side of rectangle
						self.ui.image.setCursor(QtGui.QCursor(QtCore.Qt.SizeHorCursor))
						self.resizeType = "left"
						self.rectToResize = rectangles[currentIndex].index((i,j,k,m))
						self.resizeReady = True
						break
				elif abs(x-i-k)<=2:
					if abs(y-j)<=2:   #upper-right corner of rectangle
						self.ui.image.setCursor(QtGui.QCursor(QtCore.Qt.SizeBDiagCursor))
						self.resizeType = "upright"
						self.rectToResize = rectangles[currentIndex].index((i,j,k,m))
						self.resizeReady = True
						break
					elif abs(y-j-m)<=2:   #lower-right corner of rectangle
						self.ui.image.setCursor(QtGui.QCursor(QtCore.Qt.SizeFDiagCursor))
						self.resizeType = "downright"
						self.rectToResize = rectangles[currentIndex].index((i,j,k,m))
						self.resizeReady = True
						break
					elif -2<=y-j<=m+2:   #right side of rectangle
						self.ui.image.setCursor(QtGui.QCursor(QtCore.Qt.SizeHorCursor))
						self.resizeType = "right"
						self.rectToResize = rectangles[currentIndex].index((i,j,k,m))
						self.resizeReady = True
						break
				elif abs(y-j)<=2 and -2<=x-i<=k+2:   #upper side of rectangle
					self.ui.image.setCursor(QtGui.QCursor(QtCore.Qt.SizeVerCursor))
					self.resizeType = "up"
					self.rectToResize = rectangles[currentIndex].index((i,j,k,m))
					self.resizeReady = True
					break
				elif abs(y-j-m)<=2 and -2<=x-i<=k+2:   #lower side of the rectangle
					self.ui.image.setCursor(QtGui.QCursor(QtCore.Qt.SizeVerCursor))
					self.resizeType = "down"
					self.rectToResize = rectangles[currentIndex].index((i,j,k,m))
					self.resizeReady = True
					break
			if not self.resizeReady:
				if self.ui.image.cursor().shape() != QtCore.Qt.CrossCursor:
					self.ui.image.setCursor(QtGui.QCursor(QtCore.Qt.CrossCursor))
				
        if self.ui.image.pixmap():
            height, width = self.ui.zoomImage.width(), self.ui.zoomImage.height()

            self.left, self.up = self.calculateZoomBorders(x,y)
  
            self.ui.coord.setText("(%d, %d)" % (x,y))
            if len(points[currentIndex]) > 0:
                del zoomPoints[:]
                for (i,j) in points[currentIndex]:
                    newX = zoomAmount * i - self.left
                    newY = zoomAmount * j - self.up
                    if 0 <= newX <= width and 0 <= newY <= height:
                        zoomPoints.append((newX, newY))
						
            if self.drawingRectangle:
				(x,y) = self.rectCoord
				(self.tempWidth, self.tempHeight) = ((event.pos().x() - x), (event.pos().y() - y))
				self.ui.image.repaint()
				self.updateZoomedImage(event.pos().x(),event.pos().y())
				self.ui.zoomImage.repaint()
            else:
				self.updateZoomedImage(x,y)

    def imageMousePressEvent(self, event):
        global zoomPoints, points, modes, currentTool, currentIndex
        x,y = event.pos().x(),event.pos().y()
        if self.ui.image.pixmap() and currentTool == "point":
            if modes["point"] == "click":
                #points[currentIndex].append((x,y))
                self.left, self.up = self.calculateZoomBorders(x,y)
                newX,newY = zoomAmount * x - self.left, zoomAmount * y - self.up
                zoomPoints.append((newX, newY))
				
                command = CommandAddPoint(currentIndex, (x,y), "Add Point @(%d-%d)" %(x,y))
                self.undoStacks[currentIndex].push(command)
                annotationChanged[currentIndex] = True
                
                self.ui.image.repaint()
                self.ui.zoomImage.repaint()
            elif modes["point"] == "drag" or modes["point"] == "tempDrag":
                self.dragIsActive = False
                for (i,j) in points[currentIndex]:
                    if abs(i-x) <= pointWidth and abs(j-y) <= pointWidth:
                        self.pointToDrag = points[currentIndex].index((i,j))
                        self.dragIsActive = True
                        self.beforePoint = (i,j)
                        self.afterPoint = (-1,-1)
						
        elif self.ui.image.pixmap() and currentTool == "rectangle":
			if modes["rectangle"] == "draw":
				if self.resizeReady:
					self.resizeIsActive = True
					self.beforeRect = rectangles[currentIndex][self.rectToResize]
				else:
					self.drawingRectangle = True
				self.rectCoord = (x,y)
			elif modes["rectangle"] == "drag" or modes["rectangle"] == "tempDrag":
				self.dragIsActive = False
				for (i,j,k,m) in rectangles[currentIndex]:
					if ((abs(x-i)<=2 or abs(x-i-k)<=2) and -2<=y-j<=m+2) or ((abs(y-j)<=2 or abs(y-j-m)<=2) and -2<=x-i<=k+2):
						#print "x:%d y:%d i:%d j:%d w:%d h:%d" % (x,y,i,j,k+i,m+j)
						self.rectToDrag = rectangles[currentIndex].index((i,j,k,m))
						self.rectDragPoint = event.pos()
						self.dragIsActive = True
						self.beforeRect = (i,j,k,m)
						self.afterRect = (-1,-1,-1,-1)

    def imageMouseReleaseEvent(self, event):
        global points, modes, currentTool, currentIndex
        if self.ui.image.pixmap() and currentTool == "point":
            if (modes["point"] == "drag" or modes["point"] == "tempDrag") and self.dragIsActive:
                annotationChanged[currentIndex] = True
                self.ui.image.repaint()
                self.dragIsActive = False
                if self.afterPoint == (-1,-1):
					self.afterPoint = (event.pos().x(),event.pos().y())
                command = CommandDragPoint(currentIndex, self.beforePoint, self.afterPoint, "Drag Point")
                self.undoStacks[currentIndex].push(command)
				
        elif self.ui.image.pixmap() and currentTool == "rectangle":
			if modes["rectangle"] == "draw":
				if self.resizeIsActive:
					(i,j,w,h) = rectangles[currentIndex][self.rectToResize]
					if w < 0:
						i += w
						w = abs(w)
					if h < 0:
						j += h
						h = abs(h)
					rectangles[currentIndex][self.rectToResize] = self.afterRect = (i,j,w,h)
					command = CommandResizeRect(currentIndex, self.beforeRect, self.afterRect, "Drag Rectangle")
					self.undoStacks[currentIndex].push(command)
					self.resizeIsActive = False
					annotationChanged[currentIndex] = True
					self.ui.image.repaint()
				else:
					(x,y) = self.rectCoord
					width, height = (event.pos().x() - x), (event.pos().y() - y)
					if width != 0 and height != 0:	
						if width < 0:
							width = abs(width)
							x = event.pos().x()
						if height < 0:
							height = abs(height)
							y = event.pos().y()
						command = CommandAddRect(currentIndex, (x,y,width,height), "Add Rectangle @(%d-%d-%d-%d)" %(x,y,width,height))
						self.undoStacks[currentIndex].push(command)
						annotationChanged[currentIndex] = True
					if self.drawingRectangle:
						self.drawingRectangle = False
						self.ui.image.repaint()
			if (modes["rectangle"] == "drag" or modes["rectangle"] == "tempDrag") and self.dragIsActive:
				annotationChanged[currentIndex] = True
				self.ui.image.repaint()
				self.dragIsActive = False
				if self.afterRect == (-1,-1,-1,-1):
					(i,j,k,m) = self.beforeRect
					deltaX,deltaY = event.pos().x()-self.rectDragPoint.x(),event.pos().y()-self.rectDragPoint.y()
					self.afterRect = (i+deltaX,j+deltaY,k,m)
				command = CommandDragRect(currentIndex, self.beforeRect, self.afterRect, "Drag Rectangle")
				self.undoStacks[currentIndex].push(command)
				

    def zoomImagePaintEvent(self, event):
        global zoomAmount, zoomPoints, pointWidth
        if self.ui.zoomImage.pixmap():
            self.ui.zoomImage.paint.begin(self.ui.zoomImage)
            self.ui.zoomImage.paint.setPen(self.ui.zoomImage.pen)
            self.ui.zoomImage.paint.drawImage(self.ui.zoomImage.rect(), QtGui.QImage(self.ui.zoomImage.pixmap()))
            self.ui.zoomImage.paint.setPen(self.ui.image.pen)
            if pointsVisible and len(zoomPoints) > 0:
                for (i,j) in zoomPoints:
                    if useSmartColor:
                        r,g,b = getSmartColor(currentImage.getpixel(((i+self.left)/zoomAmount,(j+self.up)/zoomAmount)))
                        self.ui.zoomImage.paint.setPen(QtGui.QPen(QtGui.QColor(r,g,b), pointWidth*3))

                    self.ui.zoomImage.paint.drawPoint(i,j)
                    if indicesVisible:
                        try:
                            index = -1
                            for k, p in enumerate(points[currentIndex]):
                                dx = p[0] - (i+self.left)/zoomAmount
                                dy = p[1] - (j+self.up)/zoomAmount 
                                if abs(dx) < 0.1 and abs(dy) < 0.1:
                                    index = k
                            if index > -1:
                                self.ui.zoomImage.paint.drawText(i+3,j-3, QtCore.QString.number(index))
                        except ValueError:
                            pass
                            
            self.ui.zoomImage.paint.setPen(self.ui.zoomImage.crossPen)
            self.ui.zoomImage.paint.drawLine(0, self.ui.zoomImage.height()/2, self.ui.zoomImage.width(), self.ui.zoomImage.height()/2)
            self.ui.zoomImage.paint.drawLine(self.ui.zoomImage.width()/2, 0, self.ui.zoomImage.width()/2, self.ui.zoomImage.height())
            self.ui.zoomImage.paint.drawEllipse(self.ui.zoomImage.width()/2-15,self.ui.zoomImage.height()/2-15,30,30)
            self.ui.zoomImage.paint.end()
        
    def imagePaintEvent(self, event):
        global points, currentIndex, currentImage
        if self.ui.image.pixmap():
            if len(annotationChanged) and annotationChanged[currentIndex]:
            	self.setWindowTitle("%s* (%s) - pilab-annotator" % (self.ui.imageComboBox.currentText(), path))
            elif len(annotationChanged) and not annotationChanged[currentIndex]:
            	self.setWindowTitle("%s (%s) - pilab-annotator" % (self.ui.imageComboBox.currentText(), path))
            self.ui.image.pen.setWidth(pointWidth)
            self.ui.image.paint.begin(self.ui.image)
            self.ui.image.paint.setPen(self.ui.image.pen)
            self.ui.image.paint.drawImage(self.ui.image.rect(), QtGui.QImage(self.ui.image.pixmap()))
            #print points
            if pointsVisible and len(points[currentIndex]) > 0:
                for (i,j) in points[currentIndex]:
                    if useSmartColor:
                        r,g,b = getSmartColor(currentImage.getpixel((i,j)))
                        self.ui.image.paint.setPen(QtGui.QPen(QtGui.QColor(r,g,b), pointWidth))
                        
                    self.ui.image.paint.drawPoint(i,j)
                    # if indicesVisible:
                        # self.ui.image.paint.drawText(i+4,j-4, QtCore.QString.number(points[currentIndex].index((i,j))))
            if self.drawingRectangle:
				self.ui.image.paint.setPen(self.rectPen)
				(x,y) = self.rectCoord
				self.ui.image.paint.drawRect(x,y,self.tempWidth,self.tempHeight)
            if rectanglesVisible and len(rectangles)>0:
				for index,(i,j,k,m) in enumerate(rectangles[currentIndex]):
					self.ui.image.paint.setPen(self.rectPen)
					self.ui.image.paint.drawRect(i,j,k,m)
					self.ui.image.paint.drawText(i+3,j+12, QtCore.QString.number(index))
            self.ui.image.paint.end()
			
    def closeEvent(self, event):
		saveAll = False
		for i in range(self.ui.imageComboBox.count()):
			if annotationChanged[i]:
				self.ui.imageComboBox.setCurrentIndex(i)
				if saveAll:
					self.saveAnnotations()
					event.accept()
				else:					
					quit_msg = "Save changes to the annotation file of \"%s\"?" % self.ui.imageComboBox.itemText(i)
					reply = QtGui.QMessageBox.question(self, 'Quit', quit_msg, QtGui.QMessageBox.Save | 
														QtGui.QMessageBox.SaveAll | QtGui.QMessageBox.Discard |
														QtGui.QMessageBox.Cancel)
					if reply == QtGui.QMessageBox.Save:
						self.saveAnnotations()
						event.accept()
					elif reply == QtGui.QMessageBox.SaveAll:
						saveAll = True
						self.saveAnnotations()
						event.accept()
					elif reply == QtGui.QMessageBox.Cancel:
						event.ignore()
						break
				
		#quit_msg = "Are you sure you want to exit the program?"
		#reply = QtGui.QMessageBox.question(self, 'Message', quit_msg, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)

		#if reply == QtGui.QMessageBox.Yes:
		#	event.accept()
		#else:
		#	event.ignore()

    def connectSignals(self):
        self.connect(self.ui.toolboxAction, QtCore.SIGNAL("triggered(bool)"), 
                             self.ui.toolBox, QtCore.SLOT("setVisible(bool)"))
        self.connect(self.ui.toolBox, QtCore.SIGNAL("visibilityChanged(bool)"), 
                             self.ui.toolboxAction, QtCore.SLOT("setChecked(bool)"))
        self.connect(self.ui.optionsAction, QtCore.SIGNAL("triggered(bool)"), 
                             self.ui.optionBox, QtCore.SLOT("setVisible(bool)"))
        self.connect(self.ui.optionBox, QtCore.SIGNAL("visibilityChanged(bool)"), 
                             self.ui.optionsAction, QtCore.SLOT("setChecked(bool)"))
        self.connect(self.ui.zoomAction, QtCore.SIGNAL("triggered(bool)"),
                             self.ui.zoomBox, QtCore.SLOT("setVisible(bool)"))
        self.connect(self.ui.zoomBox, QtCore.SIGNAL("visibilityChanged(bool)"), 
                             self.ui.zoomAction, QtCore.SLOT("setChecked(bool)"))
        self.connect(self.ui.navigationAction, QtCore.SIGNAL("triggered(bool)"), 
                             self.ui.navigationBox, QtCore.SLOT("setVisible(bool)"))
        self.connect(self.ui.navigationBox, QtCore.SIGNAL("visibilityChanged(bool)"), 
                             self.ui.navigationAction, QtCore.SLOT("setChecked(bool)"))

        self.connect(self.ui.indicesAction, QtCore.SIGNAL("triggered(bool)"), self.showIndices)
        self.connect(self.ui.pointsAction, QtCore.SIGNAL("triggered(bool)"), self.showPoints)
        self.connect(self.ui.rectanglesAction, QtCore.SIGNAL("triggered(bool)"), self.showRectangles)
        self.connect(self.ui.openAction, QtCore.SIGNAL("triggered()"), self.openImageDirectory)
        self.connect(self.ui.saveAction, QtCore.SIGNAL("triggered()"), self.saveAnnotations)
        self.connect(self.ui.imageComboBox, QtCore.SIGNAL("currentIndexChanged(QString)"), self.changeImage)
        self.connect(self.ui.prevButton, QtCore.SIGNAL("clicked()"), self.previousImage)
        self.connect(self.ui.nextButton, QtCore.SIGNAL("clicked()"), self.nextImage)
        self.connect(self.ui.plusTenButton, QtCore.SIGNAL("clicked()"), self.plusTenImage)
        self.connect(self.ui.minusTenButton, QtCore.SIGNAL("clicked()"), self.minusTenImage)
        self.connect(self.ui.firstButton, QtCore.SIGNAL("clicked()"), self.firstImage)
        self.connect(self.ui.lastButton, QtCore.SIGNAL("clicked()"), self.lastImage)
        self.connect(self.ui.dotButton, QtCore.SIGNAL("toggled(bool)"), self.handleDotButton)
        self.connect(self.ui.rectangleButton, QtCore.SIGNAL("toggled(bool)"), self.handleRectButton)
        self.connect(self.ui.dotClickButton, QtCore.SIGNAL("toggled(bool)"), self.handleDotClickButton)
        self.connect(self.ui.dotDragButton, QtCore.SIGNAL("toggled(bool)"), self.handleDotDragButton)
        self.connect(self.ui.rectClickButton, QtCore.SIGNAL("toggled(bool)"), self.handleRectClickButton)
        self.connect(self.ui.rectDragButton, QtCore.SIGNAL("toggled(bool)"), self.handleRectDragButton)
        self.connect(self.ui.undoButton, QtCore.SIGNAL("clicked()"), self.undo)
        self.connect(self.ui.redoButton, QtCore.SIGNAL("clicked()"), self.redo)
        self.connect(self.ui.undoAction, QtCore.SIGNAL("triggered()"), self.undo)
        self.connect(self.ui.redoAction, QtCore.SIGNAL("triggered()"), self.redo)

    def previousImage(self):
        global zoomPoints
        index = self.ui.imageComboBox.currentIndex() - 1
        if index < 0:
            index = 0
        self.ui.imageComboBox.setCurrentIndex(index)
        zoomPoints = []
        self.ui.image.repaint()
        self.ui.zoomImage.repaint()
    def nextImage(self):
        global zoomPoints
        index = self.ui.imageComboBox.currentIndex() + 1
        if index >= self.ui.imageComboBox.count():
            index = self.ui.imageComboBox.count() - 1
        self.ui.imageComboBox.setCurrentIndex(index)
        zoomPoints = []
        self.ui.image.repaint()
        self.ui.zoomImage.repaint()
    def plusTenImage(self):
        global zoomPoints
        index = self.ui.imageComboBox.currentIndex() + 10
        if index >= self.ui.imageComboBox.count():
            index = self.ui.imageComboBox.count() - 1
        self.ui.imageComboBox.setCurrentIndex(index)
        zoomPoints = []
        self.ui.image.repaint()
        self.ui.zoomImage.repaint()
    def minusTenImage(self):
        global zoomPoints
        index = self.ui.imageComboBox.currentIndex() - 10
        if index < 0:
            index = 0
        self.ui.imageComboBox.setCurrentIndex(index)
        zoomPoints = []
        self.ui.image.repaint()
        self.ui.zoomImage.repaint()
    def lastImage(self):
        global zoomPoints
        self.ui.imageComboBox.setCurrentIndex(self.ui.imageComboBox.count() - 1)
        zoomPoints = []
        self.ui.image.repaint()
        self.ui.zoomImage.repaint()
    def firstImage(self):
        global zoomPoints
        self.ui.imageComboBox.setCurrentIndex(0)
        zoomPoints = []
        self.ui.image.repaint()
        self.ui.zoomImage.repaint()

    def openImageDirectory(self, imagePath=None):
        global path
        global points, rectangles, annotationChanged
        if imagePath:
            path = imagePath
        else:  
            path = str(QtGui.QFileDialog.getExistingDirectory(self, "Open directory", "."))
        if path:
            try:
                allFiles = os.listdir(path)
                imageFiles = sorted([x for x in allFiles if os.path.splitext(x)[-1] in extensions])        
                self.ui.imageComboBox.clear()
                points = []
                rectangles = []
                annotationChanged = []
                self.undoStacks = []
                self.ui.coord.setText("")
                if len(imageFiles) > 0:
                    for imageFile in imageFiles:
						objects = []
						try:
							annotationFile = os.path.join(path, os.path.splitext(imageFile)[0] + ".xml") # @TODO: hardcoded extension!
							xmldoc = minidom.parse(annotationFile)
							objects = xmldoc.getElementsByTagName("objects")			
						except:
							points.append([])
							rectangles.append([])
						else:
							pts = []
							rects = []
							pointsOK = True
							rectsOK = True

							for object in objects:
								lines = object.childNodes[1].data.splitlines()
								if object.attributes["type"].value == "points":
									try:
										for line in lines:
											(x,y) = line.split(' ')
											pts.append((int(x), int(y)))
									except:
										points.append([])
										pointsOK = False
								elif object.attributes["type"].value == "rectangles":
									try:
										for line in lines:
											(x,y,z,t) = line.split(' ')   # @TODO: uncomment when rectangle is implemented
											rects.append((int(x), int(y), int(z), int(t)))	
									except:
										rectangles.append([])
										rectsOK = False
							if pointsOK:
								points.append(pts)
							if rectsOK:
								rectangles.append(rects)

						undoRedoStatus.append([False,False])
						annotationChanged.append(False)
						self.stack = QtGui.QUndoStack(self)
						self.undoStacks.append(self.stack)

                        #self.connect(self.undoStacks[-1], QtCore.SIGNAL("indexChanged(int)"), self.ui.image, QtCore.SLOT("repaint()"))
						self.connect(self.undoStacks[-1], QtCore.SIGNAL("indexChanged(int)"), self.ui.zoomImage, QtCore.SLOT("repaint()"))
						self.connect(self.undoStacks[-1], QtCore.SIGNAL("canUndoChanged(bool)"), self.undoChange)
						self.connect(self.undoStacks[-1], QtCore.SIGNAL("canRedoChanged(bool)"), self.redoChange)
                        #self.connect(self.undoStacks[-1], QtCore.SIGNAL("canUndoChanged(bool)"), self.ui.undoAction.setEnabled)
                        #self.connect(self.undoStacks[-1], QtCore.SIGNAL("canRedoChanged(bool)"), self.ui.redoAction.setEnabled)
                            
                    self.ui.imageComboBox.addItems(imageFiles)
                    # self.loadImage("%s/%s" % (path, self.ui.imageComboBox.currentText()))
                    self.setWindowTitle("%s (%s) - pilab-annotator" % (self.ui.imageComboBox.currentText(), path))
                    self.ui.saveAction.setEnabled(True)
                else:
                    self.ui.statusBar.showMessage("No image found in the directory.", warningTimeout)
                    self.setWindowTitle("pilab-annotator")
            except OSError:
                self.ui.statusBar.showMessage(OSError, warningTimeout)
        

    def saveAnnotations(self):
        "Currently supports only saving xml files"
        global points, path, lastSavedState, annotationChanged
        filename = os.path.splitext(str(self.ui.imageComboBox.currentText()))[0]
        filePath = os.path.join(str(path), str(filename) + ".xml")
        currentIndex = self.ui.imageComboBox.currentIndex()
        lastSavedState = self.undoStacks[currentIndex].index()
        annotationChanged[currentIndex] = False
       
        doc = Document()
        
        annotation = doc.createElement("annotation")
        doc.appendChild(annotation)
		
        objects = doc.createElement("objects")
        objects.setAttribute("type", "points")
        objects.setAttribute("count", "%.0f" % len(points[currentIndex]))
        annotation.appendChild(objects)
		
        text = ""
        for (x,y) in points[currentIndex]:
            text += "%.0f %.0f\n" % (x,y)
        if text == "":
			text = "\n"
        cDataSection = doc.createCDATASection(text)
        objects.appendChild(cDataSection)

        objects = doc.createElement("objects")
        objects.setAttribute("type", "rectangles")
        objects.setAttribute("count", "%.0f" % len(rectangles[currentIndex]))
        annotation.appendChild(objects)
		
        text = ""
        for (x,y,w,h) in rectangles[currentIndex]:
            text += "%.0f %.0f %.0f %.0f\n" % (x,y,w,h)
        if text == "":
			text = "\n"
        cDataSection = doc.createCDATASection(text)
        objects.appendChild(cDataSection)

        f = open(filePath, 'w')
        f.write(doc.toprettyxml(indent="  ", encoding="UTF-8"))
        f.close()
        
        self.ui.statusBar.showMessage("File saved to %s" % (filePath))
        self.setWindowTitle("%s (%s) - pilab-annotator" % (self.ui.imageComboBox.currentText(), path))
        
    def updateZoomedImage(self, x, y):
        width = self.ui.zoomImage.width()
        height =  width = self.ui.zoomImage.height()
        x,y = self.calculateZoomBorders(x,y)
        myPixmap = self.zoomedPixmap.copy(x, y, width, height)
        self.ui.zoomImage.setPixmap(myPixmap)
        self.ui.zoomImage.setFixedSize(myPixmap.size())

    def loadImage(self, path):
        global zoomAmount, currentImage
        pixmap = QtGui.QPixmap(path)
        self.ui.image.setPixmap(pixmap)
        self.ui.image.setFixedSize(pixmap.size())

        self.zoomedPixmap = pixmap.scaled (self.ui.image.width()*zoomAmount, self.ui.image.height()*zoomAmount, QtCore.Qt.KeepAspectRatio)
        myPixmap = self.zoomedPixmap.copy(0,0, self.ui.zoomImage.width(), self.ui.zoomImage.height())
        self.ui.zoomImage.setPixmap(myPixmap)
        self.ui.zoomImage.setFixedSize(myPixmap.size())

        currentImage = Image.open(path)
        # convert to grayscale
        if currentImage.mode != "L":
            currentImage= currentImage.convert("L")
            
        # Sobel operator
        # edge1 = currentImage.filter(ImageFilter.Kernel((3,3), [1, 0, -1, 2, 0, -2, 1, 0, -1], scale=4))
        # edge2 = currentImage.filter(ImageFilter.Kernel((3,3), [1, 2, 1, 0, 0, 0, -1, -2, -1], scale=4))
        # edge3 = currentImage.filter(ImageFilter.Kernel((3,3), [-1, 0, 1, -2, 0, 2, -1, 0, 1], scale=4))
        # edge4 = currentImage.filter(ImageFilter.Kernel((3,3), [-1, -2, -1, 0, 0, 0, 1, 2, 1], scale=4))
        
        # Scharr operator
        edge1 = currentImage.filter(ImageFilter.Kernel((3,3), [3, 0, -3, 10, 0, -10, 3, 0, -3], scale=16))
        edge2 = currentImage.filter(ImageFilter.Kernel((3,3), [3, 10, 3, 0, 0, 0, -3, -10, -3], scale=16))
        edge3 = currentImage.filter(ImageFilter.Kernel((3,3), [-3, 0, 3, -10, 0, 10, -3, 0, 3], scale=16))
        edge4 = currentImage.filter(ImageFilter.Kernel((3,3), [-3, -10, -3, 0, 0, 0, 3, 10, 3], scale=16))
        
        currentImage = ImageChops.add(ImageChops.add(ImageChops.add(edge1, edge2), edge3), edge4)

        # currentImage.save("tmp.png")

    def changeImage(self, text):
        global path, currentIndex, undoRedoStatus
        self.loadImage("%s/%s" % (path, text))
        self.setWindowTitle("%s (%s) - pilab-annotator" % (self.ui.imageComboBox.currentText(), path))
        currentIndex = self.ui.imageComboBox.currentIndex()
        self.ui.indexLabel.setText("(%d / %d)" % (currentIndex+1, self.ui.imageComboBox.count()))
        self.ui.image.repaint()
        self.ui.zoomImage.repaint()
		
        self.undoChange(undoRedoStatus[currentIndex][0])
        self.redoChange(undoRedoStatus[currentIndex][1])

    def showIndices(self, check):
        global indicesVisible
        indicesVisible = check
        self.ui.image.repaint()
        self.ui.zoomImage.repaint()
		
    def showPoints(self, check):
        global pointsVisible
        pointsVisible = check
        self.ui.image.repaint()
        self.ui.zoomImage.repaint()
		
    def showRectangles(self, check):
        global rectanglesVisible
        rectanglesVisible = check
        self.ui.image.repaint()
        self.ui.zoomImage.repaint()

    def handleDotButton(self, check):
        global currentTool
        if check:
            currentTool = "point"
            self.showDotOptions()
            
    def handleRectButton(self, check):
        global currentTool
        if check:
            currentTool = "rectangle"
            self.showRectOptions()

    def handleDotUndoButton(self):
		global points, currentIndex
		self.undoStack.undo()
		self.ui.image.repaint()

    def handleDotClickButton(self, check):
        if check:
            global modes
            modes["point"] = "click"
            self.ui.image.setCursor(QtGui.QCursor(QtCore.Qt.CrossCursor))
            
    def handleDotDragButton(self, check):
        if check:
            global modes
            modes["point"] = "drag"
            self.ui.image.setCursor(QtGui.QCursor(QtCore.Qt.SizeAllCursor))
			
    def handleRectClickButton(self, check):
        if check:
            global modes
            modes["rectangle"] = "draw"
            self.ui.image.setCursor(QtGui.QCursor(QtCore.Qt.CrossCursor))
            
    def handleRectDragButton(self, check):
        if check:
            global modes
            modes["rectangle"] = "drag"
            self.ui.image.setCursor(QtGui.QCursor(QtCore.Qt.SizeAllCursor))

    def showDotOptions(self):
        self.ui.dotClickButton.show()
        self.ui.dotDragButton.show()
        self.ui.rectClickButton.hide()
        self.ui.rectDragButton.hide()
        
    def showRectOptions(self):
        self.ui.rectClickButton.show()
        self.ui.rectDragButton.show()
        self.ui.dotClickButton.hide()
        self.ui.dotDragButton.hide()
	
    def undo(self):
		global currentIndex, lastSavedState
		self.undoStacks[currentIndex].undo()
		if self.undoStacks[currentIndex].index() == lastSavedState:
			annotationChanged[currentIndex] = False
		else:
			annotationChanged[currentIndex] = True
		self.ui.zoomImage.repaint()
		self.ui.image.repaint()
		
    def redo(self):
		global currentIndex, lastSavedState
		self.undoStacks[currentIndex].redo()
		if self.undoStacks[currentIndex].index() == lastSavedState:
			annotationChanged[currentIndex] = False
		else:
			annotationChanged[currentIndex] = True
		self.ui.zoomImage.repaint()
		self.ui.image.repaint()
	
    def undoChange(self, b):
		global undoRedoStatus,currentIndex
		self.ui.undoAction.setEnabled(b)
		self.ui.undoButton.setEnabled(b)
		undoRedoStatus[currentIndex][0] = b
		
    def redoChange(self, b):
		global undoRedoStatus,currentIndex
		self.ui.redoAction.setEnabled(b)
		self.ui.redoButton.setEnabled(b)
		undoRedoStatus[currentIndex][1] = b

    def calculateZoomBorders(self, mouseX, mouseY):
        left = mouseX * zoomAmount  - self.ui.zoomImage.width()/2
        up = mouseY * zoomAmount - self.ui.zoomImage.height()/2
        if left < 0:
            left = 0
        elif left + self.ui.zoomImage.width() > self.zoomedPixmap.width():
            left = self.zoomedPixmap.width() - self.ui.zoomImage.width()
        if up < 0:
            up = 0
        elif up + self.ui.zoomImage.height() > self.zoomedPixmap.height():
            up = self.zoomedPixmap.height() - self.ui.zoomImage.height()
        
        return (left, up)
Example #5
0
class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.ui = Ui_mainWindow()
        self.ui.setupUi(self)
        self.fill_list_view()
        self.ui.insert.clicked.connect(self.insert_line)
        self.ui.delete_2.clicked.connect(self.delete_selected)
        self.ui.update.clicked.connect(self.show_update_form)
        self.ui.update_button.clicked.connect(self.update_selected)

        # hide form for updating on start
        self.hide_update_form()

    def fill_list_view(self):
        values = c.get_all()
        model = QStandardItemModel()
        self.ui.listView.setModel(model)

        for i, number, text in values:
            line = "{}: {}, {}".format(i, number, text)
            item = QStandardItem(line)
            model.appendRow(item)

    def insert_line(self):
        number = self.ui.number.value()
        text = self.ui.text.text()
        if not text:
            return
        c.transaction('create', number, text)
        self.ui.number.setValue(1)
        self.ui.text.setText('')
        self.fill_list_view()

    def delete_selected(self):
        selected = self.ui.listView.selectedIndexes()
        for s in selected:
            id, _ = s.data().split(': ')
            c.transaction('deleted', int(id))
            self.fill_list_view()

    def hide_update_form(self):
        self.ui.update_form_label.hide()
        self.ui.update_id.hide()
        self.ui.update_button.hide()
        self.ui.update_number.hide()
        self.ui.update_text.hide()

    def show_update_form(self):
        selected = self.ui.listView.selectedIndexes()
        for s in selected:
            id, number_text = s.data().split(': ')
            number, text = number_text.split(', ')

            self.ui.update_form_label.show()
            self.ui.update_id.setText(id)
            self.ui.update_id.show()
            self.ui.update_number.setValue(int(number))
            self.ui.update_number.show()
            self.ui.update_text.setText(text)
            self.ui.update_text.show()
            self.ui.update_button.show()

    def update_selected(self):
        id = int(self.ui.update_id.text())
        number = self.ui.update_number.value()
        text = self.ui.update_text.text()

        c.transaction('set_number', id, number)
        c.transaction('set_text', id, text)

        self.hide_update_form()
        self.fill_list_view()
Example #6
0
    def __init__(self):
        global pointWidth
        QtGui.QMainWindow.__init__(self)

        # Set up the user interface from Designer.
        self.ui = Ui_mainWindow()
        self.ui.setupUi(self)
        self.setCentralWidget(self.ui.scrollArea)

        self.pModeButtonGroup = QtGui.QButtonGroup(self)
        self.pModeButtonGroup.addButton(self.ui.dotClickButton)
        self.pModeButtonGroup.addButton(self.ui.dotDragButton)

        self.rModeButtonGroup = QtGui.QButtonGroup(self)
        self.rModeButtonGroup.addButton(self.ui.rectClickButton)
        self.rModeButtonGroup.addButton(self.ui.rectDragButton)

        self.toolButtonGroup = QtGui.QButtonGroup(self)
        self.toolButtonGroup.addButton(self.ui.dotButton)
        self.toolButtonGroup.addButton(self.ui.rectangleButton)

        self.undoStacks = []
        self.connectSignals()

        if currentTool == "point":
            self.ui.rectClickButton.hide()
            self.ui.rectDragButton.hide()
        else:
            self.ui.dotClickButton.hide()
            self.ui.dotDragButton.hide()

        self.ui.saveAction.setEnabled(False)

        self.dragIsActive = False
        self.drawingRectangle = False
        self.resizeReady = False
        self.resizeIsActive = False
        self.resizeType = ""

        self.ui.indicesAction.setChecked(indicesVisible)
        self.ui.pointsAction.setChecked(pointsVisible)
        self.ui.rectanglesAction.setChecked(rectanglesVisible)

        # Force pointwidth to be odd
        if pointWidth % 2 == 0:
            pointWidth += 1

        self.ui.zoomImage.paint = QtGui.QPainter()
        self.ui.zoomImage.pen = QtGui.QPen(penColor)
        self.ui.zoomImage.pen.setWidth(pointWidth * zoomAmount)
        self.ui.zoomImage.crossPen = QtGui.QPen(QtCore.Qt.black)
        self.ui.zoomImage.crossPen.setWidth(1)

        self.ui.image.paint = QtGui.QPainter()
        self.ui.image.pen = QtGui.QPen(penColor)

        self.rectPen = QtGui.QPen(penColor)
        self.rectPen.setDashPattern(dashPattern)
        #self.rectPen.setWidth(pointWidth-1)

        self.ui.coo = QtGui.QLabel()
        self.ui.statusBar.addPermanentWidget(self.ui.coo)
        self.ui.coord = QtGui.QLabel()
        self.ui.statusBar.addPermanentWidget(self.ui.coord)

        self.keyPressEvent = self.mainKeyPressEvent
        self.keyReleaseEvent = self.mainKeyReleaseEvent
        self.ui.zoomImage.paintEvent = self.zoomImagePaintEvent
        self.ui.image.paintEvent = self.imagePaintEvent
        self.ui.image.mousePressEvent = self.imageMousePressEvent
        self.ui.image.mouseReleaseEvent = self.imageMouseReleaseEvent
        self.ui.image.mouseMoveEvent = self.imageMouseMoveEvent
Example #7
0
class MainWindow(QtGui.QMainWindow):
    def __init__(self):
        global pointWidth
        QtGui.QMainWindow.__init__(self)

        # Set up the user interface from Designer.
        self.ui = Ui_mainWindow()
        self.ui.setupUi(self)
        self.setCentralWidget(self.ui.scrollArea)

        self.pModeButtonGroup = QtGui.QButtonGroup(self)
        self.pModeButtonGroup.addButton(self.ui.dotClickButton)
        self.pModeButtonGroup.addButton(self.ui.dotDragButton)

        self.rModeButtonGroup = QtGui.QButtonGroup(self)
        self.rModeButtonGroup.addButton(self.ui.rectClickButton)
        self.rModeButtonGroup.addButton(self.ui.rectDragButton)

        self.toolButtonGroup = QtGui.QButtonGroup(self)
        self.toolButtonGroup.addButton(self.ui.dotButton)
        self.toolButtonGroup.addButton(self.ui.rectangleButton)

        self.undoStacks = []
        self.connectSignals()

        if currentTool == "point":
            self.ui.rectClickButton.hide()
            self.ui.rectDragButton.hide()
        else:
            self.ui.dotClickButton.hide()
            self.ui.dotDragButton.hide()

        self.ui.saveAction.setEnabled(False)

        self.dragIsActive = False
        self.drawingRectangle = False
        self.resizeReady = False
        self.resizeIsActive = False
        self.resizeType = ""

        self.ui.indicesAction.setChecked(indicesVisible)
        self.ui.pointsAction.setChecked(pointsVisible)
        self.ui.rectanglesAction.setChecked(rectanglesVisible)

        # Force pointwidth to be odd
        if pointWidth % 2 == 0:
            pointWidth += 1

        self.ui.zoomImage.paint = QtGui.QPainter()
        self.ui.zoomImage.pen = QtGui.QPen(penColor)
        self.ui.zoomImage.pen.setWidth(pointWidth * zoomAmount)
        self.ui.zoomImage.crossPen = QtGui.QPen(QtCore.Qt.black)
        self.ui.zoomImage.crossPen.setWidth(1)

        self.ui.image.paint = QtGui.QPainter()
        self.ui.image.pen = QtGui.QPen(penColor)

        self.rectPen = QtGui.QPen(penColor)
        self.rectPen.setDashPattern(dashPattern)
        #self.rectPen.setWidth(pointWidth-1)

        self.ui.coo = QtGui.QLabel()
        self.ui.statusBar.addPermanentWidget(self.ui.coo)
        self.ui.coord = QtGui.QLabel()
        self.ui.statusBar.addPermanentWidget(self.ui.coord)

        self.keyPressEvent = self.mainKeyPressEvent
        self.keyReleaseEvent = self.mainKeyReleaseEvent
        self.ui.zoomImage.paintEvent = self.zoomImagePaintEvent
        self.ui.image.paintEvent = self.imagePaintEvent
        self.ui.image.mousePressEvent = self.imageMousePressEvent
        self.ui.image.mouseReleaseEvent = self.imageMouseReleaseEvent
        self.ui.image.mouseMoveEvent = self.imageMouseMoveEvent

    def mainKeyPressEvent(self, event):
        if event.key() == QtCore.Qt.Key_Shift and modes[currentTool] != "drag":
            if currentTool == "point":
                self.ui.dotDragButton.setChecked(True)
            if currentTool == "rectangle":
                self.ui.rectDragButton.setChecked(True)
            modes[currentTool] = "tempDrag"
            self.ui.image.setCursor(QtGui.QCursor(QtCore.Qt.SizeAllCursor))

    def mainKeyReleaseEvent(self, event):
        if event.key(
        ) == QtCore.Qt.Key_Shift and modes[currentTool] == "tempDrag":
            if self.ui.image.pixmap() and (currentTool == "point"
                                           or currentTool == "rectangle"):
                if (modes[currentTool] == "drag" or modes[currentTool]
                        == "tempDrag") and self.dragIsActive:
                    annotationChanged[currentIndex] = True
                    self.ui.image.repaint()
                    self.dragIsActive = False
            if currentTool == "point":
                self.ui.dotClickButton.setChecked(True)
            if currentTool == "rectangle":
                self.ui.rectClickButton.setChecked(True)
            self.ui.image.setCursor(QtGui.QCursor(QtCore.Qt.CrossCursor))

    def imageMouseMoveEvent(self, event):
        global zoomPoints, points, rectangles, currentIndex
        x, y = event.pos().x(), event.pos().y()
        if self.dragIsActive:
            if currentTool == "point":
                if 0 <= x < self.ui.image.width(
                ) and 0 <= y < self.ui.image.height():
                    points[currentIndex][self.pointToDrag] = (x, y)
                    self.ui.image.repaint()
            elif currentTool == "rectangle":
                (i, j, k, m) = self.beforeRect
                deltaX, deltaY = x - self.rectDragPoint.x(
                ), y - self.rectDragPoint.y()
                newX, newY = i + deltaX, j + deltaY
                if 0 <= x < self.ui.image.width() and 0 <= y < self.ui.image.height() \
                 and 0 <= newX < self.ui.image.width()-k and 0 <= newY < self.ui.image.height()-m:
                    rectangles[currentIndex][self.rectToDrag] = (newX, newY, k,
                                                                 m)
                    self.ui.image.repaint()

        elif self.resizeIsActive:
            (i, j, w, h) = rectangles[currentIndex][self.rectToResize]
            if self.resizeType == "upleft":
                deltaX, deltaY = x - i, y - j
                newX, newY = x, y
                newWidth, newHeight = w - deltaX, h - deltaY
                #rectangles[currentIndex][self.rectToResize] = (x,y,w-deltaX,h-deltaY)
            elif self.resizeType == "downleft":
                deltaX, deltaY = x - i, y - j - h
                newX, newY = i + deltaX, j
                newWidth, newHeight = w - deltaX, h + deltaY
                #rectangles[currentIndex][self.rectToResize] = (i+deltaX,j,w-deltaX,h+deltaY)
            elif self.resizeType == "upright":
                deltaX, deltaY = x - i - w, y - j
                newX, newY = i, j + deltaY
                newWidth, newHeight = w + deltaX, h - deltaY
                #rectangles[currentIndex][self.rectToResize] = (i,j+deltaY,w+deltaX,h-deltaY)
            elif self.resizeType == "downright":
                deltaX, deltaY = x - i - w, y - j - h
                newX, newY = i, j
                newWidth, newHeight = w + deltaX, h + deltaY
                #rectangles[currentIndex][self.rectToResize] = (i,j,w+deltaX,h+deltaY)
            elif self.resizeType == "left":
                deltaX = x - i
                newX, newY = i + deltaX, j
                newWidth, newHeight = w - deltaX, h
                #rectangles[currentIndex][self.rectToResize] = (i+deltaX,j,w-deltaX,h)
            elif self.resizeType == "right":
                deltaX = x - i - w
                newX, newY = i, j
                newWidth, newHeight = w + deltaX, h
                #rectangles[currentIndex][self.rectToResize] = (i,j,w+deltaX,h)
            elif self.resizeType == "up":
                deltaY = y - j
                newX, newY = i, j + deltaY
                newWidth, newHeight = w, h - deltaY
                #rectangles[currentIndex][self.rectToResize] = (i,j+deltaY,w,h-deltaY)
            elif self.resizeType == "down":
                deltaY = y - j - h
                newX, newY = i, j
                newWidth, newHeight = w, h + deltaY
                #rectangles[currentIndex][self.rectToResize] = (i,j,w,h+deltaY)
            #if newWidth < 0:
            #	newX -= newWidth
            #	newWidth = abs(newWidth)
            #if newHeight < 0:
            #	newY += newHeight
            #	newHeight = abs(newHeight)
            rectangles[currentIndex][self.rectToResize] = (newX, newY,
                                                           newWidth, newHeight)
            self.ui.image.repaint()

        elif currentTool == "rectangle" and modes[
                currentTool] != "drag" and modes[currentTool] != "tempDrag":
            self.resizeReady = False
            for (i, j, k, m) in rectangles[currentIndex]:
                if abs(x - i) <= 2:
                    if abs(y - j) <= 2:  #upper-left corner of rectangle
                        self.ui.image.setCursor(
                            QtGui.QCursor(QtCore.Qt.SizeFDiagCursor))
                        self.resizeType = "upleft"
                        self.rectToResize = rectangles[currentIndex].index(
                            (i, j, k, m))
                        self.resizeReady = True
                        break
                    elif abs(y - j - m) <= 2:  #lower-left corner of rectangle
                        self.ui.image.setCursor(
                            QtGui.QCursor(QtCore.Qt.SizeBDiagCursor))
                        self.resizeType = "downleft"
                        self.rectToResize = rectangles[currentIndex].index(
                            (i, j, k, m))
                        self.resizeReady = True
                        break
                    elif -2 <= y - j <= m + 2:  #left side of rectangle
                        self.ui.image.setCursor(
                            QtGui.QCursor(QtCore.Qt.SizeHorCursor))
                        self.resizeType = "left"
                        self.rectToResize = rectangles[currentIndex].index(
                            (i, j, k, m))
                        self.resizeReady = True
                        break
                elif abs(x - i - k) <= 2:
                    if abs(y - j) <= 2:  #upper-right corner of rectangle
                        self.ui.image.setCursor(
                            QtGui.QCursor(QtCore.Qt.SizeBDiagCursor))
                        self.resizeType = "upright"
                        self.rectToResize = rectangles[currentIndex].index(
                            (i, j, k, m))
                        self.resizeReady = True
                        break
                    elif abs(y - j - m) <= 2:  #lower-right corner of rectangle
                        self.ui.image.setCursor(
                            QtGui.QCursor(QtCore.Qt.SizeFDiagCursor))
                        self.resizeType = "downright"
                        self.rectToResize = rectangles[currentIndex].index(
                            (i, j, k, m))
                        self.resizeReady = True
                        break
                    elif -2 <= y - j <= m + 2:  #right side of rectangle
                        self.ui.image.setCursor(
                            QtGui.QCursor(QtCore.Qt.SizeHorCursor))
                        self.resizeType = "right"
                        self.rectToResize = rectangles[currentIndex].index(
                            (i, j, k, m))
                        self.resizeReady = True
                        break
                elif abs(
                        y - j
                ) <= 2 and -2 <= x - i <= k + 2:  #upper side of rectangle
                    self.ui.image.setCursor(
                        QtGui.QCursor(QtCore.Qt.SizeVerCursor))
                    self.resizeType = "up"
                    self.rectToResize = rectangles[currentIndex].index(
                        (i, j, k, m))
                    self.resizeReady = True
                    break
                elif abs(
                        y - j - m
                ) <= 2 and -2 <= x - i <= k + 2:  #lower side of the rectangle
                    self.ui.image.setCursor(
                        QtGui.QCursor(QtCore.Qt.SizeVerCursor))
                    self.resizeType = "down"
                    self.rectToResize = rectangles[currentIndex].index(
                        (i, j, k, m))
                    self.resizeReady = True
                    break
            if not self.resizeReady:
                if self.ui.image.cursor().shape() != QtCore.Qt.CrossCursor:
                    self.ui.image.setCursor(
                        QtGui.QCursor(QtCore.Qt.CrossCursor))

        if self.ui.image.pixmap():
            height, width = self.ui.zoomImage.width(
            ), self.ui.zoomImage.height()

            self.left, self.up = self.calculateZoomBorders(x, y)

            self.ui.coord.setText("(%d, %d)" % (x, y))
            if len(points[currentIndex]) > 0:
                del zoomPoints[:]
                for (i, j) in points[currentIndex]:
                    newX = zoomAmount * i - self.left
                    newY = zoomAmount * j - self.up
                    if 0 <= newX <= width and 0 <= newY <= height:
                        zoomPoints.append((newX, newY))

            if self.drawingRectangle:
                (x, y) = self.rectCoord
                (self.tempWidth, self.tempHeight) = ((event.pos().x() - x),
                                                     (event.pos().y() - y))
                self.ui.image.repaint()
                self.updateZoomedImage(event.pos().x(), event.pos().y())
                self.ui.zoomImage.repaint()
            else:
                self.updateZoomedImage(x, y)

    def imageMousePressEvent(self, event):
        global zoomPoints, points, modes, currentTool, currentIndex
        x, y = event.pos().x(), event.pos().y()
        if self.ui.image.pixmap() and currentTool == "point":
            if modes["point"] == "click":
                #points[currentIndex].append((x,y))
                self.left, self.up = self.calculateZoomBorders(x, y)
                newX, newY = zoomAmount * x - self.left, zoomAmount * y - self.up
                zoomPoints.append((newX, newY))

                command = CommandAddPoint(currentIndex, (x, y),
                                          "Add Point @(%d-%d)" % (x, y))
                self.undoStacks[currentIndex].push(command)
                annotationChanged[currentIndex] = True

                self.ui.image.repaint()
                self.ui.zoomImage.repaint()
            elif modes["point"] == "drag" or modes["point"] == "tempDrag":
                self.dragIsActive = False
                for (i, j) in points[currentIndex]:
                    if abs(i - x) <= pointWidth and abs(j - y) <= pointWidth:
                        self.pointToDrag = points[currentIndex].index((i, j))
                        self.dragIsActive = True
                        self.beforePoint = (i, j)
                        self.afterPoint = (-1, -1)

        elif self.ui.image.pixmap() and currentTool == "rectangle":
            if modes["rectangle"] == "draw":
                if self.resizeReady:
                    self.resizeIsActive = True
                    self.beforeRect = rectangles[currentIndex][
                        self.rectToResize]
                else:
                    self.drawingRectangle = True
                self.rectCoord = (x, y)
            elif modes["rectangle"] == "drag" or modes[
                    "rectangle"] == "tempDrag":
                self.dragIsActive = False
                for (i, j, k, m) in rectangles[currentIndex]:
                    if ((abs(x - i) <= 2 or abs(x - i - k) <= 2)
                            and -2 <= y - j <= m + 2) or (
                                (abs(y - j) <= 2 or abs(y - j - m) <= 2)
                                and -2 <= x - i <= k + 2):
                        #print "x:%d y:%d i:%d j:%d w:%d h:%d" % (x,y,i,j,k+i,m+j)
                        self.rectToDrag = rectangles[currentIndex].index(
                            (i, j, k, m))
                        self.rectDragPoint = event.pos()
                        self.dragIsActive = True
                        self.beforeRect = (i, j, k, m)
                        self.afterRect = (-1, -1, -1, -1)

    def imageMouseReleaseEvent(self, event):
        global points, modes, currentTool, currentIndex
        if self.ui.image.pixmap() and currentTool == "point":
            if (modes["point"] == "drag"
                    or modes["point"] == "tempDrag") and self.dragIsActive:
                annotationChanged[currentIndex] = True
                self.ui.image.repaint()
                self.dragIsActive = False
                if self.afterPoint == (-1, -1):
                    self.afterPoint = (event.pos().x(), event.pos().y())
                command = CommandDragPoint(currentIndex, self.beforePoint,
                                           self.afterPoint, "Drag Point")
                self.undoStacks[currentIndex].push(command)

        elif self.ui.image.pixmap() and currentTool == "rectangle":
            if modes["rectangle"] == "draw":
                if self.resizeIsActive:
                    (i, j, w, h) = rectangles[currentIndex][self.rectToResize]
                    if w < 0:
                        i += w
                        w = abs(w)
                    if h < 0:
                        j += h
                        h = abs(h)
                    rectangles[currentIndex][
                        self.rectToResize] = self.afterRect = (i, j, w, h)
                    command = CommandResizeRect(currentIndex, self.beforeRect,
                                                self.afterRect,
                                                "Drag Rectangle")
                    self.undoStacks[currentIndex].push(command)
                    self.resizeIsActive = False
                    annotationChanged[currentIndex] = True
                    self.ui.image.repaint()
                else:
                    (x, y) = self.rectCoord
                    width, height = (event.pos().x() - x), (event.pos().y() -
                                                            y)
                    if width != 0 and height != 0:
                        if width < 0:
                            width = abs(width)
                            x = event.pos().x()
                        if height < 0:
                            height = abs(height)
                            y = event.pos().y()
                        command = CommandAddRect(
                            currentIndex, (x, y, width, height),
                            "Add Rectangle @(%d-%d-%d-%d)" %
                            (x, y, width, height))
                        self.undoStacks[currentIndex].push(command)
                        annotationChanged[currentIndex] = True
                    if self.drawingRectangle:
                        self.drawingRectangle = False
                        self.ui.image.repaint()
            if (modes["rectangle"] == "drag"
                    or modes["rectangle"] == "tempDrag") and self.dragIsActive:
                annotationChanged[currentIndex] = True
                self.ui.image.repaint()
                self.dragIsActive = False
                if self.afterRect == (-1, -1, -1, -1):
                    (i, j, k, m) = self.beforeRect
                    deltaX, deltaY = event.pos().x() - self.rectDragPoint.x(
                    ), event.pos().y() - self.rectDragPoint.y()
                    self.afterRect = (i + deltaX, j + deltaY, k, m)
                command = CommandDragRect(currentIndex, self.beforeRect,
                                          self.afterRect, "Drag Rectangle")
                self.undoStacks[currentIndex].push(command)

    def zoomImagePaintEvent(self, event):
        global zoomAmount, zoomPoints, pointWidth
        if self.ui.zoomImage.pixmap():
            self.ui.zoomImage.paint.begin(self.ui.zoomImage)
            self.ui.zoomImage.paint.setPen(self.ui.zoomImage.pen)
            self.ui.zoomImage.paint.drawImage(
                self.ui.zoomImage.rect(),
                QtGui.QImage(self.ui.zoomImage.pixmap()))
            self.ui.zoomImage.paint.setPen(self.ui.image.pen)
            if pointsVisible and len(zoomPoints) > 0:
                for (i, j) in zoomPoints:
                    if useSmartColor:
                        r, g, b = getSmartColor(
                            currentImage.getpixel(
                                ((i + self.left) / zoomAmount,
                                 (j + self.up) / zoomAmount)))
                        self.ui.zoomImage.paint.setPen(
                            QtGui.QPen(QtGui.QColor(r, g, b), pointWidth * 3))

                    self.ui.zoomImage.paint.drawPoint(i, j)
                    if indicesVisible:
                        try:
                            index = -1
                            for k, p in enumerate(points[currentIndex]):
                                dx = p[0] - (i + self.left) / zoomAmount
                                dy = p[1] - (j + self.up) / zoomAmount
                                if abs(dx) < 0.1 and abs(dy) < 0.1:
                                    index = k
                            if index > -1:
                                self.ui.zoomImage.paint.drawText(
                                    i + 3, j - 3, QtCore.QString.number(index))
                        except ValueError:
                            pass

            self.ui.zoomImage.paint.setPen(self.ui.zoomImage.crossPen)
            self.ui.zoomImage.paint.drawLine(0,
                                             self.ui.zoomImage.height() / 2,
                                             self.ui.zoomImage.width(),
                                             self.ui.zoomImage.height() / 2)
            self.ui.zoomImage.paint.drawLine(self.ui.zoomImage.width() / 2, 0,
                                             self.ui.zoomImage.width() / 2,
                                             self.ui.zoomImage.height())
            self.ui.zoomImage.paint.drawEllipse(
                self.ui.zoomImage.width() / 2 - 15,
                self.ui.zoomImage.height() / 2 - 15, 30, 30)
            self.ui.zoomImage.paint.end()

    def imagePaintEvent(self, event):
        global points, currentIndex, currentImage
        if self.ui.image.pixmap():
            if len(annotationChanged) and annotationChanged[currentIndex]:
                self.setWindowTitle(
                    "%s* (%s) - pilab-annotator" %
                    (self.ui.imageComboBox.currentText(), path))
            elif len(
                    annotationChanged) and not annotationChanged[currentIndex]:
                self.setWindowTitle(
                    "%s (%s) - pilab-annotator" %
                    (self.ui.imageComboBox.currentText(), path))
            self.ui.image.pen.setWidth(pointWidth)
            self.ui.image.paint.begin(self.ui.image)
            self.ui.image.paint.setPen(self.ui.image.pen)
            self.ui.image.paint.drawImage(self.ui.image.rect(),
                                          QtGui.QImage(self.ui.image.pixmap()))
            #print points
            if pointsVisible and len(points[currentIndex]) > 0:
                for (i, j) in points[currentIndex]:
                    if useSmartColor:
                        r, g, b = getSmartColor(currentImage.getpixel((i, j)))
                        self.ui.image.paint.setPen(
                            QtGui.QPen(QtGui.QColor(r, g, b), pointWidth))

                    self.ui.image.paint.drawPoint(i, j)
                    # if indicesVisible:
                    # self.ui.image.paint.drawText(i+4,j-4, QtCore.QString.number(points[currentIndex].index((i,j))))
            if self.drawingRectangle:
                self.ui.image.paint.setPen(self.rectPen)
                (x, y) = self.rectCoord
                self.ui.image.paint.drawRect(x, y, self.tempWidth,
                                             self.tempHeight)
            if rectanglesVisible and len(rectangles) > 0:
                for index, (i, j, k, m) in enumerate(rectangles[currentIndex]):
                    self.ui.image.paint.setPen(self.rectPen)
                    self.ui.image.paint.drawRect(i, j, k, m)
                    self.ui.image.paint.drawText(i + 3, j + 12,
                                                 QtCore.QString.number(index))
            self.ui.image.paint.end()

    def closeEvent(self, event):
        saveAll = False
        for i in range(self.ui.imageComboBox.count()):
            if annotationChanged[i]:
                self.ui.imageComboBox.setCurrentIndex(i)
                if saveAll:
                    self.saveAnnotations()
                    event.accept()
                else:
                    quit_msg = "Save changes to the annotation file of \"%s\"?" % self.ui.imageComboBox.itemText(
                        i)
                    reply = QtGui.QMessageBox.question(
                        self, 'Quit', quit_msg,
                        QtGui.QMessageBox.Save | QtGui.QMessageBox.SaveAll
                        | QtGui.QMessageBox.Discard | QtGui.QMessageBox.Cancel)
                    if reply == QtGui.QMessageBox.Save:
                        self.saveAnnotations()
                        event.accept()
                    elif reply == QtGui.QMessageBox.SaveAll:
                        saveAll = True
                        self.saveAnnotations()
                        event.accept()
                    elif reply == QtGui.QMessageBox.Cancel:
                        event.ignore()
                        break

        #quit_msg = "Are you sure you want to exit the program?"
        #reply = QtGui.QMessageBox.question(self, 'Message', quit_msg, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)

        #if reply == QtGui.QMessageBox.Yes:
        #	event.accept()
        #else:
        #	event.ignore()

    def connectSignals(self):
        self.connect(self.ui.toolboxAction, QtCore.SIGNAL("triggered(bool)"),
                     self.ui.toolBox, QtCore.SLOT("setVisible(bool)"))
        self.connect(self.ui.toolBox, QtCore.SIGNAL("visibilityChanged(bool)"),
                     self.ui.toolboxAction, QtCore.SLOT("setChecked(bool)"))
        self.connect(self.ui.optionsAction, QtCore.SIGNAL("triggered(bool)"),
                     self.ui.optionBox, QtCore.SLOT("setVisible(bool)"))
        self.connect(self.ui.optionBox,
                     QtCore.SIGNAL("visibilityChanged(bool)"),
                     self.ui.optionsAction, QtCore.SLOT("setChecked(bool)"))
        self.connect(self.ui.zoomAction, QtCore.SIGNAL("triggered(bool)"),
                     self.ui.zoomBox, QtCore.SLOT("setVisible(bool)"))
        self.connect(self.ui.zoomBox, QtCore.SIGNAL("visibilityChanged(bool)"),
                     self.ui.zoomAction, QtCore.SLOT("setChecked(bool)"))
        self.connect(self.ui.navigationAction,
                     QtCore.SIGNAL("triggered(bool)"), self.ui.navigationBox,
                     QtCore.SLOT("setVisible(bool)"))
        self.connect(self.ui.navigationBox,
                     QtCore.SIGNAL("visibilityChanged(bool)"),
                     self.ui.navigationAction, QtCore.SLOT("setChecked(bool)"))

        self.connect(self.ui.indicesAction, QtCore.SIGNAL("triggered(bool)"),
                     self.showIndices)
        self.connect(self.ui.pointsAction, QtCore.SIGNAL("triggered(bool)"),
                     self.showPoints)
        self.connect(self.ui.rectanglesAction,
                     QtCore.SIGNAL("triggered(bool)"), self.showRectangles)
        self.connect(self.ui.openAction, QtCore.SIGNAL("triggered()"),
                     self.openImageDirectory)
        self.connect(self.ui.saveAction, QtCore.SIGNAL("triggered()"),
                     self.saveAnnotations)
        self.connect(self.ui.imageComboBox,
                     QtCore.SIGNAL("currentIndexChanged(QString)"),
                     self.changeImage)
        self.connect(self.ui.prevButton, QtCore.SIGNAL("clicked()"),
                     self.previousImage)
        self.connect(self.ui.nextButton, QtCore.SIGNAL("clicked()"),
                     self.nextImage)
        self.connect(self.ui.plusTenButton, QtCore.SIGNAL("clicked()"),
                     self.plusTenImage)
        self.connect(self.ui.minusTenButton, QtCore.SIGNAL("clicked()"),
                     self.minusTenImage)
        self.connect(self.ui.firstButton, QtCore.SIGNAL("clicked()"),
                     self.firstImage)
        self.connect(self.ui.lastButton, QtCore.SIGNAL("clicked()"),
                     self.lastImage)
        self.connect(self.ui.dotButton, QtCore.SIGNAL("toggled(bool)"),
                     self.handleDotButton)
        self.connect(self.ui.rectangleButton, QtCore.SIGNAL("toggled(bool)"),
                     self.handleRectButton)
        self.connect(self.ui.dotClickButton, QtCore.SIGNAL("toggled(bool)"),
                     self.handleDotClickButton)
        self.connect(self.ui.dotDragButton, QtCore.SIGNAL("toggled(bool)"),
                     self.handleDotDragButton)
        self.connect(self.ui.rectClickButton, QtCore.SIGNAL("toggled(bool)"),
                     self.handleRectClickButton)
        self.connect(self.ui.rectDragButton, QtCore.SIGNAL("toggled(bool)"),
                     self.handleRectDragButton)
        self.connect(self.ui.undoButton, QtCore.SIGNAL("clicked()"), self.undo)
        self.connect(self.ui.redoButton, QtCore.SIGNAL("clicked()"), self.redo)
        self.connect(self.ui.undoAction, QtCore.SIGNAL("triggered()"),
                     self.undo)
        self.connect(self.ui.redoAction, QtCore.SIGNAL("triggered()"),
                     self.redo)

    def previousImage(self):
        global zoomPoints
        index = self.ui.imageComboBox.currentIndex() - 1
        if index < 0:
            index = 0
        self.ui.imageComboBox.setCurrentIndex(index)
        zoomPoints = []
        self.ui.image.repaint()
        self.ui.zoomImage.repaint()

    def nextImage(self):
        global zoomPoints
        index = self.ui.imageComboBox.currentIndex() + 1
        if index >= self.ui.imageComboBox.count():
            index = self.ui.imageComboBox.count() - 1
        self.ui.imageComboBox.setCurrentIndex(index)
        zoomPoints = []
        self.ui.image.repaint()
        self.ui.zoomImage.repaint()

    def plusTenImage(self):
        global zoomPoints
        index = self.ui.imageComboBox.currentIndex() + 10
        if index >= self.ui.imageComboBox.count():
            index = self.ui.imageComboBox.count() - 1
        self.ui.imageComboBox.setCurrentIndex(index)
        zoomPoints = []
        self.ui.image.repaint()
        self.ui.zoomImage.repaint()

    def minusTenImage(self):
        global zoomPoints
        index = self.ui.imageComboBox.currentIndex() - 10
        if index < 0:
            index = 0
        self.ui.imageComboBox.setCurrentIndex(index)
        zoomPoints = []
        self.ui.image.repaint()
        self.ui.zoomImage.repaint()

    def lastImage(self):
        global zoomPoints
        self.ui.imageComboBox.setCurrentIndex(self.ui.imageComboBox.count() -
                                              1)
        zoomPoints = []
        self.ui.image.repaint()
        self.ui.zoomImage.repaint()

    def firstImage(self):
        global zoomPoints
        self.ui.imageComboBox.setCurrentIndex(0)
        zoomPoints = []
        self.ui.image.repaint()
        self.ui.zoomImage.repaint()

    def openImageDirectory(self, imagePath=None):
        global path
        global points, rectangles, annotationChanged
        if imagePath:
            path = imagePath
        else:
            path = str(
                QtGui.QFileDialog.getExistingDirectory(self, "Open directory",
                                                       "."))
        if path:
            try:
                allFiles = os.listdir(path)
                imageFiles = sorted([
                    x for x in allFiles
                    if os.path.splitext(x)[-1] in extensions
                ])
                self.ui.imageComboBox.clear()
                points = []
                rectangles = []
                annotationChanged = []
                self.undoStacks = []
                self.ui.coord.setText("")
                if len(imageFiles) > 0:
                    for imageFile in imageFiles:
                        objects = []
                        try:
                            annotationFile = os.path.join(
                                path,
                                os.path.splitext(imageFile)[0] +
                                ".xml")  # @TODO: hardcoded extension!
                            xmldoc = minidom.parse(annotationFile)
                            objects = xmldoc.getElementsByTagName("objects")
                        except:
                            points.append([])
                            rectangles.append([])
                        else:
                            pts = []
                            rects = []
                            pointsOK = True
                            rectsOK = True

                            for object in objects:
                                lines = object.childNodes[1].data.splitlines()
                                if object.attributes["type"].value == "points":
                                    try:
                                        for line in lines:
                                            (x, y) = line.split(' ')
                                            pts.append((int(x), int(y)))
                                    except:
                                        points.append([])
                                        pointsOK = False
                                elif object.attributes[
                                        "type"].value == "rectangles":
                                    try:
                                        for line in lines:
                                            (x, y, z, t) = line.split(
                                                ' '
                                            )  # @TODO: uncomment when rectangle is implemented
                                            rects.append((int(x), int(y),
                                                          int(z), int(t)))
                                    except:
                                        rectangles.append([])
                                        rectsOK = False
                            if pointsOK:
                                points.append(pts)
                            if rectsOK:
                                rectangles.append(rects)

                        undoRedoStatus.append([False, False])
                        annotationChanged.append(False)
                        self.stack = QtGui.QUndoStack(self)
                        self.undoStacks.append(self.stack)

                        #self.connect(self.undoStacks[-1], QtCore.SIGNAL("indexChanged(int)"), self.ui.image, QtCore.SLOT("repaint()"))
                        self.connect(self.undoStacks[-1],
                                     QtCore.SIGNAL("indexChanged(int)"),
                                     self.ui.zoomImage,
                                     QtCore.SLOT("repaint()"))
                        self.connect(self.undoStacks[-1],
                                     QtCore.SIGNAL("canUndoChanged(bool)"),
                                     self.undoChange)
                        self.connect(self.undoStacks[-1],
                                     QtCore.SIGNAL("canRedoChanged(bool)"),
                                     self.redoChange)
                    #self.connect(self.undoStacks[-1], QtCore.SIGNAL("canUndoChanged(bool)"), self.ui.undoAction.setEnabled)
                    #self.connect(self.undoStacks[-1], QtCore.SIGNAL("canRedoChanged(bool)"), self.ui.redoAction.setEnabled)

                    self.ui.imageComboBox.addItems(imageFiles)
                    # self.loadImage("%s/%s" % (path, self.ui.imageComboBox.currentText()))
                    self.setWindowTitle(
                        "%s (%s) - pilab-annotator" %
                        (self.ui.imageComboBox.currentText(), path))
                    self.ui.saveAction.setEnabled(True)
                else:
                    self.ui.statusBar.showMessage(
                        "No image found in the directory.", warningTimeout)
                    self.setWindowTitle("pilab-annotator")
            except OSError:
                self.ui.statusBar.showMessage(OSError, warningTimeout)

    def saveAnnotations(self):
        "Currently supports only saving xml files"
        global points, path, lastSavedState, annotationChanged
        filename = os.path.splitext(str(
            self.ui.imageComboBox.currentText()))[0]
        filePath = os.path.join(str(path), str(filename) + ".xml")
        currentIndex = self.ui.imageComboBox.currentIndex()
        lastSavedState = self.undoStacks[currentIndex].index()
        annotationChanged[currentIndex] = False

        doc = Document()

        annotation = doc.createElement("annotation")
        doc.appendChild(annotation)

        objects = doc.createElement("objects")
        objects.setAttribute("type", "points")
        objects.setAttribute("count", "%.0f" % len(points[currentIndex]))
        annotation.appendChild(objects)

        text = ""
        for (x, y) in points[currentIndex]:
            text += "%.0f %.0f\n" % (x, y)
        if text == "":
            text = "\n"
        cDataSection = doc.createCDATASection(text)
        objects.appendChild(cDataSection)

        objects = doc.createElement("objects")
        objects.setAttribute("type", "rectangles")
        objects.setAttribute("count", "%.0f" % len(rectangles[currentIndex]))
        annotation.appendChild(objects)

        text = ""
        for (x, y, w, h) in rectangles[currentIndex]:
            text += "%.0f %.0f %.0f %.0f\n" % (x, y, w, h)
        if text == "":
            text = "\n"
        cDataSection = doc.createCDATASection(text)
        objects.appendChild(cDataSection)

        f = open(filePath, 'w')
        f.write(doc.toprettyxml(indent="  ", encoding="UTF-8"))
        f.close()

        self.ui.statusBar.showMessage("File saved to %s" % (filePath))
        self.setWindowTitle("%s (%s) - pilab-annotator" %
                            (self.ui.imageComboBox.currentText(), path))

    def updateZoomedImage(self, x, y):
        width = self.ui.zoomImage.width()
        height = width = self.ui.zoomImage.height()
        x, y = self.calculateZoomBorders(x, y)
        myPixmap = self.zoomedPixmap.copy(x, y, width, height)
        self.ui.zoomImage.setPixmap(myPixmap)
        self.ui.zoomImage.setFixedSize(myPixmap.size())

    def loadImage(self, path):
        global zoomAmount, currentImage
        pixmap = QtGui.QPixmap(path)
        self.ui.image.setPixmap(pixmap)
        self.ui.image.setFixedSize(pixmap.size())

        self.zoomedPixmap = pixmap.scaled(self.ui.image.width() * zoomAmount,
                                          self.ui.image.height() * zoomAmount,
                                          QtCore.Qt.KeepAspectRatio)
        myPixmap = self.zoomedPixmap.copy(0, 0, self.ui.zoomImage.width(),
                                          self.ui.zoomImage.height())
        self.ui.zoomImage.setPixmap(myPixmap)
        self.ui.zoomImage.setFixedSize(myPixmap.size())

        currentImage = Image.open(path)
        # convert to grayscale
        if currentImage.mode != "L":
            currentImage = currentImage.convert("L")

        # Sobel operator
        # edge1 = currentImage.filter(ImageFilter.Kernel((3,3), [1, 0, -1, 2, 0, -2, 1, 0, -1], scale=4))
        # edge2 = currentImage.filter(ImageFilter.Kernel((3,3), [1, 2, 1, 0, 0, 0, -1, -2, -1], scale=4))
        # edge3 = currentImage.filter(ImageFilter.Kernel((3,3), [-1, 0, 1, -2, 0, 2, -1, 0, 1], scale=4))
        # edge4 = currentImage.filter(ImageFilter.Kernel((3,3), [-1, -2, -1, 0, 0, 0, 1, 2, 1], scale=4))

        # Scharr operator
        edge1 = currentImage.filter(
            ImageFilter.Kernel((3, 3), [3, 0, -3, 10, 0, -10, 3, 0, -3],
                               scale=16))
        edge2 = currentImage.filter(
            ImageFilter.Kernel((3, 3), [3, 10, 3, 0, 0, 0, -3, -10, -3],
                               scale=16))
        edge3 = currentImage.filter(
            ImageFilter.Kernel((3, 3), [-3, 0, 3, -10, 0, 10, -3, 0, 3],
                               scale=16))
        edge4 = currentImage.filter(
            ImageFilter.Kernel((3, 3), [-3, -10, -3, 0, 0, 0, 3, 10, 3],
                               scale=16))

        currentImage = ImageChops.add(
            ImageChops.add(ImageChops.add(edge1, edge2), edge3), edge4)

        # currentImage.save("tmp.png")

    def changeImage(self, text):
        global path, currentIndex, undoRedoStatus
        self.loadImage("%s/%s" % (path, text))
        self.setWindowTitle("%s (%s) - pilab-annotator" %
                            (self.ui.imageComboBox.currentText(), path))
        currentIndex = self.ui.imageComboBox.currentIndex()
        self.ui.indexLabel.setText(
            "(%d / %d)" % (currentIndex + 1, self.ui.imageComboBox.count()))
        self.ui.image.repaint()
        self.ui.zoomImage.repaint()

        self.undoChange(undoRedoStatus[currentIndex][0])
        self.redoChange(undoRedoStatus[currentIndex][1])

    def showIndices(self, check):
        global indicesVisible
        indicesVisible = check
        self.ui.image.repaint()
        self.ui.zoomImage.repaint()

    def showPoints(self, check):
        global pointsVisible
        pointsVisible = check
        self.ui.image.repaint()
        self.ui.zoomImage.repaint()

    def showRectangles(self, check):
        global rectanglesVisible
        rectanglesVisible = check
        self.ui.image.repaint()
        self.ui.zoomImage.repaint()

    def handleDotButton(self, check):
        global currentTool
        if check:
            currentTool = "point"
            self.showDotOptions()

    def handleRectButton(self, check):
        global currentTool
        if check:
            currentTool = "rectangle"
            self.showRectOptions()

    def handleDotUndoButton(self):
        global points, currentIndex
        self.undoStack.undo()
        self.ui.image.repaint()

    def handleDotClickButton(self, check):
        if check:
            global modes
            modes["point"] = "click"
            self.ui.image.setCursor(QtGui.QCursor(QtCore.Qt.CrossCursor))

    def handleDotDragButton(self, check):
        if check:
            global modes
            modes["point"] = "drag"
            self.ui.image.setCursor(QtGui.QCursor(QtCore.Qt.SizeAllCursor))

    def handleRectClickButton(self, check):
        if check:
            global modes
            modes["rectangle"] = "draw"
            self.ui.image.setCursor(QtGui.QCursor(QtCore.Qt.CrossCursor))

    def handleRectDragButton(self, check):
        if check:
            global modes
            modes["rectangle"] = "drag"
            self.ui.image.setCursor(QtGui.QCursor(QtCore.Qt.SizeAllCursor))

    def showDotOptions(self):
        self.ui.dotClickButton.show()
        self.ui.dotDragButton.show()
        self.ui.rectClickButton.hide()
        self.ui.rectDragButton.hide()

    def showRectOptions(self):
        self.ui.rectClickButton.show()
        self.ui.rectDragButton.show()
        self.ui.dotClickButton.hide()
        self.ui.dotDragButton.hide()

    def undo(self):
        global currentIndex, lastSavedState
        self.undoStacks[currentIndex].undo()
        if self.undoStacks[currentIndex].index() == lastSavedState:
            annotationChanged[currentIndex] = False
        else:
            annotationChanged[currentIndex] = True
        self.ui.zoomImage.repaint()
        self.ui.image.repaint()

    def redo(self):
        global currentIndex, lastSavedState
        self.undoStacks[currentIndex].redo()
        if self.undoStacks[currentIndex].index() == lastSavedState:
            annotationChanged[currentIndex] = False
        else:
            annotationChanged[currentIndex] = True
        self.ui.zoomImage.repaint()
        self.ui.image.repaint()

    def undoChange(self, b):
        global undoRedoStatus, currentIndex
        self.ui.undoAction.setEnabled(b)
        self.ui.undoButton.setEnabled(b)
        undoRedoStatus[currentIndex][0] = b

    def redoChange(self, b):
        global undoRedoStatus, currentIndex
        self.ui.redoAction.setEnabled(b)
        self.ui.redoButton.setEnabled(b)
        undoRedoStatus[currentIndex][1] = b

    def calculateZoomBorders(self, mouseX, mouseY):
        left = mouseX * zoomAmount - self.ui.zoomImage.width() / 2
        up = mouseY * zoomAmount - self.ui.zoomImage.height() / 2
        if left < 0:
            left = 0
        elif left + self.ui.zoomImage.width() > self.zoomedPixmap.width():
            left = self.zoomedPixmap.width() - self.ui.zoomImage.width()
        if up < 0:
            up = 0
        elif up + self.ui.zoomImage.height() > self.zoomedPixmap.height():
            up = self.zoomedPixmap.height() - self.ui.zoomImage.height()

        return (left, up)