升级 PaddleOCR 至 3.4.0,移除 PP-OCRv4 模型

- PaddleOCR 2.10.0 升级至 3.4.0,使用新的 TextDetection API 替代旧版 TextDetector
- V5 模型替换为 PaddleX 格式(inference.pdiparams + inference.yml)
- 移除 PP-OCRv4 模型(backend/models/V4),仅保留 PP-OCRv5
- 字幕检测选项重命名为"快速"和"精准"
- 清理 requirements.txt,移除 11 个未使用的依赖,补充缺失的依赖
- 更新设计素材

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
flavioy
2026-04-07 22:34:36 +08:00
co-authored by Claude Opus 4.6
parent d023ca775c
commit 70e669e9d4
24 changed files with 384 additions and 60 deletions
+1 -1
View File
@@ -52,7 +52,7 @@ class Config(QConfig):
# 【设置inpaint算法】 # 【设置inpaint算法】
inpaintMode = OptionsConfigItem("Main", "InpaintMode", InpaintMode.STTN_AUTO, OptionsValidator(InpaintMode), EnumSerializer(InpaintMode)) inpaintMode = OptionsConfigItem("Main", "InpaintMode", InpaintMode.STTN_AUTO, OptionsValidator(InpaintMode), EnumSerializer(InpaintMode))
subtitleDetectMode = OptionsConfigItem("Main", "SubtitleDetectMode", SubtitleDetectMode.PP_OCRv4_SERVER, OptionsValidator(SubtitleDetectMode), EnumSerializer(SubtitleDetectMode)) subtitleDetectMode = OptionsConfigItem("Main", "SubtitleDetectMode", SubtitleDetectMode.PP_OCRv5_SERVER, OptionsValidator(SubtitleDetectMode), EnumSerializer(SubtitleDetectMode))
# 【设置像素点偏差】 # 【设置像素点偏差】
# 用于判断是不是非字幕区域(一般认为字幕文本框的长度是要大于宽度的,如果字幕框的高大于宽,且大于的幅度超过指定像素点大小,则认为是错误检测) # 用于判断是不是非字幕区域(一般认为字幕文本框的长度是要大于宽度的,如果字幕框的高大于宽,且大于的幅度超过指定像素点大小,则认为是错误检测)
Regular → Executable
View File
-4
View File
@@ -1,4 +0,0 @@
filename,filesize,encoding,header␍
inference_1.onnx,50000000,,␍
inference_2.onnx,50000000,,␍
inference_3.onnx,13443410,,␍
1 filename filesize encoding header
2 inference_1.onnx 50000000
3 inference_2.onnx 50000000
4 inference_3.onnx 13443410
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+111
View File
@@ -0,0 +1,111 @@
{
"Global": {
"model_name": "PP-OCRv5_server_det"
},
"Hpi": {
"backend_configs": {
"paddle_infer": {
"trt_dynamic_shapes": {
"x": [
[
1,
3,
32,
32
],
[
1,
3,
736,
736
],
[
1,
3,
4000,
4000
]
]
}
},
"tensorrt": {
"dynamic_shapes": {
"x": [
[
1,
3,
32,
32
],
[
1,
3,
736,
736
],
[
1,
3,
4000,
4000
]
]
}
}
}
},
"PreProcess": {
"transform_ops": [
{
"DecodeImage": {
"channel_first": false,
"img_mode": "BGR"
}
},
{
"DetLabelEncode": null
},
{
"DetResizeForTest": {
"resize_long": 960
}
},
{
"NormalizeImage": {
"mean": [
0.485,
0.456,
0.406
],
"order": "hwc",
"scale": "1./255.",
"std": [
0.229,
0.224,
0.225
]
}
},
{
"ToCHWImage": null
},
{
"KeepKeys": {
"keep_keys": [
"image",
"shape",
"polys",
"ignore_tags"
]
}
}
]
},
"PostProcess": {
"name": "DBPostProcess",
"thresh": 0.3,
"box_thresh": 0.6,
"max_candidates": 1000,
"unclip_ratio": 1.5
}
}
-3
View File
@@ -1,3 +0,0 @@
filename,filesize,encoding,header␍
inference_1.onnx,50000000,,␍
inference_2.onnx,38118768,,␍
1 filename filesize encoding header
2 inference_1.onnx 50000000
3 inference_2.onnx 38118768
File diff suppressed because one or more lines are too long
+53
View File
@@ -0,0 +1,53 @@
Global:
model_name: PP-OCRv5_server_det
Hpi:
backend_configs:
paddle_infer:
trt_dynamic_shapes: &id001
x:
- - 1
- 3
- 32
- 32
- - 1
- 3
- 736
- 736
- - 1
- 3
- 4000
- 4000
tensorrt:
dynamic_shapes: *id001
PreProcess:
transform_ops:
- DecodeImage:
channel_first: false
img_mode: BGR
- DetLabelEncode: null
- DetResizeForTest:
resize_long: 960
- NormalizeImage:
mean:
- 0.485
- 0.456
- 0.406
order: hwc
scale: 1./255.
std:
- 0.229
- 0.224
- 0.225
- ToCHWImage: null
- KeepKeys:
keep_keys:
- image
- shape
- polys
- ignore_tags
PostProcess:
name: DBPostProcess
thresh: 0.3
box_thresh: 0.6
max_candidates: 1000
unclip_ratio: 1.5
Binary file not shown.
+111
View File
@@ -0,0 +1,111 @@
{
"Global": {
"model_name": "PP-OCRv5_mobile_det"
},
"Hpi": {
"backend_configs": {
"paddle_infer": {
"trt_dynamic_shapes": {
"x": [
[
1,
3,
32,
32
],
[
1,
3,
736,
736
],
[
1,
3,
4000,
4000
]
]
}
},
"tensorrt": {
"dynamic_shapes": {
"x": [
[
1,
3,
32,
32
],
[
1,
3,
736,
736
],
[
1,
3,
4000,
4000
]
]
}
}
}
},
"PreProcess": {
"transform_ops": [
{
"DecodeImage": {
"channel_first": false,
"img_mode": "BGR"
}
},
{
"DetLabelEncode": null
},
{
"DetResizeForTest": {
"resize_long": 960
}
},
{
"NormalizeImage": {
"mean": [
0.485,
0.456,
0.406
],
"order": "hwc",
"scale": "1./255.",
"std": [
0.229,
0.224,
0.225
]
}
},
{
"ToCHWImage": null
},
{
"KeepKeys": {
"keep_keys": [
"image",
"shape",
"polys",
"ignore_tags"
]
}
}
]
},
"PostProcess": {
"name": "DBPostProcess",
"thresh": 0.3,
"box_thresh": 0.6,
"max_candidates": 1000,
"unclip_ratio": 1.5
}
}
File diff suppressed because one or more lines are too long
@@ -0,0 +1,53 @@
Global:
model_name: PP-OCRv5_mobile_det
Hpi:
backend_configs:
paddle_infer:
trt_dynamic_shapes: &id001
x:
- - 1
- 3
- 32
- 32
- - 1
- 3
- 736
- 736
- - 1
- 3
- 4000
- 4000
tensorrt:
dynamic_shapes: *id001
PreProcess:
transform_ops:
- DecodeImage:
channel_first: false
img_mode: BGR
- DetLabelEncode: null
- DetResizeForTest:
resize_long: 960
- NormalizeImage:
mean:
- 0.485
- 0.456
- 0.406
order: hwc
scale: 1./255.
std:
- 0.229
- 0.224
- 0.225
- ToCHWImage: null
- KeepKeys:
keep_keys:
- image
- shape
- polys
- ignore_tags
PostProcess:
name: DBPostProcess
thresh: 0.3
box_thresh: 0.6
max_candidates: 1000
unclip_ratio: 1.5
+2 -4
View File
@@ -16,7 +16,5 @@ class SubtitleDetectMode(Enum):
""" """
字幕检测算法枚举 字幕检测算法枚举
""" """
PP_OCRv4_SERVER = "PP-OCRv4-Server" PP_OCRv5_MOBILE = "快速"
PP_OCRv4_MOBILE = "PP-OCRv4-Mobile" PP_OCRv5_SERVER = "精准"
PP_OCRv5_SERVER = "PP-OCRv5-Server"
PP_OCRv5_MOBILE = "PP-OCRv5-Mobile"
+6 -6
View File
@@ -3,6 +3,11 @@ from backend.config import config, BASE_DIR
from backend.tools.common_tools import merge_big_file_if_not_exists from backend.tools.common_tools import merge_big_file_if_not_exists
from backend.tools.constant import SubtitleDetectMode from backend.tools.constant import SubtitleDetectMode
_MODEL_NAME_MAP = {
SubtitleDetectMode.PP_OCRv5_MOBILE: "PP-OCRv5_mobile_det",
SubtitleDetectMode.PP_OCRv5_SERVER: "PP-OCRv5_server_det",
}
class ModelConfig: class ModelConfig:
def __init__(self): def __init__(self):
self.LAMA_MODEL_DIR = os.path.join(BASE_DIR, 'models', 'big-lama') self.LAMA_MODEL_DIR = os.path.join(BASE_DIR, 'models', 'big-lama')
@@ -13,14 +18,9 @@ class ModelConfig:
self.DET_MODEL_DIR = os.path.join(BASE_DIR,'models', 'V5', 'ch_det_fast') self.DET_MODEL_DIR = os.path.join(BASE_DIR,'models', 'V5', 'ch_det_fast')
elif config.subtitleDetectMode.value == SubtitleDetectMode.PP_OCRv5_SERVER: elif config.subtitleDetectMode.value == SubtitleDetectMode.PP_OCRv5_SERVER:
self.DET_MODEL_DIR = os.path.join(BASE_DIR, 'models', 'V5', 'ch_det') self.DET_MODEL_DIR = os.path.join(BASE_DIR, 'models', 'V5', 'ch_det')
elif config.subtitleDetectMode.value == SubtitleDetectMode.PP_OCRv4_MOBILE:
self.DET_MODEL_DIR = os.path.join(BASE_DIR,'models', 'V4', 'ch_det_fast')
elif config.subtitleDetectMode.value == SubtitleDetectMode.PP_OCRv4_SERVER:
self.DET_MODEL_DIR = os.path.join(BASE_DIR, 'models', 'V4', 'ch_det')
else: else:
raise ValueError(f"Invalid subtitle detect mode: {config.subtitleDetectMode.value}") raise ValueError(f"Invalid subtitle detect mode: {config.subtitleDetectMode.value}")
self.DET_MODEL_NAME = _MODEL_NAME_MAP[config.subtitleDetectMode.value]
merge_big_file_if_not_exists(self.LAMA_MODEL_DIR, 'bit-lama.pt') merge_big_file_if_not_exists(self.LAMA_MODEL_DIR, 'bit-lama.pt')
merge_big_file_if_not_exists(self.PROPAINTER_MODEL_DIR, 'ProPainter.pth') merge_big_file_if_not_exists(self.PROPAINTER_MODEL_DIR, 'ProPainter.pth')
merge_big_file_if_not_exists(self.DET_MODEL_DIR, 'inference.onnx')
+25 -25
View File
@@ -1,4 +1,3 @@
import os
import sys import sys
from functools import cached_property from functools import cached_property
@@ -27,36 +26,37 @@ class SubtitleDetect:
def text_detector(self): def text_detector(self):
import paddle import paddle
paddle.disable_signal_handler() paddle.disable_signal_handler()
from paddleocr.tools.infer import utility from paddleocr import TextDetection
from paddleocr.tools.infer.predict_det import TextDetector
hardware_accelerator = HardwareAccelerator.instance() hardware_accelerator = HardwareAccelerator.instance()
onnx_providers = hardware_accelerator.onnx_providers onnx_providers = hardware_accelerator.onnx_providers
model_config = ModelConfig() model_config = ModelConfig()
parser = utility.init_args() return TextDetection(
args = parser.parse_args([]) model_name=model_config.DET_MODEL_NAME,
args.det_algorithm = 'DB' model_dir=model_config.DET_MODEL_DIR,
args.det_model_dir = os.path.join(model_config.DET_MODEL_DIR, 'inference.onnx') if len(onnx_providers) > 0 else model_config.DET_MODEL_DIR device="cpu",
args.use_gpu=False enable_hpi=len(onnx_providers) > 0,
args.use_onnx=len(onnx_providers) > 0 )
args.onnx_providers=onnx_providers
return TextDetector(args)
def detect_subtitle(self, img): def detect_subtitle(self, img):
temp_list = [] temp_list = []
dt_boxes, elapse = self.text_detector(img) results = self.text_detector.predict(img)
coordinate_list = get_coordinates(dt_boxes.tolist()) for res in results:
if coordinate_list: dt_polys = res['dt_polys']
for coordinate in coordinate_list: if dt_polys is None or len(dt_polys) == 0:
xmin, xmax, ymin, ymax = coordinate continue
if self.sub_areas is not None and len(self.sub_areas) > 0: coordinate_list = get_coordinates(dt_polys.tolist())
for sub_area in self.sub_areas: if coordinate_list:
s_ymin, s_ymax, s_xmin, s_xmax = sub_area for coordinate in coordinate_list:
if (s_xmin <= xmin and xmax <= s_xmax xmin, xmax, ymin, ymax = coordinate
and s_ymin <= ymin if self.sub_areas is not None and len(self.sub_areas) > 0:
and ymax <= s_ymax): for sub_area in self.sub_areas:
temp_list.append((xmin, xmax, ymin, ymax)) s_ymin, s_ymax, s_xmin, s_xmax = sub_area
else: if (s_xmin <= xmin and xmax <= s_xmax
temp_list.append((xmin, xmax, ymin, ymax)) and s_ymin <= ymin
and ymax <= s_ymax):
temp_list.append((xmin, xmax, ymin, ymax))
else:
temp_list.append((xmin, xmax, ymin, ymax))
return temp_list return temp_list
def find_subtitle_frame_no(self, sub_remover=None): def find_subtitle_frame_no(self, sub_remover=None):
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 405 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 26 KiB

+20 -17
View File
@@ -1,25 +1,28 @@
albumentations~=1.4.10
filesplit==3.0.2 filesplit==3.0.2
opencv-python==4.11.0.86 opencv-python==4.11.0.86
scikit-image==0.25.2 scikit-image==0.25.2
imgaug==0.4.0
pyclipper==1.3.0.post6
lmdb==1.6.2
PyYAML==6.0.2
omegaconf==2.3.0
tqdm==4.67.1 tqdm==4.67.1
pyside6-fluent-widgets==1.7.7 pyside6-fluent-widgets==1.7.7
easydict==1.13
scikit-learn==1.6.1
pandas==2.2.3
webdataset==0.2.111
numpy==2.2.5 numpy==2.2.5
protobuf==6.30.2 av==17.0.0
av==14.3.0
einops==0.8.1 einops==0.8.1
paddleocr==2.10.0 paddleocr==3.4.0
onnxruntime-gpu==1.20.1; sys_platform == 'linux' matplotlib
Pillow
scipy
requests
darkdetect
je-showinfilemanager==1.1.6a4
# torch and torchvision are installed separately (see Dockerfile for platform-specific versions)
# Training only
#matplotlib
#lpips
#tensorboardX
# Hardware acceleration
#onnxruntime-gpu==1.20.1; sys_platform == 'linux'
# do not upgrade, windows 10/11 compatable issues, check hardware_acclerator.py:100 # do not upgrade, windows 10/11 compatable issues, check hardware_acclerator.py:100
onnxruntime-directml==1.20.1; sys_platform == 'win32' #onnxruntime-directml==1.20.1; sys_platform == 'win32'
onnxruntime==1.22.0; sys_platform == 'darwin' #onnxruntime==1.22.0; sys_platform == 'darwin'
je-showinfilemanager==1.1.6a4