基于深度学习的激光束识别(数据)
说明
在深度学习的项目中,可以说数据是十分重要的。因为如果数据有错误或者数据不合适的话,那后面所设计的网络和所调节的参数可能都要重新更改过,这样就会严重影响项目完成的效率。在这里数据主要分为两部分:一是数据准备,二是在pytorch中进行数据加载。
数据准备
数据来源主要是导师从现场拍摄的现场视频,这应该是最原始的数据了。以下为最原始的MP4数据:
首先我们做的是用OpenCV将视屏拆成一帧一帧的图片,具体代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44import cv2
import os
# 要提取视频的文件名,隐藏后缀
source_file_name = 'laser'
# 在这里把后缀接上
video_path = os.path.join("video/", source_file_name + '.mp4')
# 提取视频的频率,每1帧提取一个
frame_frequency = 1
# 输出图片到当前目录vedio文件夹下
out_put_directory_name = 'Image2/'
# 如果文件目录不存在则创建目录
if not os.path.exists(out_put_directory_name):
os.makedirs(out_put_directory_name)
# 从路径中获取视屏并放入变量中
camera = cv2.VideoCapture(video_path)
# 设置初始num的值
num = 0
# 开始从视屏中提取图片
while True:
num = num + 1
# 读取视屏中的图片
res, image = camera.read()
# 如果视屏图片全部读完了,提取图片结束
if not res:
print('not res , not image')
break
# 将图片以num值为名写入指定路径的文档中并打出图片名称
cv2.imwrite(out_put_directory_name + str(int(num)) + '.jpg', image)
print(out_put_directory_name + str(int(num)) + '.jpg')
# 图片提取结束
print('图片提取结束')
camera.release()
在将视屏分解为各个图片后,接下来我们就得在图片上标数据了。至于怎么标数据这点我们开始讨论了很久。因为要识别光束线的长度,那么计算机就得把完整的光束都识别出来,这样就能够计算出光束的长度了。要识别整个光束就意味着要找到光束的特征点,很明显光束有两个特征点就是一头一尾。为什么说找到一头一尾就能够知道这是光束呢?其实神经网络认识到一个物体可以用人的方式进行思考,人一眼就能看出光束的头和尾是因为头和尾的像素特征和周围的环境有着比较明显的差别,所以计算机也能通过这些像素的特征差别来进行寻找和区分光束和背景。所以我们标注了光束的头和尾的像素的坐标点。坐标点的方法是一张图片一个txt文档然后以[w_top h_top w_bottom h_bottom have_or_not]的格式来表示激光束的标注的坐标值。例如[302 396 315 915 1]表示激光束顶部的横坐标是302纵坐标是396,底部的横坐标是315纵坐标是915,然后1表示图片中有激光束的存在。
标注完坐标点后我们对原始图片进行裁剪。因为我们最初设计的网络是用的RGB图来作为输入数据的(训练模块会解释为什么用大小的图片),然后我们得用OpenCV将图片裁剪成大小的图片。
1 | def tailor(item): |
以上为将图片按照对应像素点比例进行裁剪的函数,通过以上函数我们能够将每张要训练的图片裁剪成像素的RGB图片。
接下来就要进行图片标注数据的解析与归一化了。因为数据都是整数,所以要将数据进行归一化。归一化操作为:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31def normal(x1, y1, x2, y2, w, h):
'''
功能:将标注坐标(x,y)进行归一化
参数:
——x1:上顶点标注的横坐标
——y1:上顶点标注的纵坐标
——x2:下顶点标注的横坐标
——y2:下顶点标注的纵坐标
——w:原图片的宽
——h:原图片的高
返回值:
——x1:上顶点归一化后的横坐标值
——y1:上顶点归一化后的纵坐标值
——x2:下顶点归一化后的横坐标值
——y2:下顶点归一化后的纵坐标值
'''
# 将横纵坐标转换成浮点数
x1 = x1 / 1.0
y1 = y1 / 1.0
x2 = x2 / 1.0
y2 = y2 / 1.0
# 将横纵坐标进行归一化
x1 = x1 / w
y1 = y1 / h
x2 = x2 / w
y2 = y2 / h
return (x1, y1, x2, y2)
知道怎么归一化了就得将数据从txt文档中提取出来然后进行归一化最后放入到新的txt文档中。具体操作如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31def convert_annotation(image_id):
'''
功能:将Annotation中的txt文档中的坐标进行归一化然后
存入labels中。
参数:
——image_id:Annotations中的.txt文档的文件名例如'1.txt'
'''
with open('Annotations/%s' % (image_id)) as in_file:
# 将文件名以'.'隔开取前面数字字符串放入image_id中
image_id = image_id.split('.')[0]
# 将.txt文档中的内容以每个整行数值的格式方式列表中
line = [x.split() for x in in_file]
pixel = [int(x) for y in line for x in y]
# 读入图片数据并将pixel内的坐标点放入归一化函数进行归一化
img = cv2.imread('Image/' + image_id + '.jpg')
normal = normal(pixel[0], pixel[1] - 300, pixel[2],
pixel[3] - 300, img.shape[1], img.shape[0])
# 将归一化后的数值放入pixel中
for i in range(4):
pixel[i] = normal[i]
# 将归一化后的pixel内的数值存入labels中的.txt文档内
with open('labels/%s.txt' % (image_id), 'w') as out_file:
out_file.write(" ".join([str(a) for a in pixel]) + '\n')
# 打印出文件名id和归一化后的坐标
print('image_id={}, pixel={}'.format(image_id, pixel))
数据加载
经过我们数据准备阶段,最重要的归一化后的标注数据已经放在了labels文档当中了,接下来就是新建一个dataset类了。在pytorch中会自动调用dataset类来进行数据的加载。此类的代码为:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61class dataset(Dataset):
def __init__(self, is_train = True):
# 设置存储着文件名的列表
self.file_names = []
# 如果是要进行训练读取训练数据文档,否则读取验证数据文档
if is_train:
# 打开训练文档
with open("ImageSets/Main/train.txt", 'r') as f:
# 将训练数据的文档名存储到文件列表中,.strip()去除字符串前后的空格或换行符
self.file_names = [x.strip() for x in f]
else:
# 打开验证数据文档
with open("ImageSets/Main/val.txt", 'r') as f:
# 将验证数据的文档名存储到文件列表中
self.file_names = [x.strip() for x in f]
# 图片存储路径和label数据文档存储数据路径
self.img_path = "Image/"
self.label_path = "labels/"
def __len__(self):
'''
功能:返回文件名的个数
'''
# 返回文件名的个数
return len(self.file_names)
def __getitem__(self, item):
'''
功能:对图像数据进行规范化处理
参数:
picture_index:图片在文件名当中的索引
返回值:
img:经过维度转换后的图片的数值
labels:转换成numpy数组后的label数据
'''
# 读取需要图像处理和数据转换的图像
img = cv2.imread(self.img_path + self.file_names[item] + '.jpg')
# 将img数据数值进行维度转换原先(h,w,c),转换后(c,w,h)
img = img.transpose(2, 1, 0)
# 将像素值进行归一化处理
img = img / 255.
with open(self.label_path+self.file_names[item] + ".txt") as f:
# 将.txt文档中的内容放入列表中
line = [x.split() for x in f]
label = [float(x) for y in line for x in y]
# 新建一个值都是零的大小为5的numpy数组
labels = np.zeros((5))
# 将标注的值都放入numpy数组中
labels[0:5] = np.array([label[0], label[1], label[2], label[3], label[4]])
return img, labels
至此,数据准备阶段已全部完成。