Boooil's BLOG.

植物病虫害识别系统开发手记Vol_1

2021/01/30 Share

数据预处理


  • 数据集

    ​ 本数据集来自AI Challenger2018农作物检测比赛所用数据集,官方前后总共发布了两次比赛数据集.第一次数据集有很多图像存在标签交叉的情况(即相同的图像存在不同的标签,特别是病害程度一般和严重存在交叉情况),训练图像总数为32768张,验证图像总数为4992张,测试集A图像总数为4959张;因为比赛社区很多人反馈数据交叉的现象,官方在比赛的又发布了第二次比赛数据,第二次发布的数据是对存在标签交叉部分的进行更新,训练图像总数为31718张,验证图像总数为4540张。

    ​ 用于训练的数据集为第二个版本。

  • 数据可视化

    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
    import os
    import pandas as pd
    import matplotlib.pyplot as plt
    train_path = 'data/data17627/AgriculturalDisease_trainingset/images'
    valid_path = "data/data17627/AgriculturalDisease_validationset/images"
    train_list = os.listdir(train_path)
    valid_list = os.listdir(valid_path)
    print('AgriculturalDisease_trainingset:',len(train_list))
    print('AgriculturalDisease_validationset:',len(valid_list))

    train_json_path = 'data/data17627/AgriculturalDisease_trainingset/AgriculturalDisease_train_annotations.json'
    valid_json_path = 'data/data17627/AgriculturalDisease_validationset/AgriculturalDisease_validation_annotations.json'
    # train_json_path = 'work/data/train_no_44_45_9_24.json'
    # valid_json_path = 'work/data/valid_no_44_45_9_24.json'
    with open(train_json_path,encoding='utf-8') as datafile1:
    train_label_df = pd.read_json(datafile1,orient='records')
    with open(valid_json_path,encoding='utf-8') as datafile2:
    valid_label_df = pd.read_json(datafile2,orient='records')
    # 查看有没有缺失值
    print(train_label_df.isnull().sum())
    print(valid_label_df.isnull().sum())

    plt.figure(figsize=(12, 8))
    plt.subplot(2, 1, 1)
    train_label_df['disease_class'].value_counts().plot(kind='bar',grid=True,rot = 45,alpha = 0.8,title = 'trainset_label_distribute',legend = True )
    plt.subplot(2, 1, 2)
    valid_label_df['disease_class'].value_counts().plot(kind='bar',grid=True,rot = 45,alpha = 0.8,title = 'validationset_label_distribute')
    # 查看各类样本总数
    train_label_df['disease_class'].value_counts().sort_index()

    ​ 进行可视化后,得到结果

​ 其中横坐标为作物的病种类,纵坐标为数量。

  • 数据剔除

    ​ 通过可视化我们发现,44和45类型的图片数量很少,接近于没有,为了让结果准确率更高,我们可以将这两类剔除。

    ​ 原理很简单,44之前的disease_label不用动,45之后的disease_label减2即可。

    1
    2
    3
    4
    5
    6
    with codecs.open(train_file) as flist:
    lines = json.load(flist)
    new_list = [i for i in lines if i['disease_class'] not in [44,45]]
    for i in range(len(new_list)):
    if(new_list[i]['disease_class'] >43 ):
    new_list[i]['disease_class'] -= 2
  • 对图片的操作

    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
    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
    def resize_img(img, target_size):
    """
    强制缩放图片
    :param img:
    :param target_size:
    :return:
    """
    target_size = input_size
    img = img.resize((target_size[1], target_size[2]), Image.BILINEAR)
    return img


    def random_crop(img, scale=[0.08, 1.0], ratio=[3. / 4., 4. / 3.]):
    aspect_ratio = math.sqrt(np.random.uniform(*ratio))
    w = 1. * aspect_ratio
    h = 1. / aspect_ratio

    bound = min((float(img.size[0]) / img.size[1]) / (w**2),
    (float(img.size[1]) / img.size[0]) / (h**2))
    scale_max = min(scale[1], bound)
    scale_min = min(scale[0], bound)

    target_area = img.size[0] * img.size[1] * np.random.uniform(scale_min,
    scale_max)
    target_size = math.sqrt(target_area)
    w = int(target_size * w)
    h = int(target_size * h)

    i = np.random.randint(0, img.size[0] - w + 1)
    j = np.random.randint(0, img.size[1] - h + 1)

    img = img.crop((i, j, i + w, j + h))
    img = img.resize((train_parameters['input_size'][1], train_parameters['input_size'][2]), Image.BILINEAR)
    return img


    def rotate_image(img):
    """
    图像增强,增加随机旋转角度
    """
    angle = np.random.randint(-14, 15)
    img = img.rotate(angle)
    return img


    def random_brightness(img):
    """
    图像增强,亮度调整
    :param img:
    :return:
    """
    prob = np.random.uniform(0, 1)
    if prob < train_parameters['image_enhance_strategy']['brightness_prob']:
    brightness_delta = train_parameters['image_enhance_strategy']['brightness_delta']
    delta = np.random.uniform(-brightness_delta, brightness_delta) + 1
    img = ImageEnhance.Brightness(img).enhance(delta)
    return img


    def random_contrast(img):
    """
    图像增强,对比度调整
    :param img:
    :return:
    """
    prob = np.random.uniform(0, 1)
    if prob < train_parameters['image_enhance_strategy']['contrast_prob']:
    contrast_delta = train_parameters['image_enhance_strategy']['contrast_delta']
    delta = np.random.uniform(-contrast_delta, contrast_delta) + 1
    img = ImageEnhance.Contrast(img).enhance(delta)
    return img


    def random_saturation(img):
    """
    图像增强,饱和度调整
    :param img:
    :return:
    """
    prob = np.random.uniform(0, 1)
    if prob < train_parameters['image_enhance_strategy']['saturation_prob']:
    saturation_delta = train_parameters['image_enhance_strategy']['saturation_delta']
    delta = np.random.uniform(-saturation_delta, saturation_delta) + 1
    img = ImageEnhance.Color(img).enhance(delta)
    return img


    def random_hue(img):
    """
    图像增强,色度调整
    :param img:
    :return:
    """
    prob = np.random.uniform(0, 1)
    if prob < train_parameters['image_enhance_strategy']['hue_prob']:
    hue_delta = train_parameters['image_enhance_strategy']['hue_delta']
    delta = np.random.uniform(-hue_delta, hue_delta)
    img_hsv = np.array(img.convert('HSV'))
    img_hsv[:, :, 0] = img_hsv[:, :, 0] + delta
    img = Image.fromarray(img_hsv, mode='HSV').convert('RGB')
    return img


    def distort_color(img):
    """
    概率的图像增强
    :param img:
    :return:
    """
    prob = np.random.uniform(0, 1)
    # Apply different distort order
    if prob < 0.35:
    img = random_brightness(img)
    img = random_contrast(img)
    img = random_saturation(img)
    img = random_hue(img)
    elif prob < 0.7:
    img = random_brightness(img)
    img = random_saturation(img)
    img = random_hue(img)
    img = random_contrast(img)
    return img

    ​ 一些常规的对图象进行的预处理,为了之后的训练得到较好的效果。