Пример #1
0
    def write_xml(self):
        imgFolderName = ustr(self.image_path).split('/')[-2]
        print imgFolderName
        #imgFileName = str(self.image_path).split('/')[-1]
        imgFileNameWithoutExt = ustr(self.image_path).split('.')[0]
        print imgFileNameWithoutExt

        image = QtGui.QImage()
        image.load(ustr(self.image_path))
        imageShape = [
            image.height(),
            image.width(), 1 if image.isGrayscale() else 3
        ]
        writer = PascalVocWriter(imgFolderName,
                                 imgFileNameWithoutExt,
                                 imageShape,
                                 localImgPath=ustr(self.image_path))
        #writer.verified = self.verified
        item = {}
        item['name'] = ''
        item['flood1name'] = imgFileNameWithoutExt + '_index.bmp'
        item['flood2name'] = imgFileNameWithoutExt + '_category.bmp'
        writer.addObject(item['name'], item['flood1name'], item['flood2name'])

        writer.save()
        return
Пример #2
0
 def create(self):
     self.mode = self.CREATE
     if self.image_path == "":
          QMessageBox.information(self,"Information", u"请先打开一张图片!")
          return
     if os.path.exists(ustr(self.image_path)+'.xml'):
         os.rm(ustr(self.image_path)+'.xml')
     self.points = []
     self.pre_pos = None
     #1:bgr  0:grayscale
     self.image = cv2.imdecode(np.fromfile(ustr(self.image_path), dtype=np.uint8), 1)
     #self.image = cv2.imdecode(self.label_Image.pixmap, 1)
     self.image_gray = cv2.imdecode(np.fromfile(ustr(self.image_path), dtype=np.uint8), 0)
     h, w = self.image.shape[:2]
     self.mask = np.zeros((h+2, w+2), np.uint8)
     self.flooded = copy.deepcopy(self.image_gray)
     self.flooded[:]=0
     self.flooded2 = copy.deepcopy(self.image_gray)
     self.flooded2[:]=0
     self.flooded2_show = copy.deepcopy(self.image)
     self.flooded2_show[:]=0
     self.mask[:] = 0
     cv2.namedWindow('image', cv2.WINDOW_KEEPRATIO | cv2.WINDOW_NORMAL)
     cv2.imshow('image',self.image)
     cv2.setMouseCallback('image',self.draw)
Пример #3
0
 def open_previmg(self):
     image_list = []
     dir_path1 = ustr(self.image_path).split('/')[:-1]
     current_image = ustr(self.image_path).split('/')[-1]
     dir_path = '/'.join(dir_path1)
     dir_items = os.listdir(dir_path)
     for item in dir_items:
         if item.endswith('.jpg') or item.endswith('.png') or item.endswith(
                 '.jpeg'):
             image_list.append(item)
     #print image_list
     #print image_list.index(current_image)
     if image_list.index(current_image) == 0:
         QtGui.QMessageBox.information(self, "Information", u"已经是第一张了!")
         return
     current_image_index = image_list.index(current_image) - 1
     next_image = dir_path + '/' + image_list[current_image_index]
     png = QtGui.QPixmap(next_image).scaled(self.label_Image.width(),
                                            self.label_Image.height())
     self.label_Image.setPixmap(png)
     self.image_path = next_image
     #self.label_imagepath.setText(self.image_path)
     self.setWindowTitle(
         _translate("MainWindow", "LableMe" + " " + ustr(self.image_path),
                    None))
Пример #4
0
 def saveFile(self, _value=False):
     if self.defaultSaveDir is not None and len(ustr(self.defaultSaveDir)):
         # print('handle the image:' + self.filePath)
         if self.filePath:
             imgFileName = os.path.basename(self.filePath)
             savedFileName = os.path.splitext(imgFileName)[0] + LabelFile.suffix
             savedPath = os.path.join(ustr(self.defaultSaveDir), savedFileName)
             self._saveFile(savedPath)
     else:
         self._saveFile(self.filePath if self.labelFile
                        else self.saveFileDialog())
Пример #5
0
 def open(self):
     img_name = ustr(
         QtGui.QFileDialog.getOpenFileName(
             self, 'Open file', ".",
             "*.jpg;;*.png;;*.jpeg;;*.bmp;;All Files (*)"))
     #print unicode(img_name, 'ascii')
     print(img_name)
     self.png = QtGui.QPixmap(img_name).scaled(self.label_Image.width(),
                                               self.label_Image.height())
     self.label_Image.setPixmap(self.png)
     self.image_path = img_name
     #self.image_path.setText(self.image_path)
     self.setWindowTitle(
         _translate("MainWindow", "LabelMe" + " " + ustr(self.image_path),
                    None))
Пример #6
0
    def saveLabels(self, annotationFilePath):
        annotationFilePath = ustr(annotationFilePath)
        if self.labelFile is None:
            self.labelFile = LabelFile()
            self.labelFile.verified = self.canvas.verified

        def format_shape(s):
            return dict(label=s.label,
                        line_color=s.line_color.getRgb()
                        if s.line_color != self.lineColor else None,
                        fill_color=s.fill_color.getRgb()
                        if s.fill_color != self.fillColor else None,
                        points=[(p.x(), p.y()) for p in s.points],
                       # add chris
                        difficult = s.difficult)

        shapes = [format_shape(shape) for shape in self.canvas.shapes]
        # Can add differrent annotation formats here
        try:
            if self.usingPascalVocFormat is True:
                print ('Img: ' + self.filePath +
                       ' -> Its xml: ' + annotationFilePath)
                self.labelFile.savePascalVocFormat(annotationFilePath, shapes, self.filePath, self.imageData,
                                                   self.lineColor.getRgb(), self.fillColor.getRgb())
            else:
                self.labelFile.save(annotationFilePath, shapes, self.filePath, self.imageData,
                                    self.lineColor.getRgb(), self.fillColor.getRgb())
            return True
        except LabelFileError as e:
            self.errorMessage(u'Error saving label data',
                              u'<b>%s</b>' % e)
            return False
Пример #7
0
    def openDir(self, _value=False):
        if not self.mayContinue():
            return

        path = os.path.dirname(self.filePath)\
            if self.filePath else '.'

        if self.lastOpenDir is not None and len(self.lastOpenDir) > 1:
            path = self.lastOpenDir

        dirpath = ustr(QFileDialog.getExistingDirectory(self,
                                                     '%s - Open Directory' % __appname__, path,  QFileDialog.ShowDirsOnly
                                                     | QFileDialog.DontResolveSymlinks))

        if dirpath is not None and len(dirpath) > 1:
            self.lastOpenDir = dirpath

        self.dirname = dirpath
        self.filePath = None
        self.fileListWidget.clear()
        self.mImgList = self.scanAllImages(dirpath)
        self.openNextImg()
        for imgPath in self.mImgList:
            item = QListWidgetItem(imgPath)
            self.fileListWidget.addItem(item)
Пример #8
0
    def changeSavedir(self, _value=False):
        if self.defaultSaveDir is not None:
            path = ustr(self.defaultSaveDir)
        else:
            path = '.'

        dirpath = ustr(QFileDialog.getExistingDirectory(self,
                                                       '%s - Save to the directory' % __appname__, path,  QFileDialog.ShowDirsOnly
                                                       | QFileDialog.DontResolveSymlinks))

        if dirpath is not None and len(dirpath) > 1:
            self.defaultSaveDir = dirpath

        self.statusBar().showMessage('%s . Annotation will be saved to %s' %
                                     ('Change saved folder', self.defaultSaveDir))
        self.statusBar().show()
 def appendObjects(self, top):
     for each_object in self.boxlist:
         object_item = SubElement(top, 'object')
         name = SubElement(object_item, 'name')
         name.text = ustr(each_object['name'])
         pose = SubElement(object_item, 'pose')
         pose.text = "Unspecified"
         truncated = SubElement(object_item, 'truncated')
         if int(float(each_object['ymax'])) == int(float(self.imgSize[0])) or (int(float(each_object['ymin'])) == 1):
             truncated.text = "1"  # max == height or min
         elif (int(float(each_object['xmax'])) == int(float(self.imgSize[1]))) or (int(float(each_object['xmin'])) == 1):
             truncated.text = "1"  # max == width or min
         else:
             truncated.text = "0"
         difficult = SubElement(object_item, 'difficult')
         difficult.text = str(bool(each_object['difficult']) & 1)
         bndbox = SubElement(object_item, 'bndbox')
         xmin = SubElement(bndbox, 'xmin')
         xmin.text = str(each_object['xmin'])
         ymin = SubElement(bndbox, 'ymin')
         ymin.text = str(each_object['ymin'])
         xmax = SubElement(bndbox, 'xmax')
         xmax.text = str(each_object['xmax'])
         ymax = SubElement(bndbox, 'ymax')
         ymax.text = str(each_object['ymax'])
Пример #10
0
def generateColorByText(text):
    s = str(ustr(text))   
    hashCode = int(hashlib.sha256(s.encode('utf-8')).hexdigest(), 16)
    r = int((hashCode / 255) % 255)
    g = int((hashCode / 65025)  % 255)
    b = int((hashCode / 16581375)  % 255)
    return QColor(r, g, b, 100)
Пример #11
0
    def closeEvent(self, event):
        if not self.mayContinue():
            event.ignore()
        s = self.settings
        # If it loads images from dir, don't load it at the begining
        if self.dirname is None:
            s['filename'] = self.filePath if self.filePath else ''
        else:
            s['filename'] = ''

        s['window/size'] = self.size()
        s['window/position'] = self.pos()
        s['window/state'] = self.saveState()
        s['line/color'] = self.lineColor
        s['fill/color'] = self.fillColor
        s['recentFiles'] = self.recentFiles
        s['advanced'] = not self._beginner
        if self.defaultSaveDir is not None and len(self.defaultSaveDir) > 1:
            s['savedir'] = ustr(self.defaultSaveDir)
        else:
            s['savedir'] = ""

        if self.lastOpenDir is not None and len(self.lastOpenDir) > 1:
            s['lastOpenDir'] = self.lastOpenDir
        else:
            s['lastOpenDir'] = ""
Пример #12
0
 def openFile(self, _value=False):
     if not self.mayContinue():
         return
     path = os.path.dirname(ustr(self.filePath)) if self.filePath else '.'
     formats = ['*.%s' % fmt.data().decode("ascii").lower() for fmt in QImageReader.supportedImageFormats()]
     filters = "Image & Label files (%s)" % ' '.join(formats + ['*%s' % LabelFile.suffix])
     filename = QFileDialog.getOpenFileName(self, '%s - Choose Image or Label file' % __appname__, path, filters)
     if filename:
         if isinstance(filename, (tuple, list)):
             filename = filename[0]
         self.loadFile(filename)
Пример #13
0
    def scanAllImages(self, folderPath):
        extensions = ['.jpeg', '.jpg', '.png', '.bmp']
        images = []

        for root, dirs, files in os.walk(folderPath):
            for file in files:
                if file.lower().endswith(tuple(extensions)):
                    relatviePath = os.path.join(root, file)
                    path = ustr(os.path.abspath(relatviePath))
                    images.append(path)
        images.sort(key=lambda x: x.lower())
        return images
Пример #14
0
 def delete_line(self):
     if self.pre_pos is not None:
         point1 = self.points.pop()
         #print point1
         point2 = self.points.pop()
         #print point2
         cv2.circle(self.image,point1,2,(0,0,0),2)
         cv2.circle(self.mask,point1,2,(0,0,0),2)
         cv2.circle(self.image,point2,2,(0,0,0),2)
         cv2.circle(self.mask,point2,2,(0,0,0),2)
         cv2.line(ustr(self.image), point2, point1, (0,0,0),2)
         cv2.line(self.mask, point2, point1, (0,0,0), 2)
         cv2.imshow('image', self.image)
         self.pre_pos = None
Пример #15
0
    def openAnnotation(self, _value=False):
        if self.filePath is None:
            return

        path = os.path.dirname(ustr(self.filePath))\
            if self.filePath else '.'
        if self.usingPascalVocFormat:
            filters = "Open Annotation XML file (%s)" % \
                      ' '.join(['*.xml'])
            filename = QFileDialog.getOpenFileName(self,'%s - Choose a xml file' % __appname__, path, filters)
            if filename:
                if isinstance(filename, (tuple, list)):
                    filename = filename[0]
            self.loadPascalXMLByFilename(filename)
Пример #16
0
 def _cast(self, key, value):
     # XXX: Very nasty way of converting types to QVariant methods :P
     t = self.types.get(key)
     if t is not None and t != QVariant:
         if t is str:
             return ustr(value)
         else:
             try:
                 method = getattr(QVariant, re.sub(
                     '^Q', 'to', t.__name__, count=1))
                 return method(value)
             except AttributeError as e:
                 # print(e)
                 return value
     return value
Пример #17
0
def render_blocks(blocks, md):
    rendered = []
    append=rendered.append
    for section in blocks:
        if type(section) is TupleType:
            l=len(section)
            if l==1:
                # Simple var
                section=section[0]
                if type(section) is StringType: section=md[section]
                else: section=section(md)
                section=ustr(section)
            else:
                # if
                cache={}
                md._push(cache)
                try:
                    i=0
                    m=l-1
                    while i < m:
                        cond=section[i]
                        if type(cond) is StringType:
                            n=cond
                            try:
                                cond=md[cond]
                                cache[n]=cond
                            except KeyError, v:
                                v=str(v)
                                if n != v: raise KeyError, v, sys.exc_traceback
                                cond=None
                        else: cond=cond(md)
                        if cond:
                            section=section[i+1]
                            if section: section=render_blocks(section,md)
                            else: section=''
                            m=0
                            break
                        i=i+2
                    if m:
                        if i==m: section=render_blocks(section[i],md)
                        else: section=''

                finally: md._pop()

        elif type(section) is not StringType and type(section) is not UnicodeType:
            section=section(md)
Пример #18
0
def render_blocks(blocks, md):
    rendered = []
    append = rendered.append
    for section in blocks:
        if type(section) is TupleType:
            l = len(section)
            if l == 1:
                # Simple var
                section = section[0]
                if type(section) is StringType: section = md[section]
                else: section = section(md)
                section = ustr(section)
            else:
                # if
                cache = {}
                md._push(cache)
                try:
                    i = 0
                    m = l - 1
                    while i < m:
                        cond = section[i]
                        if type(cond) is StringType:
                            n = cond
                            try:
                                cond = md[cond]
                                cache[n] = cond
                            except KeyError, v:
                                v = str(v)
                                if n != v: raise KeyError, v, sys.exc_traceback
                                cond = None
                        else:
                            cond = cond(md)
                        if cond:
                            section = section[i + 1]
                            if section: section = render_blocks(section, md)
                            else: section = ''
                            m = 0
                            break
                        i = i + 2
                    if m:
                        if i == m: section = render_blocks(section[i], md)
                        else: section = ''

                finally:
                    md._pop()
Пример #19
0
    def draw(self,event,x,y,flags,param):
        #self.save_file()
        fixed_range=True
        path = ustr(self.image_path).split('.')[0]
        suffix = 'bmp'
        #print path
        mask_name = path + '_mask.' + suffix
        flood_name = path + '_index.' + suffix
        flood2_name = path + '_category.' + suffix

        self.choose_category.emit()

        if event == cv2.EVENT_LBUTTONDOWN:
            self.points.append((x,y))
            #cv2.circle(self.label_Image.pixmap,(x,y),2,(0,0,255),2)
            cv2.circle(self.image,(x,y),2,(0,0,255),2)
            cv2.circle(self.mask,(x,y),2,(255,255,255),2)
            #print self.points
            #print self.pre_pos

            if self.pre_pos is not None:
                cv2.line(ustr(self.image), self.pre_pos, (x,y), (0,255,0),2)
                cv2.line(self.mask, self.pre_pos, (x,y), (255,255,255), 2)
                if self.isEqual(self.points[0],self.points[-1]):
                    cv2.line(ustr(self.image), (x,y), self.points[0], (0,255,0),2)
                    cv2.line(self.mask, (x,y), self.points[0], (255,255,255), 2)
                    self.pre_pos = None
                    self.points = []
                else:
                    self.pre_pos = (x, y)
            else:
                #self.first_pos = (x, y)
                self.pre_pos = (x, y)
            self.mask_ = self.mask.copy()
            self.mask2_ = self.mask.copy()
            cv2.imshow('image', self.image)
            #cv2.imshow('mask', self.mask)
            #self.pre_pos = (x, y)

        #elif event == cv2.EVENT_LBUTTONDBLCLK:
        #    QtGui.QMessageBox.information(self,"Information", u"确定删除?")

        elif event == cv2.EVENT_RBUTTONUP:
            self.pre_pos = None
    	    #print(self.mask.dtype)
    	    fixed_range=True
    	    flags=8
            #print 'step 1'

            #点击到区域外撤销
            tmp_mask2_ = self.mask.copy()
            tmp = self.bgr_list[ustr(self.object)]
            if self.flooded.item(y,x) != 0 or self.flooded2.item(y,x) != 0 :
                cv2.floodFill(self.flooded2_show, tmp_mask2_, (x,y), (0,0,0), (0,)*3, (0,)*3, flags)
                cv2.floodFill(self.flooded, self.mask_, (x,y), 0, (255,)*3, (160,)*3, flags)
                cv2.floodFill(self.flooded2, self.mask2_, (x,y), 0, (255,)*3, (160,)*3, flags)
                #cv2.imshow('index',self.flooded)
                cv2.imshow('category',self.flooded2_show)
                cv2.imencode('.bmp',self.flooded)[1].tofile(ustr(flood_name))
                cv2.imencode('.bmp',self.flooded2)[1].tofile(ustr(flood2_name))
                #self.index_num = self.index_num - 1
            else:
                self.index_num = self.index_num + 1
                tmp_mask = self.mask.copy()
                print self.index_num
                #cv2.floodFill(self.flooded, tmp_mask, (x,y), (random.randint(0,255), random.randint(0,255), random.randint(0,255)), (0,)*3, (0,)*3, 4)
                cv2.floodFill(self.flooded, tmp_mask, (x,y), self.index_num, (0,)*3, (0,)*3, 4)
                mask_gray=self.mask.copy()
                res,thres=cv2.threshold(mask_gray,0,255,cv2.THRESH_BINARY)
                thresgray=cv2.cvtColor(thres,cv2.COLOR_GRAY2BGR)
                #cv2.imshow('index',self.flooded)
                cv2.imencode('.bmp',self.flooded)[1].tofile(ustr(flood_name))

                tmp_mask2 = self.mask.copy()
                tmp_mask3 = self.mask.copy()

                print self.bgr_list[unicode(self.object)]
                tmp = self.bgr_list[unicode(self.object)][1:-1].split(',')
                b = int(tmp[0])
                g = int(tmp[1])
                r = int(tmp[2])
                print self.gray_list[unicode(self.object)]

                cv2.floodFill(self.flooded2_show, tmp_mask3, (x,y), (b, g, r),  (0,)*3, (0,)*3, flags)
                cv2.floodFill(self.flooded2, tmp_mask2, (x,y), int(self.gray_list[unicode(self.object)]),  (0,)*3, (0,)*3, flags)
                cv2.imshow('category',self.flooded2_show)
                cv2.imencode('.bmp',self.flooded2)[1].tofile(ustr(flood2_name))
Пример #20
0
def html_quote(v, name='(Unknown name)', md={}):
    return escape(ustr(v), 1)
Пример #21
0
 def save_file(self):
     if self.image_path:
         image_file_name = ustr(self.image_path).split('.')[0]
         saved_file_name = image_file_name + '.xml'
Пример #22
0
 def fileitemDoubleClicked(self, item=None):
     currIndex = self.mImgList.index(ustr(item.text()))
     if currIndex < len(self.mImgList):
         filename = self.mImgList[currIndex]
         if filename:
             self.loadFile(filename)
Пример #23
0
    def loadFile(self, filePath=None):
        """Load the specified file, or the last opened file if None."""
        self.resetState()
        self.canvas.setEnabled(False)
        if filePath is None:
            filePath = self.settings.get('filename')

        unicodeFilePath = ustr(filePath)
        # Tzutalin 20160906 : Add file list and dock to move faster
        # Highlight the file item
        if unicodeFilePath and self.fileListWidget.count() > 0:
            index = self.mImgList.index(unicodeFilePath)
            fileWidgetItem = self.fileListWidget.item(index)
            fileWidgetItem.setSelected(True)

        if unicodeFilePath and os.path.exists(unicodeFilePath):
            if LabelFile.isLabelFile(unicodeFilePath):
                try:
                    self.labelFile = LabelFile(unicodeFilePath)
                except LabelFileError as e:
                    self.errorMessage(u'Error opening file',
                                      (u"<p><b>%s</b></p>"
                                       u"<p>Make sure <i>%s</i> is a valid label file.")
                                      % (e, unicodeFilePath))
                    self.status("Error reading %s" % unicodeFilePath)
                    return False
                self.imageData = self.labelFile.imageData
                self.lineColor = QColor(*self.labelFile.lineColor)
                self.fillColor = QColor(*self.labelFile.fillColor)
            else:
                # Load image:
                # read data first and store for saving into label file.
                self.imageData = read(unicodeFilePath, None)
                self.labelFile = None
            image = QImage.fromData(self.imageData)
            if image.isNull():
                self.errorMessage(u'Error opening file',
                                  u"<p>Make sure <i>%s</i> is a valid image file." % unicodeFilePath)
                self.status("Error reading %s" % unicodeFilePath)
                return False
            self.status("Loaded %s" % os.path.basename(unicodeFilePath))
            self.image = image
            self.filePath = unicodeFilePath
            self.canvas.loadPixmap(QPixmap.fromImage(image))
            if self.labelFile:
                self.loadLabels(self.labelFile.shapes)
            self.setClean()
            self.canvas.setEnabled(True)
            self.adjustScale(initial=True)
            self.paintCanvas()
            self.addRecentFile(self.filePath)
            self.toggleActions(True)

            # Label xml file and show bound box according to its filename
            if self.usingPascalVocFormat is True:
                if self.defaultSaveDir is not None:
                    basename = os.path.basename(
                        os.path.splitext(self.filePath)[0]) + XML_EXT
                    xmlPath = os.path.join(self.defaultSaveDir, basename)
                    self.loadPascalXMLByFilename(xmlPath)
                else:
                    xmlPath = filePath.split(".")[0] + XML_EXT
                    if os.path.isfile(xmlPath):
                        self.loadPascalXMLByFilename(xmlPath)

            self.setWindowTitle(__appname__ + ' ' + filePath)

            # Default : select last item if there is at least one item
            if self.labelList.count():
                self.labelList.setCurrentItem(self.labelList.item(self.labelList.count()-1))
                self.labelList.setItemSelected(self.labelList.item(self.labelList.count()-1), True)

            self.canvas.setFocus(True)
            return True
        return False
Пример #24
0
def html_quote(v, name='(Unknown name)', md={}):
    return escape(ustr(v), 1)
Пример #25
0
    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.prevLabelText = ''

        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)

        # Add chris
        self.diffcButton = QCheckBox("Difficult")
        self.diffcButton.setChecked(False)
        self.diffcButton.stateChanged.connect(self.btnstate)

        self.labelListContainer = QWidget()
        self.labelListContainer.setLayout(listLayout)
        listLayout.addWidget(self.editButton)  # , 0, Qt.AlignCenter)
        # Add chris
        listLayout.addWidget(self.diffcButton)
        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+Shift+O', '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')

        verify = action('&Verify Image', self.verifyImg,
                        'space', 'verify', u'Verify Image')

        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, verify, 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 = ustr(defaultFilename)
        self.recentFiles = []
        self.maxRecent = 7
        self.lineColor = None
        self.fillColor = None
        self.zoom_level = 100
        self.fit_window = False
        # Add Chris
        self.difficult = 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 = ustr(settings.get('savedir', None))
        self.lastOpenDir = ustr(settings.get('lastOpenDir', None))
        if saveDir is not None and 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
        # Add chris
        Shape.Difficult = self.difficult

        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 or ""))

        # Callbacks:
        self.zoomWidget.valueChanged.connect(self.paintCanvas)

        self.populateModeActions()