u
This commit is contained in:
1 parent
a96f04630e
commit
7837b87959
27 files changed
+508
-894
No files matched your search
@@ -1,6 +1,46 @@
|
|||||||
package com.email;
|
package com.email;
|
||||||
|
|
||||||
|
import com.email.core.fetch.EmailFetcher;
|
||||||
|
import com.email.core.fetch.ImapJavaMailEmailFetcher;
|
||||||
|
import com.email.domain.entity.UserAccount;
|
||||||
|
|
||||||
|
import javax.mail.*;
|
||||||
|
import javax.mail.Flags;
|
||||||
|
import javax.mail.search.FlagTerm;
|
||||||
|
import javax.net.ssl.SSLSocket;
|
||||||
|
import javax.net.ssl.SSLSocketFactory;
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
public class Test {
|
public class Test {
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
UserAccount userAccount = new UserAccount();
|
||||||
|
userAccount.setEmail("717406575@qq.com");
|
||||||
|
userAccount.setPassword("dhqesrwzgblrbcac");
|
||||||
|
userAccount.setImapHost("imap.qq.com");
|
||||||
|
userAccount.setImapPort("993");
|
||||||
|
|
||||||
|
EmailFetcher emailFetcher = new ImapJavaMailEmailFetcher();
|
||||||
|
|
||||||
|
emailFetcher.fetchAll(
|
||||||
|
userAccount,
|
||||||
|
|
||||||
|
// progressConsumer: 打印进度
|
||||||
|
progress -> System.out.printf("📩 [%s] 已拉取 %d / %d 封邮件%n",
|
||||||
|
progress.getFolderName(),
|
||||||
|
progress.getCurrent(),
|
||||||
|
progress.getTotal()
|
||||||
|
),
|
||||||
|
|
||||||
|
// folderConsumer: 开始处理某个文件夹
|
||||||
|
folder -> {
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
// fetchDataConsumer: 每封邮件拉取完成后处理
|
||||||
|
emailData -> {
|
||||||
|
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -35,7 +35,7 @@ public class EmailImapClient {
|
|||||||
props.put("mail.imaps.partialfetch", "false");
|
props.put("mail.imaps.partialfetch", "false");
|
||||||
|
|
||||||
|
|
||||||
// 在连接参数中强制指定ID信息
|
// 在连接参数中强制指定ID信息
|
||||||
props.put("mail.imap.id.mechanism", "OAUTH2");
|
props.put("mail.imap.id.mechanism", "OAUTH2");
|
||||||
props.put("mail.imap.id.name", "your_client_name");
|
props.put("mail.imap.id.name", "your_client_name");
|
||||||
props.put("mail.imap.id.version", "1.0.0");
|
props.put("mail.imap.id.version", "1.0.0");
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package com.email.client;
|
||||||
|
|
||||||
|
import com.email.domain.entity.UserAccount;
|
||||||
|
|
||||||
|
import javax.mail.Session;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
public class EmailImapClient2 {
|
||||||
|
private UserAccount userAccount;
|
||||||
|
|
||||||
|
public void connect(){
|
||||||
|
Properties props = new Properties();
|
||||||
|
props.put("mail.store.protocol", "imap");
|
||||||
|
props.put("mail.imap.host", userAccount.getImapHost());
|
||||||
|
props.put("mail.imap.port", userAccount.getImapPort());
|
||||||
|
props.put("mail.imap.ssl.enable", "true");
|
||||||
|
props.put("mail.imap.starttls.enable", "true");
|
||||||
|
props.put("mail.imap.partialfetch", "false");
|
||||||
|
props.put("mail.imaps.partialfetch", "false");
|
||||||
|
|
||||||
|
|
||||||
|
// 在连接参数中强制指定ID信息
|
||||||
|
props.put("mail.imap.id.mechanism", "OAUTH2");
|
||||||
|
props.put("mail.imap.id.name", userAccount.getDisplayName());
|
||||||
|
props.put("mail.imap.id.version", "1.0.0");
|
||||||
|
|
||||||
|
props.put("mail.imap.fetchsize", "4194304");
|
||||||
|
HashMap<String, String> imapId = new HashMap<>();
|
||||||
|
imapId.put("name", String.valueOf(userAccount.getId()));
|
||||||
|
imapId.put("version", "1.0.0");
|
||||||
|
imapId.put("vendor", "vendor");
|
||||||
|
imapId.put("support-email", userAccount.getEmail());
|
||||||
|
Session.getInstance(props);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
package com.email.client;
|
|
||||||
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.Base64;
|
|
||||||
|
|
||||||
public class ImapUtf7 {
|
|
||||||
public static String decode(String encoded) {
|
|
||||||
if (encoded == null) return null;
|
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
int i = 0;
|
|
||||||
while (i < encoded.length()) {
|
|
||||||
char ch = encoded.charAt(i);
|
|
||||||
if (ch == '&') {
|
|
||||||
int start = ++i;
|
|
||||||
while (i < encoded.length() && encoded.charAt(i) != '-') {
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
if (i == start) {
|
|
||||||
sb.append('&');
|
|
||||||
i++; // 跳过 '-'
|
|
||||||
} else {
|
|
||||||
String base64 = encoded.substring(start, i).replace(',', '/');
|
|
||||||
byte[] utf16Bytes = Base64.getDecoder().decode(base64);
|
|
||||||
sb.append(new String(utf16Bytes, StandardCharsets.UTF_16BE));
|
|
||||||
i++; // 跳过 '-'
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sb.append(ch);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package com.email.core.fetch;
|
||||||
|
|
||||||
|
import com.email.core.fetch.model.EmailFetchData;
|
||||||
|
import com.email.core.fetch.model.EmailFetchProgress;
|
||||||
|
import com.email.domain.entity.EmailFolder;
|
||||||
|
import com.email.domain.entity.UserAccount;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public interface EmailFetcher {
|
||||||
|
void fetchAll(UserAccount userAccount,
|
||||||
|
Consumer<EmailFetchProgress> emailFetchProgressConsumer,
|
||||||
|
Consumer<EmailFolder> emailFolderConsumer,
|
||||||
|
Consumer<EmailFetchData> emailFetchDataConsumer);
|
||||||
|
}
|
||||||
+4
@@ -0,0 +1,4 @@
|
|||||||
|
package com.email.core.fetch;
|
||||||
|
|
||||||
|
public class ImapCommandEmailFetcher {
|
||||||
|
}
|
||||||
+163
@@ -0,0 +1,163 @@
|
|||||||
|
package com.email.core.fetch;
|
||||||
|
|
||||||
|
import com.email.constants.ResponseStatusConstants;
|
||||||
|
import com.email.core.fetch.model.EmailFetchData;
|
||||||
|
import com.email.core.fetch.model.EmailFetchProgress;
|
||||||
|
import com.email.domain.entity.EmailFolder;
|
||||||
|
import com.email.domain.entity.UserAccount;
|
||||||
|
import com.email.enums.ResponseEnum;
|
||||||
|
import com.email.exception.auth.AuthException;
|
||||||
|
import com.sun.javaws.progress.Progress;
|
||||||
|
import com.sun.mail.imap.IMAPFolder;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import javax.mail.*;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class ImapJavaMailEmailFetcher implements EmailFetcher {
|
||||||
|
|
||||||
|
private final ExecutorService folderExecutor = Executors.newFixedThreadPool(10);
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fetchAll(UserAccount userAccount, Consumer<EmailFetchProgress> progressConsumer, Consumer<EmailFolder> folderConsumer, Consumer<EmailFetchData> fetchDataConsumer) {
|
||||||
|
Store store = null;
|
||||||
|
try {
|
||||||
|
store = connect(userAccount); // connect 内部已处理异常
|
||||||
|
|
||||||
|
List<Folder> allFolders = listAllFolders(store.getDefaultFolder());
|
||||||
|
|
||||||
|
CountDownLatch folderLatch = new CountDownLatch(allFolders.size());
|
||||||
|
|
||||||
|
for (Folder folder : allFolders) {
|
||||||
|
folderExecutor.submit(() -> {
|
||||||
|
try {
|
||||||
|
processFolder(folder, progressConsumer, folderConsumer, fetchDataConsumer);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("处理文件夹 [{}] 失败:{}", folder.getFullName(), e.getMessage(), e);
|
||||||
|
} finally {
|
||||||
|
folderLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
folderLatch.await(); // 等待所有文件夹处理完
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("抓取邮件失败:" + e.getMessage(), e);
|
||||||
|
} finally {
|
||||||
|
if (store != null && store.isConnected()) {
|
||||||
|
try {
|
||||||
|
store.close();
|
||||||
|
} catch (MessagingException closeEx) {
|
||||||
|
log.warn("关闭邮箱连接时异常:{}", closeEx.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 递归获取所有文件夹(包括子文件夹)
|
||||||
|
private List<Folder> listAllFolders(Folder folder) throws MessagingException {
|
||||||
|
List<Folder> allFolders = new ArrayList<>();
|
||||||
|
|
||||||
|
if ((folder.getType() & Folder.HOLDS_MESSAGES) != 0) {
|
||||||
|
allFolders.add(folder);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((folder.getType() & Folder.HOLDS_FOLDERS) != 0) {
|
||||||
|
Folder[] subFolders = folder.list();
|
||||||
|
for (Folder sub : subFolders) {
|
||||||
|
allFolders.addAll(listAllFolders(sub));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return allFolders;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processFolder(Folder folder,
|
||||||
|
Consumer<EmailFetchProgress> progressConsumer,
|
||||||
|
Consumer<EmailFolder> folderConsumer,
|
||||||
|
Consumer<EmailFetchData> fetchDataConsumer) throws Exception {
|
||||||
|
if (!(folder instanceof IMAPFolder)) return;
|
||||||
|
|
||||||
|
folder.open(Folder.READ_ONLY);
|
||||||
|
|
||||||
|
int totalMessages = folder.getMessageCount();
|
||||||
|
if (totalMessages == 0) {
|
||||||
|
folder.close(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EmailFolder emailFolder = new EmailFolder();
|
||||||
|
|
||||||
|
folderConsumer.accept(emailFolder);
|
||||||
|
|
||||||
|
FetchProfile fetchProfile = new FetchProfile();
|
||||||
|
fetchProfile.add(FetchProfile.Item.ENVELOPE);
|
||||||
|
fetchProfile.add(FetchProfile.Item.CONTENT_INFO);
|
||||||
|
|
||||||
|
Message[] messages = folder.getMessages();
|
||||||
|
folder.fetch(messages, fetchProfile);
|
||||||
|
|
||||||
|
for (int i = 0; i < messages.length; i++) {
|
||||||
|
Message message = messages[i];
|
||||||
|
try {
|
||||||
|
progressConsumer.accept(new EmailFetchProgress(folder.getFullName(), i + 1, totalMessages));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("处理邮件失败 folder={} index={} error={}", folder.getFullName(), i, e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
folder.close(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Store connect(UserAccount account) {
|
||||||
|
Properties props = new Properties();
|
||||||
|
props.put("mail.store.protocol", "imaps");
|
||||||
|
props.put("mail.imap.ssl.enable", "true");
|
||||||
|
props.put("mail.imap.connectiontimeout", "10000");
|
||||||
|
props.put("mail.imap.timeout", "10000");
|
||||||
|
|
||||||
|
try {
|
||||||
|
Session session = Session.getInstance(props);
|
||||||
|
Store store = session.getStore("imaps");
|
||||||
|
|
||||||
|
store.connect(
|
||||||
|
account.getImapHost(),
|
||||||
|
Integer.parseInt(account.getImapPort()),
|
||||||
|
account.getEmail(),
|
||||||
|
account.getPassword()
|
||||||
|
);
|
||||||
|
|
||||||
|
return store;
|
||||||
|
} catch (AuthenticationFailedException e) {
|
||||||
|
log.warn("邮箱认证失败:账号={},原因={}", account.getEmail(), e.getMessage(), e);
|
||||||
|
throw new AuthException(ResponseEnum.AUTH_EMAIL_INVALID_CREDENTIALS);
|
||||||
|
} catch (NoSuchProviderException e) {
|
||||||
|
log.warn("邮箱协议不支持:账号={},原因={}", account.getEmail(), e.getMessage(), e);
|
||||||
|
throw new AuthException(ResponseEnum.AUTH_EMAIL_PROTOCOL_UNSUPPORTED);
|
||||||
|
} catch (MessagingException e) {
|
||||||
|
log.warn("邮箱服务器连接失败:账号={},Host={},Port={},SSL={},原因={}",
|
||||||
|
account.getEmail(),
|
||||||
|
account.getImapHost(),
|
||||||
|
account.getImapPort(),
|
||||||
|
account.getImapSsl(),
|
||||||
|
e.getMessage(),
|
||||||
|
e
|
||||||
|
);
|
||||||
|
throw new AuthException(ResponseEnum.AUTH_EMAIL_CONNECTION_FAILED);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("邮箱连接发生未知错误:账号={},原因={}", account.getEmail(), e.getMessage(), e);
|
||||||
|
throw new AuthException(ResponseEnum.AUTH_EMAIL_UNKNOWN_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
package com.email.core.fetch.model;
|
||||||
|
|
||||||
|
import com.email.domain.entity.EmailAddress;
|
||||||
|
import com.email.domain.entity.EmailFile;
|
||||||
|
import com.email.domain.entity.EmailSummary;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class EmailFetchData {
|
||||||
|
private EmailSummary emailSummary;
|
||||||
|
private List<EmailAddress> emailAddressList;
|
||||||
|
private List<EmailFile> emailFileList;
|
||||||
|
}
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
package com.email.core.fetch.model;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class EmailFetchProgress {
|
||||||
|
private String folderName; // 文件夹名称
|
||||||
|
|
||||||
|
private Integer current; // 当前页
|
||||||
|
private Integer total; // 总数
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
package com.email.core.send;
|
||||||
|
|
||||||
|
public interface EmailSender {
|
||||||
|
}
|
||||||
+4
@@ -0,0 +1,4 @@
|
|||||||
|
package com.email.core.send;
|
||||||
|
|
||||||
|
public class SmtpCommandEmailSender {
|
||||||
|
}
|
||||||
+4
@@ -0,0 +1,4 @@
|
|||||||
|
package com.email.core.send;
|
||||||
|
|
||||||
|
public class SmtpJavaMailEmailSender {
|
||||||
|
}
|
||||||
@@ -19,7 +19,7 @@ public class EmailSentDTO {
|
|||||||
|
|
||||||
private String body; // 邮件正文内容
|
private String body; // 邮件正文内容
|
||||||
private String from; // 发件人
|
private String from; // 发件人
|
||||||
private String fromName; // 发件人
|
private String fromName; // 发件人名称
|
||||||
|
|
||||||
private Integer isSingSent; // 是否群发单显(1 是,0 否)
|
private Integer isSingSent; // 是否群发单显(1 是,0 否)
|
||||||
private Integer isHtml;
|
private Integer isHtml;
|
||||||
|
|||||||
@@ -15,14 +15,14 @@ import lombok.experimental.Accessors;
|
|||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@TableName("email_file")
|
@TableName("email_file")
|
||||||
@Accessors(chain = true)
|
@Accessors(chain = true)
|
||||||
public class EmailFile {
|
public class EmailFile {
|
||||||
@TableId
|
@TableId
|
||||||
@JsonSerialize(using = ToStringSerializer.class)
|
@JsonSerialize(using = ToStringSerializer.class)
|
||||||
private Long id; // 主键ID
|
private Long id; // 主键ID
|
||||||
private String fileName; // 文件名(不含路径)
|
private String fileName; // 文件名(不含路径)
|
||||||
private String fileExtension; // 文件扩展名,例如:jpg、pdf
|
private String fileExtension; // 文件扩展名,例如:jpg、pdf
|
||||||
private Long fileSize; // 文件大小,单位字节
|
private Long fileSize; // 文件大小,单位字节
|
||||||
private String filePath; // 文件路径(建议存相对路径)
|
private String filePath; // 文件路径(相对路径)
|
||||||
private Integer fileType; // 文件类型:0-临时,1-附件,2-内嵌资源,3-模板等
|
private Integer fileType; // 文件类型:0-临时,1-附件,2-内嵌资源,3-模板等
|
||||||
|
|
||||||
private Long emailId; // 关联的邮件ID
|
private Long emailId; // 关联的邮件ID
|
||||||
@@ -31,4 +31,3 @@ public class EmailFile {
|
|||||||
@TableField(exist = false)
|
@TableField(exist = false)
|
||||||
private String fileUrl;
|
private String fileUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -18,7 +18,13 @@ public enum ResponseEnum {
|
|||||||
AUTH_SMTP_PROTOCOL_ERROR(ResponseStatusConstants.UNAUTHORIZED, "SMTP 协议不支持或配置错误"),
|
AUTH_SMTP_PROTOCOL_ERROR(ResponseStatusConstants.UNAUTHORIZED, "SMTP 协议不支持或配置错误"),
|
||||||
AUTH_IMAP_PROTOCOL_ERROR(ResponseStatusConstants.UNAUTHORIZED, "IMAP 协议不支持或配置错误"),
|
AUTH_IMAP_PROTOCOL_ERROR(ResponseStatusConstants.UNAUTHORIZED, "IMAP 协议不支持或配置错误"),
|
||||||
AUTH_SERVER_CONNECTION_FAILED(ResponseStatusConstants.UNAUTHORIZED, "邮箱服务器连接失败,请检查是否已经开通 IMAP/SMTP 协议"),
|
AUTH_SERVER_CONNECTION_FAILED(ResponseStatusConstants.UNAUTHORIZED, "邮箱服务器连接失败,请检查是否已经开通 IMAP/SMTP 协议"),
|
||||||
AUTH_UNKNOWN_ERROR(ResponseStatusConstants.UNAUTHORIZED,"邮箱服务器连接失败,请重新登录");
|
AUTH_UNKNOWN_ERROR(ResponseStatusConstants.UNAUTHORIZED,"邮箱服务器连接失败,请重新登录"),
|
||||||
|
|
||||||
|
AUTH_EMAIL_INVALID_CREDENTIALS(ResponseStatusConstants.UNAUTHORIZED,"邮箱账户或密码错误"),
|
||||||
|
AUTH_EMAIL_PROTOCOL_UNSUPPORTED(ResponseStatusConstants.UNAUTHORIZED,"邮箱协议不支持"),
|
||||||
|
AUTH_EMAIL_CONNECTION_FAILED(ResponseStatusConstants.UNAUTHORIZED,"邮箱服务器连接失败,请检查配置"),
|
||||||
|
AUTH_EMAIL_UNKNOWN_ERROR(ResponseStatusConstants.UNAUTHORIZED,"连接邮箱时发生未知错误");
|
||||||
|
|
||||||
|
|
||||||
private final Integer code; //响应码
|
private final Integer code; //响应码
|
||||||
private final String message; //相应信息
|
private final String message; //相应信息
|
||||||
|
|||||||
Whitespace-only changes.
Binary file not shown.
|
Before Width: | Height: | Size: 77 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 90 KiB |
@@ -1,663 +0,0 @@
|
|||||||
# 识别结果
|
|
||||||
|
|
||||||
参数基本采用默认参数,都训练 **10轮** 。
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## PP-OCRv5_server (极好)
|
|
||||||
|
|
||||||
识别效果:**极好** ,基本都是别出来了,并且正确。
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### PP-OCRv5_server_det.yml
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
Global:
|
|
||||||
model_name: PP-OCRv5_server_det # To use static model for inference.
|
|
||||||
debug: false
|
|
||||||
use_gpu: true
|
|
||||||
epoch_num: &epoch_num 10
|
|
||||||
log_smooth_window: 20
|
|
||||||
print_batch_step: 10
|
|
||||||
save_model_dir: ./output-v5server/PP-OCRv5_server_det
|
|
||||||
save_epoch_step: 200
|
|
||||||
eval_batch_step:
|
|
||||||
- 0
|
|
||||||
- 200
|
|
||||||
cal_metric_during_train: false
|
|
||||||
checkpoints:
|
|
||||||
pretrained_model: ./pretrain_models/PP-OCRv5_server_det_pretrained.pdparams
|
|
||||||
save_inference_dir: null
|
|
||||||
use_visualdl: false
|
|
||||||
infer_img: doc/imgs_en/img_10.jpg
|
|
||||||
save_res_path: ./checkpoints/det_db/predicts_db.txt
|
|
||||||
distributed: false
|
|
||||||
|
|
||||||
Architecture:
|
|
||||||
model_type: det
|
|
||||||
algorithm: DB
|
|
||||||
Transform: null
|
|
||||||
Backbone:
|
|
||||||
name: PPHGNetV2_B4
|
|
||||||
det: True
|
|
||||||
Neck:
|
|
||||||
name: LKPAN
|
|
||||||
out_channels: 256
|
|
||||||
intracl: true
|
|
||||||
Head:
|
|
||||||
name: PFHeadLocal
|
|
||||||
k: 50
|
|
||||||
mode: "large"
|
|
||||||
|
|
||||||
|
|
||||||
Loss:
|
|
||||||
name: DBLoss
|
|
||||||
balance_loss: true
|
|
||||||
main_loss_type: DiceLoss
|
|
||||||
alpha: 5
|
|
||||||
beta: 10
|
|
||||||
ohem_ratio: 3
|
|
||||||
|
|
||||||
Optimizer:
|
|
||||||
name: Adam
|
|
||||||
beta1: 0.9
|
|
||||||
beta2: 0.999
|
|
||||||
lr:
|
|
||||||
name: Cosine
|
|
||||||
learning_rate: 0.001 #(8*8c)
|
|
||||||
warmup_epoch: 2
|
|
||||||
regularizer:
|
|
||||||
name: L2
|
|
||||||
factor: 1e-6
|
|
||||||
|
|
||||||
PostProcess:
|
|
||||||
name: DBPostProcess
|
|
||||||
thresh: 0.3
|
|
||||||
box_thresh: 0.6
|
|
||||||
max_candidates: 1000
|
|
||||||
unclip_ratio: 1.5
|
|
||||||
|
|
||||||
Metric:
|
|
||||||
name: DetMetric
|
|
||||||
main_indicator: hmean
|
|
||||||
|
|
||||||
Train:
|
|
||||||
dataset:
|
|
||||||
name: SimpleDataSet
|
|
||||||
data_dir: ./data/input0/images #图片文件夹路径
|
|
||||||
label_file_list:
|
|
||||||
- ./det_train_label.txt #标签路径
|
|
||||||
ratio_list: [1.0]
|
|
||||||
transforms:
|
|
||||||
- DecodeImage:
|
|
||||||
img_mode: BGR
|
|
||||||
channel_first: false
|
|
||||||
- DetLabelEncode: null
|
|
||||||
- CopyPaste: null
|
|
||||||
- IaaAugment:
|
|
||||||
augmenter_args:
|
|
||||||
- type: Fliplr
|
|
||||||
args:
|
|
||||||
p: 0.5
|
|
||||||
- type: Affine
|
|
||||||
args:
|
|
||||||
rotate:
|
|
||||||
- -10
|
|
||||||
- 10
|
|
||||||
- type: Resize
|
|
||||||
args:
|
|
||||||
size:
|
|
||||||
- 0.5
|
|
||||||
- 3
|
|
||||||
- EastRandomCropData:
|
|
||||||
size:
|
|
||||||
- 640
|
|
||||||
- 640
|
|
||||||
max_tries: 50
|
|
||||||
keep_ratio: true
|
|
||||||
- MakeBorderMap:
|
|
||||||
shrink_ratio: 0.4
|
|
||||||
thresh_min: 0.3
|
|
||||||
thresh_max: 0.7
|
|
||||||
total_epoch: *epoch_num
|
|
||||||
- MakeShrinkMap:
|
|
||||||
shrink_ratio: 0.4
|
|
||||||
min_text_size: 8
|
|
||||||
total_epoch: *epoch_num
|
|
||||||
- NormalizeImage:
|
|
||||||
scale: 1./255.
|
|
||||||
mean:
|
|
||||||
- 0.485
|
|
||||||
- 0.456
|
|
||||||
- 0.406
|
|
||||||
std:
|
|
||||||
- 0.229
|
|
||||||
- 0.224
|
|
||||||
- 0.225
|
|
||||||
order: hwc
|
|
||||||
- ToCHWImage: null
|
|
||||||
- KeepKeys:
|
|
||||||
keep_keys:
|
|
||||||
- image
|
|
||||||
- threshold_map
|
|
||||||
- threshold_mask
|
|
||||||
- shrink_map
|
|
||||||
- shrink_mask
|
|
||||||
loader:
|
|
||||||
shuffle: true
|
|
||||||
drop_last: false
|
|
||||||
batch_size_per_card: 10
|
|
||||||
num_workers: 1
|
|
||||||
|
|
||||||
Eval:
|
|
||||||
dataset:
|
|
||||||
name: SimpleDataSet
|
|
||||||
data_dir: ./data/input0/images
|
|
||||||
label_file_list:
|
|
||||||
- ./det_eval_label.txt
|
|
||||||
transforms:
|
|
||||||
- DecodeImage:
|
|
||||||
img_mode: BGR
|
|
||||||
channel_first: false
|
|
||||||
- DetLabelEncode: null
|
|
||||||
- DetResizeForTest:
|
|
||||||
- NormalizeImage:
|
|
||||||
scale: 1./255.
|
|
||||||
mean:
|
|
||||||
- 0.485
|
|
||||||
- 0.456
|
|
||||||
- 0.406
|
|
||||||
std:
|
|
||||||
- 0.229
|
|
||||||
- 0.224
|
|
||||||
- 0.225
|
|
||||||
order: hwc
|
|
||||||
- ToCHWImage: null
|
|
||||||
- KeepKeys:
|
|
||||||
keep_keys:
|
|
||||||
- image
|
|
||||||
- shape
|
|
||||||
- polys
|
|
||||||
- ignore_tags
|
|
||||||
loader:
|
|
||||||
shuffle: false
|
|
||||||
drop_last: false
|
|
||||||
batch_size_per_card: 1
|
|
||||||
num_workers: 1
|
|
||||||
profiler_options: null
|
|
||||||
```
|
|
||||||
|
|
||||||
### PP-OCRv5_server_rec.yml
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
Global:
|
|
||||||
model_name: PP-OCRv5_server_rec # To use static model for inference.
|
|
||||||
debug: false
|
|
||||||
use_gpu: true
|
|
||||||
epoch_num: 10
|
|
||||||
log_smooth_window: 20
|
|
||||||
print_batch_step: 10
|
|
||||||
save_model_dir: ./output-v5server/PP-OCRv5_server_rec
|
|
||||||
save_epoch_step: 200
|
|
||||||
eval_batch_step: [0, 200]
|
|
||||||
cal_metric_during_train: true
|
|
||||||
calc_epoch_interval: 1
|
|
||||||
pretrained_model: ./pretrain_models/PP-OCRv5_server_rec_pretrained.pdparams
|
|
||||||
checkpoints:
|
|
||||||
save_inference_dir:
|
|
||||||
use_visualdl: false
|
|
||||||
infer_img: doc/imgs_words/ch/word_1.jpg
|
|
||||||
character_dict_path: ./ppocr/utils/dict/ppocrv5_dict.txt
|
|
||||||
max_text_length: &max_text_length 25
|
|
||||||
infer_mode: false
|
|
||||||
use_space_char: true
|
|
||||||
distributed: true
|
|
||||||
save_res_path: ./output-v5server/rec/predicts_ppocrv5.txt
|
|
||||||
d2s_train_image_shape: [3, 48, 320]
|
|
||||||
|
|
||||||
|
|
||||||
Optimizer:
|
|
||||||
name: Adam
|
|
||||||
beta1: 0.9
|
|
||||||
beta2: 0.999
|
|
||||||
lr:
|
|
||||||
name: Cosine
|
|
||||||
learning_rate: 0.0005
|
|
||||||
warmup_epoch: 1
|
|
||||||
regularizer:
|
|
||||||
name: L2
|
|
||||||
factor: 3.0e-05
|
|
||||||
|
|
||||||
|
|
||||||
Architecture:
|
|
||||||
model_type: rec
|
|
||||||
algorithm: SVTR_HGNet
|
|
||||||
Transform:
|
|
||||||
Backbone:
|
|
||||||
name: PPHGNetV2_B4
|
|
||||||
text_rec: True
|
|
||||||
Head:
|
|
||||||
name: MultiHead
|
|
||||||
head_list:
|
|
||||||
- CTCHead:
|
|
||||||
Neck:
|
|
||||||
name: svtr
|
|
||||||
dims: 120
|
|
||||||
depth: 2
|
|
||||||
hidden_dims: 120
|
|
||||||
kernel_size: [1, 3]
|
|
||||||
use_guide: True
|
|
||||||
Head:
|
|
||||||
fc_decay: 0.00001
|
|
||||||
- NRTRHead:
|
|
||||||
nrtr_dim: 384
|
|
||||||
max_text_length: *max_text_length
|
|
||||||
|
|
||||||
Loss:
|
|
||||||
name: MultiLoss
|
|
||||||
loss_config_list:
|
|
||||||
- CTCLoss:
|
|
||||||
- NRTRLoss:
|
|
||||||
|
|
||||||
PostProcess:
|
|
||||||
name: CTCLabelDecode
|
|
||||||
|
|
||||||
Metric:
|
|
||||||
name: RecMetric
|
|
||||||
main_indicator: acc
|
|
||||||
|
|
||||||
Train:
|
|
||||||
dataset:
|
|
||||||
name: MultiScaleDataSet
|
|
||||||
ds_width: false
|
|
||||||
data_dir: ./RecTrainData/
|
|
||||||
ext_op_transform_idx: 1
|
|
||||||
label_file_list:
|
|
||||||
- ./rec_train_label.txt
|
|
||||||
transforms:
|
|
||||||
- DecodeImage:
|
|
||||||
img_mode: BGR
|
|
||||||
channel_first: false
|
|
||||||
- RecAug:
|
|
||||||
- MultiLabelEncode:
|
|
||||||
gtc_encode: NRTRLabelEncode
|
|
||||||
- KeepKeys:
|
|
||||||
keep_keys:
|
|
||||||
- image
|
|
||||||
- label_ctc
|
|
||||||
- label_gtc
|
|
||||||
- length
|
|
||||||
- valid_ratio
|
|
||||||
sampler:
|
|
||||||
name: MultiScaleSampler
|
|
||||||
scales: [[320, 32], [320, 48], [320, 64]]
|
|
||||||
first_bs: &bs 12
|
|
||||||
fix_bs: false
|
|
||||||
divided_factor: [8, 16] # w, h
|
|
||||||
is_training: True
|
|
||||||
loader:
|
|
||||||
shuffle: true
|
|
||||||
batch_size_per_card: 10
|
|
||||||
drop_last: true
|
|
||||||
num_workers: 1
|
|
||||||
Eval:
|
|
||||||
dataset:
|
|
||||||
name: SimpleDataSet
|
|
||||||
data_dir: ./RecEvalData/
|
|
||||||
label_file_list:
|
|
||||||
- ./rec_eval_label.txt
|
|
||||||
transforms:
|
|
||||||
- DecodeImage:
|
|
||||||
img_mode: BGR
|
|
||||||
channel_first: false
|
|
||||||
- MultiLabelEncode:
|
|
||||||
gtc_encode: NRTRLabelEncode
|
|
||||||
- RecResizeImg:
|
|
||||||
image_shape: [3, 48, 320]
|
|
||||||
- KeepKeys:
|
|
||||||
keep_keys:
|
|
||||||
- image
|
|
||||||
- label_ctc
|
|
||||||
- label_gtc
|
|
||||||
- length
|
|
||||||
- valid_ratio
|
|
||||||
loader:
|
|
||||||
shuffle: false
|
|
||||||
drop_last: false
|
|
||||||
batch_size_per_card: 1
|
|
||||||
num_workers: 1
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## PP-OCRv5_mobile
|
|
||||||
|
|
||||||
### PP-OCRv5_mobile_det.yml
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
Global:
|
|
||||||
model_name: PP-OCRv5_mobile_det # To use static model for inference.
|
|
||||||
debug: false
|
|
||||||
use_gpu: true
|
|
||||||
epoch_num: &epoch_num 100
|
|
||||||
log_smooth_window: 20
|
|
||||||
print_batch_step: 100
|
|
||||||
save_model_dir: ./output-v5mobile/PP-OCRv5_mobile_det
|
|
||||||
save_epoch_step: 200
|
|
||||||
eval_batch_step:
|
|
||||||
- 0
|
|
||||||
- 200
|
|
||||||
cal_metric_during_train: false
|
|
||||||
checkpoints:
|
|
||||||
pretrained_model: https://paddleocr.bj.bcebos.com/pretrained/PPLCNetV3_x0_75_ocr_det.pdparams
|
|
||||||
save_inference_dir: null
|
|
||||||
use_visualdl: false
|
|
||||||
infer_img: doc/imgs_en/img_10.jpg
|
|
||||||
save_res_path: ./checkpoints/det_db/predicts_db.txt
|
|
||||||
d2s_train_image_shape: [3, 640, 640]
|
|
||||||
distributed: true
|
|
||||||
|
|
||||||
Architecture:
|
|
||||||
model_type: det
|
|
||||||
algorithm: DB
|
|
||||||
Transform: null
|
|
||||||
Backbone:
|
|
||||||
name: PPLCNetV3
|
|
||||||
scale: 0.75
|
|
||||||
det: True
|
|
||||||
Neck:
|
|
||||||
name: RSEFPN
|
|
||||||
out_channels: 96
|
|
||||||
shortcut: True
|
|
||||||
Head:
|
|
||||||
name: DBHead
|
|
||||||
k: 50
|
|
||||||
fix_nan: True
|
|
||||||
|
|
||||||
Loss:
|
|
||||||
name: DBLoss
|
|
||||||
balance_loss: true
|
|
||||||
main_loss_type: DiceLoss
|
|
||||||
alpha: 5
|
|
||||||
beta: 10
|
|
||||||
ohem_ratio: 3
|
|
||||||
|
|
||||||
Optimizer:
|
|
||||||
name: Adam
|
|
||||||
beta1: 0.9
|
|
||||||
beta2: 0.999
|
|
||||||
lr:
|
|
||||||
name: Cosine
|
|
||||||
learning_rate: 0.001 #(8*8c)
|
|
||||||
warmup_epoch: 2
|
|
||||||
regularizer:
|
|
||||||
name: L2
|
|
||||||
factor: 5.0e-05
|
|
||||||
|
|
||||||
PostProcess:
|
|
||||||
name: DBPostProcess
|
|
||||||
thresh: 0.3
|
|
||||||
box_thresh: 0.6
|
|
||||||
max_candidates: 1000
|
|
||||||
unclip_ratio: 1.5
|
|
||||||
|
|
||||||
Metric:
|
|
||||||
name: DetMetric
|
|
||||||
main_indicator: hmean
|
|
||||||
|
|
||||||
Train:
|
|
||||||
dataset:
|
|
||||||
name: SimpleDataSet
|
|
||||||
data_dir: ./data/input0/images #图片文件夹路径
|
|
||||||
label_file_list:
|
|
||||||
- ./det_train_label.txt #标签路径
|
|
||||||
ratio_list: [1.0]
|
|
||||||
transforms:
|
|
||||||
- DecodeImage:
|
|
||||||
img_mode: BGR
|
|
||||||
channel_first: false
|
|
||||||
- DetLabelEncode: null
|
|
||||||
- CopyPaste: null
|
|
||||||
- IaaAugment:
|
|
||||||
augmenter_args:
|
|
||||||
- type: Fliplr
|
|
||||||
args:
|
|
||||||
p: 0.5
|
|
||||||
- type: Affine
|
|
||||||
args:
|
|
||||||
rotate:
|
|
||||||
- -10
|
|
||||||
- 10
|
|
||||||
- type: Resize
|
|
||||||
args:
|
|
||||||
size:
|
|
||||||
- 0.5
|
|
||||||
- 3
|
|
||||||
- EastRandomCropData:
|
|
||||||
size:
|
|
||||||
- 640
|
|
||||||
- 640
|
|
||||||
max_tries: 50
|
|
||||||
keep_ratio: true
|
|
||||||
- MakeBorderMap:
|
|
||||||
shrink_ratio: 0.4
|
|
||||||
thresh_min: 0.3
|
|
||||||
thresh_max: 0.7
|
|
||||||
total_epoch: *epoch_num
|
|
||||||
- MakeShrinkMap:
|
|
||||||
shrink_ratio: 0.4
|
|
||||||
min_text_size: 8
|
|
||||||
total_epoch: *epoch_num
|
|
||||||
- NormalizeImage:
|
|
||||||
scale: 1./255.
|
|
||||||
mean:
|
|
||||||
- 0.485
|
|
||||||
- 0.456
|
|
||||||
- 0.406
|
|
||||||
std:
|
|
||||||
- 0.229
|
|
||||||
- 0.224
|
|
||||||
- 0.225
|
|
||||||
order: hwc
|
|
||||||
- ToCHWImage: null
|
|
||||||
- KeepKeys:
|
|
||||||
keep_keys:
|
|
||||||
- image
|
|
||||||
- threshold_map
|
|
||||||
- threshold_mask
|
|
||||||
- shrink_map
|
|
||||||
- shrink_mask
|
|
||||||
loader:
|
|
||||||
shuffle: true
|
|
||||||
drop_last: false
|
|
||||||
batch_size_per_card: 14
|
|
||||||
num_workers: 1
|
|
||||||
|
|
||||||
Eval:
|
|
||||||
dataset:
|
|
||||||
name: SimpleDataSet
|
|
||||||
data_dir: ./data/input0/images
|
|
||||||
label_file_list:
|
|
||||||
- ./det_eval_label.txt
|
|
||||||
transforms:
|
|
||||||
- DecodeImage:
|
|
||||||
img_mode: BGR
|
|
||||||
channel_first: false
|
|
||||||
- DetLabelEncode: null
|
|
||||||
- DetResizeForTest:
|
|
||||||
- NormalizeImage:
|
|
||||||
scale: 1./255.
|
|
||||||
mean:
|
|
||||||
- 0.485
|
|
||||||
- 0.456
|
|
||||||
- 0.406
|
|
||||||
std:
|
|
||||||
- 0.229
|
|
||||||
- 0.224
|
|
||||||
- 0.225
|
|
||||||
order: hwc
|
|
||||||
- ToCHWImage: null
|
|
||||||
- KeepKeys:
|
|
||||||
keep_keys:
|
|
||||||
- image
|
|
||||||
- shape
|
|
||||||
- polys
|
|
||||||
- ignore_tags
|
|
||||||
loader:
|
|
||||||
shuffle: false
|
|
||||||
drop_last: false
|
|
||||||
batch_size_per_card: 1
|
|
||||||
num_workers: 1
|
|
||||||
profiler_options: null
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### PP-OCRv5_mobile_rec.yml
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
Global:
|
|
||||||
model_name: PP-OCRv5_mobile_rec # To use static model for inference.
|
|
||||||
debug: false
|
|
||||||
use_gpu: true
|
|
||||||
epoch_num: 75
|
|
||||||
log_smooth_window: 20
|
|
||||||
print_batch_step: 10
|
|
||||||
save_model_dir: ./output/PP-OCRv5_mobile_rec
|
|
||||||
save_epoch_step: 10
|
|
||||||
eval_batch_step: [0, 2000]
|
|
||||||
cal_metric_during_train: true
|
|
||||||
pretrained_model: https://paddle-model-ecology.bj.bcebos.com/paddlex/official_pretrained_model/PP-OCRv5_mobile_rec_pretrained.pdparams
|
|
||||||
checkpoints:
|
|
||||||
save_inference_dir:
|
|
||||||
use_visualdl: false
|
|
||||||
infer_img: doc/imgs_words/ch/word_1.jpg
|
|
||||||
character_dict_path: ./ppocr/utils/dict/ppocrv5_dict.txt
|
|
||||||
max_text_length: &max_text_length 25
|
|
||||||
infer_mode: false
|
|
||||||
use_space_char: true
|
|
||||||
distributed: true
|
|
||||||
save_res_path: ./output/rec/predicts_ppocrv5.txt
|
|
||||||
d2s_train_image_shape: [3, 48, 320]
|
|
||||||
|
|
||||||
|
|
||||||
Optimizer:
|
|
||||||
name: Adam
|
|
||||||
beta1: 0.9
|
|
||||||
beta2: 0.999
|
|
||||||
lr:
|
|
||||||
name: Cosine
|
|
||||||
learning_rate: 0.0005
|
|
||||||
warmup_epoch: 5
|
|
||||||
regularizer:
|
|
||||||
name: L2
|
|
||||||
factor: 3.0e-05
|
|
||||||
|
|
||||||
|
|
||||||
Architecture:
|
|
||||||
model_type: rec
|
|
||||||
algorithm: SVTR_LCNet
|
|
||||||
Transform:
|
|
||||||
Backbone:
|
|
||||||
name: PPLCNetV3
|
|
||||||
scale: 0.95
|
|
||||||
Head:
|
|
||||||
name: MultiHead
|
|
||||||
head_list:
|
|
||||||
- CTCHead:
|
|
||||||
Neck:
|
|
||||||
name: svtr
|
|
||||||
dims: 120
|
|
||||||
depth: 2
|
|
||||||
hidden_dims: 120
|
|
||||||
kernel_size: [1, 3]
|
|
||||||
use_guide: True
|
|
||||||
Head:
|
|
||||||
fc_decay: 0.00001
|
|
||||||
- NRTRHead:
|
|
||||||
nrtr_dim: 384
|
|
||||||
max_text_length: *max_text_length
|
|
||||||
|
|
||||||
Loss:
|
|
||||||
name: MultiLoss
|
|
||||||
loss_config_list:
|
|
||||||
- CTCLoss:
|
|
||||||
- NRTRLoss:
|
|
||||||
|
|
||||||
PostProcess:
|
|
||||||
name: CTCLabelDecode
|
|
||||||
|
|
||||||
Metric:
|
|
||||||
name: RecMetric
|
|
||||||
main_indicator: acc
|
|
||||||
|
|
||||||
Train:
|
|
||||||
dataset:
|
|
||||||
name: MultiScaleDataSet
|
|
||||||
ds_width: false
|
|
||||||
data_dir: ./RecTrainData/
|
|
||||||
ext_op_transform_idx: 1
|
|
||||||
label_file_list:
|
|
||||||
- ./rec_train_label.txt
|
|
||||||
transforms:
|
|
||||||
- DecodeImage:
|
|
||||||
img_mode: BGR
|
|
||||||
channel_first: false
|
|
||||||
- RecConAug:
|
|
||||||
prob: 0.5
|
|
||||||
ext_data_num: 2
|
|
||||||
image_shape: [48, 320, 3]
|
|
||||||
max_text_length: *max_text_length
|
|
||||||
- RecAug:
|
|
||||||
- MultiLabelEncode:
|
|
||||||
gtc_encode: NRTRLabelEncode
|
|
||||||
- KeepKeys:
|
|
||||||
keep_keys:
|
|
||||||
- image
|
|
||||||
- label_ctc
|
|
||||||
- label_gtc
|
|
||||||
- length
|
|
||||||
- valid_ratio
|
|
||||||
sampler:
|
|
||||||
name: MultiScaleSampler
|
|
||||||
scales: [[320, 32], [320, 48], [320, 64]]
|
|
||||||
first_bs: &bs 128
|
|
||||||
fix_bs: false
|
|
||||||
divided_factor: [8, 16] # w, h
|
|
||||||
is_training: True
|
|
||||||
loader:
|
|
||||||
shuffle: true
|
|
||||||
batch_size_per_card: 14
|
|
||||||
drop_last: true
|
|
||||||
num_workers: 1
|
|
||||||
Eval:
|
|
||||||
dataset:
|
|
||||||
name: SimpleDataSet
|
|
||||||
data_dir: ./RecEvalData/
|
|
||||||
label_file_list:
|
|
||||||
- ./rec_eval_label.txt
|
|
||||||
transforms:
|
|
||||||
- DecodeImage:
|
|
||||||
img_mode: BGR
|
|
||||||
channel_first: false
|
|
||||||
- MultiLabelEncode:
|
|
||||||
gtc_encode: NRTRLabelEncode
|
|
||||||
- RecResizeImg:
|
|
||||||
image_shape: [3, 48, 320]
|
|
||||||
- KeepKeys:
|
|
||||||
keep_keys:
|
|
||||||
- image
|
|
||||||
- label_ctc
|
|
||||||
- label_gtc
|
|
||||||
- length
|
|
||||||
- valid_ratio
|
|
||||||
loader:
|
|
||||||
shuffle: false
|
|
||||||
drop_last: false
|
|
||||||
batch_size_per_card: 14
|
|
||||||
num_workers: 1
|
|
||||||
```
|
|
||||||
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 102 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 103 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 85 KiB |
File renamed without changes.
@@ -0,0 +1,193 @@
|
|||||||
|
注:这里以 **识别集装箱号** 为案例进行演示
|
||||||
|
|
||||||
|
# 相关网站
|
||||||
|
|
||||||
|
- paddlepaddle:https://www.paddlepaddle.org.cn/
|
||||||
|
- github:https://github.com/PaddlePaddle/PaddleOCR/tree/main
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# 1 环境配置
|
||||||
|
|
||||||
|
当前使用的是虚拟环境:
|
||||||
|
|
||||||
|
- python:3.11
|
||||||
|
- paddlepaddle:3.1
|
||||||
|
- paddleocr:3.1.0
|
||||||
|
|
||||||
|
## 1.1 安装paddlepaddle
|
||||||
|
|
||||||
|
网站:https://www.paddlepaddle.org.cn/install/quick?docurl=/documentation/docs/zh/develop/install/pip/linux-pip.html
|
||||||
|
|
||||||
|
需要注意自己的 CUDA 版本,不要过高即可,查看命令:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nvidia-smi
|
||||||
|
```
|
||||||
|
|
||||||
|
输出如下:
|
||||||
|
|
||||||
|
```
|
||||||
|
+-----------------------------------------------------------------------------+
|
||||||
|
| NVIDIA-SMI 525.105.17 Driver Version: 525.105.17 CUDA Version: 12.0 |
|
||||||
|
|-------------------------------+----------------------+----------------------+
|
||||||
|
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
|
||||||
|
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|
||||||
|
| | | MIG M. |
|
||||||
|
|===============================+======================+======================|
|
||||||
|
| 0 Tesla T4 On | 00000000:00:09.0 Off | 0 |
|
||||||
|
| N/A 27C P8 8W / 70W | 4MiB / 15360MiB | 0% Default |
|
||||||
|
| | | N/A |
|
||||||
|
+-------------------------------+----------------------+----------------------+
|
||||||
|
|
||||||
|
+-----------------------------------------------------------------------------+
|
||||||
|
| Processes: |
|
||||||
|
| GPU GI CI PID Type Process name GPU Memory |
|
||||||
|
| ID ID Usage |
|
||||||
|
|=============================================================================|
|
||||||
|
| No running processes found |
|
||||||
|
+-----------------------------------------------------------------------------+
|
||||||
|
```
|
||||||
|
|
||||||
|
当前电脑的 CUDA 版本为 12.0,所以下载 小于等于 12.0版本的paddlepaddle 即可
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python -m pip install paddlepaddle-gpu==3.1.0 -i https://www.paddlepaddle.org.cn/packages/stable/cu118/
|
||||||
|
```
|
||||||
|
|
||||||
|
检查是否安装成功:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python -c "import paddle; paddle.utils.run_check()"
|
||||||
|
```
|
||||||
|
|
||||||
|
输出以下内容即代表成功:
|
||||||
|
|
||||||
|
```
|
||||||
|
(ocr) root@VM-0-80-ubuntu:/workspace# python -c "import paddle; paddle.utils.run_check()"
|
||||||
|
/root/miniforge3/envs/ocr/lib/python3.11/site-packages/paddle/utils/cpp_extension/extension_utils.py:715: UserWarning: No ccache found. Please be aware that recompiling all source files may be required. You can download and install ccache from: https://github.com/ccache/ccache/blob/master/doc/INSTALL.md
|
||||||
|
warnings.warn(warning_message)
|
||||||
|
Running verify PaddlePaddle program ...
|
||||||
|
I0710 06:19:32.810492 2651 pir_interpreter.cc:1524] New Executor is Running ...
|
||||||
|
W0710 06:19:32.813128 2651 gpu_resources.cc:114] Please NOTE: device: 0, GPU Compute Capability: 7.5, Driver API Version: 12.0, Runtime API Version: 11.7
|
||||||
|
I0710 06:19:35.382279 2651 pir_interpreter.cc:1547] pir interpreter is running by multi-thread mode ...
|
||||||
|
PaddlePaddle works well on 1 GPU.
|
||||||
|
PaddlePaddle is installed successfully! Let's start deep learning with PaddlePaddle now.
|
||||||
|
```
|
||||||
|
|
||||||
|
## 1.2 下载paddleocr
|
||||||
|
|
||||||
|
下载网站:https://github.com/PaddlePaddle/PaddleOCR/releases
|
||||||
|
|
||||||
|
当前使用的版本是 3.1.0
|
||||||
|
|
||||||
|
下载后解压
|
||||||
|
|
||||||
|
```bash
|
||||||
|
unzip PaddleOCR-3.1.0.zip
|
||||||
|
```
|
||||||
|
|
||||||
|
安装依赖
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd PaddleOCR-3.1.0
|
||||||
|
|
||||||
|
pip install -r requirements.txt --user
|
||||||
|
```
|
||||||
|
|
||||||
|
测试是否能正常运行:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python tools/infer/predict_system.py --image_dir="/workspace/img/" --use_angle_cls=True --use_space_char=True
|
||||||
|
```
|
||||||
|
|
||||||
|
输出以下内容即成功:
|
||||||
|
```
|
||||||
|
ppocr INFO: not find det model file path None
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# 2 准备数据集
|
||||||
|
|
||||||
|
## 2.1 标注工具
|
||||||
|
|
||||||
|
### 2.1.1 PPOcrLabel
|
||||||
|
|
||||||
|
> 存在问题:EXE 安装包运行会报错。但是该工具在本地运行标注的话还是比较推荐的。
|
||||||
|
|
||||||
|
下载地址:
|
||||||
|
|
||||||
|
- 专门为 PPOCR 制作的标注工具
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 2.1.2 X-AnyLabeling
|
||||||
|
|
||||||
|
下载地址:
|
||||||
|
|
||||||
|
- 支持多种导出格式,其中就支持 PPOCR 的格式
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 2.2 数据集结构
|
||||||
|
|
||||||
|
示例:
|
||||||
|
|
||||||
|
```
|
||||||
|
conno/1b4e2845-e9ba-4233-9268-bf07801ace0e.jpg [{"transcription": "RKSU5020243", "points": [[233, 317], [299, 317], [258, 833], [181, 839]], "difficult": false}]
|
||||||
|
conno/6ffd244b-1d27-4084-998b-e4d7ac076c5f.jpg [{"transcription": "ZGXU6173701", "points": [[717, 448], [781, 419], [835, 980], [751, 996]], "difficult": false}]
|
||||||
|
conno/0ba730a8-052b-4662-88fa-bfd3c7dbd118.jpg [{"transcription": "WHLU5706937", "points": [[565, 567], [915, 485], [915, 551], [578, 635]], "difficult": false}]
|
||||||
|
conno/8f50bf55-f825-43ac-87a5-f744aa3c2099.jpg [{"transcription": "EISU9420010", "points": [[295, 744], [624, 747], [618, 813], [299, 806]], "difficult": false}]
|
||||||
|
conno/33e22c52-64b6-4715-87d9-d3a7823b97f7.jpg [{"transcription": "SSKU1302201", "points": [[660, 676], [960, 671], [966, 724], [662, 737]], "difficult": false}]
|
||||||
|
conno/34a24249-7670-4be2-981f-19c502ee7da2.jpg [{"transcription": "TKRU4507940", "points": [[660, 395], [724, 395], [717, 882], [619, 902]], "difficult": false}]
|
||||||
|
conno/67ead2d0-89c0-455c-aef0-49a76a3492aa.jpg [{"transcription": "待识别", "points": [[585, 415], [589, 415], [593, 501], [917, 341], [893, 263]], "difficult": false}]
|
||||||
|
conno/78c58cfa-ff0f-4890-9fd9-07a0b639b9ca.jpg [{"transcription": "LYGU3568255", "points": [[553, 393], [587, 491], [972, 334], [983, 245]], "difficult": false}]
|
||||||
|
conno/481aee74-f9ce-4145-a8c7-f4c1f45fcc75.jpg [{"transcription": "RKSU4005584", "points": [[56, 298], [19, 935], [101, 937], [115, 280]], "difficult": false}]
|
||||||
|
conno/630d6e72-f99d-4922-8886-ea14f9e1a9bd.jpg [{"transcription": "FCIU2682384", "points": [[562, 737], [572, 803], [867, 712], [858, 655]], "difficult": false}]
|
||||||
|
conno/9751b358-0b48-4006-8a73-89e816d37b67.jpg [{"transcription": "CNIU2452605", "points": [[608, 801], [606, 867], [908, 837], [906, 773]], "difficult": false}]
|
||||||
|
```
|
||||||
|
|
||||||
|
# 3 准备预训练模型
|
||||||
|
|
||||||
|
> 如果已经有预训练模型的话,可以忽略这一步。
|
||||||
|
|
||||||
|
下载地址:https://github.com/PaddlePaddle/PaddleOCR/blob/release/3.1/docs/version3.x/model_list.md
|
||||||
|
|
||||||
|
如果报 404 的话,根据 版本 + 路径 进行查找即可。
|
||||||
|
|
||||||
|
## 3.1 文本检测训练模型
|
||||||
|
|
||||||
|
PP-OCRv5_mobile_det
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 3.2 文本识别训练模型
|
||||||
|
|
||||||
|
PP-OCRv5_mobile_rec
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
# 4 数据整理
|
||||||
|
|
||||||
|
## 4.1 检测模型所需数据准备
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# 报错处理
|
||||||
|
|
||||||
|
## ImportError: libGL.so.1: cannot open shared object file: No such file or directory
|
||||||
|
|
||||||
|
### 问题原因
|
||||||
|
|
||||||
|
- 缺少 `libGL.so.1` 库
|
||||||
|
|
||||||
|
### 解决方案
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install libgl1-mesa-glx
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
File renamed without changes.
File renamed without changes.
@@ -1,189 +0,0 @@
|
|||||||
# 通用错误
|
|
||||||
|
|
||||||
## Microsoft Visual C++ 14.0 or greater is required.
|
|
||||||
|
|
||||||
### 1. 下载Microsoft C++ Build Tools
|
|
||||||
打开网址:[Microsoft C++ Build Tools](https://visualstudio.microsoft.com/zh-hans/visual-cpp-build-tools/)
|
|
||||||
|
|
||||||
点击下载【下载生成工具】,并打开。
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
接着在Workloads中,点击选择【C++ build tools】
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
并选择单个组件的C++工具开始下载。
|
|
||||||
|
|
||||||
### 2. 重启
|
|
||||||
显示下载完成后,重启机器即可。
|
|
||||||
|
|
||||||
# [xclabel](https://gitee.com/Vanishi/xclabel)
|
|
||||||
|
|
||||||
## 环境
|
|
||||||
|
|
||||||
- python:3.10
|
|
||||||
|
|
||||||
## 安装
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git clone https://gitee.com/Vanishi/xclabel.git
|
|
||||||
```
|
|
||||||
|
|
||||||
创建虚拟环境
|
|
||||||
|
|
||||||
```bash
|
|
||||||
conda create -n xclabel python=3.10
|
|
||||||
|
|
||||||
conda activate xclabel
|
|
||||||
|
|
||||||
//更新pip
|
|
||||||
python -m pip install --upgrade pip -i https://pypi.tuna.tsinghua.edu.cn/simple
|
|
||||||
|
|
||||||
//安装requirements
|
|
||||||
python -m pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
|
|
||||||
```
|
|
||||||
|
|
||||||
## 运行
|
|
||||||
|
|
||||||
- 环境安装完成后,启动服务: python manage.py runserver 0.0.0.0:9924
|
|
||||||
- 访问服务:在浏览器输入 [http://127.0.0.1:9924](https://gitee.com/link?target=http%3A%2F%2F127.0.0.1%3A9924) 就可以开始了,默认账号 admin admin888
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 报错
|
|
||||||
|
|
||||||
### FileNotFoundError: [WinError 3] 系统找不到指定的路径。: 'E:\\'
|
|
||||||
|
|
||||||
修改 config.json 配置路径即可
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"host": "127.0.0.1",
|
|
||||||
"port": 9924,
|
|
||||||
"ffmpeg": "ffmpeg",
|
|
||||||
"storageDir": "D:\\project\\bxc\\gitee\\xclabel\\static\\storage",
|
|
||||||
"yolo8": {
|
|
||||||
"install_dir": "D:\\project\\ai\\yolov8",
|
|
||||||
"venv": "venv\\Scripts\\activate.bat",
|
|
||||||
"name": "yolo",
|
|
||||||
"model": "yolov8n.pt"
|
|
||||||
},
|
|
||||||
"yolo11": {
|
|
||||||
"install_dir": "D:\\project\\ai\\yolov11",
|
|
||||||
"venv": "venv\\Scripts\\activate.bat",
|
|
||||||
"name": "yolo",
|
|
||||||
"model": "yolo11n.pt"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [PPOCRLabel](https://github.com/PFCCLab/PPOCRLabel)
|
|
||||||
|
|
||||||
## 环境
|
|
||||||
|
|
||||||
- python:3.9
|
|
||||||
- paddlepadle:3.0.0
|
|
||||||
- ppocrlabel:3.1.1
|
|
||||||
|
|
||||||
## 安装
|
|
||||||
|
|
||||||
创建虚拟环境
|
|
||||||
|
|
||||||
```bash
|
|
||||||
conda create -n ppocrlabel python=3.9
|
|
||||||
conda activate ppocrlabel
|
|
||||||
```
|
|
||||||
|
|
||||||
安装PaddlePaddle
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pip3 install --upgrade pip
|
|
||||||
|
|
||||||
python -m pip install paddlepaddle-gpu==3.0.0 -i https://www.paddlepaddle.org.cn/packages/stable/cu126/
|
|
||||||
```
|
|
||||||
|
|
||||||
下载 [PPOCRLabel](https://github.com/PFCCLab/PPOCRLabel)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git clone https://github.com/PFCCLab/PPOCRLabel.git
|
|
||||||
```
|
|
||||||
|
|
||||||
安装相关依赖
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pip install pyproject.toml
|
|
||||||
|
|
||||||
|
|
||||||
pip install openpyxl
|
|
||||||
pip install opencv-python
|
|
||||||
pip install PyQt5
|
|
||||||
pip install pandas
|
|
||||||
pip install paddleocr
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 启动
|
|
||||||
|
|
||||||
```bash
|
|
||||||
python PPOCRLabel.py --lang ch
|
|
||||||
```
|
|
||||||
|
|
||||||
出现以下页面即代表启动成功
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
## 打包 exe
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd ./PPOCRLabel
|
|
||||||
# 安装pyinstaller
|
|
||||||
pip install pyinstaller
|
|
||||||
|
|
||||||
# 重新生成资源
|
|
||||||
pyrcc5 -o libs/resources.py resources.qrc
|
|
||||||
|
|
||||||
# 打包可执行程序
|
|
||||||
pyinstaller -c PPOCRLabel.py --add-data "D:\\devtool/anaconda3\\envs\\ppocrlabel\\Lib\\site-packages\\paddlex;./paddlex" --collect-all paddleocr --collect-all pyclipper --collect-all imghdr --collect-all skimage --collect-all imgaug --collect-all scipy.io --collect-all lmdb --collect-all paddle --hidden-import=pyqt5 -p ./libs -p ./ -p ./data -p ./resources -F
|
|
||||||
|
|
||||||
pyinstaller -F -w --clean --add-data "D:/devtool/anaconda3/envs/ppocrlabel/Lib/site-packages/paddlex;./paddlex" --collect-all paddleocr --collect-all pyclipper --collect-all imghdr --collect-all skimage --collect-all imgaug --collect-all scipy.io --collect-all lmdb --collect-all paddle --collect-submodules paddleocr --collect-submodules paddlex --collect-submodules paddlex.inference.pipelines --collect-submodules paddlex.utils --collect-submodules paddlex.visualize --collect-submodules paddlex.cv.models --hidden-import=pyqt5 --hidden-import=shapely --hidden-import=visualdl --hidden-import=skimage.metrics -p ./libs -p ./ -p ./data -p ./resources PPOCRLabel.py
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 运行dist中的可执行程序,以windows为例
|
|
||||||
PPOCRLabel.exe --lang ch
|
|
||||||
```
|
|
||||||
|
|
||||||
## 报错
|
|
||||||
|
|
||||||
### DLL load failed while importing aggregations
|
|
||||||
|
|
||||||
**conda虚拟环境下**报这个错误,解决方案
|
|
||||||
|
|
||||||
```bash
|
|
||||||
conda install pandas
|
|
||||||
```
|
|
||||||
|
|
||||||
验证
|
|
||||||
|
|
||||||
```python
|
|
||||||
import pandas as pd
|
|
||||||
print(pd.__version__)
|
|
||||||
df = pd.DataFrame({"a": [1, 2], "b": [3, 4]})
|
|
||||||
print(df)
|
|
||||||
```
|
|
||||||
|
|
||||||
输出下面结果,代表成功
|
|
||||||
|
|
||||||
```
|
|
||||||
2.3.0
|
|
||||||
a b
|
|
||||||
0 1 3
|
|
||||||
1 2 4
|
|
||||||
```
|
|
||||||
|
|
||||||
Reference in new issue
Block a user