【FP60】林业害虫数据集——目标检测、图像分类
文章目录
- 1、FP60(Forest Pest60)基本介绍
- 2、一些数据处理
- 2.1、数据划分
- 2.2、xml格式转yolo格式
- 2.3、check标注框
- 3、数据集获取
1、FP60(Forest Pest60)基本介绍
根据中国江苏省林业有害生物分布情况,筛选出 **15 **个科 60 种,见表,常见且易于获取的林业害虫。主要从互联网上收集林业害虫图像。在收集过程中,以每种林业有害生物的拉丁文学名作为查询关键词,然后在常见的图片搜索引擎中搜索,包括 Google、Bing 和百度。手动筛选搜索结果以过滤低质量图像。我们总共有 7253 张高质量的林业害虫图像,大小从 93×140 到 6016×4106 不等。
此外,对FP60数据集又进行了二次划分,分别为FP40(40种)、FP15(15种),每个数据集已经预处理为YOLO格式。
下图显示了该数据集中 60 种林业有害生物的图像,每张图片代表一种林业有害生物。
每个数据集的文件结构如下:
FP60||___dataset| |______images| | |_______train| | | |__________1-1-1.jpg| | | |__________ ......| | |_______test| | | |__________2-4-82.jpg| | | |__________ ......| | |_______val| | | |__________2-4-1.jpg| | | |__________ ......| || |______labels | | |_______train| | | |__________1-1-1.txt| | | |__________ ......| | |_______test| | | |__________2-4-82.txt| | | |__________ ......| | |_______val| | | |__________2-4-1.txt| | | |__________ ......
同时,文件中也有对应的处理代码。
2、一些数据处理
下面这些代码不仅仅只针对当前数据集,对其他目标检测数据集同样适用(注意要求改文件路径)。
2.1、数据划分
import os
import shutil
def get_dataset_name(file):file_names = []with open(file, 'r', encoding='utf-8') as f:lines = f.readlines()for line in lines:file_names.append(line.split('\n')[0])return file_names
def copy_file(s_folder,d_folder,file_name,type='.jpg'):s_file = os.path.join(s_folder,file_name+type)d_file = os.path.join(d_folder,file_name+type)if not os.path.exists(d_file):shutil.copyfile(s_file,d_file)
def process_multi_files(file_names,s_folder,d_folder,type):for name in file_names:copy_file(s_folder,d_folder,name,type)
def main():train_file_txt = './labels/train.txt'val_file_txt = './labels/trainval.txt'test_file_txt_1 = './labels/test.txt'test_file_txt_2 = './labels/val.txt'image_path = './images'xml_path = './annotations'train_img_fold = './datasets/images/train'test_img_fold = './datasets/images/test'val_img_fold = './datasets/images/val'# train_txt_fold = './datasets/txt/train'# test_txt_fold = './datasets/txt/test'# val_txt_fold = './datasets/txt/val'train_xml_fold = './datasets/xml/train'test_xml_fold = './datasets/xml/test'val_xml_fold = './datasets/xml/val'train_file_names = get_dataset_name(train_file_txt)val_file_names = get_dataset_name(val_file_txt)test_file_names_1 = get_dataset_name(test_file_txt_1)test_file_names_2 = get_dataset_name(test_file_txt_2)test_file_names_1.extend(test_file_names_2)# 复制训练集图片process_multi_files(train_file_names,image_path,train_img_fold,'.jpg')# 复制验证集图片process_multi_files(val_file_names,image_path,val_img_fold,'.jpg')#复制测试集图片process_multi_files(test_file_names_1,image_path,test_img_fold,'.jpg')# 复制训练集xmlprocess_multi_files(train_file_names,xml_path,train_xml_fold,'.xml')# 复制验证集xmlprocess_multi_files(val_file_names,xml_path,val_xml_fold,'.xml')#复制测试集xmlprocess_multi_files(test_file_names_1,xml_path,test_xml_fold,'.xml')
if __name__ == "__main__":main()
2.2、xml格式转yolo格式
# 导入相关库
import os
from lxml import etree
from tqdm import tqdmdef voc2txt():# 获取xml文件夹下的所有xml文件名,存入列表xmls_list = os.listdir(xmls_ori_path)for xml_name in tqdm(xmls_list):# 打开写入文件txt_name = xml_name.replace('xml', 'txt')f = open(os.path.join(txts_save_path, txt_name), 'w') # 代开待写入的txt文件with open(os.path.join(xmls_ori_path, xml_name), 'rb') as fp:# 开始解析xml文件xml = etree.HTML(fp.read())width = int(xml.xpath('//size/width/text()')[0])height = int(xml.xpath('//size/height/text()')[0])# 获取对象标签obj = xml.xpath('//object')for each in obj:name = each.xpath("./name/text()")[0]classes = dic[name]xmin = int(each.xpath('./bndbox/xmin/text()')[0])xmax = int(each.xpath('./bndbox/xmax/text()')[0])ymin = int(each.xpath('./bndbox/ymin/text()')[0])ymax = int(each.xpath('./bndbox/ymax/text()')[0])# 归一化dw = 1 / widthdh = 1 / heightx_center = (xmin + xmax) / 2y_center = (ymax + ymin) / 2w = (xmax - xmin)h = (ymax - ymin)x, y, w, h = x_center * dw, y_center * dh, w * dw, h * dh# 写入f.write(str(classes) + ' ' + str(x) + ' ' + str(y) + ' ' + str(w) + ' ' + str(h) + ' ' + '\n')f.close() # 关闭txt文件if __name__ == '__main__':dic = {'2-4': "0", '3-1': "1", '5-2': "2",'5-3': "3",'6-3': "4",'6-4': "5",'8-3': "6",'11-4': "7",'12-3': "8",'12-4': "9",'13-1': "10",'14-1': "11",'14-3': "12",'14-5': "13",'15-1': "14",}#训练数据# xmls_ori_path = r"./datasets/xml/train" # xml文件所在的文件夹# txts_save_path = r"./datasets/txt/train" # txt文件所在的文件夹#验证数据# xmls_ori_path = r"./datasets/xml/val" # xml文件所在的文件夹# txts_save_path = r"./datasets/txt/val" # txt文件所在的文件夹#测试数据xmls_ori_path = r"./datasets/xml/test" # xml文件所在的文件夹txts_save_path = r"./datasets/txt/test" # txt文件所在的文件夹voc2txt()
2.3、check标注框
import os
import cv2class check_label:def __init__(self, classes:list, label_path:str, img_path:str, result_path:str=None):self.classes = classesself.line_width = 5 #线宽self.rec_color = (0, 0, 255) #颜色self.font_color = (255, 255, 255) #字体颜色self.font = cv2.FONT_HERSHEY_SIMPLEXself.font_size = 5 #字体大小self.font_thickness = 4self.font_x_offset = 0#字体x坐标偏移self.font_y_offset = -15#字体y坐标偏移self.isDrawFontRec = False#是否绘制字体矩形框self.isShowFont = False#是否绘制字体self.isShowConfidence = False#是否绘制置信度self.label_path = label_path # 数据集标注结果文件(yolo格式)self.img_path = img_path # 图像文件self.result_path = result_path # 在图像上画好标注框文件self.label_files = os.listdir(label_path)self.img_files = os.listdir(img_path)#self.label_files.sort(key=lambda x: int(x[:-4]))#self.img_files.sort(key=lambda x: int(x[:-4]))def paint(self, imgName, pos):img = cv2.imread(self.img_path + "/" + imgName)size = img.shapeimgW = size[1]imgH = size[0]# print("pos:", len(pos))for pos_i in pos:# a, x, y, w, h, b = "orange", pos_i[1], pos_i[2], pos_i[3], pos_i[4], pos_i[4]pos_i = pos_i.split(' ')x_center = float(pos_i[1]) * imgW + 1y_center = float(pos_i[2]) * imgH + 1x_min = int(x_center - 0.5 * float(pos_i[3]) * imgW)y_min = int(y_center - 0.5 * float(pos_i[4]) * imgH)x_max = int(x_center + 0.5 * float(pos_i[3]) * imgW)y_max = int(y_center + 0.5 * float(pos_i[4]) * imgH)x = x_miny = y_minw = x_max - x_minh = y_max - y_min# rotate90(imgW, imgH, x_min, y_min, w, h, x_center, y_center)# rotate180(imgW, imgH, x_min, y_min, w, h, x_center, y_center)# rotate270(imgW, imgH, x_min, y_min, w, h, x_center, y_center)# b = float(pos_i[5])b = 0.5if self.isShowConfidence:a = self.classes[int(pos_i[0])]else:a = ""cv2.rectangle(img, (x, y), (x + w, y + h), self.rec_color, self.line_width)if self.isDrawFontRec:cv2.rectangle(img, (x + self.font_x_offset, y + self.font_y_offset), (x + w, y + abs(self.font_y_offset)), self.rec_color,-1)if self.isShowFont:cv2.putText(img, '{} {:.3f}'.format(a, b), (x + self.font_x_offset, y + self.font_y_offset), self.font, self.font_size,self.font_color, self.font_thickness)cv2.imshow("img", img)cv2.waitKey(0)# cv2.imwrite(self.result_path + "/" + imgName, img)def process(self):for label_file, img_file in zip(self.label_files, self.img_files):print(img_file, label_file)if not os.path.isdir(label_file):f = open(self.label_path + "/" + label_file, "r", encoding='utf-8')result = f.read().splitlines()# print(result)self.paint(img_file, result)f.close()
classes = ['2-4','3-1','5-2','5-3','6-3','6-4','8-3','11-4','12-3','12-4','13-1','14-1','14-3','14-5','15-1',]
cl = check_label(classes,'./txt','./images')
cl.process()
3、数据集获取
林业害虫数据集下载链接