当前位置:   article > 正文

基于LeNet与YOLOV8在2024年mm杯甲骨文图像文字识别数据集研究_yolov8文本识别

yolov8文本识别

1、数据展示与处理

  • 数据集下载:https://pan.baidu.com/s/1cp-DUwgS3c_d8EFhBwXRHw?pwd=pf1t
  • 数据选择:下载后的数据集分为4个文件1_Pre_test 、2_Train、3_Test、4_Recognize
    由于本文只讲解如何搭建一个较为完整的图像识别分类模型,所以选取的数据集为2_Train与4_Recognize这二份数据集。
  • 其中2_Train文件夹下有对应的image以及json数据类型。但在json中所展示的数据集如下:
    {"img_name": "b02519Z", "ann": [[64.0, 194.0, 134.0, 277.0, 1.0], [150.0, 168.0, 204.0, 344.0, 1.0], [206.0, 170.0, 259.0, 349.0, 1.0]]}。ann每一行所对应的信息是对应img_name的一个图像框,也即为已经标注好的甲骨文信息。同时在4_Recongnize文件夹下有二个子文件夹,在训练集下有已经分好的图片类别,在测试集下有待识别文字的图片。接下来我们讨论如何处理这些数据集。
  • 在YOLOV8训练数据集中,数据类型应该为YOLO TXT类型,具体可参考这位博主:https://blog.csdn.net/wlh156423/article/details/118861987
    在处理的同时,可以看出在json文件下,并没有为我们识别文字信息为那一类,故而需要采取一类模型对文字进行分类处理,将训练好的模型对上述信息进行分类,最后转为YOLO TXT类型再进行YOLOV8的模型训练,即可得到想要模型。
  • 图像分类模型有多具体可以参考:https://zhuanlan.zhihu.com/p/562609779
    本文采用LeNet模型对所含信息进行分类。

2、具体实现过程

在开始实现以上操作时,我们需要准备python环境,具体流程可以参考:(本文所采用python=3.9的环境)https://blog.csdn.net/weixin_43366149/article/details/132206526

第一步训练LeNet模型

搭建LeNet模型

本文将此代码保存为LeNet.py。

  1. import torch
  2. import torch.nn as nn
  3. class LeNet(nn.Module):
  4. def __init__(self, num_classes=10):
  5. super(LeNet, self).__init__()
  6. self.conv1 = nn.Conv2d(1, 6, kernel_size=5) # 输入通道数为1(灰度图像),输出通道数为6,卷积核大小为5x5
  7. self.conv2 = nn.Conv2d(6, 16, kernel_size=5) # 输入通道数为6,输出通道数为16,卷积核大小为5x5
  8. self.fc1 = nn.Linear(16*5*5, 120) # 全连接层,输入大小为16*5*5,输出大小为120
  9. self.fc2 = nn.Linear(120, 84) # 全连接层,输入大小为120,输出大小为84
  10. self.fc3 = nn.Linear(84, num_classes) # 全连接层,输入大小为84,输出大小为类别数
  11. def forward(self, x):
  12. # 输入数据经过卷积层1,使用ReLU激活函数,再经过2x2最大池化层
  13. x = torch.max_pool2d(torch.relu(self.conv1(x)), (2, 2))
  14. # 输入数据经过卷积层2,使用ReLU激活函数,再经过2x2最大池化层
  15. x = torch.max_pool2d(torch.relu(self.conv2(x)), (2, 2))
  16. # 将特征图展平成一维向量
  17. x = x.view(-1, 16*5*5)
  18. # 经过全连接层1和ReLU激活函数
  19. x = torch.relu(self.fc1(x))
  20. # 经过全连接层2和ReLU激活函数
  21. x = torch.relu(self.fc2(x))
  22. # 经过全连接层3
  23. x = self.fc3(x)
  24. return x
  25. # # 创建LeNet模型实例
  26. # model = LeNet(num_classes=10)
  27. # # 输出模型结构
  28. # print(model)

 处理数据集

本文将其命名为Mydata.py。

  1. import os
  2. from PIL import Image
  3. from torch.utils.data import Dataset
  4. class MyDataset(Dataset):
  5. def __init__(self, data_dir, transform=None):
  6. """
  7. 初始化 MyDataset 类。
  8. Args:
  9. data_dir (str): 数据目录的路径。
  10. transform (callable, optional): 对图像进行预处理的转换函数。
  11. """
  12. self.data_dir = data_dir
  13. self.transform = transform
  14. # 获取类别文件夹和类别名称
  15. self.classes = sorted([d.name for d in os.scandir(data_dir) if d.is_dir()])
  16. self.class_to_idx = {cls_name: idx for idx, cls_name in enumerate(self.classes)}
  17. # 获取图像文件路径和对应的类别标签
  18. self.image_paths = []
  19. self.labels = []
  20. for class_name in self.classes:
  21. class_dir = os.path.join(data_dir, class_name)
  22. for img_name in os.listdir(class_dir):
  23. img_path = os.path.join(class_dir, img_name)
  24. self.image_paths.append(img_path)
  25. self.labels.append(self.class_to_idx[class_name])
  26. def __len__(self):
  27. """
  28. 返回数据集中样本的数量。
  29. """
  30. return len(self.image_paths)
  31. def __getitem__(self, index):
  32. """
  33. 根据索引获取样本(图像和标签)。
  34. Args:
  35. index (int): 样本的索引。
  36. Returns:
  37. tuple: (image, label) 图像和标签。
  38. """
  39. # 获取图像路径和标签
  40. img_path = self.image_paths[index]
  41. label = self.labels[index]
  42. # 打开图像并进行预处理
  43. image = Image.open(img_path)
  44. if self.transform:
  45. image = self.transform(image)
  46. return image, label

搭建训练主程序

本文将其命名为train_lenet.py。

  1. import torch
  2. import torch.nn as nn
  3. import torch.optim as optim
  4. from torch.utils.data import DataLoader
  5. from LeNet import LeNet
  6. from Mydata import MyDataset
  7. from torchvision import transforms
  8. from torch.utils.tensorboard import SummaryWriter
  9. # 定义训练参数
  10. batch_size = 64
  11. learning_rate = 0.001
  12. num_epochs = 5
  13. # 检查是否可以使用CUDA加速
  14. device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
  15. # 创建数据集实例
  16. data_dir = "4_Recognize/训练集"
  17. transform = transforms.Compose([
  18. transforms.Resize((32, 32)),
  19. transforms.Grayscale(num_output_channels=1), # Convert to grayscale
  20. transforms.ToTensor(),
  21. transforms.Normalize((0.5,), (0.5,))
  22. ])
  23. dataset = MyDataset(data_dir, transform=transform)
  24. data_loader = DataLoader(dataset, batch_size=batch_size, shuffle=True)
  25. # 创建LeNet模型实例
  26. model = LeNet(num_classes=76)
  27. model.to(device)
  28. # 定义损失函数和优化器
  29. criterion = nn.CrossEntropyLoss()
  30. optimizer = optim.Adam(model.parameters(), lr=learning_rate)
  31. # 创建SummaryWriter实例
  32. writer = SummaryWriter()
  33. # 训练模型
  34. total_steps = len(data_loader)
  35. for epoch in range(num_epochs):
  36. for i, (images, labels) in enumerate(data_loader):
  37. images = images.to(device)
  38. labels = labels.to(device)
  39. # 前向传播
  40. outputs = model(images)
  41. loss = criterion(outputs, labels)
  42. # 反向传播和优化
  43. optimizer.zero_grad()
  44. loss.backward()
  45. optimizer.step()
  46. if (i + 1) % 100 == 0:
  47. print(f'Epoch [{epoch + 1}/{num_epochs}], Step [{i + 1}/{total_steps}], Loss: {loss.item():.4f}')
  48. # 将损失写入日志
  49. writer.add_scalar('Loss/train', loss.item(), epoch * total_steps + i)
  50. print('Finished Training')
  51. # 关闭SummaryWriter
  52. writer.close()
  53. # 保存模型
  54. torch.save(model.state_dict(), 'lenet_model.pth')

最后保存所需模型文件即可,本文主要讨论的是方法以及具体实现思路,本文未进行模型评估检验,感兴趣的小伙伴可以外加代码对模型精度进行检验。

第二步处理2_Train文件

JSON转YOLO TXT 

通过参考https://blog.csdn.net/wlh156423/article/details/118861987 ​​​​​​本文对其进行改进,即可得到如下代码实现:

  1. import os
  2. import json
  3. import shutil
  4. from PIL import Image
  5. def convert_bbox(img_size, box):
  6. dw = 1. / img_size[0]
  7. dh = 1. / img_size[1]
  8. x = (box[0] + box[2]) / 2.0 - 1
  9. y = (box[1] + box[3]) / 2.0 - 1
  10. w = box[2] - box[0]
  11. h = box[3] - box[1]
  12. x = x * dw
  13. w = w * dw
  14. y = y * dh
  15. h = h * dh
  16. return (x, y, w, h)
  17. def get_image_size(image_path):
  18. with Image.open(image_path) as img:
  19. width, height = img.size
  20. return width, height
  21. def extract_data_from_json(json_folder, train_folder):
  22. images_folder = os.path.join(train_folder, 'images')
  23. labels_folder = os.path.join(train_folder, 'labels')
  24. os.makedirs(images_folder, exist_ok=True)
  25. os.makedirs(labels_folder, exist_ok=True)
  26. json_files = [f for f in os.listdir(json_folder) if f.endswith('.json')]
  27. for json_file in json_files:
  28. with open(os.path.join(json_folder, json_file)) as f:
  29. data = json.load(f)
  30. img_name = data.get('img_name')
  31. ann = data.get('ann')
  32. img_path = os.path.join('2_Train', img_name + '.jpg')
  33. img_w, img_h = get_image_size(img_path)
  34. shutil.copy(img_path, os.path.join(images_folder, img_name + '.jpg'))
  35. txt_path = os.path.join(labels_folder, img_name + '.txt')
  36. with open(txt_path, 'w') as txt_file:
  37. for bbox in ann:
  38. bbox = convert_bbox((img_w, img_h), bbox[:-1]) # Ignore the class label for now
  39. txt_file.write(f"0 {' '.join(map(str, bbox))}\n") # Assuming class index is 0
  40. if __name__ == "__main__":
  41. json_folder_path = '2_Train'
  42. train_folder_path = 'train'
  43. extract_data_from_json(json_folder_path, train_folder_path)

将JSON文件转化为所需要的YOLO TXT文件,且保存再同项目train文件夹下。其中txt数据类如下

0 0.3091482649842271 0.5269662921348315 0.22082018927444794 0.1865168539325843
0 0.555205047318612 0.5730337078651686 0.17034700315457413 0.39550561797752815
0 0.7302839116719243 0.5808988764044944 0.167192429022082 0.402247191011236

将对应的信息框进行分类

  1. import torch
  2. import torchvision.transforms as transforms
  3. from PIL import Image
  4. from LeNet import LeNet
  5. import os
  6. # 定义预处理操作
  7. transform = transforms.Compose([
  8. transforms.Grayscale(), # 转为灰度图像
  9. transforms.Resize((32, 32)), # 改变尺寸以适配LeNet模型输入
  10. transforms.ToTensor(), # 转为张量
  11. ])
  12. # 初始化模型
  13. model = LeNet(num_classes=76)
  14. model.load_state_dict(torch.load("lenet_model.pth"))
  15. model.eval() # 设置为评估模式
  16. # 文件和文件夹路径
  17. label_dir = 'B题/labels/train'
  18. image_dir = 'B题/images/train'
  19. output_dir = 'new_data'
  20. if not os.path.exists(output_dir):
  21. os.makedirs(output_dir)
  22. # 遍历标签文件夹
  23. for label_file in os.listdir(label_dir):
  24. label_path = os.path.join(label_dir, label_file)
  25. image_path = os.path.join(image_dir, label_file.replace('.txt', '.jpg')) # 假设图片文件名与标签相同,仅扩展名不同
  26. if os.path.exists(image_path):
  27. img = Image.open(image_path) # 加载图像
  28. with open(label_path, 'r') as file:
  29. lines = file.readlines()
  30. new_lines = []
  31. for line in lines:
  32. parts = line.strip().split()
  33. # 假设标签格式为:class x_center y_center width height
  34. _, x_center, y_center, width, height = map(float, parts)
  35. bbox = [
  36. (x_center - width / 2) * img.width,
  37. (y_center - height / 2) * img.height,
  38. width * img.width,
  39. height * img.height
  40. ] # 计算实际像素坐标和尺寸
  41. # 裁剪并转换图像
  42. cropped_img = img.crop((bbox[0], bbox[1], bbox[0] + bbox[2], bbox[1] + bbox[3]))
  43. input_tensor = transform(cropped_img).unsqueeze(0)
  44. # 模型预测
  45. with torch.no_grad():
  46. output = model(input_tensor)
  47. predicted_class = output.argmax(1).item()
  48. # 更新行
  49. new_line = f"{predicted_class} {x_center} {y_center} {width} {height}\n"
  50. new_lines.append(new_line)
  51. # 保存新的标签文件
  52. new_label_path = os.path.join(output_dir, label_file)
  53. with open(new_label_path, 'w') as new_file:
  54. new_file.writelines(new_lines)

这段代码会将原本的标签进行处理并且以txt形式保存在new_data文件夹下,小伙伴们运行时记得更改路径为自己的路径。转化后的图片txt信息如下

59 0.3091482649842271 0.5269662921348315 0.22082018927444794 0.1865168539325843
69 0.555205047318612 0.5730337078651686 0.17034700315457413 0.39550561797752815
6 0.7302839116719243 0.5808988764044944 0.167192429022082 0.402247191011236

提取类别标签

基于yolov8训练数据集时需要类别标签,本文运用如下代码进行相关处理

  1. import os
  2. # 指定文件夹路径
  3. folder_path = '4_Recognize/训练集'
  4. # 获取子文件夹名称并按照指定格式保存
  5. with open('name.txt', 'w') as file:
  6. for idx, subfolder in enumerate(sorted(os.listdir(folder_path))):
  7. file.write(f"{idx}: {subfolder}\n")

第三步进行YOLOV8模型训练

训练操作可以参考https://blog.csdn.net/qq_42452134/article/details/135149531

以下是实现过程

建立一个python文件且输入如下代码

  1. from ultralytics import YOLO
  2. # 加载模型
  3. model = YOLO('yolov8n.yaml').load('yolov8n.pt') # 从YAML构建并转移权重
  4. if __name__ == '__main__':
  5. # 训练模型
  6. results = model.train(data='fnal.yaml', epochs=10, imgsz=256)
  7. metrics = model.val()

建立对应的.yaml文件,这里就需要用到我们提取的类别标签。(本文命名为fnal.yaml)

  1. # 这里的path需要指向你项目中数据集的目录
  2. path: E:/dell/比赛/new/train/
  3. # 这里分别指向你训练、验证、测试的文件地址,只需要指向图片的文件夹即可。但是要注意图片和labels名称要对应
  4. train: images/train # train images (relative to 'path') 128 images
  5. val: images/val # val images (relative to 'path') 128 images
  6. test: images/test # test images (optional)
  7. # Classes
  8. names:
  9. 0: 万
  10. 1: 丘
  11. 2: 丙
  12. 3: 丧
  13. 4: 乘
  14. 5: 亦
  15. 6: 人
  16. 7: 今
  17. 8: 介
  18. 9: 从
  19. 10: 令
  20. 11: 以
  21. 12: 伊
  22. 13: 何
  23. 14: 余
  24. 15: 允
  25. 16: 元
  26. 17: 兄
  27. 18: 光
  28. 19: 兔
  29. 20: 入
  30. 21: 凤
  31. 22: 化
  32. 23: 北
  33. 24: 印
  34. 25: 及
  35. 26: 取
  36. 27: 口
  37. 28: 吉
  38. 29: 囚
  39. 30: 夫
  40. 31: 央
  41. 32: 宗
  42. 33: 宾
  43. 34: 尞
  44. 35: 巳
  45. 36: 帽
  46. 37: 并
  47. 38: 彘
  48. 39: 往
  49. 40: 御
  50. 41: 微
  51. 42: 旨
  52. 43: 昃
  53. 44: 木
  54. 45: 朿
  55. 46: 涎
  56. 47: 灾
  57. 48: 焦
  58. 49: 爽
  59. 50: 牝
  60. 51: 牡
  61. 52: 牧
  62. 53: 生
  63. 54: 田
  64. 55: 疑
  65. 56: 祝
  66. 57: 福
  67. 58: 立
  68. 59: 羊
  69. 60: 羌
  70. 61: 翌
  71. 62: 翼
  72. 63: 老
  73. 64: 艰
  74. 65: 艺
  75. 66: 若
  76. 67: 莫
  77. 68: 获
  78. 69: 衣
  79. 70: 逆
  80. 71: 门
  81. 72: 降
  82. 73: 陟
  83. 74: 雍
  84. 75: 鹿

同时要注意文件夹类型的指向,文件夹的命名也很关键,具体操作可以看https://blog.csdn.net/qq_42452134/article/details/135181244这位博主所讲内容。

这样我们就可以开始训练了

3、所得结果

训练的图片展示

当我们进行训练后,可以在项目路径下的runs文件中观看所得参数图像,以及python运行框中查看模型是否训练完全。

预测

再训练好模型后如何进行预测呢?可以参考官方文档https://docs.ultralytics.com/modes/predict/#key-features-of-predict-mode

本文给出相应的二份预测处理的代码

  1. from PIL import Image
  2. from ultralytics import YOLO
  3. # Load a pretrained YOLOv8n model
  4. model = YOLO('yolov8n.pt')
  5. # Run inference on 'bus.jpg'
  6. results = model(['4_Recognize/测试集/w01790.jpg', '4_Recognize/测试集/w01791.jpg']) # results list
  7. # Visualize the results
  8. for i, r in enumerate(results):
  9. # Plot results image
  10. im_bgr = r.plot() # BGR-order numpy array
  11. im_rgb = Image.fromarray(im_bgr[..., ::-1]) # RGB-order PIL image
  12. # Show results to screen (in supported environments)
  13. r.show()
  14. # Save results to disk
  15. r.save(filename=f'results{i}.jpg')
  1. # -*- coding: gbk -*-
  2. import os
  3. from PIL import Image
  4. from tqdm import tqdm
  5. from glob import glob
  6. from ultralytics import YOLO
  7. # 定义测试集图片文件夹和保存预测图片的文件夹
  8. test_images_folder = "4_Recognize/测试集"
  9. output_folder = "new_images"
  10. # 加载训练好的YOLOv8模型
  11. model = YOLO("yolov8n.pt") # 替换为你训练好的模型的路径
  12. # 确保保存预测图片的文件夹存在
  13. os.makedirs(output_folder, exist_ok=True)
  14. # 获取测试集中所有图片的路径
  15. test_image_paths = glob(os.path.join(test_images_folder, "*.jpg")) + glob(os.path.join(test_images_folder, "*.png"))
  16. # 对每张图片进行预测并保存预测后的图片
  17. # 对每张图片进行预测并保存预测后的图片
  18. for image_path in tqdm(test_image_paths, desc="Predicting"):
  19. # 读取图片
  20. image = Image.open(image_path)
  21. # 对图片进行预测
  22. predicted_images = model.predict(image)
  23. # 处理每个预测结果并保存到文件夹中
  24. for idx, predicted_image in enumerate(predicted_images):
  25. # 构建保存预测图片的路径,这里假设以预测结果的索引命名文件
  26. output_path = os.path.join(output_folder, f"{os.path.basename(image_path)}_{idx}.jpg")
  27. # 保存预测后的图片
  28. predicted_image.save(output_path)
  29. print("预测完成,并且预测图片已保存到'new_images'文件夹中。")

4、结语

本文只是提供一种参考思路且对对应数据集进行了处理。在进行相关的图像识别中,最让人头疼的应该是数据集,例如本次比赛的数据集处理起来较为复杂,如果不熟悉YOLO数据类型,以及对应关系转化,难以将题目进行。

同时作者参与此次比赛收获颇多,虽然是赛后补救,但也希望提供给大家一种思路,以及运用YOLOV8的细节。

  1. YOLOV8运行需要用所需的YOLO TXT类型文件,(即txt文件名为图像文件名,且txt文件中装有标签类与信息框数据)
  2. YOLOV8进行数据训练需要注意.yaml的路径设置要注意,以及对应路径下所包含的文件名不能改变,且文件摆放不能改变具体可以参考上文我推荐的文章。

第一次发表文章,望对大家有所帮助。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/724046
推荐阅读
相关标签
  

闽ICP备14008679号