Merge remote-tracking branch 'origin/dygraph' into dygraph
commit
000028c920
|
@ -17,28 +17,12 @@
|
||||||
import argparse
|
import argparse
|
||||||
import ast
|
import ast
|
||||||
import codecs
|
import codecs
|
||||||
|
import json
|
||||||
import os.path
|
import os.path
|
||||||
import platform
|
import platform
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from collections import defaultdict
|
|
||||||
import json
|
|
||||||
import cv2
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
__dir__ = os.path.dirname(os.path.abspath(__file__))
|
|
||||||
|
|
||||||
import numpy as np
|
|
||||||
|
|
||||||
|
|
||||||
sys.path.append(__dir__)
|
|
||||||
sys.path.append(os.path.abspath(os.path.join(__dir__, '../..')))
|
|
||||||
sys.path.append(os.path.abspath(os.path.join(__dir__, '../PaddleOCR')))
|
|
||||||
sys.path.append("..")
|
|
||||||
|
|
||||||
from paddleocr import PaddleOCR
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
|
@ -46,18 +30,16 @@ try:
|
||||||
from PyQt5.QtCore import *
|
from PyQt5.QtCore import *
|
||||||
from PyQt5.QtWidgets import *
|
from PyQt5.QtWidgets import *
|
||||||
except ImportError:
|
except ImportError:
|
||||||
# needed for py3+qt4
|
print("Please install pyqt5...")
|
||||||
# Ref:
|
|
||||||
# http://pyqt.sourceforge.net/Docs/PyQt4/incompatible_apis.html
|
|
||||||
# http://stackoverflow.com/questions/21217399/pyqt4-qtcore-qvariant-object-instead-of-a-string
|
|
||||||
if sys.version_info.major >= 3:
|
|
||||||
import sip
|
|
||||||
|
|
||||||
sip.setapi('QVariant', 2)
|
__dir__ = os.path.dirname(os.path.abspath(__file__))
|
||||||
from PyQt4.QtGui import *
|
|
||||||
from PyQt4.QtCore import *
|
|
||||||
|
|
||||||
from combobox import ComboBox
|
sys.path.append(__dir__)
|
||||||
|
sys.path.append(os.path.abspath(os.path.join(__dir__, '../..')))
|
||||||
|
sys.path.append(os.path.abspath(os.path.join(__dir__, '../PaddleOCR')))
|
||||||
|
sys.path.append("..")
|
||||||
|
|
||||||
|
from paddleocr import PaddleOCR
|
||||||
from libs.constants import *
|
from libs.constants import *
|
||||||
from libs.utils import *
|
from libs.utils import *
|
||||||
from libs.settings import Settings
|
from libs.settings import Settings
|
||||||
|
@ -68,7 +50,6 @@ from libs.zoomWidget import ZoomWidget
|
||||||
from libs.autoDialog import AutoDialog
|
from libs.autoDialog import AutoDialog
|
||||||
from libs.labelDialog import LabelDialog
|
from libs.labelDialog import LabelDialog
|
||||||
from libs.colorDialog import ColorDialog
|
from libs.colorDialog import ColorDialog
|
||||||
from libs.toolBar import ToolBar
|
|
||||||
from libs.ustr import ustr
|
from libs.ustr import ustr
|
||||||
from libs.hashableQListWidgetItem import HashableQListWidgetItem
|
from libs.hashableQListWidgetItem import HashableQListWidgetItem
|
||||||
from libs.editinlist import EditInList
|
from libs.editinlist import EditInList
|
||||||
|
@ -76,29 +57,15 @@ from libs.editinlist import EditInList
|
||||||
__appname__ = 'PPOCRLabel'
|
__appname__ = 'PPOCRLabel'
|
||||||
|
|
||||||
|
|
||||||
class WindowMixin(object):
|
class MainWindow(QMainWindow):
|
||||||
|
|
||||||
def menu(self, title, actions=None):
|
|
||||||
menu = self.menuBar().addMenu(title)
|
|
||||||
if actions:
|
|
||||||
addActions(menu, actions)
|
|
||||||
return menu
|
|
||||||
|
|
||||||
def toolbar(self, title, actions=None):
|
|
||||||
toolbar = ToolBar(title)
|
|
||||||
toolbar.setObjectName(u'%sToolBar' % title)
|
|
||||||
# toolbar.setOrientation(Qt.Vertical)
|
|
||||||
toolbar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
|
|
||||||
if actions:
|
|
||||||
addActions(toolbar, actions)
|
|
||||||
self.addToolBar(Qt.LeftToolBarArea, toolbar)
|
|
||||||
return toolbar
|
|
||||||
|
|
||||||
|
|
||||||
class MainWindow(QMainWindow, WindowMixin):
|
|
||||||
FIT_WINDOW, FIT_WIDTH, MANUAL_ZOOM = list(range(3))
|
FIT_WINDOW, FIT_WIDTH, MANUAL_ZOOM = list(range(3))
|
||||||
|
|
||||||
def __init__(self, lang="ch", gpu=False, defaultFilename=None, defaultPrefdefClassFile=None, defaultSaveDir=None):
|
def __init__(self,
|
||||||
|
lang="ch",
|
||||||
|
gpu=False,
|
||||||
|
default_filename=None,
|
||||||
|
default_predefined_class_file=None,
|
||||||
|
default_save_dir=None):
|
||||||
super(MainWindow, self).__init__()
|
super(MainWindow, self).__init__()
|
||||||
self.setWindowTitle(__appname__)
|
self.setWindowTitle(__appname__)
|
||||||
self.setWindowState(Qt.WindowMaximized) # set window max
|
self.setWindowState(Qt.WindowMaximized) # set window max
|
||||||
|
@ -115,8 +82,14 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
self.stringBundle = StringBundle.getBundle(localeStr='zh-CN' if lang == 'ch' else 'en') # 'en'
|
self.stringBundle = StringBundle.getBundle(localeStr='zh-CN' if lang == 'ch' else 'en') # 'en'
|
||||||
getStr = lambda strId: self.stringBundle.getString(strId)
|
getStr = lambda strId: self.stringBundle.getString(strId)
|
||||||
|
|
||||||
self.defaultSaveDir = defaultSaveDir
|
self.defaultSaveDir = default_save_dir
|
||||||
self.ocr = PaddleOCR(use_pdserving=False, use_angle_cls=True, det=True, cls=True, use_gpu=gpu, lang=lang, show_log=False)
|
self.ocr = PaddleOCR(use_pdserving=False,
|
||||||
|
use_angle_cls=True,
|
||||||
|
det=True,
|
||||||
|
cls=True,
|
||||||
|
use_gpu=gpu,
|
||||||
|
lang=lang,
|
||||||
|
show_log=False)
|
||||||
|
|
||||||
if os.path.exists('./data/paddle.png'):
|
if os.path.exists('./data/paddle.png'):
|
||||||
result = self.ocr.ocr('./data/paddle.png', cls=True, det=True)
|
result = self.ocr.ocr('./data/paddle.png', cls=True, det=True)
|
||||||
|
@ -134,7 +107,6 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
self.labelFile = None
|
self.labelFile = None
|
||||||
self.currIndex = 0
|
self.currIndex = 0
|
||||||
|
|
||||||
|
|
||||||
# Whether we need to save or not.
|
# Whether we need to save or not.
|
||||||
self.dirty = False
|
self.dirty = False
|
||||||
|
|
||||||
|
@ -144,7 +116,7 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
self.screencast = "https://github.com/PaddlePaddle/PaddleOCR"
|
self.screencast = "https://github.com/PaddlePaddle/PaddleOCR"
|
||||||
|
|
||||||
# Load predefined classes to the list
|
# Load predefined classes to the list
|
||||||
self.loadPredefinedClasses(defaultPrefdefClassFile)
|
self.loadPredefinedClasses(default_predefined_class_file)
|
||||||
|
|
||||||
# Main widgets and related state.
|
# Main widgets and related state.
|
||||||
self.labelDialog = LabelDialog(parent=self, listItem=self.labelHist)
|
self.labelDialog = LabelDialog(parent=self, listItem=self.labelHist)
|
||||||
|
@ -160,7 +132,7 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
self.PPreader = None
|
self.PPreader = None
|
||||||
self.autoSaveNum = 5
|
self.autoSaveNum = 5
|
||||||
|
|
||||||
################# file list ###############
|
# ================== File List ==================
|
||||||
self.fileListWidget = QListWidget()
|
self.fileListWidget = QListWidget()
|
||||||
self.fileListWidget.itemClicked.connect(self.fileitemDoubleClicked)
|
self.fileListWidget.itemClicked.connect(self.fileitemDoubleClicked)
|
||||||
self.fileListWidget.setIconSize(QSize(25, 25))
|
self.fileListWidget.setIconSize(QSize(25, 25))
|
||||||
|
@ -181,12 +153,12 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
fileListContainer = QWidget()
|
fileListContainer = QWidget()
|
||||||
fileListContainer.setLayout(filelistLayout)
|
fileListContainer.setLayout(filelistLayout)
|
||||||
self.fileListName = getStr('fileList')
|
self.fileListName = getStr('fileList')
|
||||||
self.filedock = QDockWidget(self.fileListName, self)
|
self.fileDock = QDockWidget(self.fileListName, self)
|
||||||
self.filedock.setObjectName(getStr('files'))
|
self.fileDock.setObjectName(getStr('files'))
|
||||||
self.filedock.setWidget(fileListContainer)
|
self.fileDock.setWidget(fileListContainer)
|
||||||
self.addDockWidget(Qt.LeftDockWidgetArea, self.filedock)
|
self.addDockWidget(Qt.LeftDockWidgetArea, self.fileDock)
|
||||||
|
|
||||||
######## Right area ##########
|
# ================== Right Area ==================
|
||||||
listLayout = QVBoxLayout()
|
listLayout = QVBoxLayout()
|
||||||
listLayout.setContentsMargins(0, 0, 0, 0)
|
listLayout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
|
||||||
|
@ -202,7 +174,6 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
self.DelButton = QToolButton()
|
self.DelButton = QToolButton()
|
||||||
self.DelButton.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
|
self.DelButton.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
|
||||||
|
|
||||||
|
|
||||||
lefttoptoolbox = QHBoxLayout()
|
lefttoptoolbox = QHBoxLayout()
|
||||||
lefttoptoolbox.addWidget(self.newButton)
|
lefttoptoolbox.addWidget(self.newButton)
|
||||||
lefttoptoolbox.addWidget(self.reRecogButton)
|
lefttoptoolbox.addWidget(self.reRecogButton)
|
||||||
|
@ -210,23 +181,23 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
lefttoptoolboxcontainer.setLayout(lefttoptoolbox)
|
lefttoptoolboxcontainer.setLayout(lefttoptoolbox)
|
||||||
listLayout.addWidget(lefttoptoolboxcontainer)
|
listLayout.addWidget(lefttoptoolboxcontainer)
|
||||||
|
|
||||||
|
# ================== Label List ==================
|
||||||
################## label list ####################
|
|
||||||
# Create and add a widget for showing current label items
|
# Create and add a widget for showing current label items
|
||||||
self.labelList = EditInList()
|
self.labelList = EditInList()
|
||||||
labelListContainer = QWidget()
|
labelListContainer = QWidget()
|
||||||
labelListContainer.setLayout(listLayout)
|
labelListContainer.setLayout(listLayout)
|
||||||
#self.labelList.itemActivated.connect(self.labelSelectionChanged)
|
|
||||||
self.labelList.itemSelectionChanged.connect(self.labelSelectionChanged)
|
self.labelList.itemSelectionChanged.connect(self.labelSelectionChanged)
|
||||||
self.labelList.clicked.connect(self.labelList.item_clicked)
|
self.labelList.clicked.connect(self.labelList.item_clicked)
|
||||||
|
|
||||||
# Connect to itemChanged to detect checkbox changes.
|
# Connect to itemChanged to detect checkbox changes.
|
||||||
self.labelList.itemChanged.connect(self.labelItemChanged)
|
self.labelList.itemChanged.connect(self.labelItemChanged)
|
||||||
self.labelListDock = QDockWidget(getStr('recognitionResult'),self)
|
self.labelListDockName = getStr('recognitionResult')
|
||||||
|
self.labelListDock = QDockWidget(self.labelListDockName, self)
|
||||||
self.labelListDock.setWidget(self.labelList)
|
self.labelListDock.setWidget(self.labelList)
|
||||||
self.labelListDock.setFeatures(QDockWidget.NoDockWidgetFeatures)
|
self.labelListDock.setFeatures(QDockWidget.NoDockWidgetFeatures)
|
||||||
listLayout.addWidget(self.labelListDock)
|
listLayout.addWidget(self.labelListDock)
|
||||||
|
|
||||||
################## detection box ####################
|
# ================== Detection Box ==================
|
||||||
self.BoxList = QListWidget()
|
self.BoxList = QListWidget()
|
||||||
|
|
||||||
# self.BoxList.itemActivated.connect(self.boxSelectionChanged)
|
# self.BoxList.itemActivated.connect(self.boxSelectionChanged)
|
||||||
|
@ -234,12 +205,13 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
self.BoxList.itemDoubleClicked.connect(self.editBox)
|
self.BoxList.itemDoubleClicked.connect(self.editBox)
|
||||||
# Connect to itemChanged to detect checkbox changes.
|
# Connect to itemChanged to detect checkbox changes.
|
||||||
self.BoxList.itemChanged.connect(self.boxItemChanged)
|
self.BoxList.itemChanged.connect(self.boxItemChanged)
|
||||||
self.BoxListDock = QDockWidget(getStr('detectionBoxposition'), self)
|
self.BoxListDockName = getStr('detectionBoxposition')
|
||||||
|
self.BoxListDock = QDockWidget(self.BoxListDockName, self)
|
||||||
self.BoxListDock.setWidget(self.BoxList)
|
self.BoxListDock.setWidget(self.BoxList)
|
||||||
self.BoxListDock.setFeatures(QDockWidget.NoDockWidgetFeatures)
|
self.BoxListDock.setFeatures(QDockWidget.NoDockWidgetFeatures)
|
||||||
listLayout.addWidget(self.BoxListDock)
|
listLayout.addWidget(self.BoxListDock)
|
||||||
|
|
||||||
############ lower right area ############
|
# ================== Lower Right Area ==================
|
||||||
leftbtmtoolbox = QHBoxLayout()
|
leftbtmtoolbox = QHBoxLayout()
|
||||||
leftbtmtoolbox.addWidget(self.SaveButton)
|
leftbtmtoolbox.addWidget(self.SaveButton)
|
||||||
leftbtmtoolbox.addWidget(self.DelButton)
|
leftbtmtoolbox.addWidget(self.DelButton)
|
||||||
|
@ -251,26 +223,26 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
self.dock.setObjectName(getStr('labels'))
|
self.dock.setObjectName(getStr('labels'))
|
||||||
self.dock.setWidget(labelListContainer)
|
self.dock.setWidget(labelListContainer)
|
||||||
|
|
||||||
|
# ================== Zoom Bar ==================
|
||||||
|
self.imageSlider = QSlider(Qt.Horizontal)
|
||||||
|
self.imageSlider.valueChanged.connect(self.CanvasSizeChange)
|
||||||
|
self.imageSlider.setMinimum(-9)
|
||||||
|
self.imageSlider.setMaximum(510)
|
||||||
|
self.imageSlider.setSingleStep(1)
|
||||||
|
self.imageSlider.setTickPosition(QSlider.TicksBelow)
|
||||||
|
self.imageSlider.setTickInterval(1)
|
||||||
|
|
||||||
########## zoom bar #########
|
|
||||||
self.imgsplider = QSlider(Qt.Horizontal)
|
|
||||||
self.imgsplider.valueChanged.connect(self.CanvasSizeChange)
|
|
||||||
self.imgsplider.setMinimum(-150)
|
|
||||||
self.imgsplider.setMaximum(150)
|
|
||||||
self.imgsplider.setSingleStep(1)
|
|
||||||
self.imgsplider.setTickPosition(QSlider.TicksBelow)
|
|
||||||
self.imgsplider.setTickInterval(1)
|
|
||||||
op = QGraphicsOpacityEffect()
|
op = QGraphicsOpacityEffect()
|
||||||
op.setOpacity(0.2)
|
op.setOpacity(0.2)
|
||||||
self.imgsplider.setGraphicsEffect(op)
|
self.imageSlider.setGraphicsEffect(op)
|
||||||
# self.imgsplider.setAttribute(Qt.WA_TranslucentBackground)
|
|
||||||
self.imgsplider.setStyleSheet("background-color:transparent")
|
self.imageSlider.setStyleSheet("background-color:transparent")
|
||||||
self.imgsliderDock = QDockWidget(getStr('ImageResize'), self)
|
self.imageSliderDock = QDockWidget(getStr('ImageResize'), self)
|
||||||
self.imgsliderDock.setObjectName(getStr('IR'))
|
self.imageSliderDock.setObjectName(getStr('IR'))
|
||||||
self.imgsliderDock.setWidget(self.imgsplider)
|
self.imageSliderDock.setWidget(self.imageSlider)
|
||||||
self.imgsliderDock.setFeatures(QDockWidget.DockWidgetFloatable)
|
self.imageSliderDock.setFeatures(QDockWidget.DockWidgetFloatable)
|
||||||
self.imgsliderDock.setAttribute(Qt.WA_TranslucentBackground)
|
self.imageSliderDock.setAttribute(Qt.WA_TranslucentBackground)
|
||||||
self.addDockWidget(Qt.RightDockWidgetArea, self.imgsliderDock)
|
self.addDockWidget(Qt.RightDockWidgetArea, self.imageSliderDock)
|
||||||
|
|
||||||
self.zoomWidget = ZoomWidget()
|
self.zoomWidget = ZoomWidget()
|
||||||
self.colorDialog = ColorDialog(parent=self)
|
self.colorDialog = ColorDialog(parent=self)
|
||||||
|
@ -278,7 +250,7 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
|
|
||||||
self.msgBox = QMessageBox()
|
self.msgBox = QMessageBox()
|
||||||
|
|
||||||
########## thumbnail #########
|
# ================== Thumbnail ==================
|
||||||
hlayout = QHBoxLayout()
|
hlayout = QHBoxLayout()
|
||||||
m = (0, 0, 0, 0)
|
m = (0, 0, 0, 0)
|
||||||
hlayout.setSpacing(0)
|
hlayout.setSpacing(0)
|
||||||
|
@ -294,10 +266,10 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
self.iconlist.setFlow(QListView.TopToBottom)
|
self.iconlist.setFlow(QListView.TopToBottom)
|
||||||
self.iconlist.setSpacing(10)
|
self.iconlist.setSpacing(10)
|
||||||
self.iconlist.setIconSize(QSize(50, 50))
|
self.iconlist.setIconSize(QSize(50, 50))
|
||||||
self.iconlist.setMovement(False)
|
self.iconlist.setMovement(QListView.Static)
|
||||||
self.iconlist.setResizeMode(QListView.Adjust)
|
self.iconlist.setResizeMode(QListView.Adjust)
|
||||||
self.iconlist.itemClicked.connect(self.iconitemDoubleClicked)
|
self.iconlist.itemClicked.connect(self.iconitemDoubleClicked)
|
||||||
self.iconlist.setStyleSheet("background-color:transparent; border: none;")
|
self.iconlist.setStyleSheet("QListWidget{ background-color:transparent; border: none;}")
|
||||||
self.iconlist.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
self.iconlist.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
||||||
self.nextButton = QToolButton()
|
self.nextButton = QToolButton()
|
||||||
self.nextButton.setIcon(newIcon("next", 40))
|
self.nextButton.setIcon(newIcon("next", 40))
|
||||||
|
@ -310,12 +282,11 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
hlayout.addWidget(self.iconlist)
|
hlayout.addWidget(self.iconlist)
|
||||||
hlayout.addWidget(self.nextButton)
|
hlayout.addWidget(self.nextButton)
|
||||||
|
|
||||||
|
|
||||||
iconListContainer = QWidget()
|
iconListContainer = QWidget()
|
||||||
iconListContainer.setLayout(hlayout)
|
iconListContainer.setLayout(hlayout)
|
||||||
iconListContainer.setFixedHeight(100)
|
iconListContainer.setFixedHeight(100)
|
||||||
|
|
||||||
########### Canvas ###########
|
# ================== Canvas ==================
|
||||||
self.canvas = Canvas(parent=self)
|
self.canvas = Canvas(parent=self)
|
||||||
self.canvas.zoomRequest.connect(self.zoomRequest)
|
self.canvas.zoomRequest.connect(self.zoomRequest)
|
||||||
self.canvas.setDrawingShapeToSquare(settings.get(SETTING_DRAW_SQUARE, False))
|
self.canvas.setDrawingShapeToSquare(settings.get(SETTING_DRAW_SQUARE, False))
|
||||||
|
@ -338,32 +309,17 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
centerLayout = QVBoxLayout()
|
centerLayout = QVBoxLayout()
|
||||||
centerLayout.setContentsMargins(0, 0, 0, 0)
|
centerLayout.setContentsMargins(0, 0, 0, 0)
|
||||||
centerLayout.addWidget(scroll)
|
centerLayout.addWidget(scroll)
|
||||||
#centerLayout.addWidget(self.icondock)
|
|
||||||
centerLayout.addWidget(iconListContainer, 0, Qt.AlignCenter)
|
centerLayout.addWidget(iconListContainer, 0, Qt.AlignCenter)
|
||||||
centercontainer = QWidget()
|
centerContainer = QWidget()
|
||||||
centercontainer.setLayout(centerLayout)
|
centerContainer.setLayout(centerLayout)
|
||||||
|
|
||||||
# self.scrolldock = QDockWidget('WorkSpace',self)
|
self.setCentralWidget(centerContainer)
|
||||||
# self.scrolldock.setObjectName('WorkSpace')
|
|
||||||
# self.scrolldock.setWidget(centercontainer)
|
|
||||||
# self.scrolldock.setFeatures(QDockWidget.NoDockWidgetFeatures)
|
|
||||||
# orititle = self.scrolldock.titleBarWidget()
|
|
||||||
# tmpwidget = QWidget()
|
|
||||||
# self.scrolldock.setTitleBarWidget(tmpwidget)
|
|
||||||
# del orititle
|
|
||||||
self.setCentralWidget(centercontainer) #self.scrolldock
|
|
||||||
self.addDockWidget(Qt.RightDockWidgetArea, self.dock)
|
self.addDockWidget(Qt.RightDockWidgetArea, self.dock)
|
||||||
|
|
||||||
|
self.dock.setFeatures(QDockWidget.DockWidgetClosable | QDockWidget.DockWidgetFloatable)
|
||||||
|
self.fileDock.setFeatures(QDockWidget.NoDockWidgetFeatures)
|
||||||
|
|
||||||
# self.filedock.setFeatures(QDockWidget.DockWidgetFloatable)
|
# ================== Actions ==================
|
||||||
self.filedock.setFeatures(self.filedock.features() ^ QDockWidget.DockWidgetFloatable)
|
|
||||||
|
|
||||||
self.dockFeatures = QDockWidget.DockWidgetClosable | QDockWidget.DockWidgetFloatable
|
|
||||||
self.dock.setFeatures(self.dock.features() ^ self.dockFeatures)
|
|
||||||
|
|
||||||
self.filedock.setFeatures(QDockWidget.NoDockWidgetFeatures)
|
|
||||||
|
|
||||||
###### Actions #######
|
|
||||||
action = partial(newAction, self)
|
action = partial(newAction, self)
|
||||||
quit = action(getStr('quit'), self.close,
|
quit = action(getStr('quit'), self.close,
|
||||||
'Ctrl+Q', 'quit', getStr('quitApp'))
|
'Ctrl+Q', 'quit', getStr('quitApp'))
|
||||||
|
@ -410,7 +366,6 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
'Ctrl+A', 'hide', getStr('showAllBoxDetail'),
|
'Ctrl+A', 'hide', getStr('showAllBoxDetail'),
|
||||||
enabled=False)
|
enabled=False)
|
||||||
|
|
||||||
|
|
||||||
help = action(getStr('tutorial'), self.showTutorialDialog, None, 'help', getStr('tutorialDetail'))
|
help = action(getStr('tutorial'), self.showTutorialDialog, None, 'help', getStr('tutorialDetail'))
|
||||||
showInfo = action(getStr('info'), self.showInfoDialog, None, 'help', getStr('info'))
|
showInfo = action(getStr('info'), self.showInfoDialog, None, 'help', getStr('info'))
|
||||||
showSteps = action(getStr('steps'), self.showStepsDialog, None, 'help', getStr('steps'))
|
showSteps = action(getStr('steps'), self.showStepsDialog, None, 'help', getStr('steps'))
|
||||||
|
@ -451,7 +406,7 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
'Ctrl+E', 'edit', getStr('editLabelDetail'),
|
'Ctrl+E', 'edit', getStr('editLabelDetail'),
|
||||||
enabled=False)
|
enabled=False)
|
||||||
|
|
||||||
######## New actions #######
|
# ================== New Actions ==================
|
||||||
AutoRec = action(getStr('autoRecognition'), self.autoRecognition,
|
AutoRec = action(getStr('autoRecognition'), self.autoRecognition,
|
||||||
'', 'Auto', getStr('autoRecognition'), enabled=False)
|
'', 'Auto', getStr('autoRecognition'), enabled=False)
|
||||||
|
|
||||||
|
@ -495,7 +450,7 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
# self.preButton.setDefaultAction(openPrevImg)
|
# self.preButton.setDefaultAction(openPrevImg)
|
||||||
# self.nextButton.setDefaultAction(openNextImg)
|
# self.nextButton.setDefaultAction(openNextImg)
|
||||||
|
|
||||||
############# Zoom layout ##############
|
# ================== Zoom layout ==================
|
||||||
zoomLayout = QHBoxLayout()
|
zoomLayout = QHBoxLayout()
|
||||||
zoomLayout.addStretch()
|
zoomLayout.addStretch()
|
||||||
self.zoominButton = QToolButton()
|
self.zoominButton = QToolButton()
|
||||||
|
@ -522,7 +477,6 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
icon='color', tip=getStr('shapeFillColorDetail'),
|
icon='color', tip=getStr('shapeFillColorDetail'),
|
||||||
enabled=False)
|
enabled=False)
|
||||||
|
|
||||||
|
|
||||||
# Label list context menu.
|
# Label list context menu.
|
||||||
labelMenu = QMenu()
|
labelMenu = QMenu()
|
||||||
addActions(labelMenu, (edit, delete))
|
addActions(labelMenu, (edit, delete))
|
||||||
|
@ -548,16 +502,14 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
zoomActions=zoomActions, saveLabel=saveLabel,
|
zoomActions=zoomActions, saveLabel=saveLabel,
|
||||||
undo=undo, undoLastPoint=undoLastPoint, open_dataset_dir=open_dataset_dir,
|
undo=undo, undoLastPoint=undoLastPoint, open_dataset_dir=open_dataset_dir,
|
||||||
rotateLeft=rotateLeft, rotateRight=rotateRight, lock=lock,
|
rotateLeft=rotateLeft, rotateRight=rotateRight, lock=lock,
|
||||||
fileMenuActions=(
|
fileMenuActions=(opendir, open_dataset_dir, saveLabel, resetAll, quit),
|
||||||
opendir, open_dataset_dir, saveLabel, resetAll, quit),
|
|
||||||
beginner=(), advanced=(),
|
beginner=(), advanced=(),
|
||||||
editMenu=(createpoly, edit, copy, delete, singleRere, None, undo, undoLastPoint,
|
editMenu=(createpoly, edit, copy, delete, singleRere, None, undo, undoLastPoint,
|
||||||
None, rotateLeft, rotateRight, None, color1, self.drawSquaresOption, lock),
|
None, rotateLeft, rotateRight, None, color1, self.drawSquaresOption, lock),
|
||||||
beginnerContext=(create, edit, copy, delete, singleRere, rotateLeft, rotateRight, lock),
|
beginnerContext=(create, edit, copy, delete, singleRere, rotateLeft, rotateRight, lock),
|
||||||
advancedContext=(createMode, editMode, edit, copy,
|
advancedContext=(createMode, editMode, edit, copy,
|
||||||
delete, shapeLineColor, shapeFillColor),
|
delete, shapeLineColor, shapeFillColor),
|
||||||
onLoadActive=(
|
onLoadActive=(create, createMode, editMode),
|
||||||
create, createMode, editMode),
|
|
||||||
onShapesPresent=(hideAll, showAll))
|
onShapesPresent=(hideAll, showAll))
|
||||||
|
|
||||||
# menus
|
# menus
|
||||||
|
@ -570,7 +522,6 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
recentFiles=QMenu('Open &Recent'),
|
recentFiles=QMenu('Open &Recent'),
|
||||||
labelList=labelMenu)
|
labelList=labelMenu)
|
||||||
|
|
||||||
|
|
||||||
self.lastLabel = None
|
self.lastLabel = None
|
||||||
# Add option to enable/disable labels being displayed at the top of bounding boxes
|
# Add option to enable/disable labels being displayed at the top of bounding boxes
|
||||||
self.displayLabelOption = QAction(getStr('displayLabel'), self)
|
self.displayLabelOption = QAction(getStr('displayLabel'), self)
|
||||||
|
@ -591,7 +542,8 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
self.autoSaveOption.triggered.connect(self.autoSaveFunc)
|
self.autoSaveOption.triggered.connect(self.autoSaveFunc)
|
||||||
|
|
||||||
addActions(self.menus.file,
|
addActions(self.menus.file,
|
||||||
(opendir, open_dataset_dir, None, saveLabel, saveRec, self.autoSaveOption, None, resetAll, deleteImg, quit))
|
(opendir, open_dataset_dir, None, saveLabel, saveRec, self.autoSaveOption, None, resetAll, deleteImg,
|
||||||
|
quit))
|
||||||
|
|
||||||
addActions(self.menus.help, (showKeys, showSteps, showInfo))
|
addActions(self.menus.help, (showKeys, showSteps, showInfo))
|
||||||
addActions(self.menus.view, (
|
addActions(self.menus.view, (
|
||||||
|
@ -601,23 +553,19 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
zoomIn, zoomOut, zoomOrg, None,
|
zoomIn, zoomOut, zoomOrg, None,
|
||||||
fitWindow, fitWidth))
|
fitWindow, fitWidth))
|
||||||
|
|
||||||
addActions(self.menus.autolabel, (AutoRec, reRec, alcm, None, help)) #
|
addActions(self.menus.autolabel, (AutoRec, reRec, alcm, None, help))
|
||||||
|
|
||||||
self.menus.file.aboutToShow.connect(self.updateFileMenu)
|
self.menus.file.aboutToShow.connect(self.updateFileMenu)
|
||||||
|
|
||||||
# Custom context menu for the canvas widget:
|
# Custom context menu for the canvas widget:
|
||||||
addActions(self.canvas.menus[0], self.actions.beginnerContext)
|
addActions(self.canvas.menus[0], self.actions.beginnerContext)
|
||||||
#addActions(self.canvas.menus[1], (
|
|
||||||
# action('&Copy here', self.copyShape),
|
|
||||||
# action('&Move here', self.moveShape)))
|
|
||||||
|
|
||||||
|
|
||||||
self.statusBar().showMessage('%s started.' % __appname__)
|
self.statusBar().showMessage('%s started.' % __appname__)
|
||||||
self.statusBar().show()
|
self.statusBar().show()
|
||||||
|
|
||||||
# Application state.
|
# Application state.
|
||||||
self.image = QImage()
|
self.image = QImage()
|
||||||
self.filePath = ustr(defaultFilename)
|
self.filePath = ustr(default_filename)
|
||||||
self.lastOpenDir = None
|
self.lastOpenDir = None
|
||||||
self.recentFiles = []
|
self.recentFiles = []
|
||||||
self.maxRecent = 7
|
self.maxRecent = 7
|
||||||
|
@ -628,7 +576,7 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
# Add Chris
|
# Add Chris
|
||||||
self.difficult = False
|
self.difficult = False
|
||||||
|
|
||||||
## Fix the compatible issue for qt4 and qt5. Convert the QStringList to python list
|
# Fix the compatible issue for qt4 and qt5. Convert the QStringList to python list
|
||||||
if settings.get(SETTING_RECENT_FILES):
|
if settings.get(SETTING_RECENT_FILES):
|
||||||
if have_qstring():
|
if have_qstring():
|
||||||
recentFileQStringList = settings.get(SETTING_RECENT_FILES)
|
recentFileQStringList = settings.get(SETTING_RECENT_FILES)
|
||||||
|
@ -657,7 +605,6 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
# Add chris
|
# Add chris
|
||||||
Shape.difficult = self.difficult
|
Shape.difficult = self.difficult
|
||||||
|
|
||||||
|
|
||||||
# ADD:
|
# ADD:
|
||||||
# Populate the File menu dynamically.
|
# Populate the File menu dynamically.
|
||||||
self.updateFileMenu()
|
self.updateFileMenu()
|
||||||
|
@ -681,6 +628,12 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
if self.filePath and os.path.isdir(self.filePath):
|
if self.filePath and os.path.isdir(self.filePath):
|
||||||
self.openDirDialog(dirpath=self.filePath, silent=True)
|
self.openDirDialog(dirpath=self.filePath, silent=True)
|
||||||
|
|
||||||
|
def menu(self, title, actions=None):
|
||||||
|
menu = self.menuBar().addMenu(title)
|
||||||
|
if actions:
|
||||||
|
addActions(menu, actions)
|
||||||
|
return menu
|
||||||
|
|
||||||
def keyReleaseEvent(self, event):
|
def keyReleaseEvent(self, event):
|
||||||
if event.key() == Qt.Key_Control:
|
if event.key() == Qt.Key_Control:
|
||||||
self.canvas.setDrawingShapeToSquare(False)
|
self.canvas.setDrawingShapeToSquare(False)
|
||||||
|
@ -690,11 +643,9 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
# Draw rectangle if Ctrl is pressed
|
# Draw rectangle if Ctrl is pressed
|
||||||
self.canvas.setDrawingShapeToSquare(True)
|
self.canvas.setDrawingShapeToSquare(True)
|
||||||
|
|
||||||
|
|
||||||
def noShapes(self):
|
def noShapes(self):
|
||||||
return not self.itemsToShapes
|
return not self.itemsToShapes
|
||||||
|
|
||||||
|
|
||||||
def populateModeActions(self):
|
def populateModeActions(self):
|
||||||
self.canvas.menus[0].clear()
|
self.canvas.menus[0].clear()
|
||||||
addActions(self.canvas.menus[0], self.actions.beginnerContext)
|
addActions(self.canvas.menus[0], self.actions.beginnerContext)
|
||||||
|
@ -702,7 +653,6 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
actions = (self.actions.create,) # if self.beginner() else (self.actions.createMode, self.actions.editMode)
|
actions = (self.actions.create,) # if self.beginner() else (self.actions.createMode, self.actions.editMode)
|
||||||
addActions(self.menus.edit, actions + self.actions.editMenu)
|
addActions(self.menus.edit, actions + self.actions.editMenu)
|
||||||
|
|
||||||
|
|
||||||
def setDirty(self):
|
def setDirty(self):
|
||||||
self.dirty = True
|
self.dirty = True
|
||||||
self.actions.save.setEnabled(True)
|
self.actions.save.setEnabled(True)
|
||||||
|
@ -818,8 +768,9 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
if self.lang == 'ch':
|
if self.lang == 'ch':
|
||||||
self.msgBox.warning(self, "提示", "\n 该图片已经有标注框,旋转操作会打乱标注,建议清除标注框后旋转。")
|
self.msgBox.warning(self, "提示", "\n 该图片已经有标注框,旋转操作会打乱标注,建议清除标注框后旋转。")
|
||||||
else:
|
else:
|
||||||
self.msgBox.warning (self, "Warn", "\n The picture already has a label box, and rotation will disrupt the label.\
|
self.msgBox.warning(self, "Warn", "\n The picture already has a label box, "
|
||||||
It is recommended to clear the label box and rotate it.")
|
"and rotation will disrupt the label. "
|
||||||
|
"It is recommended to clear the label box and rotate it.")
|
||||||
|
|
||||||
def rotateImgAction(self, k=1, _value=False):
|
def rotateImgAction(self, k=1, _value=False):
|
||||||
|
|
||||||
|
@ -894,14 +845,13 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
self.setDirty()
|
self.setDirty()
|
||||||
self.updateComboBox()
|
self.updateComboBox()
|
||||||
|
|
||||||
######## detection box related functions #######
|
# =================== detection box related functions ===================
|
||||||
|
|
||||||
def boxItemChanged(self, item):
|
def boxItemChanged(self, item):
|
||||||
shape = self.itemsToShapesbox[item]
|
shape = self.itemsToShapesbox[item]
|
||||||
|
|
||||||
box = ast.literal_eval(item.text())
|
box = ast.literal_eval(item.text())
|
||||||
# print('shape in labelItemChanged is',shape.points)
|
# print('shape in labelItemChanged is',shape.points)
|
||||||
if box != [(p.x(), p.y()) for p in shape.points]:
|
if box != [(int(p.x()), int(p.y())) for p in shape.points]:
|
||||||
# shape.points = box
|
# shape.points = box
|
||||||
shape.points = [QPointF(p[0], p[1]) for p in box]
|
shape.points = [QPointF(p[0], p[1]) for p in box]
|
||||||
|
|
||||||
|
@ -964,7 +914,6 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
else:
|
else:
|
||||||
return self.mImgList[currIndex - 2: currIndex + 3]
|
return self.mImgList[currIndex - 2: currIndex + 3]
|
||||||
|
|
||||||
|
|
||||||
# Tzutalin 20160906 : Add file list and dock to move faster
|
# Tzutalin 20160906 : Add file list and dock to move faster
|
||||||
def fileitemDoubleClicked(self, item=None):
|
def fileitemDoubleClicked(self, item=None):
|
||||||
self.currIndex = self.mImgList.index(ustr(os.path.join(os.path.abspath(self.dirname), item.text())))
|
self.currIndex = self.mImgList.index(ustr(os.path.join(os.path.abspath(self.dirname), item.text())))
|
||||||
|
@ -983,9 +932,8 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
self.loadFile(filename)
|
self.loadFile(filename)
|
||||||
|
|
||||||
def CanvasSizeChange(self):
|
def CanvasSizeChange(self):
|
||||||
if len(self.mImgList) > 0:
|
if len(self.mImgList) > 0 and self.imageSlider.hasFocus():
|
||||||
self.zoomWidget.setValue(self.zoomWidgetValue + self.imgsplider.value())
|
self.zoomWidget.setValue(self.imageSlider.value())
|
||||||
|
|
||||||
|
|
||||||
def shapeSelectionChanged(self, selected_shapes):
|
def shapeSelectionChanged(self, selected_shapes):
|
||||||
self._noSelectionSlot = True
|
self._noSelectionSlot = True
|
||||||
|
@ -1030,6 +978,10 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
action.setEnabled(True)
|
action.setEnabled(True)
|
||||||
self.updateComboBox()
|
self.updateComboBox()
|
||||||
|
|
||||||
|
# update show counting
|
||||||
|
self.BoxListDock.setWindowTitle(self.BoxListDockName + f" ({self.BoxList.count()})")
|
||||||
|
self.labelListDock.setWindowTitle(self.labelListDockName + f" ({self.labelList.count()})")
|
||||||
|
|
||||||
def remLabels(self, shapes):
|
def remLabels(self, shapes):
|
||||||
if shapes is None:
|
if shapes is None:
|
||||||
# print('rm empty label')
|
# print('rm empty label')
|
||||||
|
@ -1080,7 +1032,6 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
self.updateComboBox()
|
self.updateComboBox()
|
||||||
self.canvas.loadShapes(s)
|
self.canvas.loadShapes(s)
|
||||||
|
|
||||||
|
|
||||||
def singleLabel(self, shape):
|
def singleLabel(self, shape):
|
||||||
if shape is None:
|
if shape is None:
|
||||||
# print('rm empty label')
|
# print('rm empty label')
|
||||||
|
@ -1130,7 +1081,8 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
try:
|
try:
|
||||||
trans_dic = []
|
trans_dic = []
|
||||||
for box in shapes:
|
for box in shapes:
|
||||||
trans_dic.append({"transcription": box['label'], "points": box['points'], 'difficult': box['difficult']})
|
trans_dic.append(
|
||||||
|
{"transcription": box['label'], "points": box['points'], 'difficult': box['difficult']})
|
||||||
self.PPlabel[annotationFilePath] = trans_dic
|
self.PPlabel[annotationFilePath] = trans_dic
|
||||||
if mode == 'Auto':
|
if mode == 'Auto':
|
||||||
self.Cachelabel[annotationFilePath] = trans_dic
|
self.Cachelabel[annotationFilePath] = trans_dic
|
||||||
|
@ -1150,7 +1102,6 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
# fix copy and delete
|
# fix copy and delete
|
||||||
# self.shapeSelectionChanged(True)
|
# self.shapeSelectionChanged(True)
|
||||||
|
|
||||||
|
|
||||||
def labelSelectionChanged(self):
|
def labelSelectionChanged(self):
|
||||||
if self._noSelectionSlot:
|
if self._noSelectionSlot:
|
||||||
return
|
return
|
||||||
|
@ -1163,7 +1114,6 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
else:
|
else:
|
||||||
self.canvas.deSelectShape()
|
self.canvas.deSelectShape()
|
||||||
|
|
||||||
|
|
||||||
def boxSelectionChanged(self):
|
def boxSelectionChanged(self):
|
||||||
if self._noSelectionSlot:
|
if self._noSelectionSlot:
|
||||||
# self.BoxList.scrollToItem(self.currentBox(), QAbstractItemView.PositionAtCenter)
|
# self.BoxList.scrollToItem(self.currentBox(), QAbstractItemView.PositionAtCenter)
|
||||||
|
@ -1177,7 +1127,6 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
else:
|
else:
|
||||||
self.canvas.deSelectShape()
|
self.canvas.deSelectShape()
|
||||||
|
|
||||||
|
|
||||||
def labelItemChanged(self, item):
|
def labelItemChanged(self, item):
|
||||||
shape = self.itemsToShapes[item]
|
shape = self.itemsToShapes[item]
|
||||||
label = item.text()
|
label = item.text()
|
||||||
|
@ -1239,6 +1188,7 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
|
|
||||||
def addZoom(self, increment=10):
|
def addZoom(self, increment=10):
|
||||||
self.setZoom(self.zoomWidget.value() + increment)
|
self.setZoom(self.zoomWidget.value() + increment)
|
||||||
|
self.imageSlider.setValue(self.zoomWidget.value() + increment) # set zoom slider value
|
||||||
|
|
||||||
def zoomRequest(self, delta):
|
def zoomRequest(self, delta):
|
||||||
# get the current scrollbar positions
|
# get the current scrollbar positions
|
||||||
|
@ -1331,7 +1281,6 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
fileWidgetItem = self.fileListWidget.item(index)
|
fileWidgetItem = self.fileListWidget.item(index)
|
||||||
print('unicodeFilePath is', unicodeFilePath)
|
print('unicodeFilePath is', unicodeFilePath)
|
||||||
fileWidgetItem.setSelected(True)
|
fileWidgetItem.setSelected(True)
|
||||||
###
|
|
||||||
self.iconlist.clear()
|
self.iconlist.clear()
|
||||||
self.additems5(None)
|
self.additems5(None)
|
||||||
|
|
||||||
|
@ -1394,9 +1343,11 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
# show file list image count
|
# show file list image count
|
||||||
select_indexes = self.fileListWidget.selectedIndexes()
|
select_indexes = self.fileListWidget.selectedIndexes()
|
||||||
if len(select_indexes) > 0:
|
if len(select_indexes) > 0:
|
||||||
self.filedock.setWindowTitle(self.fileListName + f" ({select_indexes[0].row() + 1}"
|
self.fileDock.setWindowTitle(self.fileListName + f" ({select_indexes[0].row() + 1}"
|
||||||
f"/{self.fileListWidget.count()})")
|
f"/{self.fileListWidget.count()})")
|
||||||
|
# update show counting
|
||||||
|
self.BoxListDock.setWindowTitle(self.BoxListDockName + f" ({self.BoxList.count()})")
|
||||||
|
self.labelListDock.setWindowTitle(self.labelListDockName + f" ({self.labelList.count()})")
|
||||||
|
|
||||||
self.canvas.setFocus(True)
|
self.canvas.setFocus(True)
|
||||||
return True
|
return True
|
||||||
|
@ -1422,7 +1373,6 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
self.loadLabels(shapes)
|
self.loadLabels(shapes)
|
||||||
self.canvas.verified = False
|
self.canvas.verified = False
|
||||||
|
|
||||||
|
|
||||||
def validFilestate(self, filePath):
|
def validFilestate(self, filePath):
|
||||||
if filePath not in self.fileStatedict.keys():
|
if filePath not in self.fileStatedict.keys():
|
||||||
return None
|
return None
|
||||||
|
@ -1517,8 +1467,6 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
natural_sort(images, key=lambda x: x.lower())
|
natural_sort(images, key=lambda x: x.lower())
|
||||||
return images
|
return images
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def openDirDialog(self, _value=False, dirpath=None, silent=False):
|
def openDirDialog(self, _value=False, dirpath=None, silent=False):
|
||||||
if not self.mayContinue():
|
if not self.mayContinue():
|
||||||
return
|
return
|
||||||
|
@ -1538,7 +1486,7 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
self.lastOpenDir = targetDirPath
|
self.lastOpenDir = targetDirPath
|
||||||
self.importDirImages(targetDirPath)
|
self.importDirImages(targetDirPath)
|
||||||
|
|
||||||
def openDatasetDirDialog(self,):
|
def openDatasetDirDialog(self):
|
||||||
if self.lastOpenDir and os.path.exists(self.lastOpenDir):
|
if self.lastOpenDir and os.path.exists(self.lastOpenDir):
|
||||||
if platform.system() == 'Windows':
|
if platform.system() == 'Windows':
|
||||||
os.startfile(self.lastOpenDir)
|
os.startfile(self.lastOpenDir)
|
||||||
|
@ -1550,7 +1498,8 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
if self.lang == 'ch':
|
if self.lang == 'ch':
|
||||||
self.msgBox.warning(self, "提示", "\n 原文件夹已不存在,请从新选择数据集路径!")
|
self.msgBox.warning(self, "提示", "\n 原文件夹已不存在,请从新选择数据集路径!")
|
||||||
else:
|
else:
|
||||||
self.msgBox.warning(self, "Warn", "\n The original folder no longer exists, please choose the data set path again!")
|
self.msgBox.warning(self, "Warn",
|
||||||
|
"\n The original folder no longer exists, please choose the data set path again!")
|
||||||
|
|
||||||
self.actions.open_dataset_dir.setEnabled(False)
|
self.actions.open_dataset_dir.setEnabled(False)
|
||||||
defaultOpenDirPath = os.path.dirname(self.filePath) if self.filePath else '.'
|
defaultOpenDirPath = os.path.dirname(self.filePath) if self.filePath else '.'
|
||||||
|
@ -1572,7 +1521,6 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
self.lastOpenDir = dirpath
|
self.lastOpenDir = dirpath
|
||||||
self.dirname = dirpath
|
self.dirname = dirpath
|
||||||
|
|
||||||
|
|
||||||
self.defaultSaveDir = dirpath
|
self.defaultSaveDir = dirpath
|
||||||
self.statusBar().showMessage('%s started. Annotation will be saved to %s' %
|
self.statusBar().showMessage('%s started. Annotation will be saved to %s' %
|
||||||
(__appname__, self.defaultSaveDir))
|
(__appname__, self.defaultSaveDir))
|
||||||
|
@ -1607,7 +1555,7 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
self.actions.rotateRight.setEnabled(True)
|
self.actions.rotateRight.setEnabled(True)
|
||||||
|
|
||||||
self.fileListWidget.setCurrentRow(0) # set list index to first
|
self.fileListWidget.setCurrentRow(0) # set list index to first
|
||||||
self.filedock.setWindowTitle(self.fileListName + f" (1/{self.fileListWidget.count()})") # show image count
|
self.fileDock.setWindowTitle(self.fileListName + f" (1/{self.fileListWidget.count()})") # show image count
|
||||||
|
|
||||||
def openPrevImg(self, _value=False):
|
def openPrevImg(self, _value=False):
|
||||||
if len(self.mImgList) <= 0:
|
if len(self.mImgList) <= 0:
|
||||||
|
@ -1655,30 +1603,6 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
imgidx = self.getImglabelidx(self.filePath)
|
imgidx = self.getImglabelidx(self.filePath)
|
||||||
self._saveFile(imgidx, mode=mode)
|
self._saveFile(imgidx, mode=mode)
|
||||||
|
|
||||||
|
|
||||||
def saveFileAs(self, _value=False):
|
|
||||||
assert not self.image.isNull(), "cannot save empty image"
|
|
||||||
self._saveFile(self.saveFileDialog())
|
|
||||||
|
|
||||||
def saveFileDialog(self, removeExt=True):
|
|
||||||
caption = '%s - Choose File' % __appname__
|
|
||||||
filters = 'File (*%s)' % LabelFile.suffix
|
|
||||||
openDialogPath = self.currentPath()
|
|
||||||
dlg = QFileDialog(self, caption, openDialogPath, filters)
|
|
||||||
dlg.setDefaultSuffix(LabelFile.suffix[1:])
|
|
||||||
dlg.setAcceptMode(QFileDialog.AcceptSave)
|
|
||||||
filenameWithoutExtension = os.path.splitext(self.filePath)[0]
|
|
||||||
dlg.selectFile(filenameWithoutExtension)
|
|
||||||
dlg.setOption(QFileDialog.DontUseNativeDialog, False)
|
|
||||||
if dlg.exec_():
|
|
||||||
fullFilePath = ustr(dlg.selectedFiles()[0])
|
|
||||||
if removeExt:
|
|
||||||
return os.path.splitext(fullFilePath)[0] # Return file path without the extension.
|
|
||||||
else:
|
|
||||||
return fullFilePath
|
|
||||||
return ''
|
|
||||||
|
|
||||||
|
|
||||||
def saveLockedShapes(self):
|
def saveLockedShapes(self):
|
||||||
self.canvas.lockedShapes = []
|
self.canvas.lockedShapes = []
|
||||||
self.canvas.selectedShapes = []
|
self.canvas.selectedShapes = []
|
||||||
|
@ -1691,7 +1615,6 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
self.canvas.selectedShapes.remove(s)
|
self.canvas.selectedShapes.remove(s)
|
||||||
self.canvas.shapes.remove(s)
|
self.canvas.shapes.remove(s)
|
||||||
|
|
||||||
|
|
||||||
def _saveFile(self, annotationFilePath, mode='Manual'):
|
def _saveFile(self, annotationFilePath, mode='Manual'):
|
||||||
if len(self.canvas.lockedShapes) != 0:
|
if len(self.canvas.lockedShapes) != 0:
|
||||||
self.saveLockedShapes()
|
self.saveLockedShapes()
|
||||||
|
@ -1831,6 +1754,8 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
if self.noShapes():
|
if self.noShapes():
|
||||||
for action in self.actions.onShapesPresent:
|
for action in self.actions.onShapesPresent:
|
||||||
action.setEnabled(False)
|
action.setEnabled(False)
|
||||||
|
self.BoxListDock.setWindowTitle(self.BoxListDockName + f" ({self.BoxList.count()})")
|
||||||
|
self.labelListDock.setWindowTitle(self.labelListDockName + f" ({self.labelList.count()})")
|
||||||
|
|
||||||
def chshapeLineColor(self):
|
def chshapeLineColor(self):
|
||||||
color = self.colorDialog.getColor(self.lineColor, u'Choose line color',
|
color = self.colorDialog.getColor(self.lineColor, u'Choose line color',
|
||||||
|
@ -1867,7 +1792,6 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
else:
|
else:
|
||||||
self.labelHist.append(line)
|
self.labelHist.append(line)
|
||||||
|
|
||||||
|
|
||||||
def togglePaintLabelsOption(self):
|
def togglePaintLabelsOption(self):
|
||||||
for shape in self.canvas.shapes:
|
for shape in self.canvas.shapes:
|
||||||
shape.paintLabel = self.displayLabelOption.isChecked()
|
shape.paintLabel = self.displayLabelOption.isChecked()
|
||||||
|
@ -1930,7 +1854,6 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
self.setDirty()
|
self.setDirty()
|
||||||
self.saveCacheLabel()
|
self.saveCacheLabel()
|
||||||
|
|
||||||
|
|
||||||
def reRecognition(self):
|
def reRecognition(self):
|
||||||
img = cv2.imread(self.filePath)
|
img = cv2.imread(self.filePath)
|
||||||
# org_box = [dic['points'] for dic in self.PPlabel[self.getImglabelidx(self.filePath)]]
|
# org_box = [dic['points'] for dic in self.PPlabel[self.getImglabelidx(self.filePath)]]
|
||||||
|
@ -1976,6 +1899,9 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
self.canvas.isInTheSameImage = False
|
self.canvas.isInTheSameImage = False
|
||||||
self.setDirty()
|
self.setDirty()
|
||||||
elif len(self.result_dic) == len(self.canvas.shapes) and rec_flag == 0:
|
elif len(self.result_dic) == len(self.canvas.shapes) and rec_flag == 0:
|
||||||
|
if self.lang == 'ch':
|
||||||
|
QMessageBox.information(self, "Information", "识别结果保持一致!")
|
||||||
|
else:
|
||||||
QMessageBox.information(self, "Information", "The recognition result remains unchanged!")
|
QMessageBox.information(self, "Information", "The recognition result remains unchanged!")
|
||||||
else:
|
else:
|
||||||
print('Can not recgonise in ', self.filePath)
|
print('Can not recgonise in ', self.filePath)
|
||||||
|
@ -2041,7 +1967,6 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
self.AutoRecognition.setEnabled(True)
|
self.AutoRecognition.setEnabled(True)
|
||||||
self.actions.AutoRec.setEnabled(True)
|
self.actions.AutoRec.setEnabled(True)
|
||||||
|
|
||||||
|
|
||||||
def modelChoose(self):
|
def modelChoose(self):
|
||||||
print(self.comboBox.currentText())
|
print(self.comboBox.currentText())
|
||||||
lg_idx = {'Chinese & English': 'ch', 'English': 'en', 'French': 'french', 'German': 'german',
|
lg_idx = {'Chinese & English': 'ch', 'English': 'en', 'French': 'french', 'German': 'german',
|
||||||
|
@ -2068,14 +1993,12 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
self.actions.saveLabel.setEnabled(True)
|
self.actions.saveLabel.setEnabled(True)
|
||||||
self.actions.saveRec.setEnabled(True)
|
self.actions.saveRec.setEnabled(True)
|
||||||
|
|
||||||
|
|
||||||
def saveFilestate(self):
|
def saveFilestate(self):
|
||||||
with open(self.fileStatepath, 'w', encoding='utf-8') as f:
|
with open(self.fileStatepath, 'w', encoding='utf-8') as f:
|
||||||
for key in self.fileStatedict:
|
for key in self.fileStatedict:
|
||||||
f.write(key + '\t')
|
f.write(key + '\t')
|
||||||
f.write(str(self.fileStatedict[key]) + '\n')
|
f.write(str(self.fileStatedict[key]) + '\n')
|
||||||
|
|
||||||
|
|
||||||
def loadLabelFile(self, labelpath):
|
def loadLabelFile(self, labelpath):
|
||||||
labeldict = {}
|
labeldict = {}
|
||||||
if not os.path.exists(labelpath):
|
if not os.path.exists(labelpath):
|
||||||
|
@ -2094,7 +2017,6 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
labeldict[file] = []
|
labeldict[file] = []
|
||||||
return labeldict
|
return labeldict
|
||||||
|
|
||||||
|
|
||||||
def savePPlabel(self, mode='Manual'):
|
def savePPlabel(self, mode='Manual'):
|
||||||
savedfile = [self.getImglabelidx(i) for i in self.fileStatedict.keys()]
|
savedfile = [self.getImglabelidx(i) for i in self.fileStatedict.keys()]
|
||||||
with open(self.PPlabelpath, 'w', encoding='utf-8') as f:
|
with open(self.PPlabelpath, 'w', encoding='utf-8') as f:
|
||||||
|
@ -2147,8 +2069,10 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
ques_img.append(key)
|
ques_img.append(key)
|
||||||
print("Can not read image ", e)
|
print("Can not read image ", e)
|
||||||
if ques_img:
|
if ques_img:
|
||||||
QMessageBox.information(self, "Information", "The following images can not be saved, "
|
QMessageBox.information(self,
|
||||||
"please check the image path and labels.\n" + "".join(str(i)+'\n' for i in ques_img))
|
"Information",
|
||||||
|
"The following images can not be saved, please check the image path and labels.\n"
|
||||||
|
+ "".join(str(i) + '\n' for i in ques_img))
|
||||||
QMessageBox.information(self, "Information", "Cropped images have been saved in " + str(crop_img_dir))
|
QMessageBox.information(self, "Information", "Cropped images have been saved in " + str(crop_img_dir))
|
||||||
|
|
||||||
def speedChoose(self):
|
def speedChoose(self):
|
||||||
|
@ -2188,15 +2112,15 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
self.canvas.loadShapes(shapes, replace=replace)
|
self.canvas.loadShapes(shapes, replace=replace)
|
||||||
print("loadShapes") # 1
|
print("loadShapes") # 1
|
||||||
|
|
||||||
|
|
||||||
def lockSelectedShape(self):
|
def lockSelectedShape(self):
|
||||||
"""lock the selsected shapes.
|
"""lock the selected shapes.
|
||||||
|
|
||||||
Add self.selectedShapes to lock self.canvas.lockedShapes,
|
Add self.selectedShapes to lock self.canvas.lockedShapes,
|
||||||
which holds the ratio of the four coordinates of the locked shapes
|
which holds the ratio of the four coordinates of the locked shapes
|
||||||
to the width and height of the image
|
to the width and height of the image
|
||||||
"""
|
"""
|
||||||
width, height = self.image.width(), self.image.height()
|
width, height = self.image.width(), self.image.height()
|
||||||
|
|
||||||
def format_shape(s):
|
def format_shape(s):
|
||||||
return dict(label=s.label, # str
|
return dict(label=s.label, # str
|
||||||
line_color=s.line_color.getRgb(),
|
line_color=s.line_color.getRgb(),
|
||||||
|
@ -2204,6 +2128,7 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
ratio=[[int(p.x()) / width, int(p.y()) / height] for p in s.points], # QPonitF
|
ratio=[[int(p.x()) / width, int(p.y()) / height] for p in s.points], # QPonitF
|
||||||
# add chris
|
# add chris
|
||||||
difficult=s.difficult) # bool
|
difficult=s.difficult) # bool
|
||||||
|
|
||||||
# lock
|
# lock
|
||||||
if len(self.canvas.lockedShapes) == 0:
|
if len(self.canvas.lockedShapes) == 0:
|
||||||
for s in self.canvas.selectedShapes:
|
for s in self.canvas.selectedShapes:
|
||||||
|
@ -2237,9 +2162,11 @@ def read(filename, default=None):
|
||||||
except:
|
except:
|
||||||
return default
|
return default
|
||||||
|
|
||||||
|
|
||||||
def str2bool(v):
|
def str2bool(v):
|
||||||
return v.lower() in ("true", "t", "1")
|
return v.lower() in ("true", "t", "1")
|
||||||
|
|
||||||
|
|
||||||
def get_main_app(argv=[]):
|
def get_main_app(argv=[]):
|
||||||
"""
|
"""
|
||||||
Standard boilerplate Qt application code.
|
Standard boilerplate Qt application code.
|
||||||
|
@ -2248,23 +2175,24 @@ def get_main_app(argv=[]):
|
||||||
app = QApplication(argv)
|
app = QApplication(argv)
|
||||||
app.setApplicationName(__appname__)
|
app.setApplicationName(__appname__)
|
||||||
app.setWindowIcon(newIcon("app"))
|
app.setWindowIcon(newIcon("app"))
|
||||||
# Tzutalin 201705+: Accept extra agruments to change predefined class file
|
# Tzutalin 201705+: Accept extra arguments to change predefined class file
|
||||||
argparser = argparse.ArgumentParser()
|
arg_parser = argparse.ArgumentParser()
|
||||||
argparser.add_argument("--lang", type=str, default='en', nargs="?")
|
arg_parser.add_argument("--lang", type=str, default='en', nargs="?")
|
||||||
argparser.add_argument("--gpu", type=str2bool, default=False, nargs="?")
|
arg_parser.add_argument("--gpu", type=str2bool, default=True, nargs="?")
|
||||||
argparser.add_argument("--predefined_classes_file",
|
arg_parser.add_argument("--predefined_classes_file",
|
||||||
default=os.path.join(os.path.dirname(__file__), "data", "predefined_classes.txt"),
|
default=os.path.join(os.path.dirname(__file__), "data", "predefined_classes.txt"),
|
||||||
nargs="?")
|
nargs="?")
|
||||||
args = argparser.parse_args(argv[1:])
|
args = arg_parser.parse_args(argv[1:])
|
||||||
# Usage : labelImg.py image predefClassFile saveDir
|
|
||||||
win = MainWindow(lang=args.lang, gpu=args.gpu,
|
win = MainWindow(lang=args.lang,
|
||||||
defaultPrefdefClassFile=args.predefined_classes_file)
|
gpu=args.gpu,
|
||||||
|
default_predefined_class_file=args.predefined_classes_file)
|
||||||
win.show()
|
win.show()
|
||||||
return app, win
|
return app, win
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
'''construct main app and run it'''
|
"""construct main app and run it"""
|
||||||
app, _win = get_main_app(sys.argv)
|
app, _win = get_main_app(sys.argv)
|
||||||
return app.exec_()
|
return app.exec_()
|
||||||
|
|
||||||
|
@ -2276,5 +2204,5 @@ if __name__ == '__main__':
|
||||||
output = os.system('pyrcc5 -o libs/resources.py resources.qrc')
|
output = os.system('pyrcc5 -o libs/resources.py resources.qrc')
|
||||||
assert output == 0, "operate the cmd have some problems ,please check whether there is a in the lib " \
|
assert output == 0, "operate the cmd have some problems ,please check whether there is a in the lib " \
|
||||||
"directory resources.py "
|
"directory resources.py "
|
||||||
import libs.resources
|
|
||||||
sys.exit(main())
|
sys.exit(main())
|
||||||
|
|
|
@ -8,6 +8,8 @@ PPOCRLabel is a semi-automatic graphic annotation tool suitable for OCR field, w
|
||||||
|
|
||||||
### Recent Update
|
### Recent Update
|
||||||
|
|
||||||
|
- 2022.01:(by [PeterH0323](https://github.com/peterh0323) )
|
||||||
|
- Improve user experience: prompt for the number of files and labels, optimize interaction, and fix bugs such as only use CPU when inference
|
||||||
- 2021.11.17:
|
- 2021.11.17:
|
||||||
- Support install and start PPOCRLabel through the whl package (by [d2623587501](https://github.com/d2623587501))
|
- Support install and start PPOCRLabel through the whl package (by [d2623587501](https://github.com/d2623587501))
|
||||||
- Dataset segmentation: Divide the annotation file into training, verification and testing parts (refer to section 3.5 below, by [MrCuiHao](https://github.com/MrCuiHao))
|
- Dataset segmentation: Divide the annotation file into training, verification and testing parts (refer to section 3.5 below, by [MrCuiHao](https://github.com/MrCuiHao))
|
||||||
|
@ -110,7 +112,7 @@ python PPOCRLabel.py
|
||||||
|
|
||||||
6. Click 're-Recognition', model will rewrite ALL recognition results in ALL detection box<sup>[3]</sup>.
|
6. Click 're-Recognition', model will rewrite ALL recognition results in ALL detection box<sup>[3]</sup>.
|
||||||
|
|
||||||
7. Double click the result in 'recognition result' list to manually change inaccurate recognition results.
|
7. Single click the result in 'recognition result' list to manually change inaccurate recognition results.
|
||||||
|
|
||||||
8. **Click "Check", the image status will switch to "√",then the program automatically jump to the next.**
|
8. **Click "Check", the image status will switch to "√",then the program automatically jump to the next.**
|
||||||
|
|
||||||
|
@ -143,15 +145,17 @@ python PPOCRLabel.py
|
||||||
### 3.1 Shortcut keys
|
### 3.1 Shortcut keys
|
||||||
|
|
||||||
| Shortcut keys | Description |
|
| Shortcut keys | Description |
|
||||||
|--------------------------| ------------------------------------------------ |
|
|--------------------------|--------------------------------------------------|
|
||||||
| Ctrl + Shift + R | Re-recognize all the labels of the current image |
|
| Ctrl + Shift + R | Re-recognize all the labels of the current image |
|
||||||
| W | Create a rect box |
|
| W | Create a rect box |
|
||||||
| Q | Create a four-points box |
|
| Q | Create a four-points box |
|
||||||
|
| X | Rotate the box anti-clockwise |
|
||||||
|
| C | Rotate the box clockwise |
|
||||||
| Ctrl + E | Edit label of the selected box |
|
| Ctrl + E | Edit label of the selected box |
|
||||||
| Ctrl + R | Re-recognize the selected box |
|
| Ctrl + R | Re-recognize the selected box |
|
||||||
| Ctrl + C | Copy and paste the selected box |
|
| Ctrl + C | Copy and paste the selected box |
|
||||||
| Ctrl + Left Mouse Button | Multi select the label box |
|
| Ctrl + Left Mouse Button | Multi select the label box |
|
||||||
| Ctrl + X | Delete the selected box |
|
| Alt + X | Delete the selected box |
|
||||||
| Ctrl + V | Check image |
|
| Ctrl + V | Check image |
|
||||||
| Ctrl + Shift + d | Delete image |
|
| Ctrl + Shift + d | Delete image |
|
||||||
| D | Next image |
|
| D | Next image |
|
||||||
|
|
|
@ -8,6 +8,8 @@ PPOCRLabel是一款适用于OCR领域的半自动化图形标注工具,内置P
|
||||||
|
|
||||||
#### 近期更新
|
#### 近期更新
|
||||||
|
|
||||||
|
- 2022.01:(by [PeterH0323](https://github.com/peterh0323) )
|
||||||
|
- 提升用户体验:新增文件与标记数目提示、优化交互、修复gpu使用等问题
|
||||||
- 2021.11.17:
|
- 2021.11.17:
|
||||||
- 新增支持通过whl包安装和启动PPOCRLabel(by [d2623587501](https://github.com/d2623587501))
|
- 新增支持通过whl包安装和启动PPOCRLabel(by [d2623587501](https://github.com/d2623587501))
|
||||||
- 标注数据集切分:对标注数据进行训练、验证与测试集划分(参考下方3.5节,by [MrCuiHao](https://github.com/MrCuiHao))
|
- 标注数据集切分:对标注数据进行训练、验证与测试集划分(参考下方3.5节,by [MrCuiHao](https://github.com/MrCuiHao))
|
||||||
|
@ -102,7 +104,7 @@ python PPOCRLabel.py --lang ch
|
||||||
4. 手动标注:点击 “矩形标注”(推荐直接在英文模式下点击键盘中的 “W”),用户可对当前图片中模型未检出的部分进行手动绘制标记框。点击键盘Q,则使用四点标注模式(或点击“编辑” - “四点标注”),用户依次点击4个点后,双击左键表示标注完成。
|
4. 手动标注:点击 “矩形标注”(推荐直接在英文模式下点击键盘中的 “W”),用户可对当前图片中模型未检出的部分进行手动绘制标记框。点击键盘Q,则使用四点标注模式(或点击“编辑” - “四点标注”),用户依次点击4个点后,双击左键表示标注完成。
|
||||||
5. 标记框绘制完成后,用户点击 “确认”,检测框会先被预分配一个 “待识别” 标签。
|
5. 标记框绘制完成后,用户点击 “确认”,检测框会先被预分配一个 “待识别” 标签。
|
||||||
6. 重新识别:将图片中的所有检测画绘制/调整完成后,点击 “重新识别”,PPOCR模型会对当前图片中的**所有检测框**重新识别<sup>[3]</sup>。
|
6. 重新识别:将图片中的所有检测画绘制/调整完成后,点击 “重新识别”,PPOCR模型会对当前图片中的**所有检测框**重新识别<sup>[3]</sup>。
|
||||||
7. 内容更改:双击识别结果,对不准确的识别结果进行手动更改。
|
7. 内容更改:单击识别结果,对不准确的识别结果进行手动更改。
|
||||||
8. **确认标记:点击 “确认”,图片状态切换为 “√”,跳转至下一张。**
|
8. **确认标记:点击 “确认”,图片状态切换为 “√”,跳转至下一张。**
|
||||||
9. 删除:点击 “删除图像”,图片将会被删除至回收站。
|
9. 删除:点击 “删除图像”,图片将会被删除至回收站。
|
||||||
10. 导出结果:用户可以通过菜单中“文件-导出标记结果”手动导出,同时也可以点击“文件 - 自动导出标记结果”开启自动导出。手动确认过的标记将会被存放在所打开图片文件夹下的*Label.txt*中。在菜单栏点击 “文件” - "导出识别结果"后,会将此类图片的识别训练数据保存在*crop_img*文件夹下,识别标签保存在*rec_gt.txt*中<sup>[4]</sup>。
|
10. 导出结果:用户可以通过菜单中“文件-导出标记结果”手动导出,同时也可以点击“文件 - 自动导出标记结果”开启自动导出。手动确认过的标记将会被存放在所打开图片文件夹下的*Label.txt*中。在菜单栏点击 “文件” - "导出识别结果"后,会将此类图片的识别训练数据保存在*crop_img*文件夹下,识别标签保存在*rec_gt.txt*中<sup>[4]</sup>。
|
||||||
|
@ -132,15 +134,17 @@ python PPOCRLabel.py --lang ch
|
||||||
### 3.1 快捷键
|
### 3.1 快捷键
|
||||||
|
|
||||||
| 快捷键 | 说明 |
|
| 快捷键 | 说明 |
|
||||||
|------------------| ---------------------------- |
|
|------------------|----------------|
|
||||||
| Ctrl + shift + R | 对当前图片的所有标记重新识别 |
|
| Ctrl + shift + R | 对当前图片的所有标记重新识别 |
|
||||||
| W | 新建矩形框 |
|
| W | 新建矩形框 |
|
||||||
| Q | 新建四点框 |
|
| Q | 新建四点框 |
|
||||||
|
| X | 框逆时针旋转 |
|
||||||
|
| C | 框顺时针旋转 |
|
||||||
| Ctrl + E | 编辑所选框标签 |
|
| Ctrl + E | 编辑所选框标签 |
|
||||||
| Ctrl + R | 重新识别所选标记 |
|
| Ctrl + R | 重新识别所选标记 |
|
||||||
| Ctrl + C | 复制并粘贴选中的标记框 |
|
| Ctrl + C | 复制并粘贴选中的标记框 |
|
||||||
| Ctrl + 鼠标左键 | 多选标记框 |
|
| Ctrl + 鼠标左键 | 多选标记框 |
|
||||||
| Ctrl + X | 删除所选框 |
|
| Alt + X | 删除所选框 |
|
||||||
| Ctrl + V | 确认本张图片标记 |
|
| Ctrl + V | 确认本张图片标记 |
|
||||||
| Ctrl + Shift + d | 删除本张图片 |
|
| Ctrl + Shift + d | 删除本张图片 |
|
||||||
| D | 下一张图片 |
|
| D | 下一张图片 |
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
# Copyright (c) <2015-Present> Tzutalin
|
|
||||||
# Copyright (C) 2013 MIT, Computer Science and Artificial Intelligence Laboratory. Bryan Russell, Antonio Torralba,
|
|
||||||
# William T. Freeman. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
|
||||||
# associated documentation files (the "Software"), to deal in the Software without restriction, including without
|
|
||||||
# limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
|
||||||
# Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
||||||
# The above copyright notice and this permission notice shall be included in all copies or substantial portions of
|
|
||||||
# the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
|
||||||
# NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
|
||||||
# SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
|
||||||
# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
# THE SOFTWARE.
|
|
||||||
|
|
||||||
import sys
|
|
||||||
try:
|
|
||||||
from PyQt5.QtWidgets import QWidget, QHBoxLayout, QComboBox
|
|
||||||
except ImportError:
|
|
||||||
# needed for py3+qt4
|
|
||||||
# Ref:
|
|
||||||
# http://pyqt.sourceforge.net/Docs/PyQt4/incompatible_apis.html
|
|
||||||
# http://stackoverflow.com/questions/21217399/pyqt4-qtcore-qvariant-object-instead-of-a-string
|
|
||||||
if sys.version_info.major >= 3:
|
|
||||||
import sip
|
|
||||||
sip.setapi('QVariant', 2)
|
|
||||||
from PyQt4.QtGui import QWidget, QHBoxLayout, QComboBox
|
|
||||||
|
|
||||||
|
|
||||||
class ComboBox(QWidget):
|
|
||||||
def __init__(self, parent=None, items=[]):
|
|
||||||
super(ComboBox, self).__init__(parent)
|
|
||||||
|
|
||||||
layout = QHBoxLayout()
|
|
||||||
self.cb = QComboBox()
|
|
||||||
self.items = items
|
|
||||||
self.cb.addItems(self.items)
|
|
||||||
|
|
||||||
self.cb.currentIndexChanged.connect(parent.comboSelectionChanged)
|
|
||||||
|
|
||||||
layout.addWidget(self.cb)
|
|
||||||
self.setLayout(layout)
|
|
||||||
|
|
||||||
def update_items(self, items):
|
|
||||||
self.items = items
|
|
||||||
|
|
||||||
self.cb.clear()
|
|
||||||
self.cb.addItems(self.items)
|
|
|
@ -11,19 +11,13 @@
|
||||||
# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
# THE SOFTWARE.
|
# THE SOFTWARE.
|
||||||
|
|
||||||
try:
|
import copy
|
||||||
from PyQt5.QtGui import *
|
|
||||||
from PyQt5.QtCore import *
|
|
||||||
from PyQt5.QtWidgets import *
|
|
||||||
except ImportError:
|
|
||||||
from PyQt4.QtGui import *
|
|
||||||
from PyQt4.QtCore import *
|
|
||||||
|
|
||||||
#from PyQt4.QtOpenGL import *
|
|
||||||
|
|
||||||
|
from PyQt5.QtCore import Qt, pyqtSignal, QPointF, QPoint
|
||||||
|
from PyQt5.QtGui import QPainter, QBrush, QColor, QPixmap
|
||||||
|
from PyQt5.QtWidgets import QWidget, QMenu, QApplication
|
||||||
from libs.shape import Shape
|
from libs.shape import Shape
|
||||||
from libs.utils import distance
|
from libs.utils import distance
|
||||||
import copy
|
|
||||||
|
|
||||||
CURSOR_DEFAULT = Qt.ArrowCursor
|
CURSOR_DEFAULT = Qt.ArrowCursor
|
||||||
CURSOR_POINT = Qt.PointingHandCursor
|
CURSOR_POINT = Qt.PointingHandCursor
|
||||||
|
@ -31,8 +25,6 @@ CURSOR_DRAW = Qt.CrossCursor
|
||||||
CURSOR_MOVE = Qt.ClosedHandCursor
|
CURSOR_MOVE = Qt.ClosedHandCursor
|
||||||
CURSOR_GRAB = Qt.OpenHandCursor
|
CURSOR_GRAB = Qt.OpenHandCursor
|
||||||
|
|
||||||
# class Canvas(QGLWidget):
|
|
||||||
|
|
||||||
|
|
||||||
class Canvas(QWidget):
|
class Canvas(QWidget):
|
||||||
zoomRequest = pyqtSignal(int)
|
zoomRequest = pyqtSignal(int)
|
||||||
|
@ -129,7 +121,6 @@ class Canvas(QWidget):
|
||||||
def selectedVertex(self):
|
def selectedVertex(self):
|
||||||
return self.hVertex is not None
|
return self.hVertex is not None
|
||||||
|
|
||||||
|
|
||||||
def mouseMoveEvent(self, ev):
|
def mouseMoveEvent(self, ev):
|
||||||
"""Update line with last point and current coordinates."""
|
"""Update line with last point and current coordinates."""
|
||||||
pos = self.transformPos(ev.pos())
|
pos = self.transformPos(ev.pos())
|
||||||
|
@ -333,7 +324,6 @@ class Canvas(QWidget):
|
||||||
|
|
||||||
self.movingShape = False
|
self.movingShape = False
|
||||||
|
|
||||||
|
|
||||||
def endMove(self, copy=False):
|
def endMove(self, copy=False):
|
||||||
assert self.selectedShapes and self.selectedShapesCopy
|
assert self.selectedShapes and self.selectedShapesCopy
|
||||||
assert len(self.selectedShapesCopy) == len(self.selectedShapes)
|
assert len(self.selectedShapesCopy) == len(self.selectedShapes)
|
||||||
|
@ -410,7 +400,6 @@ class Canvas(QWidget):
|
||||||
self.selectionChanged.emit(shapes)
|
self.selectionChanged.emit(shapes)
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
|
|
||||||
def selectShapePoint(self, point, multiple_selection_mode):
|
def selectShapePoint(self, point, multiple_selection_mode):
|
||||||
"""Select the first shape created which contains this point."""
|
"""Select the first shape created which contains this point."""
|
||||||
if self.selectedVertex(): # A vertex is marked for selection.
|
if self.selectedVertex(): # A vertex is marked for selection.
|
||||||
|
@ -494,7 +483,6 @@ class Canvas(QWidget):
|
||||||
else:
|
else:
|
||||||
shape.moveVertexBy(index, shiftPos)
|
shape.moveVertexBy(index, shiftPos)
|
||||||
|
|
||||||
|
|
||||||
def boundedMoveShape(self, shapes, pos):
|
def boundedMoveShape(self, shapes, pos):
|
||||||
if type(shapes).__name__ != 'list': shapes = [shapes]
|
if type(shapes).__name__ != 'list': shapes = [shapes]
|
||||||
if self.outOfPixmap(pos):
|
if self.outOfPixmap(pos):
|
||||||
|
@ -515,6 +503,7 @@ class Canvas(QWidget):
|
||||||
if dp:
|
if dp:
|
||||||
for shape in shapes:
|
for shape in shapes:
|
||||||
shape.moveBy(dp)
|
shape.moveBy(dp)
|
||||||
|
shape.close()
|
||||||
self.prevPoint = pos
|
self.prevPoint = pos
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
@ -728,6 +717,31 @@ class Canvas(QWidget):
|
||||||
self.moveOnePixel('Up')
|
self.moveOnePixel('Up')
|
||||||
elif key == Qt.Key_Down and self.selectedShapes:
|
elif key == Qt.Key_Down and self.selectedShapes:
|
||||||
self.moveOnePixel('Down')
|
self.moveOnePixel('Down')
|
||||||
|
elif key == Qt.Key_X and self.selectedShapes:
|
||||||
|
for i in range(len(self.selectedShapes)):
|
||||||
|
self.selectedShape = self.selectedShapes[i]
|
||||||
|
if self.rotateOutOfBound(0.01):
|
||||||
|
continue
|
||||||
|
self.selectedShape.rotate(0.01)
|
||||||
|
self.shapeMoved.emit()
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
elif key == Qt.Key_C and self.selectedShapes:
|
||||||
|
for i in range(len(self.selectedShapes)):
|
||||||
|
self.selectedShape = self.selectedShapes[i]
|
||||||
|
if self.rotateOutOfBound(-0.01):
|
||||||
|
continue
|
||||||
|
self.selectedShape.rotate(-0.01)
|
||||||
|
self.shapeMoved.emit()
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
def rotateOutOfBound(self, angle):
|
||||||
|
for shape in range(len(self.selectedShapes)):
|
||||||
|
self.selectedShape = self.selectedShapes[shape]
|
||||||
|
for i, p in enumerate(self.selectedShape.points):
|
||||||
|
if self.outOfPixmap(self.selectedShape.rotatePoint(p, angle)):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
def moveOnePixel(self, direction):
|
def moveOnePixel(self, direction):
|
||||||
# print(self.selectedShape.points)
|
# print(self.selectedShape.points)
|
||||||
|
|
|
@ -1,29 +1,27 @@
|
||||||
import sys, time
|
# !/usr/bin/env python
|
||||||
from PyQt5 import QtWidgets
|
# -*- coding: utf-8 -*-
|
||||||
from PyQt5.QtGui import *
|
from PyQt5.QtCore import QModelIndex
|
||||||
from PyQt5.QtCore import *
|
from PyQt5.QtWidgets import QListWidget
|
||||||
from PyQt5.QtWidgets import *
|
|
||||||
|
|
||||||
class EditInList(QListWidget):
|
class EditInList(QListWidget):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(EditInList, self).__init__()
|
super(EditInList, self).__init__()
|
||||||
# click to edit
|
self.edited_item = None
|
||||||
self.clicked.connect(self.item_clicked)
|
|
||||||
|
|
||||||
def item_clicked(self, modelindex: QModelIndex) -> None:
|
def item_clicked(self, modelindex: QModelIndex):
|
||||||
self.edited_item = self.currentItem()
|
try:
|
||||||
|
if self.edited_item is not None:
|
||||||
self.closePersistentEditor(self.edited_item)
|
self.closePersistentEditor(self.edited_item)
|
||||||
item = self.item(modelindex.row())
|
except:
|
||||||
# time.sleep(0.2)
|
self.edited_item = self.currentItem()
|
||||||
self.edited_item = item
|
|
||||||
self.openPersistentEditor(item)
|
self.edited_item = self.item(modelindex.row())
|
||||||
# time.sleep(0.2)
|
self.openPersistentEditor(self.edited_item)
|
||||||
self.editItem(item)
|
self.editItem(self.edited_item)
|
||||||
|
|
||||||
def mouseDoubleClickEvent(self, event):
|
def mouseDoubleClickEvent(self, event):
|
||||||
# close edit
|
pass
|
||||||
for i in range(self.count()):
|
|
||||||
self.closePersistentEditor(self.item(i))
|
|
||||||
|
|
||||||
def leaveEvent(self, event):
|
def leaveEvent(self, event):
|
||||||
# close edit
|
# close edit
|
||||||
|
|
|
@ -12,18 +12,13 @@
|
||||||
# THE SOFTWARE.
|
# THE SOFTWARE.
|
||||||
# !/usr/bin/python
|
# !/usr/bin/python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
import math
|
||||||
|
|
||||||
try:
|
|
||||||
from PyQt5.QtGui import *
|
|
||||||
from PyQt5.QtCore import *
|
|
||||||
except ImportError:
|
|
||||||
from PyQt4.QtGui import *
|
|
||||||
from PyQt4.QtCore import *
|
|
||||||
|
|
||||||
from libs.utils import distance
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
from PyQt5.QtCore import QPointF
|
||||||
|
from PyQt5.QtGui import QColor, QPen, QPainterPath, QFont
|
||||||
|
from libs.utils import distance
|
||||||
|
|
||||||
DEFAULT_LINE_COLOR = QColor(0, 255, 0, 128)
|
DEFAULT_LINE_COLOR = QColor(0, 255, 0, 128)
|
||||||
DEFAULT_FILL_COLOR = QColor(255, 0, 0, 128)
|
DEFAULT_FILL_COLOR = QColor(255, 0, 0, 128)
|
||||||
DEFAULT_SELECT_LINE_COLOR = QColor(255, 255, 255)
|
DEFAULT_SELECT_LINE_COLOR = QColor(255, 255, 255)
|
||||||
|
@ -59,6 +54,8 @@ class Shape(object):
|
||||||
self.difficult = difficult
|
self.difficult = difficult
|
||||||
self.paintLabel = paintLabel
|
self.paintLabel = paintLabel
|
||||||
self.locked = False
|
self.locked = False
|
||||||
|
self.direction = 0
|
||||||
|
self.center = None
|
||||||
self._highlightIndex = None
|
self._highlightIndex = None
|
||||||
self._highlightMode = self.NEAR_VERTEX
|
self._highlightMode = self.NEAR_VERTEX
|
||||||
self._highlightSettings = {
|
self._highlightSettings = {
|
||||||
|
@ -74,7 +71,24 @@ class Shape(object):
|
||||||
# is used for drawing the pending line a different color.
|
# is used for drawing the pending line a different color.
|
||||||
self.line_color = line_color
|
self.line_color = line_color
|
||||||
|
|
||||||
|
def rotate(self, theta):
|
||||||
|
for i, p in enumerate(self.points):
|
||||||
|
self.points[i] = self.rotatePoint(p, theta)
|
||||||
|
self.direction -= theta
|
||||||
|
self.direction = self.direction % (2 * math.pi)
|
||||||
|
|
||||||
|
def rotatePoint(self, p, theta):
|
||||||
|
order = p - self.center
|
||||||
|
cosTheta = math.cos(theta)
|
||||||
|
sinTheta = math.sin(theta)
|
||||||
|
pResx = cosTheta * order.x() + sinTheta * order.y()
|
||||||
|
pResy = - sinTheta * order.x() + cosTheta * order.y()
|
||||||
|
pRes = QPointF(self.center.x() + pResx, self.center.y() + pResy)
|
||||||
|
return pRes
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
|
self.center = QPointF((self.points[0].x() + self.points[2].x()) / 2,
|
||||||
|
(self.points[0].y() + self.points[2].y()) / 2)
|
||||||
self._closed = True
|
self._closed = True
|
||||||
|
|
||||||
def reachMaxPoints(self):
|
def reachMaxPoints(self):
|
||||||
|
@ -83,7 +97,9 @@ class Shape(object):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def addPoint(self, point):
|
def addPoint(self, point):
|
||||||
if not self.reachMaxPoints(): # 4个点时发出close信号
|
if self.reachMaxPoints():
|
||||||
|
self.close()
|
||||||
|
else:
|
||||||
self.points.append(point)
|
self.points.append(point)
|
||||||
|
|
||||||
def popPoint(self):
|
def popPoint(self):
|
||||||
|
@ -136,9 +152,9 @@ class Shape(object):
|
||||||
font.setPointSize(8)
|
font.setPointSize(8)
|
||||||
font.setBold(True)
|
font.setBold(True)
|
||||||
painter.setFont(font)
|
painter.setFont(font)
|
||||||
if(self.label == None):
|
if self.label is None:
|
||||||
self.label = ""
|
self.label = ""
|
||||||
if(min_y < MIN_Y_LABEL):
|
if min_y < MIN_Y_LABEL:
|
||||||
min_y += MIN_Y_LABEL
|
min_y += MIN_Y_LABEL
|
||||||
painter.drawText(min_x, min_y, self.label)
|
painter.drawText(min_x, min_y, self.label)
|
||||||
|
|
||||||
|
@ -198,6 +214,8 @@ class Shape(object):
|
||||||
def copy(self):
|
def copy(self):
|
||||||
shape = Shape("%s" % self.label)
|
shape = Shape("%s" % self.label)
|
||||||
shape.points = [p for p in self.points]
|
shape.points = [p for p in self.points]
|
||||||
|
shape.center = self.center
|
||||||
|
shape.direction = self.direction
|
||||||
shape.fill = self.fill
|
shape.fill = self.fill
|
||||||
shape.selected = self.selected
|
shape.selected = self.selected
|
||||||
shape._closed = self._closed
|
shape._closed = self._closed
|
||||||
|
|
|
@ -21,10 +21,15 @@ PaddleOCR希望可以通过AI的力量助力任何一位有梦想的开发者实
|
||||||
| 通用工具 | [FastOCRLabel](https://gitee.com/BaoJianQiang/FastOCRLabel) | 完整的C#版本标注GUI | [包建强](https://gitee.com/BaoJianQiang) |
|
| 通用工具 | [FastOCRLabel](https://gitee.com/BaoJianQiang/FastOCRLabel) | 完整的C#版本标注GUI | [包建强](https://gitee.com/BaoJianQiang) |
|
||||||
| 通用工具 | [DangoOCR离线版](https://github.com/PantsuDango/DangoOCR) | 通用型桌面级即时翻译GUI | [PantsuDango](https://github.com/PantsuDango) |
|
| 通用工具 | [DangoOCR离线版](https://github.com/PantsuDango/DangoOCR) | 通用型桌面级即时翻译GUI | [PantsuDango](https://github.com/PantsuDango) |
|
||||||
| 通用工具 | [scr2txt](https://github.com/lstwzd/scr2txt) | 截屏转文字GUI | [lstwzd](https://github.com/lstwzd) |
|
| 通用工具 | [scr2txt](https://github.com/lstwzd/scr2txt) | 截屏转文字GUI | [lstwzd](https://github.com/lstwzd) |
|
||||||
|
| 通用工具 | [ocr_sdk](https://github.com/mymagicpower/AIAS/blob/main/1_image_sdks/text_recognition/ocr_sdk) | OCR java SDK工具箱 | [Calvin](https://github.com/mymagicpower) |
|
||||||
|
| 通用工具 | [iocr](https://github.com/mymagicpower/AIAS/blob/main/8_suite_hub/iocr) | IOCR 自定义模板识别(支持表格识别) | [Calvin](https://github.com/mymagicpower) |
|
||||||
| 垂类工具 | [AI Studio项目](https://aistudio.baidu.com/aistudio/projectdetail/1054614?channelType=0&channel=0) | 英文视频自动生成字幕 | [叶月水狐](https://aistudio.baidu.com/aistudio/personalcenter/thirdview/322052) |
|
| 垂类工具 | [AI Studio项目](https://aistudio.baidu.com/aistudio/projectdetail/1054614?channelType=0&channel=0) | 英文视频自动生成字幕 | [叶月水狐](https://aistudio.baidu.com/aistudio/personalcenter/thirdview/322052) |
|
||||||
| 垂类工具 | [id_card_ocr](https://github.com/baseli/id_card_ocr) | 身份证复印件识别 | [baseli](https://github.com/baseli) |
|
| 垂类工具 | [id_card_ocr](https://github.com/baseli/id_card_ocr) | 身份证复印件识别 | [baseli](https://github.com/baseli) |
|
||||||
| 垂类工具 | [Paddle_Table_Image_Reader](https://github.com/thunder95/Paddle_Table_Image_Reader) | 能看懂表格图片的数据助手 | [thunder95](https://github.com/thunder95]) |
|
| 垂类工具 | [Paddle_Table_Image_Reader](https://github.com/thunder95/Paddle_Table_Image_Reader) | 能看懂表格图片的数据助手 | [thunder95](https://github.com/thunder95]) |
|
||||||
| 前后处理 | [paddleOCRCorrectOutputs](https://github.com/yuranusduke/paddleOCRCorrectOutputs) | 获取OCR识别结果的key-value | [yuranusduke](https://github.com/yuranusduke) |
|
| 前后处理 | [paddleOCRCorrectOutputs](https://github.com/yuranusduke/paddleOCRCorrectOutputs) | 获取OCR识别结果的key-value | [yuranusduke](https://github.com/yuranusduke) |
|
||||||
|
|前处理| [optlab](https://github.com/GreatV/optlab) |OCR前处理工具箱,基于Qt和Leptonica。|[GreatV](https://github.com/GreatV)|
|
||||||
|
|应用部署| [PaddleOCRSharp](https://github.com/raoyutian/PaddleOCRSharp) |PaddleOCR的.NET封装与应用部署。|[raoyutian](https://github.com/raoyutian/PaddleOCRSharp)|
|
||||||
|
| 学术前沿模型训练与推理 | [AI Studio项目](https://aistudio.baidu.com/aistudio/projectdetail/3397137) | StarNet-MobileNetV3算法–中文训练 | [xiaoyangyang2](https://github.com/xiaoyangyang2) |
|
||||||
|
|
||||||
### 1.2 为PaddleOCR新增功能
|
### 1.2 为PaddleOCR新增功能
|
||||||
|
|
||||||
|
|
|
@ -284,7 +284,6 @@ else
|
||||||
set_amp_config=" "
|
set_amp_config=" "
|
||||||
fi
|
fi
|
||||||
for trainer in ${trainer_list[*]}; do
|
for trainer in ${trainer_list[*]}; do
|
||||||
eval ${env}
|
|
||||||
flag_quant=False
|
flag_quant=False
|
||||||
if [ ${trainer} = ${pact_key} ]; then
|
if [ ${trainer} = ${pact_key} ]; then
|
||||||
run_train=${pact_trainer}
|
run_train=${pact_trainer}
|
||||||
|
@ -344,6 +343,7 @@ else
|
||||||
|
|
||||||
# run eval
|
# run eval
|
||||||
if [ ${eval_py} != "null" ]; then
|
if [ ${eval_py} != "null" ]; then
|
||||||
|
eval ${env}
|
||||||
set_eval_params1=$(func_set_params "${eval_key1}" "${eval_value1}")
|
set_eval_params1=$(func_set_params "${eval_key1}" "${eval_value1}")
|
||||||
eval_cmd="${python} ${eval_py} ${set_eval_pretrain} ${set_use_gpu} ${set_eval_params1}"
|
eval_cmd="${python} ${eval_py} ${set_eval_pretrain} ${set_use_gpu} ${set_eval_params1}"
|
||||||
eval $eval_cmd
|
eval $eval_cmd
|
||||||
|
|
|
@ -92,11 +92,11 @@ class TextSystem(object):
|
||||||
self.draw_crop_rec_res(self.args.crop_res_save_dir, img_crop_list,
|
self.draw_crop_rec_res(self.args.crop_res_save_dir, img_crop_list,
|
||||||
rec_res)
|
rec_res)
|
||||||
filter_boxes, filter_rec_res = [], []
|
filter_boxes, filter_rec_res = [], []
|
||||||
for box, rec_reuslt in zip(dt_boxes, rec_res):
|
for box, rec_result in zip(dt_boxes, rec_res):
|
||||||
text, score = rec_reuslt
|
text, score = rec_result
|
||||||
if score >= self.drop_score:
|
if score >= self.drop_score:
|
||||||
filter_boxes.append(box)
|
filter_boxes.append(box)
|
||||||
filter_rec_res.append(rec_reuslt)
|
filter_rec_res.append(rec_result)
|
||||||
return filter_boxes, filter_rec_res
|
return filter_boxes, filter_rec_res
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -73,8 +73,8 @@ def main():
|
||||||
images = paddle.to_tensor(images)
|
images = paddle.to_tensor(images)
|
||||||
preds = model(images)
|
preds = model(images)
|
||||||
post_result = post_process_class(preds)
|
post_result = post_process_class(preds)
|
||||||
for rec_reuslt in post_result:
|
for rec_result in post_result:
|
||||||
logger.info('\t result: {}'.format(rec_reuslt))
|
logger.info('\t result: {}'.format(rec_result))
|
||||||
logger.info("success!")
|
logger.info("success!")
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue