有关海华AI比赛5

05.1.Read annotations from JSON file

Import packages

1
2
3
4
5
6
7
8
9
10
# -*- coding: UTF-8 -*- 
# import packages
%matplotlib inline
import numpy as np
import cv2
import matplotlib
import matplotlib.pyplot as plt
import json
import csv
import random

Open JSON file

1
2
with open('./dataset/resizedFullGarbageDataset/train.json', 'r', encoding='utf-8') as f:
train_labels = json.load(f) #read the file

Observe the data format

1
train_labels #observe the types of the data
1
2
3
4
5
6
7
8
9
10
11
out:{'info': None,
'lincenses': None,
'images': [{'file_name': 'images_withoutrect/11003.png',
'height': 1080,
'width': 1920,
'image_id': 11003},
{'file_name': 'images_withoutrect/11004.png',
'height': 1080,
'width': 1920,
'image_id': 11004},
......
1
2
type(train_labels) #find the tye of the labels
#out:dict
1
2
train_labels.keys()
#out:dict_keys(['info', 'lincenses', 'images', 'type', 'annotations', 'categories'])

Read categories

1
train_labels['categories'] #print the categories
1
2
3
4
5
6
7
out:[{'id': 1, 'name': '瓜子壳'},
{'id': 2, 'name': '核桃'},
{'id': 3, 'name': '花生壳'},
{'id': 4, 'name': '毛豆壳'},
{'id': 5, 'name': '西瓜子'},
{'id': 6, 'name': '枣核'},
......
1
2
type(train_labels['categories'])
#out:list
1
2
train_labels['categories'][0]#choose the first one
#out:{'id': 1, 'name': '瓜子壳'}

Convert to list in order to use easier. (Attention: id begins at 1, while the index of list begins at 0)

1
2
3
4
names = []
for label in train_labels['categories']:
names.append(label['name'])
print(names) #put the categories into a list and show it

#out:[‘瓜子壳’, ‘核桃’, ‘花生壳’, ‘毛豆壳’, ‘西瓜子’, ‘枣核’, ‘话梅核’, ‘苹果皮’, ‘柿子皮’, ‘西瓜皮’, ‘香蕉皮’, ‘柚子皮’, ‘荔枝壳’, ‘芒果皮’, ‘苹果核’, ‘干果’, ‘桔子皮’, ‘饼干’, ‘面包’, ‘糖果’, ‘宠物饲料’, ‘风干食品’, ‘蜜饯’, ‘肉干’, ‘冲泡饮料粉’, ‘奶酪’, ‘罐头’, ‘糕饼’, ‘薯片’, ‘树叶’, ‘杂草’, ‘绿植’, ‘鲜花’, ‘豆类’, ‘动物内脏’, ‘绿豆饭’, ‘谷类及加工物’, ‘贝类去硬壳’, ‘虾’, ‘面食’, ‘肉类’, ‘五谷杂粮’, ‘排骨-小肋排’, ‘鸡’, ‘鸡骨头’, ‘螺蛳’, ‘鸭’, ‘鱼’, ‘菜根’, ‘菜叶’, ‘菌菇类’, ‘鱼鳞’, ‘调料’, ‘茶叶渣’, ‘咖啡渣’, ‘粽子’, ‘动物蹄’, ‘小龙虾’, ‘蟹壳’, ‘酱料’, ‘鱼骨头’, ‘蛋壳’, ‘中药材’, ‘中药渣’, ‘镜子’, ‘玻璃制品’, ‘窗玻璃’, ‘碎玻璃片’, ‘化妆品玻璃瓶’, ‘食品及日用品玻璃瓶罐’, ‘保温杯’, ‘玻璃杯’, ‘图书期刊’, ‘报纸’, ‘食品外包装盒’, ‘鞋盒’, ‘利乐包’, ‘广告单’, ‘打印纸’, ‘购物纸袋’, ‘日历’, ‘快递纸袋’, ‘信封’, ‘烟盒’, ‘易拉罐’, ‘金属制品’, ‘吸铁石’, ‘铝制品’, ‘金属瓶罐’, ‘金属工具’, ‘罐头盒’, ‘勺子’, ‘菜刀’, ‘叉子’, ‘锅’, ‘金属筷子’, ‘数据线’, ‘塑料玩具’, ‘矿泉水瓶’, ‘塑料泡沫’, ‘塑料包装’, ‘硬塑料’, ‘一次性塑料餐盒餐具’, ‘电线’, ‘塑料衣架’, ‘密胺餐具’, ‘亚克力板’, ‘PVC管’, ‘插座’, ‘化妆品塑料瓶’, ‘篮球’, ‘足球’, ‘KT板’, ‘食品塑料盒’, ‘食用油桶’, ‘塑料杯’, ‘塑料盆’, ‘一次性餐盒’, ‘废弃衣服’, ‘鞋’, ‘碎布’, ‘书包’, ‘床上用品’, ‘棉被’, ‘丝绸手绢’, ‘枕头’, ‘毛绒玩具’, ‘皮带’, ‘电路板’, ‘充电宝’, ‘木制品’, ‘优盘’, ‘灯管灯泡’, ‘节能灯’, ‘二极管’, ‘纽扣电池’, ‘手机电池’, ‘镍镉电池’, ‘锂电池’, ‘蓄电池’, ‘胶卷’, ‘照片’, ‘指甲油瓶’, ‘X光片’, ‘农药瓶’, ‘杀虫剂及罐’, ‘蜡烛’, ‘墨盒’, ‘染发剂壳’, ‘消毒液瓶’, ‘油漆桶’, ‘药品包装’, ‘药瓶’, ‘废弃针管’, ‘输液管’, ‘口服液瓶’, ‘眼药水瓶’, ‘水银温度计’, ‘水银血压计’, ‘胶囊’, ‘药片’, ‘固体杀虫剂’, ‘甘蔗皮’, ‘坚果壳’, ‘橡皮泥’, ‘毛发’, ‘棉签’, ‘创可贴’, ‘口红’, ‘笔’, ‘纸巾’, ‘胶带’, ‘湿巾’, ‘水彩笔’, ‘打火机’, ‘防碎气泡膜’, ‘榴莲壳’, ‘睫毛膏’, ‘眼影’, ‘仓鼠浴沙’, ‘大骨棒’, ‘旧毛巾’, ‘竹制品’, ‘粉笔’, ‘一次性口罩’, ‘一次性手套’, ‘粉底液’, ‘灰土’, ‘尼龙制品’, ‘尿片’, ‘雨伞’, ‘带胶制品’, ‘牙膏皮’, ‘狗尿布’, ‘椰子壳’, ‘粉扑’, ‘破碗碟’, ‘陶瓷’, ‘卫生纸’, ‘烟头’, ‘假睫毛’, ‘猫砂’, ‘牙刷’, ‘玉米棒’]

Read annotations

1
train_labels['annotations']
1
2
3
4
5
6
7
8
9
10
11
out:[{'area': 81909.20209190401,
'iscrowd': 0,
'image_id': 11003,
'bbox': [636.08832, 305.77176, 298.5888, 274.32108000000005],
'category_id': 2},
{'area': 105273.393928704,
'iscrowd': 0,
'image_id': 11004,
'bbox': [804.4512, 420.56064, 306.46848, 343.5048],
'category_id': 2},
......
1
2
type(train_labels['annotations'])
#out:list

As an example, let’s load an image and its annotation.

1
2
3
4
5
6
7
8
9
10
11
12
13
n = random.randint(1, len(train_labels['annotations'])) # select the random n-th image as example

image_id = train_labels['annotations'][n]['image_id']
category_id = train_labels['annotations'][n]['category_id']
category_name = names[category_id - 1] # ←look here

image = cv2.imread('./dataset/resizedFullGarbageDataset/train_resized/' + str(image_id) + '.jpg') #load the pictures

plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)) #use cv2 to show the picture
print("Index:%d\nFilename:%d.jpg\nCategory:%d-%s"%(n, image_id, category_id, category_name)) #\n means changing to another row
#out:Index:47056
# Filename:265768.jpg
# Category:122-书包

8If1PA.png

Observe the distribution of classes.

1
2
3
4
5
6
7
image_ids = []
category_ids = []
category_names = []
for label in train_labels['annotations']:
image_ids.append(label['image_id']) #add pictures to the list
category_ids.append(label['category_id']) #add category
category_names.append(names[label['category_id'] - 1])
1
2
3
4
5
plt.figure(figsize=(10, 6))
plt.hist(category_ids, bins=len(names), density=0)
plt.xlim(1, 204)
plt.xlabel("category_id")
plt.ylabel("number");

8IfBPs.png

Convert annotations into CSV format

1
2
3
4
with open('./dataset/resizedFullGarbageDataset/train.csv','w') as f:
f.write("id,label,name,filename\n")
for i in range(len(image_ids)):
f.write("%s,%s,%s,%s.jpg\n"%(str(image_ids[i]), str(category_ids[i]), names[category_ids[i]-1], str(image_ids[i])))

05.2.Train a garbage classifier

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from __future__ import absolute_import, division, print_function, unicode_literals

# TensorFlow and tf.keras
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import backend as K
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.callbacks import LearningRateScheduler

# Helper libraries
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
import random
import pandas as pd # ← a new package is needed to be install, use > conda install pandas
import cv2

print(tf.__version__)

Import dataset and preprocessing

Because our dataset is a bit large, RAM may not be enough to directly load all images. We can use flow_from_dataframe to load our dataset. (click here to read more about this function)
First, load labels from our .csv file. We use pandas.read_csv, it loads csv file to DataFrame format.

1
2
df=pd.read_csv("./dataset/resizedFullGarbageDataset/train.csv", encoding='gbk', dtype=str)
df
id label name filename
0 11003 2 核桃 11003.jpg
1 11004 2 核桃 11004.jpg
2 11005 2 核桃 11005.jpg
3 11006 2 核桃 11006.jpg
…… …… …… ……

Then, use keras.preprocessing.image.ImageDataGenerator to load trainset.
‘catagories’ in the JSON file says, the dataset contains 202 classes, but actually it has only 198 classes. To avoid confusing df['label'] with index of classifier output, we use df['name'] as input.
75% of images are set as trainset, while 25% of images are set as testset.

1
2
3
4
5
6
7
8
9
10
11
12
batch_size = 32
sizeX, sizeY = 112, 112

datagen=ImageDataGenerator(rescale=1./255, validation_split=0.25)
#trainset:
trainset = datagen.flow_from_dataframe(dataframe=df, directory='./dataset/resizedFullGarbageDataset/train_resized', #the position of file
x_col='filename', y_col='name', class_mode='categorical', target_size=(sizeX,sizeY),
batch_size=batch_size, shuffle=True, seed=0Xabc123, subset='training')
#testset:
testset = datagen.flow_from_dataframe(dataframe=df, directory='./dataset/resizedFullGarbageDataset/train_resized',
x_col='filename', y_col='name', class_mode='categorical', target_size=(sizeX,sizeY),
batch_size=batch_size, shuffle=True, seed=0Xabc123, subset='validation')

Correspondingly, we can use .class_indices to see the relationship between name and index before one-hot encoding.

1
2
names = trainset.class_indices
names
1
2
3
4
5
6
7
{'KT板': 0,
'PVC管': 1,
'X光片': 2,
'一次性口罩': 3,
'一次性塑料餐盒餐具': 4,
'一次性手套': 5,
......

We can define a function to get name through index.

1
2
def getname(index):
return list(names)[index]

trainset[i] has two parts. trainset[i][0] is the i-th batch of image, while trainset[i][1] is one-hot encodings which represents classes.

1
2
3
4
5
6
7
plt.figure(figsize=(16,6))
n = random.randint(0,1874)
for i in range(4):
plt.subplot(1,4,i+1)
plt.imshow(trainset[n][0][i]) #plot the pictures
index = np.argmax(trainset[n][1][i])
plt.xlabel(str(index) + ':' + getname(index)) #show the category

87h9DP.png

Describe our model

As an example, we describe the following model.
(This example may not have good performance.)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
input_shape = (sizeX, sizeY, 3)

model = keras.Sequential([
keras.layers.Conv2D(16, kernel_size=(5, 5),
activation='relu',
input_shape=input_shape),
keras.layers.MaxPooling2D(pool_size=(2, 2)),
keras.layers.Conv2D(32, kernel_size=(5, 5), activation='relu'),
keras.layers.MaxPooling2D(pool_size=(2, 2)),
keras.layers.Flatten(),
keras.layers.Dense(120, activation='relu'),
keras.layers.Dense(84, activation='relu'),
keras.layers.Dense(198, activation='softmax')
])


model.compile(loss=keras.losses.categorical_crossentropy,
optimizer=keras.optimizers.Adam(),
metrics=["accuracy"])

Start learning

Because the dataset is large, it may take a very long time.

1
2
3
4
5
6
7
8
9
10
STEP_SIZE_TRAIN=trainset.n//trainset.batch_size
STEP_SIZE_VALID=testset.n//testset.batch_size
print(STEP_SIZE_TRAIN, STEP_SIZE_VALID)

model.fit_generator(generator=trainset,
steps_per_epoch=STEP_SIZE_TRAIN,
validation_data=testset,
validation_steps=STEP_SIZE_VALID,
epochs=1
)

Evaluate the model

1
model.evaluate_generator(testset,verbose=1) #predict

Save the trained model

1
2
modelname = 'garbageExample0'
model.save('./TrainedModels/' + modelname + '.h5')#create the file and save it

05.3.Make prediction on validationset

from future import absolute_import, division, print_function, unicode_literals

TensorFlow and tf.keras

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import backend as K
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.callbacks import LearningRateScheduler
from tensorflow.keras.preprocessing import image

Helper libraries

1
2
3
4
5
6
7
8
9
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
import random
import pandas as pd # ← a new package is needed to be install, use > conda install pandas
import cv2
import os
import json

Load trained model

1
2
modelname = 'garbageExample0'
model = keras.models.load_model('./trainedModels/' + modelname + '.h5')

Import validationset

1
2
3
4
valiset_path = './dataset/resizedFullGarbageDataset/val_resized'
valiset_filenames = os.listdir(valiset_path)
len(valiset_filenames)
#out:10000

Define getname() function

The names is in the order generated by flow_from_dataframe before training.

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
names = {'KT板': 0, 'PVC管': 1, 'X光片': 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,
'报纸': 61, '指甲油瓶': 62, '排骨-小肋排': 63, '插座': 64, '数据线': 65,
'日历': 66, '旧毛巾': 67, '易拉罐': 68, '木制品': 69, '杀虫剂及罐': 70,
'杂草': 71, '枕头': 72, '枣核': 73, '染发剂壳': 74, '柚子皮': 75,
'柿子皮': 76, '树叶': 77, '核桃': 78, '桔子皮': 79, '棉签': 80,
'棉被': 81, '椰子壳': 82, '榴莲壳': 83, '橡皮泥': 84, '毛发': 85,
'毛绒玩具': 86, '毛豆壳': 87, '水银温度计': 88, '水银血压计': 89, '油漆桶': 90,
'消毒液瓶': 91, '湿巾': 92, '灯管灯泡': 93, '灰土': 94, '烟头': 95,
'烟盒': 96, '照片': 97, '牙刷': 98, '牙膏皮': 99, '狗尿布': 100,
'猫砂': 101, '玉米棒': 102, '玻璃制品': 103, '玻璃杯': 104, '瓜子壳': 105,
'甘蔗皮': 106, '电线': 107, '电路板': 108, '皮带': 109, '眼影': 110,
'眼药水瓶': 111, '睫毛膏': 112, '矿泉水瓶': 113, '破碗碟': 114, '硬塑料': 115,
'碎玻璃片': 116, '窗玻璃': 117, '竹制品': 118, '笔': 119, '篮球': 120,
'粉底液': 121, '粉扑': 122, '粉笔': 123, '粽子': 124, '糕饼': 125,
'糖果': 126, '纸巾': 127, '纽扣电池': 128, '绿植': 129, '罐头': 130,
'罐头盒': 131, '肉干': 132, '肉类': 133, '胶卷': 134, '胶囊': 135,
'胶带': 136, '节能灯': 137, '芒果皮': 138, '花生壳': 139, '苹果核': 140,
'苹果皮': 141, '茶叶渣': 142, '荔枝壳': 143, '药品包装': 144, '药片': 145,
'药瓶': 146, '菌菇类': 147, '菜刀': 148, '菜叶': 149, '菜根': 150,
'蓄电池': 151, '薯片': 152, '虾': 153, '蛋壳': 154, '蜜饯': 155,
'螺蛳': 156, '蟹壳': 157, '西瓜子': 158, '西瓜皮': 159, '话梅核': 160,
'调料': 161, '谷类及加工物': 162, '豆类': 163, '贝类去硬壳': 164, '购物纸袋': 165,
'足球': 166, '输液管': 167, '酱料': 168, '金属制品': 169, '金属工具': 170,
'金属瓶罐': 171, '铝制品': 172, '锂电池': 173, '锅': 174, '镍镉电池': 175,
'镜子': 176, '防碎气泡膜': 177, '陶瓷': 178, '雨伞': 179, '面包': 180,
'面食': 181, '鞋': 182, '鞋盒': 183, '风干食品': 184, '食品及日用品玻璃瓶罐': 185,
'食品塑料盒': 186, '食品外包装盒': 187, '食用油桶': 188, '饼干': 189, '香蕉皮': 190,
'鱼': 191, '鱼骨头': 192, '鱼鳞': 193, '鲜花': 194, '鸡': 195,
'鸡骨头': 196, '鸭': 197}
def getname(index):
return list(names)[index]

Define get_category_id() function

1
2
3
4
5
6
7
8
with open('./dataset/resizedFullGarbageDataset/train.json', 'r', encoding='utf-8') as f:
train_labels = json.load(f)
names_dict = {}
for label in train_labels['categories']:
names_dict.update({label['name'] : label['id']})

def get_category_id(name):
return names_dict[name]

Make prediction and post process

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
results_name = []
results_label = [] # category_id

for i in range(len(valiset_filenames)):
image_path = valiset_path + '/' + valiset_filenames[i]
img = image.load_img(image_path, target_size=(112, 112))
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0) /255

pred = model.predict(x)

index = np.argmax(pred)
result_name = getname(index)
result_label = get_category_id(result_name)

results_name.append(result_name)
results_label.append(result_label)

if((i+1) % 100 == 0):
print("finished %d predictions"%(i+1)) #to show the process

Observe random 20 images

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
randNums = random.sample(range(0, len(valiset_filenames)), 20)
plt.figure(figsize=(20,18))
for i in range(0,20):
filename = valiset_filenames[randNums[i]]
image_path = valiset_path + '/' + filename
img = image.load_img(image_path, target_size=(112, 112))
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0) /255
pred = model.predict(x)
index = np.argmax(pred)
result_name = getname(index)
result_label = get_category_id(result_name)

plt.subplot(4,5,i+1)
plt.imshow(x[0])
plt.title(filename)
plt.xlabel("Prediction: %d-%s"%(result_label, result_name))

87OS7d.png

Save results

1
2
3
4
5
6
resultName = 'test0'
with open('./PredictResults/' + resultName + '.csv','w') as f:
f.write("id,label\n")
for i in range(len(valiset_filenames)):
vali_id = str(valiset_filenames[i]).replace('.jpg','')
f.write("%s,%s\n"%(vali_id, str(results_label[i])))