CNN实现花卉图片分类识别

article/2025/11/7 15:52:49

CNN实现花卉图片分

前言

本文为一个利用卷积神经网络实现花卉分类的项目,因此不会过多介绍卷积神经网络的基本知识。此项目建立在了解卷积神经网络进行图像分类的原理上进行的。

项目简介

本项目为一个图像识别项目,基于tensorflow,利用CNN网络实现识别四种花的种类。
使用tensorflow进行一个完整的图像识别。项目包括对数据集的处理,从硬盘读取数据,CNN网络的定义,训练过程以及利用实际测试数据对训练好的模型结果进行测试功能。

准备训练数据。

训练数据存放路径为: ‘D:/ML/flower/input_data’
训练模型存储路径为:'D:/ML/flower/save/‘
测试样本路径及文件名为:'D:/ML/flower/flower_photos/roses/**.jpg‘
测试用图片文件从训练数据中任意拷贝一张即可。

训练数据如图
在这里插入图片描述
以roses种类的训练数据为例,文件夹内部均为该种类花的图像文件

在这里插入图片描述

模块组成

示例代码主要由四个模块组成:
input_data.py——图像特征提取模块,模块生成四种花的品类图片路径及对应标签的List
model.py——模型模块,构建完整的CNN模型
train.py——训练模块,训练模型,并保存训练模型结果
test.py——测试模块,测试模型对图片识别的准确度

项目模块执行顺序

  • 运行train.py开始训练。
  • 训练完成后- 运行test.py,查看实际测试结果

input_data.py——图像特征提取模块,模块生成四种花的品类图片路径及对应标签的List

import os
import math
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt# -----------------生成图片路径和标签的List------------------------------------
train_dir = 'D:/ML/flower/input_data'roses = []
label_roses = []
tulips = []
label_tulips = []
dandelion = []
label_dandelion = []
sunflowers = []
label_sunflowers = []

定义函数get_files,获取图片列表及标签列表

# step1:获取所有的图片路径名,存放到
# 对应的列表中,同时贴上标签,存放到label列表中。
def get_files(file_dir, ratio):for file in os.listdir(file_dir + '/roses'):roses.append(file_dir + '/roses' + '/' + file)label_roses.append(0)for file in os.listdir(file_dir + '/tulips'):tulips.append(file_dir + '/tulips' + '/' + file)label_tulips.append(1)for file in os.listdir(file_dir + '/dandelion'):dandelion.append(file_dir + '/dandelion' + '/' + file)label_dandelion.append(2)for file in os.listdir(file_dir + '/sunflowers'):sunflowers.append(file_dir + '/sunflowers' + '/' + file)label_sunflowers.append(3)# step2:对生成的图片路径和标签List做打乱处理image_list = np.hstack((roses, tulips, dandelion, sunflowers))label_list = np.hstack((label_roses, label_tulips, label_dandelion, label_sunflowers))# 利用shuffle打乱顺序temp = np.array([image_list, label_list])temp = temp.transpose()np.random.shuffle(temp)# 将所有的img和lab转换成listall_image_list = list(temp[:, 0])all_label_list = list(temp[:, 1])# 将所得List分为两部分,一部分用来训练tra,一部分用来测试val# ratio是测试集的比例n_sample = len(all_label_list)n_val = int(math.ceil(n_sample * ratio))  # 测试样本数n_train = n_sample - n_val  # 训练样本数tra_images = all_image_list[0:n_train]tra_labels = all_label_list[0:n_train]tra_labels = [int(float(i)) for i in tra_labels]val_images = all_image_list[n_train:-1]val_labels = all_label_list[n_train:-1]val_labels = [int(float(i)) for i in val_labels]return tra_images, tra_labels, val_images, val_labels

定义函数get_batch,生成训练批次数据

# --------------------生成Batch----------------------------------------------# step1:将上面生成的List传入get_batch() ,转换类型,产生一个输入队列queue,因为img和lab
# 是分开的,所以使用tf.train.slice_input_producer(),然后用tf.read_file()从队列中读取图像
#   image_W, image_H, :设置好固定的图像高度和宽度
#   设置batch_size:每个batch要放多少张图片
#   capacity:一个队列最大多少
定义函数get_batch,生成训练批次数据
def get_batch(image, label, image_W, image_H, batch_size, capacity):# 转换类型image = tf.cast(image, tf.string)label = tf.cast(label, tf.int32)# make an input queueinput_queue = tf.train.slice_input_producer([image, label])label = input_queue[1]image_contents = tf.read_file(input_queue[0])  # read img from a queue# step2:将图像解码,不同类型的图像不能混在一起,要么只用jpeg,要么只用png等。image = tf.image.decode_jpeg(image_contents, channels=3)# step3:数据预处理,对图像进行旋转、缩放、裁剪、归一化等操作,让计算出的模型更健壮。image = tf.image.resize_image_with_crop_or_pad(image, image_W, image_H)image = tf.image.per_image_standardization(image)# step4:生成batch# image_batch: 4D tensor [batch_size, width, height, 3],dtype=tf.float32# label_batch: 1D tensor [batch_size], dtype=tf.int32image_batch, label_batch = tf.train.batch([image, label],batch_size=batch_size,num_threads=32,capacity=capacity)# 重新排列label,行数为[batch_size]label_batch = tf.reshape(label_batch, [batch_size])image_batch = tf.cast(image_batch, tf.float32)return image_batch, label_batch

model.py——CN模型构建

import tensorflow as tf#定义函数infence,定义CNN网络结构
#卷积神经网络,卷积加池化*2,全连接*2,softmax分类
#卷积层1
def inference(images, batch_size, n_classes):with tf.variable_scope('conv1') as scope:weights = tf.Variable(tf.truncated_normal(shape=[3,3,3,64],stddev=1.0,dtype=tf.float32),name = 'weights',dtype=tf.float32)biases = tf.Variable(tf.constant(value=0.1, dtype=tf.float32, shape=[64]),name='biases', dtype=tf.float32)conv = tf.nn.conv2d(images, weights, strides=[1, 1, 1, 1], padding='SAME')pre_activation = tf.nn.bias_add(conv, biases)conv1 = tf.nn.relu(pre_activation, name=scope.name)# 池化层1# 3x3最大池化,步长strides为2,池化后执行lrn()操作,局部响应归一化,对训练有利。with tf.variable_scope('pooling1_lrn') as scope:pool1 = tf.nn.max_pool(conv1, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], padding='SAME', name='pooling1')norm1 = tf.nn.lrn(pool1, depth_radius=4, bias=1.0, alpha=0.001 / 9.0, beta=0.75, name='norm1')# 卷积层2# 16个3x3的卷积核(16通道),padding=’SAME’,表示padding后卷积的图与原图尺寸一致,激活函数relu()with tf.variable_scope('conv2') as scope:weights = tf.Variable(tf.truncated_normal(shape=[3, 3, 64, 16], stddev=0.1, dtype=tf.float32),name='weights', dtype=tf.float32)biases = tf.Variable(tf.constant(value=0.1, dtype=tf.float32, shape=[16]),name='biases', dtype=tf.float32)conv = tf.nn.conv2d(norm1, weights, strides=[1, 1, 1, 1], padding='SAME')pre_activation = tf.nn.bias_add(conv, biases)conv2 = tf.nn.relu(pre_activation, name='conv2')# 池化层2# 3x3最大池化,步长strides为2,池化后执行lrn()操作,# pool2 and norm2with tf.variable_scope('pooling2_lrn') as scope:norm2 = tf.nn.lrn(conv2, depth_radius=4, bias=1.0, alpha=0.001 / 9.0, beta=0.75, name='norm2')pool2 = tf.nn.max_pool(norm2, ksize=[1, 3, 3, 1], strides=[1, 1, 1, 1], padding='SAME', name='pooling2')# 全连接层3# 128个神经元,将之前pool层的输出reshape成一行,激活函数relu()with tf.variable_scope('local3') as scope:reshape = tf.reshape(pool2, shape=[batch_size, -1])dim = reshape.get_shape()[1].valueweights = tf.Variable(tf.truncated_normal(shape=[dim, 128], stddev=0.005, dtype=tf.float32),name='weights', dtype=tf.float32)biases = tf.Variable(tf.constant(value=0.1, dtype=tf.float32, shape=[128]),name='biases', dtype=tf.float32)local3 = tf.nn.relu(tf.matmul(reshape, weights) + biases, name=scope.name)# 全连接层4# 128个神经元,激活函数relu()with tf.variable_scope('local4') as scope:weights = tf.Variable(tf.truncated_normal(shape=[128, 128], stddev=0.005, dtype=tf.float32),name='weights', dtype=tf.float32)biases = tf.Variable(tf.constant(value=0.1, dtype=tf.float32, shape=[128]),name='biases', dtype=tf.float32)local4 = tf.nn.relu(tf.matmul(local3, weights) + biases, name='local4')# dropout层#    with tf.variable_scope('dropout') as scope:#        drop_out = tf.nn.dropout(local4, 0.8)# Softmax回归层# 将前面的FC层输出,做一个线性回归,计算出每一类的得分with tf.variable_scope('softmax_linear') as scope:weights = tf.Variable(tf.truncated_normal(shape=[128, n_classes], stddev=0.005, dtype=tf.float32),name='softmax_linear', dtype=tf.float32)biases = tf.Variable(tf.constant(value=0.1, dtype=tf.float32, shape=[n_classes]),name='biases', dtype=tf.float32)softmax_linear = tf.add(tf.matmul(local4, weights), biases, name='softmax_linear')return softmax_linear# -----------------------------------------------------------------------------
# loss计算
# 传入参数:logits,网络计算输出值。labels,真实值,在这里是0或者1
# 返回参数:loss,损失值
def losses(logits, labels):with tf.variable_scope('loss') as scope:cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logits, labels=labels,name='xentropy_per_example')loss = tf.reduce_mean(cross_entropy, name='loss')tf.summary.scalar(scope.name + '/loss', loss)return loss# --------------------------------------------------------------------------
# loss损失值优化
# 输入参数:loss。learning_rate,学习速率。
# 返回参数:train_op,训练op,这个参数要输入sess.run中让模型去训练。
def trainning(loss, learning_rate):with tf.name_scope('optimizer'):optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate)global_step = tf.Variable(0, name='global_step', trainable=False)train_op = optimizer.minimize(loss, global_step=global_step)return train_op# -----------------------------------------------------------------------
# 评价/准确率计算
# 输入参数:logits,网络计算值。labels,标签,也就是真实值,在这里是0或者1。
# 返回参数:accuracy,当前step的平均准确率,也就是在这些batch中多少张图片被正确分类了。
def evaluation(logits, labels):with tf.variable_scope('accuracy') as scope:correct = tf.nn.in_top_k(logits, labels, 1)correct = tf.cast(correct, tf.float16)accuracy = tf.reduce_mean(correct)tf.summary.scalar(scope.name + '/accuracy', accuracy)return accuracy

train.py——利用D:/ML/flower/input_data/路径下的训练数据,对CNN模型进行训练

import input_data
import model# 变量声明
N_CLASSES = 4  # 四种花类型
IMG_W = 64  # resize图像,太大的话训练时间久
IMG_H = 64
BATCH_SIZE = 20
CAPACITY = 200
MAX_STEP = 2000  # 一般大于10K
learning_rate = 0.0001  # 一般小于0.0001# 获取批次batch
train_dir = 'F:/input_data'  # 训练样本的读入路径
logs_train_dir = 'F:/save'  # logs存储路径# train, train_label = input_data.get_files(train_dir)
train, train_label, val, val_label = input_data.get_files(train_dir, 0.3)
# 训练数据及标签
train_batch, train_label_batch = input_data.get_batch(train, train_label, IMG_W, IMG_H, BATCH_SIZE, CAPACITY)
# 测试数据及标签
val_batch, val_label_batch = input_data.get_batch(val, val_label, IMG_W, IMG_H, BATCH_SIZE, CAPACITY)# 训练操作定义
train_logits = model.inference(train_batch, BATCH_SIZE, N_CLASSES)
train_loss = model.losses(train_logits, train_label_batch)
train_op = model.trainning(train_loss, learning_rate)
train_acc = model.evaluation(train_logits, train_label_batch)# 测试操作定义
test_logits = model.inference(val_batch, BATCH_SIZE, N_CLASSES)
test_loss = model.losses(test_logits, val_label_batch)
test_acc = model.evaluation(test_logits, val_label_batch)# 这个是log汇总记录
summary_op = tf.summary.merge_all()# 产生一个会话
sess = tf.Session()
# 产生一个writer来写log文件
train_writer = tf.summary.FileWriter(logs_train_dir, sess.graph)
# val_writer = tf.summary.FileWriter(logs_test_dir, sess.graph)
# 产生一个saver来存储训练好的模型
saver = tf.train.Saver()
# 所有节点初始化
sess.run(tf.global_variables_initializer())
# 队列监控
coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(sess=sess, coord=coord)# 进行batch的训练
try:# 执行MAX_STEP步的训练,一步一个batchfor step in np.arange(MAX_STEP):if coord.should_stop():break_, tra_loss, tra_acc = sess.run([train_op, train_loss, train_acc])# 每隔50步打印一次当前的loss以及acc,同时记录log,写入writerif step % 10 == 0:print('Step %d, train loss = %.2f, train accuracy = %.2f%%' % (step, tra_loss, tra_acc * 100.0))summary_str = sess.run(summary_op)train_writer.add_summary(summary_str, step)# 每隔100步,保存一次训练好的模型if (step + 1) == MAX_STEP:checkpoint_path = os.path.join(logs_train_dir, 'model.ckpt')saver.save(sess, checkpoint_path, global_step=step)except tf.errors.OutOfRangeError:print('Done training -- epoch limit reached')finally:coord.request_stop()

test.py——利用D:/ML/flower/flower_photos/roses路径下的测试数据,查看识别效果

import matplotlib.pyplot as plt
import model
from input_data import get_files# 获取一张图片
def get_one_image(train):# 输入参数:train,训练图片的路径# 返回参数:image,从训练图片中随机抽取一张图片n = len(train)ind = np.random.randint(0, n)img_dir = train[ind]  # 随机选择测试的图片img = Image.open(img_dir)plt.imshow(img)plt.show()image = np.array(img)return image# 测试图片
def evaluate_one_image(image_array):with tf.Graph().as_default():BATCH_SIZE = 1N_CLASSES = 4image = tf.cast(image_array, tf.float32)image = tf.image.per_image_standardization(image)image = tf.reshape(image, [1, 64, 64, 3])logit = model.inference(image, BATCH_SIZE, N_CLASSES)logit = tf.nn.softmax(logit)x = tf.placeholder(tf.float32, shape=[64, 64, 3])# you need to change the directories to yours.logs_train_dir = 'F:/save/'saver = tf.train.Saver()with tf.Session() as sess:print("Reading checkpoints...")ckpt = tf.train.get_checkpoint_state(logs_train_dir)if ckpt and ckpt.model_checkpoint_path:global_step = ckpt.model_checkpoint_path.split('/')[-1].split('-')[-1]saver.restore(sess, ckpt.model_checkpoint_path)print('Loading success, global_step is %s' % global_step)else:print('No checkpoint file found')prediction = sess.run(logit, feed_dict={x: image_array})max_index = np.argmax(prediction)if max_index == 0:result = ('这是玫瑰花的可能性为: %.6f' % prediction[:, 0])elif max_index == 1:result = ('这是郁金香的可能性为: %.6f' % prediction[:, 1])elif max_index == 2:result = ('这是蒲公英的可能性为: %.6f' % prediction[:, 2])else:result = ('这是这是向日葵的可能性为: %.6f' % prediction[:, 3])return result# ------------------------------------------------------------------------if __name__ == '__main__':img = Image.open('F:/input_data/dandelion/1451samples2.jpg')plt.imshow(img)plt.show()imag = img.resize([64, 64])image = np.array(imag)print(evaluate_one_image(image))

项目执行结果:

1.执行train模块,结果如下:
在这里插入图片描述
同时,训练结束后,在电脑指定的训练模型存储路径可看到保存的训练好的模型数据。
在这里插入图片描述
2.执行test模块,结果如下:
显示一张测试用的图片
在这里插入图片描述
关闭显示的测试图片后,console查看测试结果如下:
在这里插入图片描述
至此我们对整个项目流程做一个总结:
图片预处理模块:对获得的花卉图片训练数据,进行预处理,构造训练用数据结构
训练模块:利用Tensorflow实现CNN(神经网络算法)模型,经过两层卷积-池化处理,并使用梯度下降算法作为优化器、Softmax算法作为分类器、平方损失函数(最小二乘法, Ordinary Least Squares)作为优化器,构建训练模型,利用训练数据对模型进行训练,最终得到训练后的模型数据,并以文件形式存储至本机。
分类准确度验证模块:利用Tensorflow的reduce_mean方法作为评估模型,对构建的花卉分类模型分类准确性进行验证。
模型测试模块:使用测试集数据,对构建并训练后的分类模型进行测试,验证实际数据的测试准确度。

具体代码以及附件可在我的个人GitHub上下载
我的githubworkspace


http://chatgpt.dhexx.cn/article/DRZakIGV.shtml

相关文章

常用图像分类网络

想对图像分类网络写个简要的概括,如有介绍不当之处,还望指出。 一、VGG网络 更新于2018年10月20日 参考博客:深度学习经典卷积神经网络之VGGNet 论文地址:VERY DEEP CONVOLUTIONAL NETWORKS FOR LARGE-SCALE IMAGE RECOGNITIO…

干货——图像分类(上)

这是译自斯坦福CS231n课程笔记image classification notes,由课程教师Andrej Karpathy授权进行翻译。本篇教程由杜客翻译完成。非常感谢那些无偿奉献的大师,在此代表所有爱好学习者向您们致敬,谢谢! 这是斯坦福大学的课程&#xf…

图像分类

图像物体分类与检测算法综述 转自《计算机学报》 目录 图像物体分类与检测算法综述 目录图像物体分类与检测概述物体分类与检测的难点与挑战物体分类与检测数据库物体分类与检测发展历程 图像物体分类与检测是计算机视觉研究中的两个重要的基本问题,也是图像分割、…

【图像分类数据集】非常全面实用的垃圾分类图片数据集共享

【图像分类数据集】非常全面实用的垃圾分类图片数据集共享 数据集介绍: 训练集 文件夹结构如下(部分: 第0类文件夹下数据展示如下(部分: 测试集 大致如下: 数据集获取方式: 总结&#xf…

python学习(18)--图片分类

图片分类 学习动机. 在这一节中我们会引入图片分类为题。这也是从一个合适的集合中分配给图片一个标记的任务。这是计算机视觉的核心问题之一。鉴于它的简单性,有一大批实用应用。更多的是,我们可以在以后的章节中看到,一些看似分离的计算机…

【OpenMMLab】图片分类发展简史

一、发展简述 图片分类是CV领域的基础任务,也是检测、分割、追踪等任务的基石。简而言之,图片分类就是给定一张图片,判断其类别,一般而言所有的候选类别是预设的。 从数学上描述,图片分类就是寻找一个函数&#xff0…

深度学习(1) ——图像分类

图像分类概述 图像分类实质上就是从给定的类别集合中为图像分配对应标签的任务,当我们输入一张图片,返回一个该图像类别的标签。限制条件:只能输入单目标图像。常用数据集:mnist、CIFAR-10、CIFAR-100、ImageNet 图像分类算法 …

CNN图片分类(Pytorch)

这篇文章主要讲述用 pytorch 完成简单 CNN 图片分类任务,如果想对 CNN 的理论知识进行了解,可以看我的这篇文章,深度学习(一)——CNN卷积神经网络。 图片分类 我们以美食图片分类为例,有testing、training、validation文件夹。下…

JavaWeb学习思维导图

这是我最近总结的JavaWeb学习思维导图,希望可以帮到大家:

javaweb学习总结

重定向 请求转发 区别:重定向后浏览器地址值会发生改变。 重定向request域对象不能共享数据,因为request域的范围是一次请求一次响应。而转发能够共享数据 请求转发的路径写法,只是需要写url-pattern的地址即可,不用带项目名&am…

JavaWeb学习心得总结

JavaWeb(JSPServlet)新手学习心得总结 说明: 由于篇幅的原因,本文只是对于JavaWeb项目的大致数据流程做一个介绍,同时引出一些JavaWeb开发中很基础的知识点,且不会精确到具体代码实现。 所以本文的适合读…

JavaWeb学习笔记总结(一)

前言:因为我是大三,这学期开课是JavaWeb,前端三剑客htmlcssjs,还有一个springboot框架的课,大二下学期才学的java跟sql,所以跨度直接到springboot有点大吧,ssm框架都没学,但是b站上有挺多教程的&#xff0c…

一.JavaWeb学习路线

Java系统学习路线: 第一阶段 第一阶段: Java 基础,包括 Java 语法,面向对象特征,常见API,集合框架。(基础) 第二阶段:Java API:输入输出,多线程,网络编程,反…

java web学习_JavaWeb学习路线

Java web,是用Java技术来解决相关web互联网领域的技术综合。Web包括:web服务器和web客户端。Java在客户端的应用有Java applet,不过使用很少。Java在服务器端的应用非常的丰富,比如Servlet,JSP和第三方框架等等。java技…

JavaWeb学习笔记

JavaWeb 1.ASP、PHP、JSP ASP: 微软&#xff1a;最早流行的就行ASP 在HTML嵌入VB的脚本 在ASP中&#xff0c;基本一个界面就有几千行代码&#xff0c;页面极其混乱&#xff0c;维护成本高 c#编程语言 IIS服务器 <h1> <% system.out.println("hello") …

javaweb学习路线

一、学习顺序 1、java语法&#xff0c;语法很重要&#xff0c;没有这个根本后面的也进行不下去&#xff0c;建议先学会应用了再去研究jdk源码&#xff0c;本身就是新手就想从原理开始了解&#xff0c;估计非常吃力&#xff0c;效果也不一定好。 2、数据库&#xff0c;首先学关…

JavaWeb知识点汇总

JavaWeb知识点汇总 前言&#xff1a;跟了狂神javaweb学习有一阵子了&#xff0c;这里简单进行笔记总结&#xff0c;也是第一次使用markdown写这么长的文章&#xff0c;虽然是跟着敲的&#xff0c;也是多理解了一遍&#xff0c;以及具体上手自己写的代码和相应效果图。发布于此…

JAVAweb入门基础

1、JAVAweb开发原理 2、web服务器 2.1、技术服务 ASP&#xff08;微软 国内最早流行;在HTML中嵌入了VB的脚本&#xff0c;ASPCom;在ASp开发中&#xff0c;基本一个页面都有几千行的业务代码&#xff0c;页面及其混乱&#xff1b;维护成本高&#xff01;&#xff09; PHP(PHP…

JavaWeb学习知识总结

1.自定义 servlet 的三种方式&#xff0c;及区别? 方式一&#xff1a;编写一个类去实现Servlet接口(必须重写Servlet接口里面所有的抽象方法)方式二&#xff1a;编写一个类去继承GenericServlet抽象类(重写生命周期的service方法&#xff08;抽象法&#xff09;)GenericServle…

JavaWeb学习路线(总结自尚硅谷雷神SSM|极其详细|思路清晰|适合入门/总复习)

文章目录 JavaWeb前言说明前端技术html&#xff08;掌握&#xff09;1.标签 css&#xff08;了解&#xff09;1.简介2.常用样式定义 JavaScript&#xff08;掌握&#xff09;1.简介2.基本语法2.1声明变量2.2声明对象2.3声明方法 3.事件 JQuery&#xff08;精通&#xff09;1.简…