作者:云时之间
来源:知乎
链接:https://zhuanlan.zhihu.com/p/139918526
编辑:王萌
上一次使用了text_renderer尝试生成类似于银行卡的数据,但是实际下来效果并不好,我分析了一下原因:
①:text_renderer输出的背景和真实银行卡图片有很大的差异
②:大多数银行卡采用的是突出的字体,text_renderer很难去模拟
分析出以上的问题后,现在的重点开始转换成如何去近似的模拟银行卡数据集,最好的方法就是使用真实的银行卡卡号片段来拼接成数据。
一边说代码,一边捋顺思路:
一:准备数据
首先准备了大概50张的银行卡卡号片段的真实图片,尽量保证每张图片的长度为3-4位,为什么分为3-4位?分析了大多数的银行卡后,发现一个规律:
信用卡卡号:0000 0000 0000 0000
储蓄卡卡号:0000 0000 0000 0000 000
我们用CTPN检测的时候,往往会一段一段的检测,然后拼接起来,这种效果理论上会更好准备的数据如下:
图片的分辨率180*46
现在分析代码:
第一步:选择生成数量,读取图片
这部分注释很清楚,不再赘述
二:裁剪图片,拼接图片
这部分是整个程序之中的关键,我绘制了一个图,结合图来说一下
因为准备的数据集是3-4个字符一张图,DenseNet的输入长度为10时比较合适(具体为什么还没搞清楚),因此拼接的图片字符长度也是10个字符:读取图片
这里用到cut_image函数对image3进行裁剪:
裁剪前后对比:
对图片进行拼接:
拼接后效果:
三:数据增强
因为DenseNet的输入为280*32的图像,并且为减少计算,需要将图像转换为灰度图像
转换为灰度图像后,这里需要使用ImageDataGenerator类,简单的说ImageDataGenerator是keras.processing.image模块里的图片生成器,每次喂进去一个batch_size的数据,然后对这个批次的数据进行样本增强,用来扩充样本数据集的大小,增强模型的泛化能力,更模拟真实情况,比如旋转,缩放,对比度转换等等。
四:划分训练集和测试集
我们将训练集和测试集按照8:2的比例进行划分
运行,数据生成完毕
五:代码
import os
import numpy as np
import cv2
from keras.preprocessing.image import ImageDataGenerator, array_to_img, img_to_array, load_img
import os
#ToTAL是生成样本种子数量 ,真实样本数量为 TOTAL * 10
print("--------实际生成样本数为ToTal* 10--------")
TOTAL=int(input("输入要生成的种子数:"))
#图片路径,显示图片的名称
path_image=r'./images_base/'
list_path=os.listdir(path_image)
loca=["0,0,30,46","30,0,60,46","60,0,90,46","90,0,120,46"]
ALLIMAGE=len(list_path)#得到给出的训练集数量,image_base的数量
print("总共{0}张图片,需要生成{1}张图片\n------------正在生成中------------------".format(ALLIMAGE,TOTAL*10))
if not os.path.exists("./images"):
os.mkdir("./images")
#对半裁图片,输入图片从120*46->60*46
def cut_image(imge,l2,l3,l0=0,l1=46):
src2 = imge[l0:l1, l2:l3]
return src2
for i in range(TOTAL):
#生成0-allmage,三个的随机数
rad_num=np.random.randint(0,ALLIMAGE,(1,3))
img_path=[]
for j in rad_num[0]:
#取image_base里边的随机图片
img_path.append([r"./images_base/"+str(list_path[j])])
# img_path=img_path[0]
imge1=cv2.imread(" ".join(img_path[0]))
imge2 = cv2.imread(" ".join(img_path[1]))
imge3 = cv2.imread(" ".join(img_path[2]))
src1=cut_image(imge3, 0, 60)
tmp = np.zeros((46, 300, 3), np.uint8)
tmp[0:46, 0:120] = imge1
tmp[0:46, 120:240] = imge2
tmp[0:46, 240:300] = src1
cv2.imshow("-",tmp)
cv2.waitKey(0)
'''
名称为image1的前4位+image2前4位+src1的前两位
'''
name = " ".join(img_path[0]).split("/")[2][0:4] + " ".join(img_path[1]).split("/")[2][0:4] + \
" ".join(img_path[2]).split("/")[2][0:2] + "I"
# print(name)
'''
tmp输入300*46->DenseNet输入为280*32->Reshape后灰度
'''
tmp = cv2.resize(tmp, (280, 32))
tmp = cv2.cvtColor(tmp, cv2.COLOR_BGR2GRAY)
'''
数据增强:
随机旋转,除以总宽度0.01,除以总宽度0.015,
空间随机缩放范围0.06
随机填充
'''
datagen = ImageDataGenerator( #数据增强
rotation_range=2,
width_shift_range=0.01,
height_shift_range=0.015,
zoom_range=0.06,
fill_mode='nearest')
#把图片的整数结构转成浮点型
x = img_to_array(tmp)
x = x.reshape((1,) + x.shape)
i = 0
'''
接收numpy数组和标签为参数,生成经过数据提升或标准化后的batch数据,并在一个无限循环中不断的返回batch数据
'''
for batch in datagen.flow(x, batch_size=1, # save_to_dir 文件夹 prefix图片名字 format格式
save_to_dir='images', save_prefix=name, save_format='jpg'):
i += 1
if i > 10: # 如果不break会无限循环
break # otherwise the generator would loop indefinitely
# cv2.imwrite("./out_data/" + name, tmp)
print("=====生成数据集======")
path_image=r'./images/'
list_path=os.listdir(path_image)
'''
生成训练集和测试集的txt文件
'''
f1=open("./data_train.txt",'w')
f2=open("./data_test.txt",'w')
for i in list(list_path)[0:int(len(list_path)*0.8)]: #划分80%训练
f1.write(""+str(i))
label=list(i)[0:10]
for j in label:
if j=="_":
f1.write(" " + str(11))
else:
f1.write(" "+str(int(j)+1))
f1.write("\n")
for i in list(list_path)[int(len(list_path)*0.8):]:
f2.write(""+str(i))
label=list(i)[0:10]
for j in label:
if j=="_":
f2.write(" " + str(11))
else:
f2.write(" "+str(int(j)+1))
f2.write("\n")
print("数据集生成完毕")