Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 4 additions & 29 deletions PPOCRLabel.py
Original file line number Diff line number Diff line change
Expand Up @@ -1229,8 +1229,6 @@ def get_str(str_id):
self.fillColor = None
self.zoom_level = 100
self.fit_window = False
# Add Chris
self.difficult = False

# Fix the compatible issue for qt4 and qt5. Convert the QStringList to python list
if settings.get(SETTING_RECENT_FILES):
Expand Down Expand Up @@ -1265,8 +1263,6 @@ def get_str(str_id):
settings.get(SETTING_FILL_COLOR, DEFAULT_FILL_COLOR)
)
self.canvas.setDrawingColor(self.lineColor)
# Add chris
Shape.difficult = self.difficult

# ADD:
# Populate the File menu dynamically.
Expand Down Expand Up @@ -1834,11 +1830,7 @@ def addLabel(self, shape):
shape.paintIdx = self.displayIndexOption.isChecked()

item = HashableQListWidgetItem(shape.label)
# current difficult checkbox is disable
# item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
# item.setCheckState(Qt.Unchecked) if shape.difficult else item.setCheckState(Qt.Checked)

# Checked means difficult is False
# item.setBackground(generateColorByText(shape.label))
self.itemsToShapes[item] = shape
self.shapesToItems[shape] = item
Expand Down Expand Up @@ -1891,7 +1883,7 @@ def remLabels(self, shapes):
def loadLabels(self, shapes):
s = []
shape_index = 0
for label, points, line_color, key_cls, difficult in shapes:
for label, points, line_color, key_cls in shapes:
shape = Shape(
label=label,
line_color=line_color,
Expand All @@ -1905,7 +1897,6 @@ def loadLabels(self, shapes):
self.setDirty()

shape.addPoint(QPointF(x, y))
shape.difficult = difficult
shape.idx = shape_index
shape_index += 1
# shape.locked = False
Expand Down Expand Up @@ -1962,7 +1953,6 @@ def format_shape(s):
line_color=s.line_color.getRgb(),
fill_color=s.fill_color.getRgb(),
points=[(int(p.x()), int(p.y())) for p in s.points], # QPonitF
difficult=s.difficult,
key_cls=s.key_cls,
) # bool

Expand All @@ -1976,7 +1966,7 @@ def format_shape(s):
]
# Can add different annotation formats here
for box in self.result_dic:
trans_dic = {"label": box[1][0], "points": box[0], "difficult": False}
trans_dic = {"label": box[1][0], "points": box[0]}
if self.kie_mode:
if len(box) == 3:
trans_dic.update({"key_cls": box[2]})
Expand All @@ -1992,7 +1982,7 @@ def format_shape(s):
trans_dict = {
"transcription": box["label"],
"points": box["points"],
"difficult": box["difficult"],
"difficult": False,
}
if self.kie_mode:
trans_dict.update({"key_cls": box["key_cls"]})
Expand Down Expand Up @@ -2070,14 +2060,6 @@ def labelItemChanged(self, item):
shape.label = item.text()
# shape.line_color = generateColorByText(shape.label)
self.setDirty()
elif not ((item.checkState() == Qt.Unchecked) ^ (not shape.difficult)):
shape.difficult = True if item.checkState() == Qt.Unchecked else False
self.setDirty()
else: # User probably changed item visibility
self.canvas.setShapeVisible(
shape, True
) # item.checkState() == Qt.Checked
# self.actions.save.setEnabled(True)
else:
logger.warning(
"enter labelItemChanged slot with unhashable item: %s %s",
Expand Down Expand Up @@ -2425,7 +2407,6 @@ def showBoundingBoxFromPPlabel(self, filePath):
[[s[0] * width, s[1] * height] for s in box["ratio"]],
DEFAULT_LOCK_COLOR,
key_cls,
box["difficult"],
)
)
else:
Expand All @@ -2435,7 +2416,6 @@ def showBoundingBoxFromPPlabel(self, filePath):
[[s[0] * width, s[1] * height] for s in box["ratio"]],
DEFAULT_LOCK_COLOR,
key_cls,
box["difficult"],
)
)
if img_idx in self.PPlabel.keys():
Expand All @@ -2447,7 +2427,6 @@ def showBoundingBoxFromPPlabel(self, filePath):
box["points"],
None,
key_cls,
box.get("difficult", False),
)
)

Expand Down Expand Up @@ -3333,7 +3312,6 @@ def TableRecognition(self):
# If not, fix them.
x, y, _ = self.canvas.snapPointToCanvas(x, y)
shape.addPoint(QPointF(x, y))
shape.difficult = False
shape.idx = order_index
order_index += 1
# shape.locked = False
Expand Down Expand Up @@ -3703,8 +3681,6 @@ def saveRecResult(self):
np.fromfile(img_path, dtype=np.uint8), cv2.IMREAD_COLOR
)
for i, label in enumerate(self.PPlabel[idx]):
if label["difficult"]:
continue
img_crop = get_rotate_crop_image(
img, np.array(label["points"], np.float32)
)
Expand Down Expand Up @@ -3818,7 +3794,6 @@ def format_shape(s):
ratio=[
[int(p.x()) / width, int(p.y()) / height] for p in s.points
], # QPonitF
difficult=s.difficult, # bool
key_cls=s.key_cls, # bool
)

Expand All @@ -3833,7 +3808,7 @@ def format_shape(s):
trans_dict = {
"transcription": box["label"],
"ratio": box["ratio"],
"difficult": box["difficult"],
"difficult": False,
}
if self.kie_mode:
trans_dict.update({"key_cls": box["key_cls"]})
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ PPOCRLabel.exe --lang ch

6. Click 're-Recognition', model will rewrite ALL recognition results in ALL detection box<sup>[3]</sup>.

7. Single 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. **Note:** If the text is illegible or extremely blurry, it is recommended to change the label to `###`. The PaddleOCR training pipeline will treat these as "ignore" regions, ensuring they don't negatively impact your model's fine-tuning.

8. **Click "Check", the image status will switch to "√",then the program automatically jump to the next.**

Expand All @@ -177,6 +177,8 @@ PPOCRLabel.exe --lang ch
10. Labeling result: the user can export the label result manually through the menu "File - Export Label", while the program will also export automatically if "File - Auto export Label Mode" is selected. The manually checked label will be stored in *Label.txt* under the opened picture folder. Click "File"-"Export Recognition Results" in the menu bar, the recognition training data of such pictures will be saved in the *crop_img* folder, and the recognition label will be saved in *rec_gt.txt*<sup>[4]</sup>.

11. Additional Feature Description
- **The "###" vs "*":** The core **PaddleOCR detection training pipeline** ignores boolean flags and specifically looks for the transcription string `###` or `*` to identify regions that should be ignored. For maximum compatibility with all fine-tuning stages (both Detection and Recognition), always use `###` for unreadable text.
- **The "difficult" flag:** You may notice a `difficult` field in the exported `Label.txt`. This is a legacy field from the original `labelImg` tool. In this version of PPOCRLabel, this field is **hardcoded to `False`** for all exported labels to ensure backward compatibility with third-party data pipelines and older versions of the application while preventing unintended data exclusion during training exports.
- `File` -> `Re-recognition`: After checking, the newly annotated box content will automatically trigger the `Re-recognition` function of the current annotation box, eliminating the need to click the Re-identify button. This is suitable for scenarios where you do not want to use Automatic Annotation but prefer manual annotation, such as license plate recognition. In a single image with only one license plate, using Automatic Annotation would require deleting many additional recognized text boxes, which is less efficient than directly re-annotating.
- `File` -> `Auto Save Unsaved changes`: By default, you need to press the `Check` button to complete the marking confirmation for the current box, which can be cumbersome. After checking, when switching to the next image (by pressing the shortcut key `D`), a prompt box asking to confirm whether to save unconfirmed markings will no longer appear. The current markings will be automatically saved and the next image will be switched, making it convenient for quick marking.
- After selecting the bounding box, there are 5 shortcut keys available to individually control the movement of the four vertices of the bounding box, suitable for scenarios that require precise control over the positions of the bounding box vertices:
Expand Down
7 changes: 5 additions & 2 deletions README_ch.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,11 +155,14 @@ PPOCRLabel.exe --lang ch
4. 手动标注:点击 “矩形标注”(推荐直接在英文模式下点击键盘中的 “W”),用户可对当前图片中模型未检出的部分进行手动绘制标记框。点击键盘Q,则使用四点标注模式(或点击“编辑” - “四点标注”),用户依次点击4个点后,双击左键表示标注完成。
5. 标记框绘制完成后,用户点击 “确认”,检测框会先被预分配一个 “待识别” 标签。
6. 重新识别:将图片中的所有检测画绘制/调整完成后,点击 “重新识别”,PP-OCR模型会对当前图片中的**所有检测框**重新识别<sup>[3]</sup>。
7. 内容更改:单击识别结果,对不准确的识别结果进行手动更改。
7. 内容更改:单击识别结果,对不准确的识别结果进行手动更改。**注意:** 如果文字无法辨认或非常模糊,建议将标签修改为 `###`。PaddleOCR 训练流程会将其视为“忽略”区域,避免其对模型微调产生负面影响。

8. **确认标记:点击 “确认”,图片状态切换为 “√”,跳转至下一张。**
9. 删除:点击 “删除图像”,图片将会被删除至回收站。
10. 导出结果:用户可以通过菜单中“文件-导出标记结果”手动导出,同时也可以点击“文件 - 自动导出标记结果”开启自动导出。手动确认过的标记将会被存放在所打开图片文件夹下的*Label.txt*中。在菜单栏点击 “文件” - "导出识别结果"后,会将此类图片的识别训练数据保存在*crop_img*文件夹下,识别标签保存在*rec_gt.txt*中<sup>[4]</sup>。
11. 补充功能说明
11. 其他功能说明
- **“###” 与 “*” 的区别:** 核心的 **PaddleOCR 检测训练流程** 会忽略布尔标志,并专门查找转录字符串 `###` 或 `*` 来识别应忽略的区域。因此,为了最大限度地兼容所有微调阶段(检测和识别),对于无法辨认的文字,请始终使用 `###`。
- **“difficult” 标志:** 您可能会在导出的 `Label.txt` 中注意到 `difficult` 字段。这是一个源自原始 `labelImg` 工具的遗留字段。在此版本的 PPOCRLabel 中,此字段已 **硬编码为 `False`**,以确保与第三方数据流水线和旧版本应用程序的后向兼容性,同时防止在训练导出期间意外排除数据。
- `文件` -> `自动重新识别` : 勾选后,对于新标注的框内容会自动触发当前标注框的重新识别功能,不需要再去点击`重新识别`按钮,适合各种原因不想使用`自动标注`只想手动标注的场景,例如车牌识别,一张图里只有一个车牌,如果使用`自动标注`,需要删除很多额外识别出来的文字框,不如直接重新标注
- `文件` -> `自动保存未提交变更` : 默认是按`确认`按钮完成当前框的标记确认,有点繁琐,勾选后,切换下一张图(按快捷键`D`)的时候,不再弹出提示框确认是否保存未确认的标记,自动保存当前标记并切换下一张图,方便快速标记
- 选中标记框后,5个可以控制标记框四个顶点单独移动的快捷键,适合需要精确控制标记框四个顶点位置的场景
Expand Down
3 changes: 0 additions & 3 deletions libs/shape.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ def __init__(
self,
label=None,
line_color=None,
difficult=False,
key_cls="None",
paintLabel=False,
paintIdx=False,
Expand All @@ -64,7 +63,6 @@ def __init__(
self.points = []
self.fill = False
self.selected = False
self.difficult = difficult
self.key_cls = key_cls
self.paintLabel = paintLabel
self.paintIdx = paintIdx
Expand Down Expand Up @@ -268,7 +266,6 @@ def copy(self):
shape.line_color = self.line_color
if self.fill_color != Shape.fill_color:
shape.fill_color = self.fill_color
shape.difficult = self.difficult
shape.key_cls = self.key_cls
return shape

Expand Down
1 change: 0 additions & 1 deletion resources/strings/strings-en.properties
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ shapeFillColor=Shape Fill Color
shapeFillColorDetail=Change the fill color for this specific shape
showHide=Show/Hide Label Panel
useDefaultLabel=Use default label
useDifficult=Difficult
boxLabelText=Box Labels
labels=Labels
autoSaveMode=Auto Save mode
Expand Down
1 change: 0 additions & 1 deletion resources/strings/strings-zh-CN.properties
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ focusAndZoom=聚焦缩放
focusAndZoomDetail=聚焦并缩放至所选框
nextImg=下一张
useDefaultLabel=使用预设标签
useDifficult=有难度的
boxLabelText=区块的标签
labels=标签
autoSaveMode=自动保存模式
Expand Down
Loading