最近需要去检索一些车辆的图片,据说Open Image的图片量比较大,所以准备去这个数据集上下载点,想着这是google弄得数据,本以为这比较方便,没想到中途遇到了些问题,哎想法是美好的,过程是坎坷的。
首先吐槽一下,现在数据格式真是五花八门,就说几种常见的数据集吧
1、VOC标记信息采用的是xml格式,类别名直接命名;
2、COCO标记信息采用json格式,类别名直接命名;
3、ImageNet标记信息采用的是xml格式,类别名采用词条索引命名;
4、OpenImage标记信息采用的是csv格式,类别名采用词条索引命名;
这些数据格式相互转化倒也容易,但还是多少有些烦的,大家都统一采用一个标准就更好了。百家争鸣是很好的,但在这种很基础的地方大家统一采用一个标准个人觉得这是一个很好的做法,希望以后会有这样的组织出来规范一下。
Open Image至2019年5月已经更新到V5了,总图片量约900万张,总计约560G。关于详细信息可以去这里:http://storage.googleapis.com/openimages/web/factsfigures.html
如果不想看英文,这篇文章:https://www.cnblogs.com/tay007/p/11282117.html对Open Image数据分布及结果做了介绍
Open Image上虽然比较人性化的划分了train val test,但只提供了全部下载,对于这么大的数据集,而且还要连接到google上去,下载成了第一大难题,好在大千世界中无私奉献的人总是有的,有个热心的人提供了一个分类下载的工具,利用这个工具你只需要下载你需要的类别就可以了,这种人真是值得敬仰。其工具及使用说明在:https://github.com/EscVM/OIDv4_ToolKit
这个工具很不错,不过只适合V4的数据集下载,由于数据结构不一样,V5的不行,截止目前作者还没写V5的下载工具。使用这个工具下载文件保存在当前文件夹下的OID文件夹,OID下分了两个文件夹:一个csv_folder;一个Dataset。这个工具使用中遇到了点疑惑,你下载600类别中的Apple类,他会在Dataset/train/Apple/Label把对应的标记框存放在txt文件中,但我下载Land vehicle是,Label文件夹就是个摆设,啥都没有,二是把数据全部存放在csv_folder/train-annotations-bbox.csv中,这个文件有时多大1G左右。没法子,只能自己解析这些文件了。在解析这些csv文件中遇到了些问题,具体下面说。
最开始我写了这么个脚本,脚本放置在OID目录下:
import csv,cv2,os
CSVMainDir='.\\csv_folder'
ClsDescptBoxPath=os.path.join(CSVMainDir,'class-descriptions-boxable.csv')
ClsDescpts=csv.reader(open(ClsDescptBoxPath,'r'))
RealClsNames={}
for ClsDescpt in ClsDescpts:
LabelName,ClsName=ClsDescpt[0],ClsDescpt[1]
RealClsNames[LabelName]=ClsName
def GetImAnnotBox():
ImMainDir='.\\Dataset'
DataType = 'validation'
ImCls = 'Apple'
ImDir = os.path.join(ImMainDir, DataType, ImCls)
AnnotName='{}-annotations-bbox.csv'.format(DataType)
AnnotPath=os.path.join(CSVMainDir,AnnotName)
AnnotInfos=csv.reader(open(AnnotPath,'r'))
ImNames=os.listdir(ImDir)
for ImName in ImNames[:]:
print('do {}\n'.format(ImName))
ImPath=os.path.join(ImDir,ImName)
if os.path.isfile(ImPath):
ImPath = os.path.join(ImDir, ImName)
Im = cv2.imread(ImPath)
ImH, ImW, _ = Im.shape
SearchWord = ImName[:-4]
ObjBoxs = {}
for AnnotInfo in AnnotInfos:
ImNameStr = AnnotInfo[0]
if ImNameStr == SearchWord:#这一句对很多图片名匹配不到,百思不得其解
LabelName=AnnotInfo[2]
xxyy=[float(AnnotInfo[4]), float(AnnotInfo[5]), float(AnnotInfo[6]), float(AnnotInfo[7])]
BBox=[int(xxyy[0]*ImW),int(xxyy[2]*ImH),int(xxyy[1]*ImW),int(xxyy[3]*ImH)]
RealClsName=RealClsNames[LabelName]
if RealClsName in ObjBoxs.keys():
ObjBoxs[RealClsName].append(BBox)
else:
ObjBoxs[RealClsName]=[BBox]
if ObjBoxs:
for Cls in ObjBoxs.keys():
Boxs=ObjBoxs[Cls]
for Box in Boxs:
x1,y1,x2,y2=Box
cv2.rectangle(Im,(x1,y1),(x2,y2),(255,0,0),2,2)
cv2.putText(Im,Cls,(int((x1+x2)/2),y1),1,2,(0,255,0),2,1)
cv2.namedWindow('Im',cv2.WINDOW_NORMAL)
cv2.imshow('Im',Im)
cv2.waitKey(1000)
else:
print('No annotbox\n')
cv2.destroyWindow('Im')
if __name__=='__main__':
GetImAnnotBox()
如上述if ImNameStr == SearchWord:#这一句对很多图片名匹配不到,百思不得其解,我单独打印ImNameStr没问题呀。是在是调试不好了,最后我把csv每一行存放在一个list变量中,改成下面这样测试可以了:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 2019/09/21 by DQ
import csv,cv2,os
def GetRealClsNames(ClsDescptBoxPath):
ClsDescpts=csv.reader(open(ClsDescptBoxPath,'r'))
RealClsNames={}
for ClsDescpt in ClsDescpts:
LabelName,ClsName=ClsDescpt[0],ClsDescpt[1]
RealClsNames[LabelName]=ClsName
return RealClsNames
def GetAnnotInfos(AnnotPath):#把csv每一行存放在一个list变量中
AnnotInfos=[]
with open(AnnotPath, 'r') as FId:
for AnnotInfo in csv.reader(FId):
AnnotInfos.append(AnnotInfo)
return AnnotInfos
def GetImAnnotBox(CSVMainDir,ImMainDir,DataType,ImCls):
ExpectClss=('Land vehicle','Van','Car')#我想显示的类别,类别比较多,都画出来,眼花了
ClsDescptBoxPath = os.path.join(CSVMainDir, 'class-descriptions-boxable.csv')
RealClsNames = GetRealClsNames(ClsDescptBoxPath)
AnnotName='{}-annotations-bbox.csv'.format(DataType)
AnnotPath=os.path.join(CSVMainDir,AnnotName)
AnnotInfos=GetAnnotInfos(AnnotPath)
ImDir = os.path.join(ImMainDir, DataType, ImCls)
ImNames=os.listdir(ImDir)
for ImName in ImNames[:]:
ImPath=os.path.join(ImDir,ImName)
if os.path.isfile(ImPath):
ImPath = os.path.join(ImDir, ImName)
Im = cv2.imread(ImPath)
ImH, ImW, _ = Im.shape
ObjBoxs = {}
for AnnotInfo in AnnotInfos:
if AnnotInfo[0]==ImName[:-4]:
xxyy=[float(AnnotInfo[4]), float(AnnotInfo[5]), float(AnnotInfo[6]), float(AnnotInfo[7])]
BBox=[int(xxyy[0]*ImW),int(xxyy[2]*ImH),int(xxyy[1]*ImW),int(xxyy[3]*ImH)]
LabelName = AnnotInfo[2]
RealClsName=RealClsNames[LabelName]
if RealClsName in ExpectClss:
if RealClsName in ObjBoxs.keys():
ObjBoxs[RealClsName].append(BBox)
else:
ObjBoxs[RealClsName]=[BBox]
if ObjBoxs:
for Cls in ObjBoxs.keys():
Boxs=ObjBoxs[Cls]
for Box in Boxs:
x1,y1,x2,y2=Box
cv2.rectangle(Im,(x1,y1),(x2,y2),(255,0,0),2,2)
cv2.putText(Im,Cls,(int((x1+x2)/2),y1),1,2,(0,0,255),2,1)
#cv2.namedWindow('Im',cv2.WINDOW_NORMAL)
#cv2.imshow('Im',Im)
#cv2.waitKey(1000)
SaveImPath=os.path.join('.\\Temp',ImName)
cv2.imwrite(SaveImPath,Im)
print('{} has annotbox\n'.format(ImName))
else:
print('{} no annotbox\n'.format(ImName))
#cv2.destroyWindow('Im')
if __name__=='__main__':
CSVMainDir='.\\OID\\csv_folder'
ImMainDir='.\\OID\\Dataset'
DataType ='validation'# 'train'
ImCls = 'Land vehicle'
GetImAnnotBox(CSVMainDir,ImMainDir,DataType,ImCls)
下面是一些截图显示:
google虽然没有明确说明但从上述示例来看,600个标记框类中的Land vehicle是个泛类或大类,Car其实也属于这个类,只要是没有明确的或车辆混杂在一起的陆地车辆类似乎都被标记这个泛化类了