Merge remote-tracking branch 'origin/dygraph' into dygraph
commit
000028c920
File diff suppressed because it is too large
Load Diff
|
@ -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>。
|
||||||
|
@ -131,23 +133,25 @@ python PPOCRLabel.py --lang ch
|
||||||
|
|
||||||
### 3.1 快捷键
|
### 3.1 快捷键
|
||||||
|
|
||||||
| 快捷键 | 说明 |
|
| 快捷键 | 说明 |
|
||||||
|------------------| ---------------------------- |
|
|------------------|----------------|
|
||||||
| Ctrl + shift + R | 对当前图片的所有标记重新识别 |
|
| Ctrl + shift + R | 对当前图片的所有标记重新识别 |
|
||||||
| W | 新建矩形框 |
|
| W | 新建矩形框 |
|
||||||
| Q | 新建四点框 |
|
| Q | 新建四点框 |
|
||||||
| Ctrl + E | 编辑所选框标签 |
|
| X | 框逆时针旋转 |
|
||||||
| Ctrl + R | 重新识别所选标记 |
|
| C | 框顺时针旋转 |
|
||||||
|
| Ctrl + E | 编辑所选框标签 |
|
||||||
|
| Ctrl + R | 重新识别所选标记 |
|
||||||
| Ctrl + C | 复制并粘贴选中的标记框 |
|
| Ctrl + C | 复制并粘贴选中的标记框 |
|
||||||
| Ctrl + 鼠标左键 | 多选标记框 |
|
| Ctrl + 鼠标左键 | 多选标记框 |
|
||||||
| Ctrl + X | 删除所选框 |
|
| Alt + X | 删除所选框 |
|
||||||
| Ctrl + V | 确认本张图片标记 |
|
| Ctrl + V | 确认本张图片标记 |
|
||||||
| Ctrl + Shift + d | 删除本张图片 |
|
| Ctrl + Shift + d | 删除本张图片 |
|
||||||
| D | 下一张图片 |
|
| D | 下一张图片 |
|
||||||
| A | 上一张图片 |
|
| A | 上一张图片 |
|
||||||
| Ctrl++ | 缩小 |
|
| Ctrl++ | 缩小 |
|
||||||
| Ctrl-- | 放大 |
|
| Ctrl-- | 放大 |
|
||||||
| ↑→↓← | 移动标记框 |
|
| ↑→↓← | 移动标记框 |
|
||||||
|
|
||||||
### 3.2 内置模型
|
### 3.2 内置模型
|
||||||
|
|
||||||
|
|
|
@ -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:
|
||||||
self.closePersistentEditor(self.edited_item)
|
if self.edited_item is not None:
|
||||||
item = self.item(modelindex.row())
|
self.closePersistentEditor(self.edited_item)
|
||||||
# time.sleep(0.2)
|
except:
|
||||||
self.edited_item = item
|
self.edited_item = self.currentItem()
|
||||||
self.openPersistentEditor(item)
|
|
||||||
# time.sleep(0.2)
|
self.edited_item = self.item(modelindex.row())
|
||||||
self.editItem(item)
|
self.openPersistentEditor(self.edited_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
|
||||||
|
|
|
@ -10,20 +10,15 @@
|
||||||
# SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
# 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
|
# 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.
|
||||||
#!/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):
|
||||||
|
@ -112,7 +128,7 @@ class Shape(object):
|
||||||
# Uncommenting the following line will draw 2 paths
|
# Uncommenting the following line will draw 2 paths
|
||||||
# for the 1st vertex, and make it non-filled, which
|
# for the 1st vertex, and make it non-filled, which
|
||||||
# may be desirable.
|
# may be desirable.
|
||||||
#self.drawVertex(vrtx_path, 0)
|
# self.drawVertex(vrtx_path, 0)
|
||||||
|
|
||||||
for i, p in enumerate(self.points):
|
for i, p in enumerate(self.points):
|
||||||
line_path.lineTo(p)
|
line_path.lineTo(p)
|
||||||
|
@ -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