背景:
在调一个行人重识别的程序,接到任务,给了一个新的数据集ALERT,这个数据集的数据安排的方式和图片文件的命名形式跟传统的主流的数据集如market和DukeMTMCreid的形式不一样。
行人重识别的数据集的特点是:
1)通常会有几百几千个行人,每个行人分配一个ID;
2)每个行人至少出现在两个摄像头内(不然无法重识别),
3)通常一个行人会出现在三个摄像头内,
4)在每个摄像头内被拍到的次数大于等于1
ALERT数据集的所有图片是按摄像头的编号(32-37)放的,然后每个摄像头下又放了n个行人的图像,每个行人文件夹中有m张图片.
ALERT的图片命名格式:ID_CAM_time_index.jpg 如:00011005_c32_t01_0001.jpg
而market和duke之类的主流数据集已经是分好query、train和test文件夹了,总而言之是不需要去动他的了~~
Market的图片命名格式:ID_CAM+slide_index_index.jpg 如:0000_c1s1_000151_01.jpg
问题:
需要把ALERT数据集的数据形式改成跟market一样,这样的话,可以最小限度地去动源代码!不至于出现“我只改了一行代码呀,怎么整个程序都崩溃了”的情况。
分析:
在搞清楚应该怎么分之后,我按比例分好了train和test,现在要做的就是要在test中,把每个id的图片,拿一张出来,放到query里面。
一开始想到的办法是简单粗暴地用windows的搜索栏搜索_0001,然后把搜索到的所有图片放进query里面,但是这样会把一个ID只在一个CAM下出现一次的那个人从test里面全部拿走,这样一来,query就找不到它要找到目标,这不是我们期望的结果。于是现在就需要实现只拿一个ID的一张图片,不论是哪个CAM下都行!
先说一下实现思路,因为没学过什么特别厉害的工具,只能在自己有限的认知里实现功能:
先验知识:因为文件在文件夹中是按文件名排序的,所以相同ID的图片肯定是连着的,所以:
1按顺序读取文件名;
2提取其ID,也就第一个‘_’前的数字,记为temp
3读取下一个文件名,提取ID,与temp做对比
i若ID等于temp,则不做操作
ii若ID不等于temp,则将该ID对应的图片的序号记下,存入list中
4重复步骤3,直至所有文件读完。
实现:
Python实现的代码如下:
get_query.py
import os
import shutil
#获取所有图片的文件路径
def file_name(file_dir):
L=[]
for root, dirs, files in os.walk(file_dir):
for file in files:
if os.path.splitext(file)[1] == '.jpg':
L.append(file)
return L
#剪切图片函数
def movepic(i):
if i < length:
id,other = L[i].split('_',1)#用‘_’分割字符串,并取得id
print('id:',id)
temp = id#用temp记录id
id_next,other_next = L[i+1].split('_',1)
if temp == id_next:
print('picture with same id')
#读取下一张图片
i = i + 1
else:
print('storing id index')
#保存该剪切的图片的序号
list_of_i.append(i)
#也一样读取下一张图片
i = i + 1
#设定文件夹
file_dir="test"
#读取所有图片文件路径,保存于数组L中
L = file_name(file_dir)
#获取数组长度(图片数量)
length = len(L)
#创建一个数组保存需要剪切的图片的序号
list_of_i=[]
i=0
for i in range(length-1):
movepic(i)
#输出需要剪切的图片的序号
print(list_of_i)
for j in list_of_i:
shutil.move('E:/ALERT/AirportALERT_image/q/test/'+L[j],
'E:/ALERT/AirportALERT_image/q/query')
print('id pictures moved')
问题
做完这一步已经可以把数据集的分布分好了,但是要把数据集“整容”成主流的模样,还需要把摄像头的非主流名字改过来,也就是要把:00011005_c32_t01_0001.jpg改成00011005_c1_t01_0001.jpg,也就是c32变成c1,c33变成c2…c37变成c6.
而这样的需要改文件名的图片文件有接近4万张,如果靠手动改,能改成神经病~~
于是也自然想到用代码的形式来实现。
分析:
通过观察图片的命名格式可以发现:其名字是用’_’连接起来的,而我们要改的字段在第二节,但是第二节字段里还有一个字母’c’,所以需要先提取‘c32’,再提取‘32’,再把‘32’转换成int型,根据映射关系,可以用旧号减去31得到新号。
实现:
Change_cam_id.py
import os
import shutil
#设置总路径
PATH = 'E:/ALERT/AirportALERT_image/q/'
#获取所有文件路径
def file_name(file_dir):
L=[]
for root, dirs, files in os.walk(file_dir):
for file in files:
if os.path.splitext(file)[1] == '.jpg':
L.append(file)
return L
#更改摄像头名字
def change_cam_id(i):
if i < length:
#先用'_'分割路径字符串,得到CAM_id
id= L[i].split('_',2)
#print('old_cam:',id[1])
#用字符‘c'分割字符串,取后半段(前半段为'')
old_cam_id = id[1].split('c')
#print('old_cam_id:',old_cam_id[1])
#新摄像头号=旧摄像头号-31,注意类型转换
new_cam_id = int(old_cam_id[1]) - 31
#print(new_cam_id)
#更改名字,需要组合路径、前中后各段信息,最后整合成新的文件路径名
os.rename(PATH+file_dir+id[0]+'_'+id[1]+'_'+id[2],
PATH+new_file_dir+id[0]+'_'+'c'+str(new_cam_id)+'_'+id[2])
#设置文件夹名字,里面有需要改名的文件
file_dir="query/"
#新文件夹名字,存放改好名字的文件
new_file_dir = "new_query/"
#获取文件路径,存放于数组L中
L = file_name(file_dir)
#获取数组长度(图片数量)
length = len(L)
i=0
for i in range(length):
change_cam_id(i)
print('finished processing'+str(i+1)+' pitures')
即使是一个很日常的问题,把分析思路和实现过程详细记录下来,也是很有收获的过程,而且可以令自己对相关知识点更加记忆深刻~~
欢迎关注“pyhon修炼之道”,我们将持续更新新鲜python文章~