水果和动物分类识别系统

水果和动物分类识别系统

1. 效果演示

水果和动物分类识别系统

2. 系统界面

在这里插入图片描述

3. 系统阐述

  1. 环境设置:首先,通过设置TF_CPP_MIN_LOG_LEVEL环境变量为3,来抑制TensorFlow在运行时输出的警告信息,以便于观察模型训练过程中的关键信息。
  2. 导入必要的库:导入TensorFlow库以及用于构建模型的Sequential、Conv2D、MaxPooling2D、Flatten和Dense等类。
  3. 构建CNN模型:使用Sequential模型构建一个简单的CNN结构,该结构包含两个卷积层、两个最大池化层、一个展平层和两个全连接层。模型的输出层有两个神经元,使用softmax激活函数,因为这是一个二分类问题。
  4. 编译模型:使用Adam优化器和交叉熵损失函数来编译模型,并指定准确率作为评估指标。
  5. 数据增强:使用ImageDataGenerator类来增强训练数据,通过随机剪切、缩放和水平翻转等操作来增加数据的多样性,提高模型的泛化能力。
  6. 准备数据:使用flow_from_directory方法从指定的目录中加载并预处理图像数据。这里假设数据集的目录结构是按照类别组织的,每个类别下有多个子目录,每个子目录包含该类别的图像。
  7. 训练模型:使用fit方法训练模型,通过生成器提供的数据进行训练。这里设置了60个epoch,并且每个epoch中使用生成器提供的数据数量作为训练步数。
  8. 保存模型:训练完成后,将模型保存为.h5文件,以便将来可以重新加载和使用。
  9. 用python的flask框架写一个界面,方便用户的使用的测试。

4. 分析与设计

1. 系统功能概述

数据预处理:对图像数据进行归一化处理,以及数据增强,如随机剪切、缩放和水平翻转。
模型构建:构建一个卷积神经网络(CNN),用于图像分类任务。
模型训练:使用增强后的数据训练CNN模型。
模型评估:评估训练好的模型在验证集上的性能。
模型保存:将训练好的模型保存为文件,以便未来使用。

2. 数据预处理

归一化:将图像数据的像素值缩放到0-1之间。
数据增强:通过随机剪切、缩放和水平翻转等操作增加数据多样性。

3. 模型构建

卷积层:使用3x3卷积核提取图像特征。
激活函数:使用ReLU激活函数。
池化层:使用2x2最大池化层减少特征图尺寸。
全连接层:使用128个神经元的全连接层。
输出层:使用2个神经元的输出层,使用softmax激活函数。

4. 模型训练

优化器:使用Adam优化器。
损失函数:使用交叉熵损失函数。
训练周期:训练60个epoch。

5. 模型评估

准确率:使用准确率作为评估指标。

6. 模型保存

保存格式:保存为.h5文件。

5. 编程实现:

1. 构建CNN模型:

def build_cnn_model(input_shape):
    """
    构建一个卷积神经网络模型。
    :param input_shape: 输入数据的形状,例如(64, 64, 3)。
    :return: 构建好的模型。
    """
    model = Sequential()
    # 第一层卷积层,32个3x3的卷积核,激活函数为ReLU
    model.add(Conv2D(32, (3, 3), activation='relu', input_shape=input_shape))
    # 第一层最大池化层,池化窗口大小为2x2
    model.add(MaxPooling2D(pool_size=(2, 2)))
    # 第二层卷积层,64个3x3的卷积核
    model.add(Conv2D(64, (3, 3), activation='relu'))
    # 第二层最大池化层,池化窗口大小为2x2
    model.add(MaxPooling2D(pool_size=(2, 2)))
    # 展平层,将多维数据展平为一维
    model.add(Flatten())
    # 第一层全连接层,128个神经元,激活函数为ReLU
    model.add(Dense(128, activation='relu'))
    # 输出层,2个神经元,激活函数为softmax(因为是二分类问题)
    model.add(Dense(2, activation='softmax'))
    return model

2. 编译模型:

def compile_model(model):
    """
    编译模型,设置优化器、损失函数和评估指标。
    :param model: 要编译的模型。
    """
    # 使用Adam优化器,损失函数为交叉熵,评估指标为准确率
    model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])

3. 准备数据增强生成器

def prepare_data_augmentation():
    """
    准备数据增强生成器,进行图像预处理。
    :return: 数据增强生成器。
    """
    # 创建一个ImageDataGenerator实例,进行归一化、随机剪切、随机缩放和随机水平翻转
    train_datagen = ImageDataGenerator(
        rescale=1. / 255,  # 归一化
        shear_range=0.2,  # 随机剪切变换
        zoom_range=0.2,   # 随机缩放变换
        horizontal_flip=True  # 随机水平翻转
    )
    return train_datagen

4. 准备数据生成器

def prepare_data_generator(train_datagen, data_dir, target_size, batch_size, class_mode):
    """
    准备数据生成器,用于从指定目录加载图像数据。
    :param train_datagen: 数据增强生成器。
    :param data_dir: 数据集的根目录。
    :param target_size: 图像大小调整为(target_size[0], target_size[1])。
    :param batch_size: 每批处理的图像数量。
    :param class_mode: 类别模式,'categorical'表示输出为one-hot编码的类别标签。
    :return: 数据生成器。
    """
    # 使用ImageDataGenerator的flow_from_directory方法创建数据生成器
    train_generator = train_datagen.flow_from_directory(
        data_dir,  # 数据集的根目录
        target_size=target_size,  # 图像大小调整为64x64
        batch_size=batch_size,  # 每批图片数量
        class_mode=class_mode  # 类别模式为categorical
    )
    return train_generator

5. 训练模型:

def train_model(model, train_generator, epochs, steps_per_epoch):
    """
    使用数据生成器训练模型。
    :param model: 要训练的模型。
    :param train_generator: 数据生成器。
    :param epochs: 训练的轮数。
    :param steps_per_epoch: 每个epoch中,使用生成器提供的数据数量作为训练步数。
    """
    # 使用fit_generator方法训练模型
    model.fit_generator(
        train_generator,  # 使用生成器提供的数据进行训练
        steps_per_epoch=steps_per_epoch,  # 每个epoch中,使用生成器提供的数据数量作为训练步数
        epochs=epochs,  # 训练60个epoch
        verbose=1  # 设置verbose为1,表示在训练过程中打印进度条
    )

6. 保存模型:

def save_model(model, filename):
    """
    保存训练好的模型。
    :param model: 要保存的模型。
    :param filename: 保存模型的文件名。
    """
    # 使用save方法保存模型
    model.save(filename)

7. 主程序:

def main():
    # 定义输入形状
    input_shape = (64, 64, 3)

    # 构建模型
    model = build_cnn_model(input_shape)

    # 编译模型
    compile_model(model)

    # 准备数据增强
    train_datagen = prepare_data_augmentation()

    # 准备数据生成器
    train_generator = prepare_data_generator(train_datagen, 'FruitAnimal', (64, 64), 32, 'categorical')

    # 训练模型
    train_model(model, train_generator, 60, len(train_generator))

    # 保存模型
    save_model(model, 'fruit_animal_classifier.h5')


# 运行主程序
if __name__ == '__main__':
    main()

测试与运行结果及其分析:

我发现后面要不停换照片来测试自己的模型是否可以分类,也就是模型是否训练好了,修改路径虽然也可以实现,但是有点麻烦,就写了一个网站,来上传图片,点击预测就可以调用模型来识别是啥东西了。

1. 模型预测的代码

import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'    # 设置TensorFlow的日志级别为3,不显示警告信息

import tensorflow as tf
from tensorflow.keras.models import load_model
from tensorflow.keras.preprocessing.image import load_img, img_to_array
import numpy as np

def predict_image(img_path):
    # 加载模型
    model = load_model('fruit_animal_classifier.h5')    # 加载之前保存的模型

    # 预测单张图片
    img = load_img(img_path, target_size=(64, 64))    # 加载图片并调整大小为64x64
    img_array = img_to_array(img)    # 将图片转换为数组
    img_array = np.expand_dims(img_array, axis=0) / 255    # 增加一个维度并归一化图片数据

    # 预测图片
    prediction = model.predict(img_array)    # 使用模型进行预测

    # 解释预测结果
    if prediction[0][0] > 0.5:
        return "动物"    # 如果预测结果大于0.5,则输出“动物”
    else:
        return "水果"    # 否则输出“水果”

# 使用函数进行预测
img_path = 'fruit.png'    # 替换为您的图片路径
result = predict_image(img_path)
print(result)

在这里插入图片描述

图1:fruit
我们可以看到要换那个img_path, 个人感觉有点麻烦,所以写了一个网站来实现。 网站采用的是flask轻量形框架,毕竟也是python的一个模块嘛。

2. 前端代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>水果与动物分类识别系统</title>
    <style>
        body {
            background-color: lightblue;
            font-family: Arial, sans-serif;
            text-align: center;
            margin-top: 50px;
        }

        .upload-container {
            display: flex;
            justify-content: center;
            align-items: center;
            padding: 10px;
            border-radius: 5px;
            margin-bottom: 20px;
        }

        .upload-button {
            display: inline-block;
            padding: 10px 20px;
            color: white;
            border: none;
            cursor: pointer;
            margin: 0 5px;
            border-radius: 3px;
            text-align: center;
        }

        .select-file {
            background-color: #2196F3;
        }

        .upload-audio {
            background-color: #4CAF50;
        }

        .audio-container {
            text-align: center;
            margin-top: 20px;
        }

        .file-type {
            font-size: 12px;
            color: #666;
        }

        h1 {
            font-size: 2em; /* 加大一号字体 */
            letter-spacing: 0.1em; /* 添加点空格 */
            color: #333333;
        }
    </style>
</head>
<body>
<h1>水果与动物分类识别系统</h1>
<p class="file-type">只能上传图片</p>
<div class="upload-container">
    <form action="/success" method="post" enctype="multipart/form-data">
        <!-- 隐藏的文件输入框 -->
        <input type="file" name="file" id="fileInput" style="display:none;" accept="image/*">
        <button type="button" class="upload-button select-file" onclick="selectFile()">
            选择图片
        </button>
        <button type="submit" class="upload-button upload-audio">开始检测</button>
    </form>
</div>

{% if flag == 'fruit' %}
    <img src="{{ img_url }}" alt="水果">
    <br>
    <img src="../static/fruit.png" alt="水果">
{% elif flag == 'animal' %}
    <img src="{{ img_url }}" alt="动物">
    <br>
    <img src="../static/animal.png" alt="动物">
{% endif %}

<script>
    function selectFile() {
        var fileInput = document.getElementById('fileInput');
        fileInput.click(); // 触发隐藏的文件输入框的点击事件
    }

    // 为隐藏的文件输入框绑定 onchange 事件
    document.getElementById('fileInput').onchange = function () {
        var file = this.files[0];
        var imgContainer = document.querySelector('.image-container');
        imgContainer.innerHTML = ''; // 清空之前的图片
        if (file) {
            var imgElem = document.createElement('img');
            imgElem.src = URL.createObjectURL(file);
            imgElem.classList.add('image');
            imgContainer.appendChild(imgElem);
        } else {
            alert("请选择一个图片文件!");
        }
    };

    // 为“开始检测”按钮绑定点击事件
    document.querySelector('.upload-audio').onclick = function (event) {
        var fileInput = document.getElementById('fileInput');
        var file = fileInput.files[0];
        if (!file) {
            event.preventDefault(); // 阻止表单提交
            alert("请选择一个图片文件!");
        }
    };
</script>
</body>
</html>

简单写了一哈前端,也就是两个按钮,一个上传图片,一个预测图片内容。

3. 后端代码

from flask import Flask, render_template, request
from use_model import predict_image

app = Flask(__name__)

# 设置请求体的最大大小为 16MB
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024


@app.route('/')
def index():
    return render_template('upload.html')


@app.route('/success', methods=['POST'])
def upload_file():
    f = request.files['file']
    # 保存文件到服务器
    f_path = './static/images/' + f.filename
    f.save(f_path)
    # 假设我们已经通过某种方式识别了图片内容,并确定了 img_url
    img_url = '../static/images/' + f.filename  # 假设图片保存在服务器的 images 文件夹中
    flag = predict_image(f_path)
    print(flag)
    return render_template('upload.html', flag=flag, img_url=img_url)


if __name__ == '__main__':
    app.run(debug=True)

随便写了两个路由,来接收前端的表单提交的图片。
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

总结

水果和动物分类识别,感觉模型,不够完善,训练集的照片没有在更加复杂的环境,训练集也被处理过了,希望有时间可以更加完善,比如选择图片的时候,放在网站展示的时候,可以对图片进行裁剪,还有可以具体分类,是啥动物水果,可以具体分类,这是需要改进的方向。希望大家可以在我的帮本上进行学习和改进

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值