天池学习赛:零基础入门CV - 街景字符编码识别

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 一、安装YOLOv5
      • 1.拉取yolov5的代码
      • 2.下载模型
      • 3.配置环境
      • 4.测试
  • 二、动手实践街景字符编码识别
    • 1.查看数据
    • 2.配置文件
        • 1.yolov5/data/mrcha.yaml文件:
        • 2.yolov5/models/yolov5s.yaml文件:
    • 3.开始训练
    • 4.提交结果


前言

阿里天池学习赛:街景字符编码识别
跟着官方的baseline走了一遍,准确率大概在0.48左右
现在想法是使用yolov5来提高精度.之前没咋接触过完整的完成一个项目,所以想记录下


一、安装YOLOv5

1.拉取yolov5的代码

git clone https://github.com/ultralytics/yolov5.git

2.下载模型

YOLOv5不是一个单独的模型,而是一个模型家族,包括了YOLOv5s、YOLOv5m、YOLOv5l、YOLOv5x、YOLOv5x+TTA,模型依次从小到大,我想先看看效果所以下载了不大不小的YOLOv5s
天池学习赛:零基础入门CV - 街景字符编码识别_第1张图片

#下载yolov5s模型放到./weights文件夹
wget https://github.com/ultralytics/yolov5/releases/download/v6.1/yolov5s.pt

3.配置环境

#打开Python环境,然后安装requirements.txt里需要的库
pip install -r requirements.txt

PS:如果哪些库安装失败了的话就看着requirements 一个一个的pip install

4.测试

在yolov5/data/images下有两张图片bus.jpg和zidane.jpg可以用来测试

python detect.py --source ./data/images/bus.jpg --weights ./weights/yolov5s.pt --conf-thres 0.25

python detect.py --source ./data/images/zidane.jpg --weights ./weights/yolov5s.pt --conf-thres 0.25

在/yolov5/runs/detect/下可以看到两张标了框的图片
天池学习赛:零基础入门CV - 街景字符编码识别_第2张图片
天池学习赛:零基础入门CV - 街景字符编码识别_第3张图片

二、动手实践街景字符编码识别

1.查看数据

给定数据集的格式
天池学习赛:零基础入门CV - 街景字符编码识别_第4张图片
其中,标签全部整合为一个json文件,且坐标为真实坐标:
在这里插入图片描述

而YOLOv5支持的VOC格式是这样的:
天池学习赛:零基础入门CV - 街景字符编码识别_第5张图片
其中images存放原始图片
labels存放对应每张图片标签的txt文件
标签格式: 类别 x y w h
坐标不是真实的坐标,而是将坐标除以宽高后的计算出来的,是相对于宽和高的比例
转化格式:
天池学习赛:零基础入门CV - 街景字符编码识别_第6张图片
所以需要写个脚本进行转化:

import json
import cv2
import os

#分别生成val和train时要记得换路径
train_json = json.load(open('json文件路径'))
img_path = '图像路径'
label_path = '标签要保存的路径'

for x in train_json:
  field = x.split('.')[-2]+'.txt'  #文件后缀名
  #print(field)
  img = cv2.imread(os.path.join(img_path,x))
  #获取图片长度
  img_h,img_w = img.shape[:2]

  length = len(train_json[x]['height']) 
  json_data = train_json[x]
  for i in range(length):
    h = json_data['height'][i]
    label = json_data['label'][i]
    w = json_data['width'][i]
    x = json_data['left'][i]
    y = json_data['top'][i]

    x = (x + w / 2) / img_w
    y = (y + h / 2) / img_h
    w = w / img_w
    h = h / img_h

    fp = open(os.path.join(label_path,field), mode="a+", encoding="utf-8")  
    file_str = str(label) + ' ' + str(round(x, 6)) + ' ' + str(round(y, 6)) + ' ' + str(round(w, 6)) + ' ' + str(round(h, 6))  
    fp.write(file_str+'\n')  

  fp.close()

可以检查下自己生成的标签对不对,使用新生成的标签对原始图像画框

import torch
import numpy as np
import cv2

label_path = 'dataset/mchar_data/VOC_data/labels/mchar_train/000012.txt'
image_path = 'dataset/mchar_data/train/mchar_train/000012.png'

#坐标转换,原始存储的是YOLOv5格式
# Convert nx4 boxes from [x, y, w, h] normalized to [x1, y1, x2, y2] where xy1=top-left, xy2=bottom-right
def xywhn2xyxy(x, w=640, h=640, padw=0, padh=0):

    y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x)
    y[:, 0] = w * (x[:, 0] - x[:, 2] / 2) + padw  # top left x
    y[:, 1] = h * (x[:, 1] - x[:, 3] / 2) + padh  # top left y
    y[:, 2] = w * (x[:, 0] + x[:, 2] / 2) + padw  # bottom right x
    y[:, 3] = h * (x[:, 1] + x[:, 3] / 2) + padh  # bottom right y
    return y

#读取labels
with open(label_path, 'r') as f:
    lb = np.array([x.split() for x in f.read().strip().splitlines()], dtype=np.float32)  # labels


# 读取图像文件
img = cv2.imread(str(image_path))
h, w = img.shape[:2]
lb[:, 1:] = xywhn2xyxy(lb[:, 1:], w, h, 0, 0)#反归一化

print(lb)
#绘图
for _, x in enumerate(lb):
    class_label = int(x[0])  # class

    cv2.rectangle(img,(round(x[1]),round(x[2])),(round(x[3]),round(x[4])),(0, 255, 0) )
    cv2.putText(img,str(class_label), (int(x[1]), int(x[2] - 2)),fontFace = cv2.FONT_HERSHEY_SIMPLEX,fontScale=1,color=(0, 0, 255),thickness=2)
#根据自己的路径修改,这里的路径是简化了的
cv2.imwrite('check/test.jpg',img)

2.配置文件

1.yolov5/data/mrcha.yaml文件:

train: /dataset/mchar_data/VOC_data/images/mchar_train
val: /dataset/mchar_data/VOC_data/images/mchar_val

# number of classes
nc: 10

# class names
names: ['0','1','2','3','4','5','6','7','8','9']

2.yolov5/models/yolov5s.yaml文件:

把nc改为 10


3.开始训练

python train.py --data mrcha.yaml --cfg yolov5s.yaml --weights yolov5s.pt --epochs 20 --device 0,1 --batch-size 64 --imgsz 300

训练完以后结果会保存在runs/train/exp下

接着使用训练好的模型来预测

python detect.py --weigths runs/train/exp4/weights/best.pt --source /dataset/mchar_data/test/mchar_test_a --save-txt

结果会保存在runs/detect/exp下 有画了框的图片以及对应框的坐标txt文件

天池学习赛:零基础入门CV - 街景字符编码识别_第7张图片
天池学习赛:零基础入门CV - 街景字符编码识别_第8张图片

4.提交结果

结果格式如下:
file_name, file_code
0010000.jpg,451
0010001.jpg,232
0010002.jpg,45
0010003.jpg,67
0010004.jpg,191
0010005.jpg,892

所以需要将所有label给生成一个csv文件
这里是使用了论坛里别人的代码:

import os


img_dir='mchar_data/test/mchar_test_a/' #测试图片路径  
result_dir='yolov5/runs/detect/exp4/labels/' #识别结果路径  
out_dir = 'path' # 输出的 txt 文件路径  
  
  
# 获取列表的第二个元素  
def takeSecond(elem):  
    return elem[1]  
  
# 读取  
dirs=os.listdir(img_dir)  
  
fp = open(out_dir+'result.csv', mode="w+", encoding="utf-8")  
  
for file in dirs:  
  
    txtFileName=file.title().split(".")[0]+'.txt'  
  
    listCode = []  
  
    if os.access(result_dir+txtFileName,os.F_OK):  
  
        with open(result_dir+txtFileName, "r") as f:  
            for line in f.readlines():  
                tmp = line.split(' ') 
                listCode.append((tmp[0],float(tmp[1])))  
  
    # 按tmp[1]从小到大排序  
    listCode.sort(key=takeSecond)  
  
    theNumber=''  
    for code in listCode:  
        theNumber+=code[0]  
  
    #保存到文件,格式:fileName,theNumber   
    fileName=file.title()    
    fp.write(fileName+','+ theNumber+ '\n')
    
fp.close()

然后可以得到下图的结果.但还需要处理一下:加个表头,并从000000.png开始
天池学习赛:零基础入门CV - 街景字符编码识别_第9张图片

使用pandas库

import pandas as pd

data = pd.read_csv('result.csv',sep=',',names=['file_name','file_code'])
#排序
data = data.sort_values(by='file_name')
#取消第一列的id
data = data.set_index('file_name') 
#将code转为int类型,不然会变成 111.0 
data['file_code'] = data['file_code'].fillna(0)
data['file_code'] = data['file_code'].round(0).astype('int')
data.to_csv('result2.csv')

最终结果:
天池学习赛:零基础入门CV - 街景字符编码识别_第10张图片

你可能感兴趣的:(计算机视觉,人工智能,目标检测)