首页 > 其他分享 >机器学习——植物叶片病害识别

机器学习——植物叶片病害识别

时间:2022-12-21 14:25:33浏览次数:72  
标签:img 叶片 image train dir path 识别 os 病害

机器学习——植物叶片病害识别

一、选题背景

  随着现代科技的发展,人们对于人工智能领域的研究越发的深入。机器学习作为人工智能和识别领域研究的重要课题非常值得我们学习和研究。
  本次机器学习设计为植物叶片病害识别,随着社会发展,在农业、林业方面机械化、智能化程度不断的提高。在林业管理上的要求追求便捷,有效,打药除害等都可以通过无人机实现。基于机器学习的植物叶片病害识别,可以通过识别无人机拍下来的树木叶片图片,快速得出该树的健康状态,是正常的,还是患病的以及患的是哪种病。通过机器学习,对正常和患病叶片的训练学习来完成识别以及提高准确度。
  通过无人机定位巡航拍照,快速收集林区的树木叶片情况,在识别完图片输出结果。通过结果可以很明确的知道哪个区的那棵树患病。在这过程中节省了大量的人力,物力,以及聘请相关植物病理学家的费用,降低成本,对于林业的发展具有重要的意义。

 二、设计方案

  本次机器学习设计具体方案,通过网上收集数据集,对数据集进行处理,数据集符合我们所使用的格式。在数据集中的文件打上标签,在对数据进行预处理,之后采用keras框架搭建、使用卷积神经网络构建以及训练模型、通过训练和验证准确性以及训练和验证损失图进行分析、最后导入测试图片进行测试并保存测试图片名称以及识别结果为一个csv数据文件。
  本次涉及的技术难点,如何将数据集中大量的数据处理成我们所需要的格式,如何提高图片的识别准确度也是一大难点。对于处理数据,可以采用编写程序,通过数据集自带的csv数据文件进行数据处理。而图片识别准确度可以通过图片的大小,添加卷积层数、对数据进行二次筛选、增加训练次数来提升图片识别的精度。

数据集来源:kaggle:https://www.kaggle.com/competitions/plant-pathology-2021-fgvc8/data
kaggle:https://www.kaggle.com/competitions/plant-pathology-2020-fgvc7/data
参考案例:kaggle讨论区,猫狗识别案例,手写字体识别等。

 三、实现步骤

植物叶片病害识别的具体实现步骤如下。

1  获取数据集

从kaggle上下载数据集,解压打开。



2  数据集的分析处理

  刚获取的数据集主要由一个图片文件夹以及三个csv文件组成,通过编写程序,使用train.csv文件对images文件夹中的文件进行处理,使数据格式符合本次设计使用。

  导入相应的库,读取数据文件,将数据文件用pandas导入,转换为DataFrame格式,打印数据查看。

import pandas as pd
from PIL import  Image
import os
import shutil
import tqdm
import matplotlib.pyplot as plt
# 传入数据路径
data_csv_path = './train.csv'                           #分类的数据
images_path = './images'                                # 原图片路径
create_image_path= './data_new'                  #文件夹的相对路径文件夹会在同级目录下创建
val_num=0.2      # 从train数据集中分出x%的数据到val中

train_data = pd.read_csv(data_csv_path)             # 将train数据用pandas导入
train_data = pd.DataFrame(train_data)               # 将数据转换成DataFrame格式
# 查看数据train.csv  1821行*5列
print(train_data)  



根据数据,创建数据文件夹,将整理好的图片分为3个类别,分别是训练集train、测试集test、验证集val与其对应的标签保存起来。
# 创建数据文件夹 后面要把整理好的图片分成train test val 与其对应的标签保存起来
fill_if=os.path.exists(create_image_path + '/train_images')
#print("检查是否存在文件夹")
if fill_if ==False:                                         # 判断文件夹是否存在,存在则跳过不存在则创建
    os.mkdir(create_image_path + '/train_images')                        # 创建一个名为data_images的文件夹
    print('创建成功')# 判断是否创建成功

# 遍历图片的名称并保存为列表格式
list_image_id = []                                      # 创建image_name的列表
for i in train_data['image_id']:                           # 遍历image_id
    list_image_id.append(i)                                 # 将image_id保存到列表里
    
print(list_image_id)



遍历所有标签于其对应的数据,并建立name与label对应的字典,并将数据保存到对应的文件夹。

for s in train_data.columns[1:]:                        # 遍历标签:  s 是对应的标签
    # print(s)
    # 创建标签对应的文件夹
    fill_if_2 = os.path.exists(create_image_path + '/train_images' + '/' + s)  # 判断文件夹是否存在
    if fill_if_2 == False:  # 判断如果文件夹存在则跳过 不存在则创建
        mak_file=os.mkdir(create_image_path + '/train_images' + '/' + s)  # 创建标签文件夹
    list_image_label = []                                   # 创建label的空列表

    for i in train_data[s]:                             # 遍历标每一个标签里的对应数据
        list_image_label.append(i)                      # 将数据添加到列表里
    # print(list_image_label)
    dic_name_health=dict(zip(list_image_id,list_image_label))  # 创建image对应label的字典  格式为{'name':label,}
    # print(dic_name_health)
    for i,j in dic_name_health.items():                 # 遍历字典并返回 i=name , j = 标签的值
        # print(i,j)
        if j == 1:                                     # 判断数据的标签为  1    i 为标签对应的name
            # print(i,j)
            img_name=i+'.jpg'
            # print(img_name)
            # 将数据保存到对应的文件夹
            img = Image.open(images_path+'/'+img_name)
            img.save(create_image_path + '/train_images' + '/' + s + '/' + img_name)

对测试集数据提取,提取过程判断文件夹存在则跳过,不存在则创建,再保存起来。

# 测试集数据提取
fill_if_test = os.path.exists(create_image_path+'/test_images')               # 判断文件夹是否存在
if fill_if_test == False:                                    # 判断如果文件夹存在则跳过 不存在则创建
    print(fill_if_test)
    mak_file=os.mkdir(create_image_path+'/test_images')                  # 创建标签文件夹
for i in os.listdir(images_path):                               # 遍历images文件夹下的数据
    if i[:4] == 'Test':                                         # 判断数据前4个字符是否为Test,将test的数据保存起来
        # 将数据保存到对应的文件夹
        img = Image.open(images_path+'/'+i)
        img.save(create_image_path+'/test_images'+'/'+i)

将数据中的部分数据划分到验证集中。
import os
import shutil
import tqdm
val_num=0.2      # 从train数据集中分出x%的数据到val中
create_val_image_path='./data_new'
img='./data_new/train_images/'

fill_if_2 = os.path.exists(create_val_image_path + '/' + 'val_images')  # 判断文件夹是否存在
if fill_if_2 == False:  # 判断如果文件夹存在则跳过 不存在则创建
    mak_file = os.mkdir(create_val_image_path + '/' + 'val_images')  # 创建标签文件夹

img_label_list=os.listdir(img)
for i in img_label_list:
    fill_if_2 = os.path.exists(create_val_image_path + '/' + 'val_images'+'/'+i)  # 判断文件夹是否存在
    if fill_if_2 == False:  # 判断如果文件夹存在则跳过 不存在则创建
        mak_file = os.mkdir(create_val_image_path + '/' + 'val_images'+'/'+i)  # 创建标签文件夹
    img_path=img+i
    img_list=os.listdir(img_path)
    # print(img_list)
    val_=int(len(img_list)*val_num)
    for j in tqdm.tqdm(range(val_)):
        shutil.move(img+i+'/'+img_list[0],create_val_image_path+ '/' + 'val_images'+'/'+i)
        img_list.remove(img_list[0])



3  构建神经模型

导入需要用到的库。
import os
import tensorflow as tf
from tensorflow.keras.optimizers import Adam
from keras_preprocessing.image import ImageDataGenerator
import matplotlib.pyplot as plt

对数据路径进行定义,查看数据类别。

base_dir = './data_new'  # 存放所有数据的位置
train_dir = os.path.join(base_dir, 'train_images')  # 指定训练数据的位置
print(os.listdir(train_dir))              # 查看数据类别
validation_dir = os.path.join(base_dir, 'val_images')  # 指定验证数据的位置



读取测试集中的一条数据,查看样本。
from keras.preprocessing import image
img_path = "./data_new/train_images/rust/Train_1624.jpg"
import numpy as np
img = image.load_img(img_path, target_size=(224,224))
img_tensor = image.img_to_array(img)
img_tensor = np.expand_dims(img_tensor, axis=0)
img_tensor /= 255.
#显示样本
import matplotlib.pyplot as plt
plt.imshow(img_tensor[0])
plt.show()



输出特征图,每行显示16个特征图。
#存储层的名称
layer_names = []
for layer in model.layers[:4]:
    layer_names.append(layer.name)
# 每行显示16个特征图
images_pre_row = 16  #每行显示的特征图数
# 循环8次显示8层的全部特征图
for layer_name, layer_activation in zip(layer_names, activations):
    n_features = layer_activation.shape[-1] #保存当前层的特征图个数
    size = layer_activation.shape[1]  #保存当前层特征图的宽高
    n_col = n_features // images_pre_row #计算当前层显示多少行
    #生成显示图像的矩阵
    display_grid = np.zeros((size*n_col, images_pre_row*size))
    #遍历将每个特张图的数据写入到显示图像的矩阵中
    for col in range(n_col):
        for row in range(images_pre_row):
            #保存该张特征图的矩阵(size,size,1)
            channel_image = layer_activation[0,:,:,col*images_pre_row+row]
            #为使图像显示更鲜明,作一些特征处理
            channel_image -= channel_image.mean()
            channel_image /= channel_image.std()
            channel_image *= 64
            channel_image += 128
            #把该特征图矩阵中不在0-255的元素值修改至0-255
            channel_image = np.clip(channel_image, 0, 255).astype("uint8")
            #该特征图矩阵填充至显示图像的矩阵中
            display_grid[col*size:(col+1)*size, row*size:(row+1)*size] = channel_image
    
    
    scale = 1./size
    #设置该层显示图像的宽高
    plt.figure(figsize=(scale*display_grid.shape[1],scale*display_grid.shape[0]))
    plt.title(layer_name)
    plt.grid(False)
    #显示图像
    plt.imshow(display_grid, aspect="auto", cmap="viridis")
plt.show()

 




神经模型参数设置,并查看本次数据大小。
model_name = 'model_224_150.h5'  # 给模型命名以 h5为后缀
class_num = 4  # 类别的个数
epoch = 150  # 训练的轮数
batch = 20  # 批次大小
resize_img = (224, 224)  # 图片送入网络的大小
class_mode = 'sparse'  # 返回的格式:categorical是返回2D的one-hot编码标签,binary是返回1D的二值标签,sparse返回1D的整数标签,None不反回任何标签仅仅生成数据
activation = 'softmax'  # 激活函数设置
loss = 'sparse_categorical_crossentropy'
train_epoch_batch = 100  # 从train迭代器中拿出来数据测次数  这个需要计算的
val_epoch_batch = 50  # 从val迭代器中拿出来数据测次数  这个需要计算的

# # 训练集 得到数据存放的文件夹
train_healthy_dir =os.path.join(train_dir,'healthy')
train_multiple_diseases_dir = os.path.join(train_dir,'multiple_diseases')
train_rust_dir =os.path.join(train_dir,'rust')
train_scab_fir = os.path.join(train_dir,'scab')
# # 判断数据集的大小
print('train_healthy_dir:',len(os.listdir(train_healthy_dir)))
print('train_multiple_diseases_dir:',len(os.listdir(train_multiple_diseases_dir)))
print('train_rust_dir:',len(os.listdir(train_rust_dir)))
print('train_scab_fir:',len(os.listdir(train_scab_fir)))
# # 验证集
validation_healthy_dir =os.path.join(validation_dir,'healthy')
validation_multiple_diseases_dir = os.path.join(validation_dir,'multiple_diseases')
validation_rust_dir =os.path.join(validation_dir,'rust')
validation_scab_dir = os.path.join(validation_dir,'scab')
# # 判断数据集的大小
print('validation_healthy_dir:',len(os.listdir(validation_healthy_dir)))
print('validation_multiple_diseases_dir:',len(os.listdir(validation_multiple_diseases_dir)))
print('validation_rust_dir:',len(os.listdir(validation_rust_dir)))
print('validation_scab_dir:',len(os.listdir(validation_scab_dir)))

 




对数据进行预处理。
# 数据预处理对数据进行归一化到【0-1】之间进行数据增强
train_datagen = ImageDataGenerator(rescale=1. / 255,  # 归一化
                                   rotation_range=40,  # 旋转图片
                                   width_shift_range=0.2,  # 改变图片的宽
                                   height_shift_range=0.2,  # 改变图片的高
                                   shear_range=0.2,  # 裁剪图片
                                   zoom_range=0.2,  # 缩放图片大小
                                   horizontal_flip=True,  # 平移图片
                                   fill_mode='nearest'
                                   )
# 测试集处理
test_datagen = ImageDataGenerator(rescale=1. / 255)

# 得到迭代器
train_generator = train_datagen.flow_from_directory(
    train_dir,                # 文件夹路径
    target_size=resize_img,   # 指定resize的大小,需要和神经网络指定的图片大小相同
    batch_size=batch,         # 批次的大小每一次拿出20个数据送入到网络训练
    class_mode=class_mode     # 返回的格式:categorical是返回2D的one-hot编码标签,binary是返回1D的二值标签,sparse返回1D的整数标签,None不反回任何标签仅仅生成数据
)

validation_generator = test_datagen.flow_from_directory(
    validation_dir,
    target_size=resize_img,
    batch_size=batch,
    class_mode=class_mode
)

 



根据CNN模型,开始构建卷积神经模型。
#Output shape计算公式:(输入尺寸-卷积核尺寸/步长+1
#对CNN模型,Param的计算方法如下:
#卷积核长度*卷积核宽度*通道数+1)*卷积核个数
#输出图片尺寸:224-3+1=222
model = tf.keras.models.Sequential([
    # 32个3*3的卷积核        relu激活函数           输入图像的大小
    #32*3*3*3+32=896
    tf.keras.layers.Conv2D(32, (3, 3), activation='relu', input_shape=(224, 224, 3)),
    tf.keras.layers.MaxPooling2D(2, 2),  # 最大池化层 2*2把  h和 w 编程原来的1/2
    
    #64*3*3*32+64=18496
    tf.keras.layers.Conv2D(64, (3, 3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2, 2),
     
    #128*3*3*64+128=73856
    tf.keras.layers.Conv2D(128, (3, 3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2, 2),
    
    #128*3*3*128+128=147584
    tf.keras.layers.Conv2D(128, (3, 3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2, 2),
    
    # 把数据拉平输入全连接层
    tf.keras.layers.Flatten(),
    # 全连接层
    #(18432+1)*512=9437696
    tf.keras.layers.Dense(512, activation='relu'),  # 512 是输出特征大小
    tf.keras.layers.Dropout(0.4),
    #(512+1)*512=262656
    tf.keras.layers.Dense(512, activation='relu'),
    tf.keras.layers.Dropout(0.4),
    # 二分类用sigmoid,1代表得到一个值
    #(512+1)*4=2052
    tf.keras.layers.Dense(class_num, activation=activation)
])
#看一下特征图的维度如何随着每层变化
model.summary()




配置训练器。

# 配置训练器
model.compile(loss=loss,
              optimizer=Adam(lr=0.001),
              metrics=['acc'])

对模型进行训练并保存,为了较高的精准度,本次训练次数为150次。上文参数设置可见。
# 因为fit直接训练不能把所有的数据全部放入到内存钟,所以使用fit_generator相当于一个生成器,动态的把所有的数据以batch的形式放入内存
history = model.fit_generator(
    train_generator,
    steps_per_epoch=train_epoch_batch,  # 这个地方需要计算
    epochs=epoch,                           # 训练轮数
    validation_data=validation_generator,
    validation_steps=val_epoch_batch,  # 这个地方需要计算
#     verbose=2
)
model.save('./models/' + model_name)            # 保存模型




根据训练的结果,绘制训练和验证准确性图,训练和验证损失图。

# # 对准确率与损失进行画图
acc = history.history['acc']
val_acc = history.history['val_acc']
loss = history.history['loss']
val_loss = history.history['val_loss']

epochs = range(len(acc))

plt.plot(epochs, acc, 'o', label='Training accuracy')
plt.plot(epochs, val_acc, 'r', label='Validation accuracy')
plt.title("Training and Validation accuracy")
plt.legend()

plt.figure()

plt.plot(epochs, loss, 'o', label='Training accuracy')
plt.plot(epochs, val_loss, 'r', label='Validation accuracy')
plt.title("Training and Validation loss")
plt.legend()
plt.show()





4  测试模型,输出结果

  载入训练完的模型,取出测试文件夹中的图片,进行测试,可选择测试文件夹中所有的图片,也可以固定测试几张图片。输出图片的测试结果,每种类别的概率,并将测试完的结果保存成csv文件。

import tensorflow as tf
import pandas as pd
import os
import matplotlib.pyplot as plt
import numpy as np
from keras.preprocessing import image
import csv
frame = pd.DataFrame()
# 定义图片路径
img_path = 'data_new/test_images/'  # 图片存放文件夹的路径最后要以“/"结尾
model_name='models/model_224_150.h5'     # 传入模型
img_list = os.listdir(img_path)  # 图片的名字的列表
all_img=len(img_list)
# 数据提取器    这里输入对应的数字可以拿只推理对应数量的图片
img_num = all_img           #这里输入  all_img  可以把说有的图片都送入网络中
class_list = ['healthy', 'multiple_diseases', 'rust', 'scab']  # 数据对应的类别标签
# 加载模型
model = tf.keras.models.load_model(model_name)  # 加载模型到预测文件
# model.summary()  # As a reminder.
# 创建空csv文件
frame.to_csv('predict_result.csv', index=False, sep=',')
with open('predict_result.csv', 'w') as csvfile:
    # 先写入columns_name
    writer = csv.writer(csvfile)
    writer.writerow(['image_id', 'healthy', 'multiple_diseases', 'rust', 'scab'])# 这里出入csv文件的列名
    writer = csv.writer(csvfile)

    for i in img_list[:img_num]:  # 遍历文件夹里的图片
        img = img_path + i  # 得到图片的相对路径
        img_resize = image.load_img(img, target_size=(224, 224))  # 加载图片并resize成(224*224)的格式
        img_array = image.img_to_array(img_resize)  # 转换成数组
        img_tensor = np.expand_dims(img_array, axis=0)
        img_input = img_tensor / 255  # 归一化到0-1之间
        outputs = model.predict(img_input)  # 获取图片信息
        outputs = outputs[0]  # 获取预测得到概率列表
        max_class = max(outputs)  # 获得预测的最大的概率值
#       print(max_class)
        class_dict = dict([i for i in zip(class_list, outputs)])  # 得到标签和预测的概率字典
        
        print("测试结果每个概率为:",class_dict)     #输出全部标签
#         print(outputs, outputs[0], i[:-4])
        print("测试结果概率最高的为:",max_class)
        # 往 csv文件里写入数据
        writer.writerow([f'{i[:-4]}', outputs[0], outputs[1], outputs[2], outputs[3]])

        """--------展示图片--------"""
        # 获取预测概率最大的数据的标签
        for k,v in class_dict.items():                  #遍历标签与概率的字典返回对应的k,v
            if v == max_class:                                  # 判断最大的概率并得到标签
                print("测试叶片结果为:",k)            # 打印最大的概率
                plt.imshow(img_input[0])
                plt.title(f'{k}')
                plt.show()

csvfile.close()  # 关闭csv文件

以下为测试结果,测试出的结果大多接近0.99,输出符合构建模型的预期。输出了每个类别的概率,最高概率为多少,最终模型输出结果是什么病害。




查看识别结果保存的csv文件。



四、总结


结论:从最终结果来看,本次设计的植物叶片病害识别,基本达到了设计初期的预期结果。刚开始,模型因为图片设置为64×64大小的,卷积层不够,识别不准确。经过不断的调整训练模型,最终将64×64调整到224×224大小,卷积层添加了2层,通过长时间训练,准确度得到了良好的提升,并达到预期。为了后面大量的测试,最后添加了将测试结果保存的步骤,这样有利于之后结果的查看以及分析。

收获:经过这次课程设计,深入了解了机器学习的实现步骤。在这过程中,遇到了许许多多的问题,配置环境导致开发软件崩溃,导入的库部分无法使用,版本不匹配,设计的模型训练精准度不够,数据集进行二次添加等等。不过好在通过百度查找相关资料,询问周边的同学朋友这些问题的到了解决。在设计模型之初,看了很多机器学习的案例,比如猫狗大战、森林火灾等等,这些案例为我提供了不少的思路,到外网上看别人对于模型各个方面的讨论,为之后有效提升模型精准度提供了帮助。发现,经过这次设计遇到的大量问题,对于机器学习的理解程度大大加深,通过在不断的错误中改正并获得经验,使知识得到了巩固加强。本次设计的模型还可以进一步扩展,比如多种病害的识别,对于识别图片进行固定规则的重命名等等。这是一段宝贵的程序设计经历,为以后设计相关程序奠定了基础,为课程画上一个完美的句号。

五、设计全部代码

  1 import pandas as pd
  2 from PIL import  Image
  3 import os
  4 import shutil
  5 import tqdm
  6 import matplotlib.pyplot as plt
  7 # 传入数据路径
  8 data_csv_path = './train.csv'                           #分类的数据
  9 images_path = './images'                                # 原图片路径
 10 create_image_path= './data_new'                  #文件夹的相对路径文件夹会在同级目录下创建
 11 val_num=0.2      # 从train数据集中分出x%的数据到val中
 12 
 13 train_data = pd.read_csv(data_csv_path)             # 将train数据用pandas导入
 14 train_data = pd.DataFrame(train_data)               # 将数据转换成DataFrame格式
 15 # 查看数据train.csv  1821行*5列
 16 # print(train_data)  
 17 # 创建数据文件夹 后面要把整理好的图片分成train test val 与其对应的标签保存起来
 18 fill_if=os.path.exists(create_image_path + '/train_images')
 19 print("检查是否存在文件夹")
 20 if fill_if ==False:                                         # 判断文件夹是否存在,存在则跳过不存在则创建
 21     os.mkdir(create_image_path + '/train_images')                        # 创建一个名为data_images的文件夹
 22     print('创建成功')# 判断是否创建成功
 23 
 24 # 遍历图片的名称并保存为列表格式
 25 list_image_id = []                                      # 创建image_name的列表
 26 for i in train_data['image_id']:                           # 遍历image_id
 27     list_image_id.append(i)                                 # 将image_id保存到列表里
 28     
 29 # print(list_image_id)
 30 # 遍历所有标签与其对应的数据并创建name与label对应的字典
 31 for s in train_data.columns[1:]:                        # 遍历标签:  s 是对应的标签
 32     # print(s)
 33     # 创建标签对应的文件夹
 34     fill_if_2 = os.path.exists(create_image_path + '/train_images' + '/' + s)  # 判断文件夹是否存在
 35     if fill_if_2 == False:  # 判断如果文件夹存在则跳过 不存在则创建
 36         mak_file=os.mkdir(create_image_path + '/train_images' + '/' + s)  # 创建标签文件夹
 37     list_image_label = []                                   # 创建label的空列表
 38 
 39     for i in train_data[s]:                             # 遍历标每一个标签里的对应数据
 40         list_image_label.append(i)                      # 将数据添加到列表里
 41     # print(list_image_label)
 42     dic_name_health=dict(zip(list_image_id,list_image_label))  # 创建image对应label的字典  格式为{'name':label,}
 43     # print(dic_name_health)
 44     for i,j in dic_name_health.items():                 # 遍历字典并返回 i=name , j = 标签的值
 45         # print(i,j)
 46         if j == 1:                                     # 判断数据的标签为  1    i 为标签对应的name
 47             # print(i,j)
 48             img_name=i+'.jpg'
 49             # print(img_name)
 50             # 将数据保存到对应的文件夹
 51             img = Image.open(images_path+'/'+img_name)
 52             img.save(create_image_path + '/train_images' + '/' + s + '/' + img_name)
 53 # 测试集数据提取
 54 fill_if_test = os.path.exists(create_image_path+'/test_images')               # 判断文件夹是否存在
 55 if fill_if_test == False:                                    # 判断如果文件夹存在则跳过 不存在则创建
 56     print(fill_if_test)
 57     mak_file=os.mkdir(create_image_path+'/test_images')                  # 创建标签文件夹
 58 for i in os.listdir(images_path):                               # 遍历images文件夹下的数据
 59     if i[:4] == 'Test':                                         # 判断数据前4个字符是否为Test,将test的数据保存起来
 60         # 将数据保存到对应的文件夹
 61         img = Image.open(images_path+'/'+i)
 62         img.save(create_image_path+'/test_images'+'/'+i)
 63 import os
 64 import shutil
 65 import tqdm
 66 val_num=0.2      # 从train数据集中分出x%的数据到val中
 67 create_val_image_path='./data_new'
 68 img='./data_new/train_images/'
 69 
 70 fill_if_2 = os.path.exists(create_val_image_path + '/' + 'val_images')  # 判断文件夹是否存在
 71 if fill_if_2 == False:  # 判断如果文件夹存在则跳过 不存在则创建
 72     mak_file = os.mkdir(create_val_image_path + '/' + 'val_images')  # 创建标签文件夹
 73 
 74 img_label_list=os.listdir(img)
 75 for i in img_label_list:
 76     fill_if_2 = os.path.exists(create_val_image_path + '/' + 'val_images'+'/'+i)  # 判断文件夹是否存在
 77     if fill_if_2 == False:  # 判断如果文件夹存在则跳过 不存在则创建
 78         mak_file = os.mkdir(create_val_image_path + '/' + 'val_images'+'/'+i)  # 创建标签文件夹
 79     img_path=img+i
 80     img_list=os.listdir(img_path)
 81     # print(img_list)
 82     val_=int(len(img_list)*val_num)
 83     for j in tqdm.tqdm(range(val_)):
 84         shutil.move(img+i+'/'+img_list[0],create_val_image_path+ '/' + 'val_images'+'/'+i)
 85         img_list.remove(img_list[0])
 86         
 87 """---------------------提取样本,查看特征-------------------"""
 88 #从测试集中读取一条样本
 89 
 90 from keras.preprocessing import image
 91 import numpy as np
 92 img_path = "./data_new/train_images/rust/Train_1624.jpg"
 93 img = image.load_img(img_path, target_size=(224,224))
 94 img_tensor = image.img_to_array(img)
 95 img_tensor = np.expand_dims(img_tensor, axis=0)
 96 img_tensor /= 255.
 97 #显示样本
 98 import matplotlib.pyplot as plt
 99 plt.imshow(img_tensor[0])
100 plt.show()
101 #存储层的名称
102 layer_names = []
103 for layer in model.layers[:4]:
104     layer_names.append(layer.name)
105 # 每行显示16个特征图
106 images_pre_row = 16  #每行显示的特征图数
107 # 循环8次显示8层的全部特征图
108 for layer_name, layer_activation in zip(layer_names, activations):
109     n_features = layer_activation.shape[-1] #保存当前层的特征图个数
110     size = layer_activation.shape[1]  #保存当前层特征图的宽高
111     n_col = n_features // images_pre_row #计算当前层显示多少行
112     #生成显示图像的矩阵
113     display_grid = np.zeros((size*n_col, images_pre_row*size))
114     #遍历将每个特张图的数据写入到显示图像的矩阵中
115     for col in range(n_col):
116         for row in range(images_pre_row):
117             #保存该张特征图的矩阵(size,size,1)
118             channel_image = layer_activation[0,:,:,col*images_pre_row+row]
119             #为使图像显示更鲜明,作一些特征处理
120             channel_image -= channel_image.mean()
121             channel_image /= channel_image.std()
122             channel_image *= 64
123             channel_image += 128
124             #把该特征图矩阵中不在0-255的元素值修改至0-255
125             channel_image = np.clip(channel_image, 0, 255).astype("uint8")
126             #该特征图矩阵填充至显示图像的矩阵中
127             display_grid[col*size:(col+1)*size, row*size:(row+1)*size] = channel_image
128     
129     
130     scale = 1./size
131     #设置该层显示图像的宽高
132     plt.figure(figsize=(scale*display_grid.shape[1],scale*display_grid.shape[0]))
133     plt.title(layer_name)
134     plt.grid(False)
135     #显示图像
136     plt.imshow(display_grid, aspect="auto", cmap="viridis")
137 plt.show()
138 
139 """---------------------开始构建-------------------"""
140 # 导入需要用到的库
141 import os
142 import tensorflow as tf
143 from tensorflow.keras.optimizers import Adam
144 from keras_preprocessing.image import ImageDataGenerator
145 import matplotlib.pyplot as plt
146 
147 """--------------------指定数据路径-------------------"""
148 # 指定好数据集
149 base_dir = './data_new'  # 存放所有数据的位置
150 train_dir = os.path.join(base_dir, 'train_images')  # 指定训练数据的位置
151 # print(os.listdir(train_dir))              # 查看数据类别
152 validation_dir = os.path.join(base_dir, 'val_images')  # 指定验证数据的位置
153 
154 
155 """------------------参数设置-------------------"""
156 model_name = 'model_224_150_1.h5'  # 给模型命名以 h5为后缀
157 class_num = 4  # 类别的个数
158 epoch = 150  # 训练的轮数
159 batch = 20  # 批次大小
160 resize_img = (224, 224)  # 图片送入网络的大小
161 class_mode = 'sparse'  # 返回的格式:categorical是返回2D的one-hot编码标签,binary是返回1D的二值标签,sparse返回1D的整数标签,None不反回任何标签仅仅生成数据
162 activation = 'softmax'  # 激活函数设置
163 loss = 'sparse_categorical_crossentropy'
164 train_epoch_batch = 100  # 从train迭代器中拿出来数据测次数  这个需要计算的
165 val_epoch_batch = 50  # 从val迭代器中拿出来数据测次数  这个需要计算的
166 
167 # # 训练集 得到数据存放的文件夹
168 # train_healthy_dir =os.path.join(train_dir,'healthy')
169 # train_multiple_diseases_dir = os.path.join(train_dir,'multiple_diseases')
170 # train_rust_dir =os.path.join(train_dir,'rust')
171 # train_scab_fir = os.path.join(train_dir,'scab')
172 # # 判断数据集的大小
173 # print('train_healthy_dir:',len(os.listdir(train_healthy_dir)))
174 # print('train_multiple_diseases_dir:',len(os.listdir(train_multiple_diseases_dir)))
175 # print('train_rust_dir:',len(os.listdir(train_rust_dir)))
176 # print('train_scab_fir:',len(os.listdir(train_scab_fir)))
177 # # 验证集
178 # validation_healthy_dir =os.path.join(validation_dir,'healthy')
179 # validation_multiple_diseases_dir = os.path.join(validation_dir,'multiple_diseases')
180 # validation_rust_dir =os.path.join(validation_dir,'rust')
181 # validation_scab_dir = os.path.join(validation_dir,'scab')
182 # # 判断数据集的大小
183 # print('validation_healthy_dir:',len(os.listdir(validation_healthy_dir)))
184 # print('validation_multiple_diseases_dir:',len(os.listdir(validation_multiple_diseases_dir)))
185 # print('validation_rust_dir:',len(os.listdir(validation_rust_dir)))
186 # print('validation_scab_dir:',len(os.listdir(validation_scab_dir)))
187 
188 
189 # 数据预处理对数据进行归一化到【0-1】之间进行数据增强
190 """--------------------数据处理-------------------"""
191 
192 train_datagen = ImageDataGenerator(rescale=1. / 255,  # 归一化
193                                    rotation_range=40,  # 旋转图片
194                                    width_shift_range=0.2,  # 改变图片的宽
195                                    height_shift_range=0.2,  # 改变图片的高
196                                    shear_range=0.2,  # 裁剪图片
197                                    zoom_range=0.2,  # 缩放图片大小
198                                    horizontal_flip=True,  # 平移图片
199                                    fill_mode='nearest'
200                                    )
201 # 测试集处理
202 test_datagen = ImageDataGenerator(rescale=1. / 255)
203 
204 # 得到迭代器
205 train_generator = train_datagen.flow_from_directory(
206     train_dir,                # 文件夹路径
207     target_size=resize_img,   # 指定resize的大小,需要和神经网络指定的图片大小相同
208     batch_size=batch,         # 批次的大小每一次拿出20个数据送入到网络训练
209     class_mode=class_mode     # 返回的格式:categorical是返回2D的one-hot编码标签,binary是返回1D的二值标签,sparse返回1D的整数标签,None不反回任何标签仅仅生成数据
210 )
211 validation_generator = test_datagen.flow_from_directory(
212     validation_dir,
213     target_size=resize_img,
214     batch_size=batch,
215     class_mode=class_mode
216 )
217 """-----------------构建卷积神经模型----------------"""
218 #Output shape计算公式:(输入尺寸-卷积核尺寸/步长+1
219 #对CNN模型,Param的计算方法如下:
220 #卷积核长度*卷积核宽度*通道数+1)*卷积核个数
221 #输出图片尺寸:224-3+1=222
222 model = tf.keras.models.Sequential([
223     # 32个3*3的卷积核        relu激活函数           输入图像的大小
224     #32*3*3*3+32=896
225     tf.keras.layers.Conv2D(32, (3, 3), activation='relu', input_shape=(224, 224, 3)),
226     tf.keras.layers.MaxPooling2D(2, 2),  # 最大池化层 2*2把  h和 w 编程原来的1/2
227     
228     #64*3*3*32+64=18496
229     tf.keras.layers.Conv2D(64, (3, 3), activation='relu'),
230     tf.keras.layers.MaxPooling2D(2, 2),
231      
232     #128*3*3*64+128=73856
233     tf.keras.layers.Conv2D(128, (3, 3), activation='relu'),
234     tf.keras.layers.MaxPooling2D(2, 2),
235     
236     #128*3*3*128+128=147584
237     tf.keras.layers.Conv2D(128, (3, 3), activation='relu'),
238     tf.keras.layers.MaxPooling2D(2, 2),
239     
240     # 把数据拉平输入全连接层
241     tf.keras.layers.Flatten(),
242     # 全连接层
243     #(18432+1)*512=9437696
244     tf.keras.layers.Dense(512, activation='relu'),  # 512 是输出特征大小
245     tf.keras.layers.Dropout(0.4),
246     #(512+1)*512=262656
247     tf.keras.layers.Dense(512, activation='relu'),
248     tf.keras.layers.Dropout(0.4),
249     # 二分类用sigmoid,1代表得到一个值
250     #(512+1)*4=2052
251     tf.keras.layers.Dense(class_num, activation=activation)
252 ])
253 #特征图的维度变化
254 # model.summary()
255 # 配置训练器
256 model.compile(loss=loss,
257               optimizer=Adam(lr=0.001),
258               metrics=['acc'])
259 
260 """---------------------训练模型并保存-------------------"""
261 # 因为fit直接训练不能把所有的数据全部放入到内存钟,所以使用fit_generator相当于一个生成器,动态的把所有的数据以batch的形式放入内存
262 history = model.fit_generator(
263     train_generator,
264     steps_per_epoch=train_epoch_batch,  # 这个地方需要计算  
265     epochs=epoch,                           # 训练轮数
266     validation_data=validation_generator,
267     validation_steps=val_epoch_batch,  # 这个地方需要计算  
268 #     verbose=2
269 )
270 model.save('./models/' + model_name)            # 保存模型
271 
272 # # 对准确率与损失进行画图
273 acc = history.history['acc']
274 val_acc = history.history['val_acc']
275 loss = history.history['loss']
276 val_loss = history.history['val_loss']
277 
278 epochs = range(len(acc))
279 
280 plt.plot(epochs, acc, 'o', label='Training accuracy')
281 plt.plot(epochs, val_acc, 'r', label='Validation accuracy')
282 plt.title("Training and Validation accuracy")
283 plt.legend()
284 
285 plt.figure()
286 
287 plt.plot(epochs, loss, 'o', label='Training accuracy')
288 plt.plot(epochs, val_loss, 'r', label='Validation accuracy')
289 plt.title("Training and Validation loss")
290 plt.legend()
291 plt.show()
292 
293 """---------------------测试模型并保存结果-------------------"""
294 import tensorflow as tf
295 import pandas as pd
296 import os
297 import matplotlib.pyplot as plt
298 import numpy as np
299 from keras.preprocessing import image
300 import csv
301 frame = pd.DataFrame()
302 """这里修改参数"""
303 # 定义图片路径
304 img_path = 'data_new/test_images/'  # 图片存放文件夹的路径最后要以“/"结尾
305 model_name='models/model_224_150.h5'     # 传入模型
306 img_list = os.listdir(img_path)  # 图片的名字的列表
307 all_img=len(img_list)
308 # 数据提取器    这里输入对应的数字可以拿只推理对应数量的图片
309 img_num = all_img           #这里输入  all_img  可以把说有的图片都送入网络中
310 class_list = ['healthy', 'multiple_diseases', 'rust', 'scab']  # 数据对应的类别标签
311 """这里修改参数"""
312 # 加载模型
313 model = tf.keras.models.load_model(model_name)  # 加载模型到预测文件
314 # model.summary()  # As a reminder.
315 # 创建空csv文件
316 frame.to_csv('predict_result.csv', index=False, sep=',')
317 with open('predict_result.csv', 'w') as csvfile:
318     # 先写入columns_name
319     writer = csv.writer(csvfile)
320     writer.writerow(['image_id', 'healthy', 'multiple_diseases', 'rust', 'scab'])# 这里出入csv文件的列名
321     writer = csv.writer(csvfile)
322 
323     for i in img_list[:img_num]:  # 遍历文件夹里的图片
324         img = img_path + i  # 得到图片的相对路径
325         img_resize = image.load_img(img, target_size=(224, 224))  # 加载图片并resize成(224*224)的格式
326         img_array = image.img_to_array(img_resize)  # 转换成数组
327         img_tensor = np.expand_dims(img_array, axis=0)
328         img_input = img_tensor / 255  # 归一化到0-1之间
329         outputs = model.predict(img_input)  # 获取图片信息
330         outputs = outputs[0]  # 获取预测得到概率列表
331         max_class = max(outputs)  # 获得预测的最大的概率值
332 #       print(max_class)
333         class_dict = dict([i for i in zip(class_list, outputs)])  # 得到标签和预测的概率字典
334         
335         print("测试结果每个概率为:",class_dict)     #输出全部标签
336 #         print(outputs, outputs[0], i[:-4])
337         print("测试结果概率最高的为:",max_class)
338         # 往 csv文件里写入数据
339         writer.writerow([f'{i[:-4]}', outputs[0], outputs[1], outputs[2], outputs[3]])
340 
341         """--------展示图片--------"""
342         # 获取预测概率最大的数据的标签
343         for k,v in class_dict.items():                  #遍历标签与概率的字典返回对应的k,v
344             if v == max_class:                                  # 判断最大的概率并得到标签
345                 print("测试叶片结果为:",k)            # 打印最大的概率
346                 plt.imshow(img_input[0])
347                 plt.title(f'{k}')
348                 plt.show()
349 
350 csvfile.close()  # 关闭csv文件

 




标签:img,叶片,image,train,dir,path,识别,os,病害
From: https://www.cnblogs.com/MuBenYou/p/16996088.html

相关文章

  • Vue-router4.0接口快速识别
    Vue-router4.0接口快速识别<router-link> :将会被渲染a标签属性名属性类型属性作用tostring/object相当于跳转调用router.push(string/object)replacebo......
  • PaddlePaddle 实现手写数字识别
    PaddlePaddle实现手写数字识别在这次实验中我们将使用PaddlePaddle来实现三种不同的分类器,用于识别手写数字。三种分类器所基于的模型分别为Softmax回归、多层感知器、......
  • 机器学习——人脸性别识别
    一、选题背景    人脸识别技术是模式识别和计算机视觉领域最富挑战性的研究课题之一,也是近年来的研究热点,人脸性别识别作为人脸识别技术的重要组成部分也受到了广......
  • 【MindStudio训练营第一季】MindX SDK情绪识别样例速跑 Atlas 200 DK版
    一、前言书接上回,我想用Atlas200DK开发者套件来跑这次的MindStudio训练营,很明显一个最大的问题就是环境,官方镜像是全部已经配置好了的环境,而我现在这只有CANN,除了CANN一......
  • 『论文笔记』基于度量学习的行人重识别方法中损失函数总结!
    基于度量学习的行人重识别方法中损失函数总结!文章目录​​一、对比损失(Contrasiveloss)​​​​二、三元组损失(Tripletloss)​​​​三、改进三元组损失(Improvedtripl......
  • 机器学习——人脸识别判断表情
    (一) 选题背景随着机器学习和深度神经网络两个领域的迅速发展以及智能设备的普及,人脸识别技术正在经历前所未有的发展,关于人脸识别技术讨论从未停歇。目前,人脸识别精度已......
  • 机器学习————验证码图片识别
    (一)选题背景首先,验证码是最初的设定是通过验证码对人类和非人类行为进行区分;大多数的网站在进行注册或者登录时都需要用到图片验证码,这都是为了防止用户通过机器人......
  • 论文解读丨【CVPR 2022】不使用人工标注提升文字识别器性能
    摘要:本文提出了一种针对文字识别的半监督方法。区别于常见的半监督方法,本文的针对文字识别这类序列识别问题做出了特定的设计。本文分享自华为云社区《[CVPR2022]不使用......
  • 微信小程序调用百度车牌识别
        <!--pages/AISearch/AISearch.wxml--><viewclass="ai_content"><viewclass="img_box"bindtap="chooseImg"><viewclass="upload_img"wx:if="{{t......
  • 论文推荐|TDSC2022 安全补丁识别最新的方案E-SPI
    摘要:TDSC2022发表了安全补丁识别最新的方案“EnhancingSecurityPatchIdentificationbyCapturingStructuresinCommits”(E-SPI)。本文分享自华为云社区《【论文......