提交 9c7405b6 编写于 作者: qq_25193841's avatar qq_25193841

Optimize the labeling experience

上级 0f3204af
......@@ -64,6 +64,7 @@ from libs.colorDialog import ColorDialog
from libs.toolBar import ToolBar
from libs.ustr import ustr
from libs.hashableQListWidgetItem import HashableQListWidgetItem
from libs.editinlist import EditInList
__appname__ = 'PPOCRLabel'
......@@ -201,12 +202,12 @@ class MainWindow(QMainWindow, WindowMixin):
################## label list ####################
# Create and add a widget for showing current label items
self.labelList = QListWidget()
self.labelList = EditInList()
labelListContainer = QWidget()
labelListContainer.setLayout(listLayout)
self.labelList.itemActivated.connect(self.labelSelectionChanged)
self.labelList.itemSelectionChanged.connect(self.labelSelectionChanged)
self.labelList.itemDoubleClicked.connect(self.editLabel)
self.labelList.clicked.connect(self.labelList.item_clicked)
# Connect to itemChanged to detect checkbox changes.
self.labelList.itemChanged.connect(self.labelItemChanged)
self.labelListDock = QDockWidget(getStr('recognitionResult'),self)
......@@ -316,7 +317,7 @@ class MainWindow(QMainWindow, WindowMixin):
self.scrollArea = scroll
self.canvas.scrollRequest.connect(self.scrollRequest)
self.canvas.newShape.connect(self.newShape)
self.canvas.newShape.connect(partial(self.newShape, False))
self.canvas.shapeMoved.connect(self.updateBoxlist) # self.setDirty
self.canvas.selectionChanged.connect(self.shapeSelectionChanged)
self.canvas.drawingPolygon.connect(self.toggleDrawingSensitive)
......@@ -354,13 +355,9 @@ class MainWindow(QMainWindow, WindowMixin):
quit = action(getStr('quit'), self.close,
'Ctrl+Q', 'quit', getStr('quitApp'))
open = action(getStr('openFile'), self.openFile,
'Ctrl+O', 'open', getStr('openFileDetail'))
opendir = action(getStr('openDir'), self.openDirDialog,
'Ctrl+u', 'open', getStr('openDir'))
save = action(getStr('save'), self.saveFile,
'Ctrl+V', 'verify', getStr('saveDetail'), enabled=False)
......@@ -506,7 +503,7 @@ class MainWindow(QMainWindow, WindowMixin):
self.drawSquaresOption.triggered.connect(self.toogleDrawSquare)
# Store actions for further handling.
self.actions = struct(save=save, open=open, resetAll=resetAll, deleteImg=deleteImg,
self.actions = struct(save=save, resetAll=resetAll, deleteImg=deleteImg,
lineColor=color1, create=create, delete=delete, edit=edit, copy=copy,
saveRec=saveRec, singleRere=singleRere,AutoRec=AutoRec,reRec=reRec,
createMode=createMode, editMode=editMode,
......@@ -515,7 +512,7 @@ class MainWindow(QMainWindow, WindowMixin):
fitWindow=fitWindow, fitWidth=fitWidth,
zoomActions=zoomActions, saveLabel=saveLabel,
fileMenuActions=(
open, opendir, saveLabel, resetAll, quit),
opendir, saveLabel, resetAll, quit),
beginner=(), advanced=(),
editMenu=(createpoly, edit, copy, delete,singleRere,
None, color1, self.drawSquaresOption),
......@@ -537,11 +534,6 @@ class MainWindow(QMainWindow, WindowMixin):
labelList=labelMenu)
# Sync single class mode from PR#106
self.singleClassMode = QAction(getStr('singleClsMode'), self)
self.singleClassMode.setShortcut("Ctrl+Shift+S")
self.singleClassMode.setCheckable(True)
self.singleClassMode.setChecked(settings.get(SETTING_SINGLE_CLASS, False))
self.lastLabel = None
# Add option to enable/disable labels being displayed at the top of bounding boxes
self.displayLabelOption = QAction(getStr('displayLabel'), self)
......@@ -550,12 +542,18 @@ class MainWindow(QMainWindow, WindowMixin):
self.displayLabelOption.setChecked(settings.get(SETTING_PAINT_LABEL, False))
self.displayLabelOption.triggered.connect(self.togglePaintLabelsOption)
self.labelDialogOption = QAction(getStr('labelDialogOption'), self)
self.labelDialogOption.setShortcut("Ctrl+Shift+L")
self.labelDialogOption.setCheckable(True)
self.labelDialogOption.setChecked(settings.get(SETTING_PAINT_LABEL, False))
self.labelDialogOption.triggered.connect(self.speedChoose)
addActions(self.menus.file,
(opendir, None, saveLabel, saveRec, None, resetAll, deleteImg, quit))
addActions(self.menus.help, (showSteps, showInfo))
addActions(self.menus.view, (
self.displayLabelOption, # labels,
self.displayLabelOption, self.labelDialogOption,
None,
hideAll, showAll, None,
zoomIn, zoomOut, zoomOrg, None,
......@@ -1062,6 +1060,7 @@ class MainWindow(QMainWindow, WindowMixin):
def labelSelectionChanged(self):
item = self.currentItem()
self.labelList.scrollToItem(item, QAbstractItemView.EnsureVisible)
if item and self.canvas.editing():
self._noSelectionSlot = True
self.canvas.selectShape(self.itemsToShapes[item])
......@@ -1069,6 +1068,7 @@ class MainWindow(QMainWindow, WindowMixin):
def boxSelectionChanged(self):
item = self.currentBox()
self.BoxList.scrollToItem(item, QAbstractItemView.EnsureVisible)
if item and self.canvas.editing():
self._noSelectionSlot = True
self.canvas.selectShape(self.itemsToShapesbox[item])
......@@ -1089,7 +1089,7 @@ class MainWindow(QMainWindow, WindowMixin):
# self.actions.save.setEnabled(True)
# Callback functions:
def newShape(self):
def newShape(self, value=True):
"""Pop-up and give focus to the label editor.
position MUST be in global coordinates.
......@@ -1098,12 +1098,11 @@ class MainWindow(QMainWindow, WindowMixin):
self.labelDialog = LabelDialog(
parent=self, listItem=self.labelHist)
# Sync single class mode from PR#106
if self.singleClassMode.isChecked() and self.lastLabel:
text = self.lastLabel
else:
if value:
text = self.labelDialog.popUp(text=self.prevLabelText)
self.lastLabel = text
else:
text = self.prevLabelText
if text is not None:
self.prevLabelText = self.stringBundle.getString('tempLabel')
......@@ -1364,7 +1363,6 @@ class MainWindow(QMainWindow, WindowMixin):
else:
settings[SETTING_LAST_OPEN_DIR] = ''
settings[SETTING_SINGLE_CLASS] = self.singleClassMode.isChecked()
settings[SETTING_PAINT_LABEL] = self.displayLabelOption.isChecked()
settings[SETTING_DRAW_SQUARE] = self.drawSquaresOption.isChecked()
settings.save()
......@@ -1497,35 +1495,6 @@ class MainWindow(QMainWindow, WindowMixin):
print('file name in openNext is ',filename)
self.loadFile(filename)
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)
# print('filename in openfile is ', self.filePath)
self.filePath = None
self.fileListWidget.clear()
self.iconlist.clear()
self.mImgList = [filename]
self.openNextImg()
if self.validFilestate(filename) is True:
item = QListWidgetItem(newIcon('done'), filename)
self.setClean()
elif self.validFilestate(filename) is None:
item = QListWidgetItem(newIcon('close'), filename)
else:
item = QListWidgetItem(newIcon('close'), filename)
self.setDirty()
self.fileListWidget.addItem(filename)
self.additems5(None)
print('opened image is', filename)
def updateFileListIcon(self, filename):
pass
......@@ -1963,6 +1932,16 @@ class MainWindow(QMainWindow, WindowMixin):
QMessageBox.information(self, "Information", "Cropped images has been saved in "+str(crop_img_dir))
def speedChoose(self):
if self.labelDialogOption.isChecked():
self.canvas.newShape.disconnect()
self.canvas.newShape.connect(partial(self.newShape, True))
else:
self.canvas.newShape.disconnect()
self.canvas.newShape.connect(partial(self.newShape, False))
def inverted(color):
return QColor(*[255 - v for v in color.getRgb()])
......
......@@ -8,6 +8,10 @@ PPOCRLabel is a semi-automatic graphic annotation tool suitable for OCR field, w
### Recent Update
- 2021.1.11: Optimize the labeling experience (by [edencfc](https://github.com/edencfc)),
- Users can choose whether to pop up the label input dialog after drawing the detection box in "View - Pop-up Label Input Dialog".
- The recognition result scrolls synchronously when users click related detection box.
- Click to modify the recognition result.(If you can't change the result, please switch to the system default input method, or switch back to the original input method again)
- 2020.12.18: Support re-recognition of a single label box (by [ninetailskim](https://github.com/ninetailskim) ), perfect shortcut keys.
### TODO:
......
......@@ -8,7 +8,11 @@ PPOCRLabel是一款适用于OCR领域的半自动化图形标注工具,内置P
#### 近期更新
- 2020.12.18: 支持对单个标记框进行重新识别(by [ninetailskim](https://github.com/ninetailskim)),完善快捷键。
- 2021.1.11:优化标注体验(by [edencfc](https://github.com/edencfc)):
- 用户可在“视图 - 弹出标记输入框”选择在画完检测框后标记输入框是否弹出。
- 识别结果与检测框同步滚动。
- 识别结果更改为单击修改。(如果无法修改,请切换为系统自带输入法,或再次切回原输入法)
- 2020.12.18: 支持对单个标记框进行重新识别(by [ninetailskim](https://github.com/ninetailskim)),完善快捷键。
#### 尽请期待
......
import sys, time
from PyQt5 import QtWidgets
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
class EditInList(QListWidget):
def __init__(self):
super(EditInList,self).__init__()
# click to edit
self.clicked.connect(self.item_clicked)
def item_clicked(self, modelindex: QModelIndex) -> None:
self.edited_item = self.currentItem()
self.closePersistentEditor(self.edited_item)
item = self.item(modelindex.row())
# time.sleep(0.2)
self.edited_item = item
self.openPersistentEditor(item)
# time.sleep(0.2)
self.editItem(item)
def mouseDoubleClickEvent(self, event):
# close edit
for i in range(self.count()):
self.closePersistentEditor(self.item(i))
def leaveEvent(self, event):
# close edit
for i in range(self.count()):
self.closePersistentEditor(self.item(i))
\ No newline at end of file
此差异已折叠。
......@@ -42,7 +42,7 @@ zoomin=放大画面
info=信息
openAnnotation=开启标签
prevImgDetail=上一个图像
fitWidth=缩放到跟当前画面一样宽
fitWidth=缩放到当前画面宽度
zoomout=缩小画面
changeSavedAnnotationDir=更改保存标签文件的预设目录
nextImgDetail=下一个图像
......@@ -96,3 +96,4 @@ hideBox=隐藏所有标注
showBox=显示所有标注
saveLabel=保存标记结果
singleRe=重识别此区块
labelDialogOption=弹出标记输入框
\ No newline at end of file
......@@ -96,3 +96,4 @@ hideBox=Hide All Box
showBox=Show All Box
saveLabel=Save Label
singleRe=Re-recognition RectBox
labelDialogOption=Pop-up Label Input Dialog
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册