news 2026/6/11 17:25:57

毕设项目分享 深度学习水果识别

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
毕设项目分享 深度学习水果识别

文章目录

  • 1 前言
  • 2 开发简介
  • 3 识别原理
    • 3.1 传统图像识别原理
    • 3.2 深度学习水果识别
  • 4 数据集
  • 5 部分关键代码
    • 5.1 处理训练集的数据结构
    • 5.2 模型网络结构
    • 5.3 训练模型
  • 6 识别效果

1 前言

Hi,大家好,这里是丹成学长,今天做一个 基于深度学习的水果识别毕业设计

项目运行效果:

毕业设计 深度学习水果分类系统

🧿 项目分享:见文末!

2 开发简介

深度学习作为机器学习领域内新兴并且蓬勃发展的一门学科, 它不仅改变着传统的机器学习方法, 也影响着我们对人类感知的理解, 已经在图像识别和语音识别等领域取得广泛的应用。 因此, 本文在深入研究深度学习理论的基础上, 将深度学习应用到水果图像识别中, 以此来提高了水果图像的识别性能。

3 识别原理

3.1 传统图像识别原理

传统的水果图像识别系统的一般过程如下图所示,主要工作集中在图像预处理和特征提取阶段。

在大多数的识别任务中, 实验所用图像往往是在严格限定的环境中采集的, 消除了外界环境对图像的影响。 但是实际环境中图像易受到光照变化、 水果反光、 遮挡等因素的影响, 这在不同程度上影响着水果图像的识别准确率。

在传统的水果图像识别系统中, 通常是对水果的纹理、 颜色、 形状等特征进行提取和识别。

3.2 深度学习水果识别

CNN 是一种专门为识别二维特征而设计的多层神经网络, 它的结构如下图所示,这种结构对平移、 缩放、 旋转等变形具有高度的不变性。

学长本次采用的 CNN 架构如图:

4 数据集

  • 数据库分为训练集(train)和测试集(test)两部分

  • 训练集包含四类apple,orange,banana,mixed(多种水果混合)四类237张图片;测试集包含每类图片各两张。图片集如下图所示。

  • 图片类别可由图片名称中提取。

训练集图片预览

测试集预览

数据集目录结构

5 部分关键代码

5.1 处理训练集的数据结构

importosimportpandasaspd train_dir='./Training/'test_dir='./Test/'fruits=[]fruits_image=[]foriinos.listdir(train_dir):forimage_filenameinos.listdir(train_dir+i):fruits.append(i)# name of the fruitfruits_image.append(i+'/'+image_filename)train_fruits=pd.DataFrame(fruits,columns=["Fruits"])train_fruits["Fruits Image"]=fruits_imageprint(train_fruits)

5.2 模型网络结构

importmatplotlib.pyplotaspltimportseabornassnsfromkeras.preprocessing.imageimportImageDataGenerator,img_to_array,load_imgfromglobimportglobfromkeras.modelsimportSequentialfromkeras.layersimportConv2D,MaxPooling2D,Activation,Dropout,Flatten,Dense img=load_img(train_dir+"Cantaloupe 1/r_234_100.jpg")plt.imshow(img)plt.axis("off")plt.show()array_image=img_to_array(img)# shape (100,100)print("Image Shape --> ",array_image.shape)# 131个类目fruitCountUnique=glob(train_dir+'/*')numberOfClass=len(fruitCountUnique)print("How many different fruits are there --> ",numberOfClass)# 构建模型model=Sequential()model.add(Conv2D(32,(3,3),input_shape=array_image.shape))model.add(Activation("relu"))model.add(MaxPooling2D())model.add(Conv2D(32,(3,3)))model.add(Activation("relu"))model.add(MaxPooling2D())model.add(Conv2D(64,(3,3)))model.add(Activation("relu"))model.add(MaxPooling2D())model.add(Flatten())model.add(Dense(1024))model.add(Activation("relu"))model.add(Dropout(0.5))# 区分131类model.add(Dense(numberOfClass))# outputmodel.add(Activation("softmax"))model.compile(loss="categorical_crossentropy",optimizer="rmsprop",metrics=["accuracy"])print("Target Size --> ",array_image.shape[:2])

5.3 训练模型

train_datagen=ImageDataGenerator(rescale=1./255,shear_range=0.3,horizontal_flip=True,zoom_range=0.3)test_datagen=ImageDataGenerator(rescale=1./255)epochs=100batch_size=32train_generator=train_datagen.flow_from_directory(train_dir,target_size=array_image.shape[:2],batch_size=batch_size,color_mode="rgb",class_mode="categorical")test_generator=test_datagen.flow_from_directory(test_dir,target_size=array_image.shape[:2],batch_size=batch_size,color_mode="rgb",class_mode="categorical")fordata_batch,labels_batchintrain_generator:print("data_batch shape --> ",data_batch.shape)print("labels_batch shape --> ",labels_batch.shape)breakhist=model.fit_generator(generator=train_generator,steps_per_epoch=1600//batch_size,epochs=epochs,validation_data=test_generator,validation_steps=800//batch_size)#保存模型 model_fruits.h5model.save('model_fruits.h5')

顺便输出训练曲线

#展示损失模型结果plt.figure()plt.plot(hist.history["loss"],label="Train Loss",color="black")plt.plot(hist.history["val_loss"],label="Validation Loss",color="darkred",linestyle="dashed",markeredgecolor="purple",markeredgewidth=2)plt.title("Model Loss",color="darkred",size=13)plt.legend()plt.show()#展示精确模型结果plt.figure()plt.plot(hist.history["accuracy"],label="Train Accuracy",color="black")plt.plot(hist.history["val_accuracy"],label="Validation Accuracy",color="darkred",linestyle="dashed",markeredgecolor="purple",markeredgewidth=2)plt.title("Model Accuracy",color="darkred",size=13)plt.legend()plt.show()

6 识别效果

fromtensorflow.keras.modelsimportload_modelimportosimportpandasaspdfromkeras.preprocessing.imageimportImageDataGenerator,img_to_array,load_imgimportcv2,matplotlib.pyplotasplt,numpyasnpfromkeras.preprocessingimportimage train_datagen=ImageDataGenerator(rescale=1./255,shear_range=0.3,horizontal_flip=True,zoom_range=0.3)model=load_model('model_fruits.h5')batch_size=32img=load_img("./Test/Apricot/3_100.jpg",target_size=(100,100))plt.imshow(img)plt.show()array_image=img_to_array(img)array_image=array_image*1./255x=np.expand_dims(array_image,axis=0)images=np.vstack([x])classes=model.predict_classes(images,batch_size=10)print(classes)train_dir='./Training/'train_generator=train_datagen.flow_from_directory(train_dir,target_size=array_image.shape[:2],batch_size=batch_size,color_mode="rgb",class_mode="categorical”)print(train_generator.class_indices)

fig=plt.figure(figsize=(16,16))axes=[]files=[]predictions=[]true_labels=[]rows=5cols=2# 随机选择几个图片defgetRandomImage(path,img_width,img_height):"""function loads a random image from a random folder in our test path"""folders=list(filter(lambdax:os.path.isdir(os.path.join(path,x)),os.listdir(path)))random_directory=np.random.randint(0,len(folders))path_class=folders[random_directory]file_path=os.path.join(path,path_class)file_names=[fforfinos.listdir(file_path)ifos.path.isfile(os.path.join(file_path,f))]random_file_index=np.random.randint(0,len(file_names))image_name=file_names[random_file_index]final_path=os.path.join(file_path,image_name)returnimage.load_img(final_path,target_size=(img_width,img_height)),final_path,path_classdefdraw_test(name,pred,im,true_label):BLACK=[0,0,0]expanded_image=cv2.copyMakeBorder(im,160,0,0,300,cv2.BORDER_CONSTANT,value=BLACK)cv2.putText(expanded_image,"predicted: "+pred,(20,60),cv2.FONT_HERSHEY_SIMPLEX,0.85,(255,0,0),2)cv2.putText(expanded_image,"true: "+true_label,(20,120),cv2.FONT_HERSHEY_SIMPLEX,0.85,(0,255,0),2)returnexpanded_image IMG_ROWS,IMG_COLS=100,100# predicting imagesforiinrange(0,10):path="./Test"img,final_path,true_label=getRandomImage(path,IMG_ROWS,IMG_COLS)files.append(final_path)true_labels.append(true_label)x=image.img_to_array(img)x=x*1./255x=np.expand_dims(x,axis=0)images=np.vstack([x])classes=model.predict_classes(images,batch_size=10)predictions.append(classes)class_labels=train_generator.class_indices class_labels={v:kfork,vinclass_labels.items()}class_list=list(class_labels.values())foriinrange(0,len(files)):image=cv2.imread(files[i])image=draw_test("Prediction",class_labels[predictions[i][0]],image,true_labels[i])axes.append(fig.add_subplot(rows,cols,i+1))plt.imshow(cv2.cvtColor(image,cv2.COLOR_BGR2RGB))plt.grid(False)plt.axis('off')plt.show()

项目运行效果:

毕业设计 深度学习水果分类系统

🧿 项目分享:见文末!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/30 9:44:36

简单理解:为什么网络通信非要用大端序?小端序不行吗?

做嵌入式网络开发(TCP/UDP/MQTT)时,总有个绕不开的操作:把 MCU 的小端序转为大端序。很多人疑惑:明明 MCU 都用小端序,网络为啥偏要选大端序?小端序直接传不行吗?核心答案&#xff1…

作者头像 李华
网站建设 2026/6/6 1:27:20

【Java抗量子加密实战指南】:深入解析ML-KEM算法实现与迁移策略

第一章:Java抗量子加密算法ML-KEM实现随着量子计算的发展,传统公钥加密体系面临前所未有的安全威胁。ML-KEM(Module-Lattice Key Encapsulation Mechanism)作为NIST标准化的后量子密码候选算法之一,基于模块格上的学习…

作者头像 李华
网站建设 2026/5/31 17:43:17

(Java虚拟线程生产适配 checklist):12项关键评估项确保零故障上线

第一章:Java虚拟线程生产适配的背景与意义随着现代应用程序对高并发处理能力的需求日益增长,传统基于操作系统线程的并发模型逐渐暴露出资源消耗大、上下文切换开销高等问题。Java 虚拟线程(Virtual Threads)作为 Project Loom 的…

作者头像 李华
网站建设 2026/6/10 12:00:22

还在用Postman?FastAPI集成Swagger UI的7大调试优势你不可不知

第一章:FastAPI集成Swagger UI的调试革命FastAPI 作为现代 Python Web 框架,凭借其异步支持、类型提示和自动 API 文档生成功能,正在迅速成为构建高性能 API 的首选工具。其内置对 Swagger UI 的支持,使得开发者无需额外配置即可在…

作者头像 李华
网站建设 2026/6/6 17:30:00

Jupyter自动加载扩展autoreload提升TensorFlow开发效率

Jupyter自动加载扩展autoreload提升TensorFlow开发效率 在深度学习项目中,你有没有经历过这样的场景:刚修改完一个模型定义函数,回到 Jupyter Notebook 想验证效果,却发现代码没变?检查了好几遍文件保存状态&#xff0…

作者头像 李华
网站建设 2026/6/9 5:50:16

行为型-中介者模式

1. 项目结构 项目结构mediator-pattern-demo/├── src/│ └── main/│ └── java/│ └── com/│ └── example/│ └── mediator/│ ├── Mediator.java│ ├…

作者头像 李华