RRoy 发表于 2021-7-15 11:41:13

果蔬成熟度检测---基于AS7341颜色传感器

多亏了人类进化出的彩色视觉,让我们只需要看果蔬的外观就能轻松分辨它们熟了没有。但现如今,果蔬类作物一般都是大规模生产,因此我们需要一种比肉眼更可靠、更方便快捷的方法来分辨出果蔬的成熟度。为了帮助食品公司、杂货店和农民分拣不同成熟度的水果和蔬菜,我开发了这个设备,它基于神经网络模型,能根据光谱颜色来检测果蔬的成熟阶段。


它的原理是:当果蔬成熟的时候,它们的颜色会随着四种色素的含量变化而改变,这四种色素分别是:

- 叶绿素(绿色)d d
- 类胡萝卜素(黄色、红色、橙色)
- 黄酮类化合物:花青素+花黄素(红色、蓝色、紫色)
- 甜菜素(红色、黄色、紫色)

这些色素是一组分子结构的物质,它们能够吸收一段特定波长的光并反射其余的光波。由于未成熟的果蔬细胞中主要含有的色素是叶绿素,所以它们往往是绿色的。当它们成熟时,叶绿素便会分解,被橙色的类胡萝卜素和红色的花青素所取代,这两种色素是一种抗氧化剂,能延缓水果在空气中的变质速度。随后,酶促褐变反应的发生会让果蔬变为褐色,酶在这些引发变色的化学反应中起到催化剂的作用,比如:

- 酚类的羟基化反应
- 酚类的氧化反应

研究了一下果蔬成熟过程的颜色变化后,我决定基于分类模型构建一个人工神经网络 (ANN) 来破译不同果蔬的光谱颜色,从而预测它们的成熟阶段。

在构建、测试这个神经网络模型之前,我先用 PHP 开发了一个Web应用程序来整理AS7341 可见光传感器生成的果蔬光谱颜色数据,并根据这些数据通过传感器创建了一个成熟果蔬的颜色数据集。 我用Arduino Nano 33 IoT把传感器产生的数据发送到了Web应用程序,再用连接到Nano 33 IoT的四个类按钮获取每个果蔬的光谱数据,并且,我根据经验将这些数据分为了不同成熟阶段(给它们做了标签),分别是:
- 初熟
- 半熟
- 成熟
- 腐烂

完成这个数据集之后,我就用TensorFlow构建了人工神经网络 (ANN) 来用光谱颜色预测果蔬的成熟阶段(标签)。

测试完程序,我就用它做了很多实验,预测了许多种果蔬的成熟阶段。就我做的这些实验来说,这个模型的使用效果绝佳!

以上就是我对这个项目的简要描述了!

## 硬件清单

- Arduino Nano 33 IoT × 1
- DFRobot Gravity: AS7341可见光谱传感器 × 1
- Raspberry Pi 3B/4 × 1
- 10K电位计(长轴) × 1
- 按钮(6×6) × 4
- 5mm LED灯(绿色) × 1
- 5mm LED灯(红色) × 1
- 面包板 × 2








![](https://cdn.jsdelivr.net/gh/RalstonLiu/mdnice4/2021-7-15/1626318147155-0b2952aec74042ea970455979130ec9b.gif)


## 步骤1:用PHP开发一个Web应用来整理果蔬光谱颜色数据

我用PHP开发了这个web应用程序(果蔬数据记录器),通过Arduino Nano 33 IoT从AS7341可见光传感器获取果蔬的光谱颜色数据,并将这些数据插入CSV文件(`spectral\\u color\\u database.CSV`)以创建基于光谱颜色的成熟阶段数据集。

Web应用程序包含一个文件(index.php),需要这些参数才能向数据集插入新行(条目):

- F1
- F2
- F3
- F4
- F5
- F6
- F7
- F8
- nir_1
- nir_2
- class
   

### index.php

检查Nano 33 IoT是否传输了所有需要的参数。

如果是,请使用获得的参数(包括当前日期)创建数据数组。

使用fputcsv函数将最近生成的数据数组作为新行插入`spectral_color_database.csv`文件。

然后,打印:数据插入成功!

如果有遗漏或没有输入数据,打印:等待来自AS7341传感器的数据插入……

```php
# Check the incoming data packet:
if(isset($_GET["F1"]) && isset($_GET["F2"]) && isset($_GET["F3"]) && isset($_GET["F4"]) && isset($_GET["F5"]) && isset($_GET["F6"]) && isset($_GET["F7"]) && isset($_GET["F8"]) && isset($_GET["nir_1"]) && isset($_GET["nir_2"]) && isset($_GET["class"])){
    # Create the data array.
    $data = array($_GET["F1"], $_GET["F2"], $_GET["F3"], $_GET["F4"], $_GET["F5"], $_GET["F6"], $_GET["F7"], $_GET["F8"], $_GET["nir_1"], $_GET["nir_2"], $_GET["class"], date("m/d"));
    # Insert the recently generated data array into the CSV file as a new row.      
    $file = fopen("spectral_color_database.csv", "a");
    fputcsv($file, $data);
    fclose($file);
    // Print result:
    echo "Data Inserted Successfully!";
}else{
    echo "Waiting for data from the AS7341 sensor to insert...";
}
```



### 1.1. 在树莓派上设置web应用

在创建了PHP web应用程序之后,在Raspberry Pi上运行它,或者您可以在任何服务器上运行该应用程序,只要它是PHP服务器。

如果您想使用Raspberry Pi,但不知道如何在上面设置LAMP web服务器,请查看[本教程](https://www.hackster.io/kutluhan-aktar/web-enabled-ml-mask-detection-robot-fines-w-penalty-receipt-23821b#toc-step-9--setting-up-a-lamp-web-server-on-raspberry-pi-8)。

首先,提取`Vegetables_and_Fruits_Data_Logger.zip`文件夹。




然后,使用终端将应用程序文件夹(`Vegetables_and_Fruits_Data_Logger`)移动到apache服务器(`/var/www/html`),因为apache服务器是受保护的位置。

```ssh
sudo mv /home/pi/Downloads/Vegetables_and_Fruits_Data_Logger/
/var/www/html/
```




如果未设置或未找到所需参数,web应用程序将打印:等待插入来自AS7341传感器的数据....

`http://localhost/Vegetables_and_Fruits_Data_Logger/`




否则,web应用程序通过添加当前日期将传入数据作为新行插入CSV文件(数据集)并打印:data Inserted Successfully!(数据插入成功)

`http://localhost/Vegetables_and_Fruits_Data_Logger/?F1=13&F2=12&F3=12&F4=12&F5=12&F6=12&F7=12&F8=12&nir_1=12&nir_2=9&class=0`




## 步骤2:设置Arduino Nano 33 IoT

如果你是Arduino Nano 33 IoT新手,请按下面的步骤在Arduino IDE上操作

下载所需的驱动-Arduino SAMD Core --点此处查看 https://www.arduino.cc/en/Guide/NANO33IoT

5cf20e567e11439ba19c5e11c2894c86.png



下载WiFiNINA库后才能连接WiFi:https://www.arduino.cc/en/Reference/WiFiNINA




### 步骤3:编程获取数据并发送到web应用

首先,为了能够通过Arduino Nano 33 IoT从AS7341可见光传感器获取光谱颜色数据,您需要安装DFRobot AS7341库: https://github.com/DFRobot/DFRobot_AS7341

- 包含所需的库及定义WiFi设置

```c
char ssid[] = "SSID";      // your network SSID (name)
char pass[] = "PASSWORD";    // your network password (use for WPA, or use as key for WEP)
int keyIndex = 0;            // your network key Index number (needed only for WEP)
int status = WL_IDLE_STATUS;

// Enter the IPAddress of your Raspberry Pi.
IPAddress server(192, 168, 1, 20);

// Initialize the Ethernet client library
WiFiClient client; /* WiFiSSLClient client; */
```

- 定义AS7341传感器设置及对象

```c
// Define the AS7341 object.
DFRobot_AS7341 as7341;
// Define AS7341 data objects:
DFRobot_AS7341::sModeOneData_t data1;
DFRobot_AS7341::sModeTwoData_t data2;
```

- 检测I2C是否可以正常通信并打开AS7341传感器上的内置LED。

```c
// Detect if I2C can communicate properly
while (as7341.begin() != 0) {
    Serial.println("I2C init failed, please check if the wire connection is correct");
    delay(1000);
}

// Enable the built-in LED on the AS7341 sensor.
as7341.enableLed(true);
```

- 检查WiFi模块并验证连接

```c
if (WiFi.status() == WL_NO_MODULE) { Serial.println("Connection Failed!"); while (true); }
// Attempt to connect to the WiFi network:
while (status != WL_CONNECTED) {
    Serial.println("Attempting to connect to WiFi !!!");
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);
    // Wait 10 seconds for connection:
    delay(10000);
}
```

- 在read_controls函数中,读取电位器及四个按钮的值

```c
void read_controls(){
// Potentiometer:
pot_val = analogRead(pot);
// Class Buttons:
class_1_val = digitalRead(class_1);
class_2_val = digitalRead(class_2);
class_3_val = digitalRead(class_3);
class_4_val = digitalRead(class_4);
}
```

在adjust_brightness函数中,设置引脚电流控制AS7341传感器上内置LED亮度.1~20对应电流4mA, 6mA, 8mA, 10mA, 12mA,......, 42mA。

用AS7341传感器开始测量,并在这些通道映射模式下读取传感器数据通道0~5的值:

- eF1F4ClearNIR
- eF5F8ClearNIR

然后,打印传感器测得的光谱颜色数据。

```c
// Start spectrum measurement:
// Channel mapping mode: 1.eF1F4ClearNIR
as7341.startMeasure(as7341.eF1F4ClearNIR);
// Read the value of sensor data channel 0~5, under eF1F4ClearNIR
data1 = as7341.readSpectralDataOne();
// Channel mapping mode: 2.eF5F8ClearNIR
as7341.startMeasure(as7341.eF5F8ClearNIR);
// Read the value of sensor data channel 0~5, under eF5F8ClearNIR
data2 = as7341.readSpectralDataTwo();
// Print data:
Serial.print("F1(405-425nm): "); Serial.println(data1.ADF1);
Serial.print("F2(435-455nm): "); Serial.println(data1.ADF2);
Serial.print("F3(470-490nm): "); Serial.println(data1.ADF3);
Serial.print("F4(505-525nm): "); Serial.println(data1.ADF4);
Serial.print("F5(545-565nm): "); Serial.println(data2.ADF5);
Serial.print("F6(580-600nm): "); Serial.println(data2.ADF6);
Serial.print("F7(620-640nm): "); Serial.println(data2.ADF7);
Serial.print("F8(670-690nm): "); Serial.println(data2.ADF8);
// CLEAR and NIR:
Serial.print("Clear_1: "); Serial.println(data1.ADCLEAR);
Serial.print("NIR_1: "); Serial.println(data1.ADNIR);
Serial.print("Clear_2: "); Serial.println(data2.ADCLEAR);
Serial.print("NIR_2: "); Serial.println(data2.ADNIR);
Serial.print("\n------------------------------\n");
delay(1000);
```

根据按下的类按钮,通过指定成熟阶段标签\将光谱颜色数据发送到PHP Web应用程序:

- 0 — 初熟
- 1 — 半熟
- 2 — 成熟
- 3 — 腐烂

```c
if(!class_1_val) make_a_get_request("/Vegetables_and_Fruits_Data_Logger/", "0");
if(!class_2_val) make_a_get_request("/Vegetables_and_Fruits_Data_Logger/", "1");
if(!class_3_val) make_a_get_request("/Vegetables_and_Fruits_Data_Logger/", "2");
if(!class_4_val) make_a_get_request("/Vegetables_and_Fruits_Data_Logger/", "3");
```

在make\_a\_get_request函数中:

1)连接果蔬数据记录器的web应用程序。

2)如连接成功,使用光谱颜色数据和选定的成熟阶段标签创建查询字符串。否则,打开5mm红色LED。

3)然后,使用查询字符串发出Get请求,将所需参数发送到web应用程序。

4)如果有可用的传入字节,则从web应用程序获取响应。

5)如果通过web应用程序将传输的数据成功插入数据集(`spectral\u color\u database.csv`),打开5mm绿色LED:
response.indexOf("Data Inserted Successfully!") > 0

6)否则,打开5mm红色LED。

```c
void make_a_get_request(String application, String _class){
// Connect to the web application named Vegetables_and_Fruits_Data_Logger. Change '80' with '443' if you are using SSL connection.
if(client.connect(server, 80)){
    // If successful:
    Serial.println("\n\nConnected to the server!");
    // Create the query string:
    String query = application + "?F1="+data1.ADF1+"&F2="+data1.ADF2+"&F3="+data1.ADF3+"&F4="+data1.ADF4+"&F5="+data2.ADF5+"&F6="+data2.ADF6+"&F7="+data2.ADF7+"&F8="+data2.ADF8+"&nir_1="+data1.ADNIR+"&nir_2="+data2.ADNIR+"&class="+_class;
    // Make an HTTP Get request:
    client.println("GET " + query + " HTTP/1.1");
    client.println("Host: 192.168.1.20");
    client.println("Connection: close");
    client.println();
}else{
    Serial.println("Server Error!");
    digitalWrite(red, HIGH);
}
delay(2000); // Wait 2 seconds after connection...
// If there are incoming bytes available, get the response from the web application.
String response = "";
while (client.available()) { char c = client.read(); response += c; }
if(response != ""){
    Serial.println(response);
    Serial.println("\n");
    // Check whether the transferred data is inserted successfully or not:
    if(response.indexOf("Data Inserted Successfully!") > 0){
      digitalWrite(green, HIGH);
    }else{
      digitalWrite(red, HIGH);
    }
}
// Turn off LEDs:
delay(3000);
digitalWrite(green, LOW);
digitalWrite(red, LOW);
}
```

![](https://cdn.jsdelivr.net/gh/RalstonLiu/mdnice4/2021-7-15/1626318745842-b9be05f3e2a34f3db51387400523d8c2.png)


![](https://cdn.jsdelivr.net/gh/RalstonLiu/mdnice4/2021-7-15/1626318756089-be7bc7c45af54dd3bc1416dd770b306a.png)


![](https://cdn.jsdelivr.net/gh/RalstonLiu/mdnice4/2021-7-15/1626318766586-a3c5b702a6b1468f8aab776b99b40bf7.png)


![](https://cdn.jsdelivr.net/gh/RalstonLiu/mdnice4/2021-7-15/1626318776463-70b6cecc1be0461995fc626b217b25bb.png)


![](https://cdn.jsdelivr.net/gh/RalstonLiu/mdnice4/2021-7-15/1626318785211-911cfddbeb944985bb732c72c4454e19.png)


在运行时, Arduino Nano 33 IoT通过串行通信打印:

- AS7341传感器上内置LED的亮度等级
- AS7341传感器产生的光谱颜色数据
- web应用程序的服务器响应

![](https://cdn.jsdelivr.net/gh/RalstonLiu/mdnice4/2021-7-15/1626318818594-d94d3e6e803a4c03aa167a7830ed50ed.png)


![](https://cdn.jsdelivr.net/gh/RalstonLiu/mdnice4/2021-7-15/1626318811487-eff1daa6aa004257b42b061e4f67d272.png)


## 步骤4:基于光谱颜色建立成熟阶段数据集

为了通过光谱颜色来训练我的果蔬成熟阶段神经网络模型,我需要收集不同水果和蔬菜的光谱颜色数据来创建一个有效的数据集。因此,我决定使用AS7341可见光传感器来收集光谱颜色数据。

AS7341可见光传感器采用业内知名的AMS公司推出的新一代AS7341光谱传感IC。它有八个通道用于可见光,一个通道用于近红外(NIR),一个不带滤光片的通道(透明),以及一个分布在环境光闪烁(闪烁)上的额外通道。该传感器拥有6个独立的16位ADC通道,可以并行的处理数据。该传感器板载了两颗亮度可调LED,甚至能在黑暗环境下收集数据。

![](https://cdn.jsdelivr.net/gh/RalstonLiu/mdnice4/2021-7-15/1626318851858-0a9044f2a3924f40842da710c37191c6.png)


在运行中,我用AS7341传感器收集了这些数据:

- F1 (405-425nm)
- F2 (435-455nm)
- F3 (470-490nm)
- F4 (505-525nm)
- F5 (545-565nm)
- F6 (580-600nm)
- F7 (620-640nm)
- F8 (670-690nm)
- Clear_1
- NIR_1
- Clear_2
- NIR_2

如前一步所述,我将AS7341传感器连接到Arduino Nano 33 IoT,以将参数和指定的成熟阶段标签发送到PHP web应用程序。获取数据后,Web应用程序通过将当前日期参数(步骤1)添加到以下列下的`spectral_color_database.csv`文件(数据集)中来插入所需的参数。

- F1
- F2
- F3
- F4
- F5
- F6
- F7
- F8
- NIR_1
- NIR_2
- Ripeness
- Date

在完成编程和组装设备后,我选择了11种不同的水果和蔬菜,通过光谱颜色收集它们的成熟度等级:

c87e006c1b4843139773c20d8f54d622.png



该设备允许用户通过按下四个类按钮之一将数据发送到web应用程序并分配成熟类(标签):

- 0 — 初熟
- 1 — 半熟
- 2 — 成熟
- 3 — 腐烂

10天内,我每天三次整理每种果蔬的光谱颜色数据和(根据经验指定的)成熟度等级:










![](https://cdn.jsdelivr.net/gh/RalstonLiu/mdnice4/2021-7-15/1626318936599-c62ab05f6b7249438450f1fc2034acee.png)


![](https://cdn.jsdelivr.net/gh/RalstonLiu/mdnice4/2021-7-15/1626318944754-93b87831ac134b388ba4b96fa1ad1e43.png)


![](https://cdn.jsdelivr.net/gh/RalstonLiu/mdnice4/2021-7-15/1626318953223-ee6084b1abfa413092cfe22c7eb17de2.png)


此设备让用户可以通过电位计调整AS7341传感器上内置LED的亮度。
如果传输的数据成功插入数据集,设备将点亮5mm绿色LED。否则,它会打开5mm红色LED。

![](https://cdn.jsdelivr.net/gh/RalstonLiu/mdnice4/2021-7-15/1626318973441-c25ac646691a4e4bb26dd0cd41ec3c0f.png)


![](https://cdn.jsdelivr.net/gh/RalstonLiu/mdnice4/2021-7-15/1626318980740-a7b70f2a7ffb43be84946d639b12fe71.png)


正如所料,水果和蔬菜在十天的数据收集过程中逐渐腐烂:

![](https://cdn.jsdelivr.net/gh/RalstonLiu/mdnice4/2021-7-15/1626318997179-12fc17501ff94c45a60f6456cbc69fe1.png)


![](https://cdn.jsdelivr.net/gh/RalstonLiu/mdnice4/2021-7-15/1626319003502-fa330e858bd14bc6a8b51baab69f61cc.png)


最后,通过每天三次的光谱颜色测量收集成熟度等级,连续十天,我得到了一个有效的数据集(spectral\\u color\\u database.csv)来训练我的神经网络模型。

![](https://cdn.jsdelivr.net/gh/RalstonLiu/mdnice4/2021-7-15/1626319017206-f99cc934399c4cddb979f4161ab8d4f3.png)


## 步骤5:用TensorFlow建立人工神经网络

当我用光谱颜色数据集完成果蔬成熟阶段测定后,我开始研究我的人工神经网络(ANN)模型来预测各种水果和蔬菜的成熟阶段。
我决定用Python中的TensorFlow创建我的神经网络模型。因此,首先,我遵循以下步骤来更好地理解我的数据集:

- 数据可视化
- 数据缩放(标准化)
- 数据预处理
- 数据拆分

如前几步所述,我在收集光谱颜色数据时,根据经验为每中水果和蔬菜条目(输入)分配了成熟阶段类。因此,我使用这些预定义类作为标签而不需要为分配标签而预处理数据集:

- 0 — 初熟
- 1 — 半熟
- 2 — 成熟
- 3 — 腐烂

在对数据集中的输入进行缩放(标准化)和预处理之后,我为每中水果和蔬菜条目提取了10个输入变量和一个标签,并将其分为上述四个类。然后,我用TensorFlow建立了一个人工神经网络模型,并用我的数据集对其进行训练,以获得最佳的结果和预测。
层:

- 10\[输入\]
- 16\[隐藏\]
- 32\[隐藏\]
- 64\[隐藏\]
- 128\[隐藏\]
- 256\[隐藏\]
- 4\[输出\]

![](https://cdn.jsdelivr.net/gh/RalstonLiu/mdnice4/2021-7-15/1626319052214-f101a971e27849b0900f7df8c748612b.png)


![](https://cdn.jsdelivr.net/gh/RalstonLiu/mdnice4/2021-7-15/1626319060134-5244aec482454f9db256017b810d0839.png)


为了执行上面的所有步骤,除所需的库外,我在Python中创建了一个名为“成熟度检测”的类:

```python
import tensorflow as tf
from tensorflow import keras
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
```

接着,我将讨论上面提到的每个步骤的Python编码。
此外,您还可以下载`build_neural_network_model.py`来检查编码。

4bf766d644934e13a9871edaa98fde0f.png
![](https://cdn.jsdelivr.net/gh/RalstonLiu/mdnice4/2021-7-15/1626319112472-4bf766d644934e13a9871edaa98fde0f.png)


### 步骤5.1:基于光谱颜色的成熟期数据可视化

在开始构建神经网络模型之前,了解给定的数据集以传递适当格式的数据是至关重要的。

因此,在这一步中,我将向您展示如何可视化成熟阶段数据集,并在Python中对其进行缩放(规范化)。

首先,从spectral\_color\_database.csv中读取成熟阶段数据集

```c
csv_path = "E:\PYTHON\Vegetables_and_Fruits_Ripeness_Detection\spectral_color_database.csv"
df = pd.read_csv(csv_path)
```

在graphics 函数中,使用Matplotlib库可视化成熟阶段数据集中请求的列:

```c
def graphics(self, column_1, column_2, x_label, y_label):
      # Show requested columns from the data set:
      plt.style.use("dark_background")
      plt.gcf().canvas.set_window_title('Vegetables and Fruits Ripeness Detection by Color')
      plt.hist2d(self.df, self.df, cmap='RdBu')
      plt.colorbar()
      plt.xlabel(x_label)
      plt.ylabel(y_label)
      plt.title(x_label)
      plt.show()
```

在数据可视化功能中,在缩放和预处理成熟阶段数据集之前,仔细检查所有列,以使用适当格式的数据构建模型。

```c
def graphics(self, column_1, column_2, x_label, y_label):
      # Show requested columns from the data set:
      plt.style.use("dark_background")
      plt.gcf().canvas.set_window_title('Vegetables and Fruits Ripeness Detection by Color')
      plt.hist2d(self.df, self.df, cmap='RdBu')
      plt.colorbar()
      plt.xlabel(x_label)
      plt.ylabel(y_label)
      plt.title(x_label)
      plt.show()
```

![](https://cdn.jsdelivr.net/gh/RalstonLiu/mdnice4/2021-7-15/1626319160130-bbd16aafaa4b49378ab4f5fafc95f2d4.png)


![](https://cdn.jsdelivr.net/gh/RalstonLiu/mdnice4/2021-7-15/1626319166820-59e551c03c2948f0af8f0f6475edcc90.png)



![](https://cdn.jsdelivr.net/gh/RalstonLiu/mdnice4/2021-7-15/1626319174176-7db6982156384f098e42856b2b8d2d99.png)


![](https://cdn.jsdelivr.net/gh/RalstonLiu/mdnice4/2021-7-15/1626319180992-978f85823f874111946e395949c02f7d.png)


![](https://cdn.jsdelivr.net/gh/RalstonLiu/mdnice4/2021-7-15/1626319188344-7d3e68a284534d9abebcc45a9a2f138d.png)


![](https://cdn.jsdelivr.net/gh/RalstonLiu/mdnice4/2021-7-15/1626319196341-12607d26d6874b72b357c106dbeac8cd.png)


![](https://cdn.jsdelivr.net/gh/RalstonLiu/mdnice4/2021-7-15/1626319203431-0f40639470c642c9a6b1a833e9979e93.png)


![](https://cdn.jsdelivr.net/gh/RalstonLiu/mdnice4/2021-7-15/1626319210345-c728908572c04b88bc7367fcfe51d628.png)


### 步骤5.2:分配标签(预定义的成熟阶段)和缩放(规范化)输入数据

在建立和训练神经网络模型之前,我为每个食物和蔬菜条目(输入)使用预定义的成熟度类作为它的标签。

在`define_and_assign_labels`函数中,为数据集中的每个输入获取预定义的成熟度类(标签)\,并将它们附加到标签数组中。

```c
def define_and_assign_labels(self):
      self.labels = self.df.pop("Ripeness")
```

在分配标签之后,我需要创建输入来训练神经网络模型。根据成熟阶段数据集,我决定使用AS7341可见光传感器生成的这十个参数作为光谱颜色数据,来创建输入:

- F1
- F2
- F3
- F4
- F5
- F6
- F7
- F8
- NIR_1
- NIR_2

在为输入选择10个参数并可视化数据集之后,我对每个参数列进行了缩放(标准化)以正确地格式化。

通常,数据集中水果或蔬菜的每个输入在缩放之前都是这样的:
- 131, 148, 184, 765, 1000, 1000, 1000, 809, 276, 273

完成缩放(标准化)后,我从每个水果和蔬菜条目的成熟阶段数据集中提取这些缩放参数列(输入):

- scaled_F1
- scaled_F2
- scaled_F3
- scaled_F4
- scaled_F5
- scaled_F6
- scaled_F7
- scaled_F8
- scaled\_NIR\_1
- scaled\_NIR\_2


输入缩放参数:
- \

在`scale_data_and_define_inputs`函数中,将每个参数列划分为所需的值,使其小于或等于1。

然后,使用缩放参数创建输入,将其附加到`inputs`数组,并使用`asarray()`函数将此数组转换为NumPy数组。

每个输入包括十个参数\:

- \

```c
def scale_data_and_define_inputs(self):
      self.df["scaled_F1"] = self.df.pop("F1") / 1000
      self.df["scaled_F2"] = self.df.pop("F2") / 1000
      self.df["scaled_F3"] = self.df.pop("F3") / 1000
      self.df["scaled_F4"] = self.df.pop("F4") / 1000
      self.df["scaled_F5"] = self.df.pop("F5") / 1000
      self.df["scaled_F6"] = self.df.pop("F6") / 1000
      self.df["scaled_F7"] = self.df.pop("F7") / 1000
      self.df["scaled_F8"] = self.df.pop("F8") / 1000
      self.df["scaled_NIR_1"] = self.df.pop("NIR_1") / 1000
      self.df["scaled_NIR_2"] = self.df.pop("NIR_2") / 1000
      # Create the inputs array using the scaled variables:
      for i in range(len(self.df)):
            self.inputs.append(np.array(, self.df["scaled_F2"], self.df["scaled_F3"], self.df["scaled_F4"], self.df["scaled_F5"], self.df["scaled_F6"], self.df["scaled_F7"], self.df["scaled_F8"], self.df["scaled_NIR_1"], self.df["scaled_NIR_2"]]))
      self.inputs = np.asarray(self.inputs)
```

![](https://cdn.jsdelivr.net/gh/RalstonLiu/mdnice4/2021-7-15/1626319983148-0f9a9e443ba34b27831b2c15fcc0ceb7.png)


## 步骤5.3: 基于光谱颜色的成熟阶段模型训练

在对成熟阶段数据集进行预处理和缩放(标准化)以创建输入和标签之后,我将它们拆分为训练集(95%)和测试集(5%):

```c
def split_data(self):
      l = len(self.df)
      # (95%, 5%) - (training, test)
      self.train_inputs = self.inputs
      self.test_inputs = self.inputs
      self.train_labels = self.labels
      self.test_labels = self.labels
```

然后,我用Keras建立了我的人工神经网络(ANN)模型,并用19个时期的训练集对其进行训练。

您可以查看教程来了解激活函数、丢失函数、epoch等:https://www.tensorflow.org/tutorials

```c
def build_and_train_model(self):
      # Build the neural network:
      self.model = keras.Sequential([
            keras.Input(shape=(10,)),
            keras.layers.Dense(16),
            keras.layers.Dense(32),
            keras.layers.Dense(64),
            keras.layers.Dense(128),
            keras.layers.Dense(256),
            keras.layers.Dense(4, activation='softmax')
      ])
      # Compile:
      self.model.compile(optimizer='adam', loss="sparse_categorical_crossentropy", metrics=['accuracy'])
      # Train:
      self.model.fit(self.train_inputs, self.train_labels, epochs=19)
      
    ...
```

![](https://cdn.jsdelivr.net/gh/RalstonLiu/mdnice4/2021-7-15/1626320015888-8fca8369c8aa4e318690fa43cfe4033d.png)


使用训练集(输入和标签)进行训练后,我的神经网络模型的精度在0.82到0.89之间。

![](https://cdn.jsdelivr.net/gh/RalstonLiu/mdnice4/2021-7-15/1626320024479-2effd46c809a45abac396d8a1cc6e6ea.png)


## 步骤5.4:评估模型

在建立和训练我的人工神经网络模型之后,我利用测试集(输入和标签)测试了它的准确性和有效性。
模型的估计精度为0.9412。

```c
      ...
      
    # Test the accuracy:
      print("\n\nModel Evaluation:")
      test_loss, test_acc = self.model.evaluate(self.test_inputs, self.test_labels)
      print("Evaluated Accuracy: ", test_acc)
```

![](https://cdn.jsdelivr.net/gh/RalstonLiu/mdnice4/2021-7-15/1626320044837-eb29c4c8b7654235b644af06545fe7ce.png)


在评估了我的神经网络模型之后,我将其保存为TensorFlow Keras H5模型(`ANN_Ripeness_Detection.h5`)。

```c
def save_model(self):
      self.model.save("E:\PYTHON\Vegetables_and_Fruits_Ripeness_Detection\model\ANN_Ripeness_Detection.h5")
```

## 步骤6:通过预测成熟阶段来试验模型

在完成并保存了我的神经网络模型之后,我用这个设备获取了水果和蔬菜的光谱颜色数据,并将它们格式化为输入参数,这取决于我在训练模型时如何对它们进行缩放(标准化)(步骤5.2)。然后,我创建了一个由格式化输入参数组成的NumPy数组(prediction\ array),用该模型通过光谱颜色预测果蔬成熟阶段。

该模型以4个数字的数组形式预测每个输入的标签(成熟度类)的可能性。它们表示模型的“可信度”,即给定的输入数组对应于基于光谱颜色\的四个不同成熟阶段类别中的每一个,如步骤5所示。

- \ 初熟
- \ 半熟
- \ 成熟
- \ 腐烂

在 `make_predictions`函数中:

1)将保存的模型(ANN\\u-richess\\u-Detection.h5)加载到内存中

2)格式化输入数据

3)然后,用NumPy数组中格式化的输入数据为每种水果和蔬菜设置输入tensor值,输入 - prediction_array

4)运行模型进行预测

5)最后,使用`argmax()`函数为每个输入显示模型预测的最精确标签(成熟度类)

```c
def make_predictions(self):
      saved_model = keras.models.load_model("E:\PYTHON\Vegetables_and_Fruits_Ripeness_Detection\model\ANN_Ripeness_Detection.h5")
      prediction_array = np.array([
            ,
            ,
            ,
            
      ])
      predictions = saved_model.predict(prediction_array)
      print("\n\nModel Predictions:\n")
      for i in range(len(prediction_array)):
            print("INPUT[" + str(i+1) + "] => ", self.ripeness_class_names)])
```

![](https://cdn.jsdelivr.net/gh/RalstonLiu/mdnice4/2021-7-15/1626320120692-61e2870bf06745bd97e1ee306957deb7.png)


我运行了这个模型来预测了我可以确定的多种水果和蔬菜的成熟阶段。就我的实验而言,模型运行得十分完美!

![](https://cdn.jsdelivr.net/gh/RalstonLiu/mdnice4/2021-7-15/1626320131327-73dda504aa914dc1907747f17d2506b0.png)


## 连接与调整

```c
// Connections
// Arduino Nano 33 IoT :         
//                              AS7341 11-Channel Spectral Color Sensor
// 3.3V --------------------------- +
// GND--------------------------- -
// A5   --------------------------- C
// A4   --------------------------- D
//                              10K Potentiometer
// A0   --------------------------- S
//                              Class Button_1 (6x6)
// D2   ---------------------------
//                              Class Button_2 (6x6)
// D3   ---------------------------
//                              Class Button_3 (6x6)
// D4   ---------------------------
//                              Class Button_4 (6x6)
// D5   ---------------------------
//                              5mm Green LED
// D6   ---------------------------
//                              5mm Red LED
// D7   ---------------------------
```

为了收集和发送AS7341可见光传感器产生的光谱颜色数据,我将传感器连接到Arduino Nano 33 IoT上。然后,我连接了四个类按钮,以便在向PHP Web应用程序发送数据时分配成熟度类(初熟、半熟、成熟、腐烂)。我用一个电位计(带旋钮的长轴)来调整AS7341传感器上内置LED的亮度。最后,我添加了5毫米的绿色和红色LED来提示来自web应用程序的响应成功与否。

![](https://cdn.jsdelivr.net/gh/RalstonLiu/mdnice4/2021-7-15/1626320151112-100663ca33854d02b434b55b0903a517.png)

![](https://cdn.jsdelivr.net/gh/RalstonLiu/mdnice4/2021-7-15/1626320158722-bee47ca94f2444e5801665cf24d2c450.png)


完成连接后,我用热胶枪把面包板和AS7341传感器固定在一个旧书架上,搭建了一个坚固的装置。

![](https://cdn.jsdelivr.net/gh/RalstonLiu/mdnice4/2021-7-15/1626320170596-c8fa1408ef984b1f863b7567074c9efd.png)

![](https://cdn.jsdelivr.net/gh/RalstonLiu/mdnice4/2021-7-15/1626320177773-46fd234acea040e8bf52959f9a83e561.png)


## 视频演示及总结


![](https://cdn.jsdelivr.net/gh/RalstonLiu/mdnice4/2021-7-15/1626320203466-2021-07-14%2013-54-35.2021-07-14%2014_07_29.gif)


在完成了上述所有步骤并进行了实验之后,该设备就可作为一个熟练的助手,可以根据水果和蔬菜的成熟阶段,通过光谱颜色对其进行分类:

![](https://cdn.jsdelivr.net/gh/RalstonLiu/mdnice4/2021-7-15/1626320215648-3a0748dae1a44ceca9c0b3554de8a8db.png)


## 拓展讨论

通过将这种光谱颜色成熟度检测方法引入到普通使用中,可以帮助\:

- 避免了农民从果蔬生长期到收获期用大量时间对果蔬进行人工分类和检验
- 改进产量估算
- 加速疾病检测



## 参考:

\Mrs Rex Fiona et al 2019 J. Phys.: Conf. Ser. 1362 012033

## 相关下载

1.数据集https://hacksterio.s3.amazonaws.com/uploads/attachments/1321630/spectral\_color\_database_B1MbS29M9D.csv
   
2.果蔬数据记录器
    (https://hacksterio.s3.amazonaws.com/uploads/attachments/1321628/vegetables_and_fruits_data_logger_WNH3wbX8v3.zip)
   
3.ANN成熟度检测.h5
    (https://hacksterio.s3.amazonaws.com/uploads/attachments/1321623/ann_ripeness_detection_kDFk1yJaTe.h5)
   
4.连接图
    https://hacksterio.s3.amazonaws.com/uploads/attachments/1321629/schematic_Ygqju7htJN.png
   

![](https://cdn.jsdelivr.net/gh/RalstonLiu/mdnice4/2021-7-15/1626320253076-e740fe005b72475486e0f902d82a64f5.png)


### 代码下载:

Vegetables\_and\_Fruits\_Ripeness\_Detection.ino
https://www.hackster.io/code_files/531808/download
build\_neural\_network_model.py
https://www.hackster.io/code_files/531809/download
index.php (web app)
https://www.hackster.io/code_files/531810/download

hnyzcj 发表于 2021-7-15 16:39:47

good zan

shzrzxlee 发表于 2021-11-7 17:34:06

这个果蔬是模型 蛮逼真的

丨偏执狂丨 发表于 2021-11-8 12:15:56

想法蛮好的

Lannister 发表于 2022-5-2 19:51:13

很强势,希望能进一步学习

阿景 发表于 2022-6-14 21:22:57

博主您好,看了您用AS7341做果蔬成熟度检测的实验,有很多的启发。我正在学习使用AS7341传感器,但是在色彩检验的时候有很大的问题,红光和蓝光的检测强度不论是什么颜色的情况下都非常地大,严重影响了实验结果。但是如果将光强减小,那么颜色就正常了,但是此时的光强非常地小,只有几十。

阿景 发表于 2022-6-14 21:24:33

阿景 发表于 2022-6-14 21:22
博主您好,看了您用AS7341做果蔬成熟度检测的实验,有很多的启发。我正在学习使用AS7341传感器,但是在色彩 ...

想问问大家知道这是什么原因吗?
页: [1]
查看完整版本: 果蔬成熟度检测---基于AS7341颜色传感器