Since trees are crucial for pollination, spreading tree diseases can cause crop yield loss, animal deaths, widespread infectious epidemics, and even land degradation due to soil erosion. Therefore, it is important to detect tree diseases before permeating forests to avoid their hazardous consequences. However, it may not be enough to merely detect diseases since various environmental factors can cause trees to be stressed and catch a highly contagious disease that leads to unrecoverable damage to forests, farms, and arable lands. Hence, it is also important to check and log environmental factors to achieve better detection results. In this regard, by getting prescient warnings regarding potential tree diseases and environmental factors, we can take necessary precautions to avoid hazardous outcomes related to forest degradation and crop yield loss.

After perusing recent research papers on tree disease detection methods and monitoring, I decided to create an easy-to-use and budget-friendly device to detect tree diseases with object detection in the hope of providing an advanced and accessible way to prevent contagious tree diseases.

To detect tree diseases precisely, I needed to collect data from trees infected with different diseases in order to train my object detection model with notable validity. Since Seeed Studio recently released the SenseCAP K1100 kit providing all required sensors for an IoT and computer vision (object detection) project, I decided to build my device based on the SenseCAP K1100 kit, including a Vision AI module and Wio Terminal. Additionally, I connected a Grove CO2 & Temperature & Humidity sensor (SCD30) to obtain accurate environmental factor measurements. Also, I could easily log the collected environmental factors in a CSV file on an SD card since Wio Terminal has a built-in MicroSD card module.

However, I could not capture tree images and run an object detection model simultaneously on Wio Terminal due to memory and RAM limitations. Therefore, I decided to utilize LattePanda 3 Delta 864 to capture images via the Vision AI module and run my object detection model according to the commands transmitted by Wio Terminal via serial communication. Since LattePanda 3 Delta is an SBC (Single-Board Computer) which can run Ubuntu operating system (x86_64), I could use Python to process the captured images and run my model.

After completing my data set by taking pictures of various infected trees, I built my object detection model with Edge Impulse to detect tree disease categories. I utilized Edge Impulse FOMO (Faster Objects, More Objects) algorithm to train my model, which is a novel machine learning algorithm that brings object detection to highly constrained devices. Since Edge Impulse is nearly compatible with all microcontrollers, development boards, and SBCs, I have not encountered any issues while uploading and running my model on LattePanda 3 Delta.

Since I had the chance to collect data on many different tree diseases while wandering in a forest, it was impractical to train the model on each disease separately with limited data. Therefore, I decided to categorize diseases based on the infected parts (stem, branch, or leaf) and use these categories as labels to train my model:

After training and testing my object detection (FOMO) model, I deployed and uploaded the model on LattePanda 3 Delta as a Linux (x86) application (.eim). Therefore, the device is capable of detecting tree diseases by running the model independently without any additional procedures.

Since I decided to make the device to inform the user of the detection results via MMS remotely after running the object detection model, I utilized Twilio's API to send the detected labels and the modified image with bounding boxes to the verified phone number.

Lastly, to make the device as robust and sturdy as possible while operating outdoors, I designed a forest-themed case with a sliding back cover and a laterally moveable Vision AI module handle (3D printable).

So, this is my project in a nutshell 😃

In the following steps, you can find more detailed information on coding, capturing tree images with the Vision AI module, logging environmental factors with Wio Terminal, building an object detection (FOMO) model with Edge Impulse, running the model on LattePanda 3 Delta, and sending the detection results via MMS.

🎁🎨 Huge thanks to Seeed Studio for sponsoring these products:

⭐ SenseCAP K1100 - The Sensor Prototype Kit | Inspect

⭐ Grove - CO2 & Temperature & Humidity Sensor (SCD30) | Inspect

🎁🎨 Huge thanks to DFRobot for sponsoring these products:

⭐ LattePanda 3 Delta 864 | Inspect

⭐ DFRobot 7'' HDMI Display with Capacitive Touchscreen | Inspect

🎁🎨 Also, huge thanks to Creality for sending me a Creality CR-200B 3D Printer.

Step 1: Designing and printing a forest-themed case

Since I focused on building a budget-friendly and accessible device that collects data in forests and informs the user of detected tree diseases, I decided to design a robust and sturdy case allowing the user to leave the device outdoors and capture tree pictures effortlessly. To avoid overexposure to dust and prevent loose wire connections, I added a sliding back cover with a handle to the case. Then, I designed a laterally moveable part for the Vision AI module to place the module on the case via its attachable trail. Also, I decided to adorn the sliding back cover with tree icons so as to complement the forest theme gloriously.

Since I needed to connect an HDMI screen to LattePanda 3 Delta to observe the running operations and the captured images, I added two stands on the top of the case to place the connected screen.

I designed the main case, its sliding back cover, and the laterally moveable part in Autodesk Fusion 360. You can download their STL files below.

Then, I sliced all 3D models (STL files) in Ultimaker Cura.

Note: The pictures above are for demonstrating the sliced models: I needed to split some models to make them compatible with the CR-200B build size (200 x 200 x 200 mm).

Since I wanted to create a solid structure representing a recuperating and transforming autumn forest, I utilized these PLA filaments:

Finally, I printed all parts (models) with my Creality CR-200B 3D Printer. It is my first fully-enclosed FDM 3D printer, and I must say that I got excellent prints effortlessly with the CR-200B :)

If you are a maker planning to print your 3D models to create more complex projects, I highly recommend the CR-200B. Since the CR-200B is fully-enclosed, you can print high-resolution 3D models with PLA and ABS filaments. Also, it has a smart filament runout sensor and the resume printing option for power failures.

According to my experience, there are only two downsides of the CR-200B: relatively small build size (200 x 200 x 200 mm) and manual leveling. Conversely, thanks to the large leveling nuts and assisted leveling, I was able to level the bed and start printing my first model in less than 30 minutes.

#️⃣ Before the first use, remove unnecessary cable ties and apply grease to the rails.

#️⃣ Test the nozzle and hot bed temperatures.

#️⃣ Go to Settings ➡ Leveling and adjust four predefined points by utilizing the leveling nuts.

#️⃣ Finally, attach the spool holder and feed the extruder with the filament.

#️⃣ Since the CR-200B is not officially supported by Cura, select the Ender-3 profile and change the build size to 200 x 200 x 200 mm. Also, to compensate for the nozzle placement, set the Nozzle offset X and Y values to -10 mm on the Extruder 1 tab.

Step 1.1: Assembling the case and making connections & adjustments

// Connections// Wio Terminal :
//                                Grove - VOC and eCO2 Gas Sensor
// SDA --------------------------- SDA
// SCL --------------------------- SCL
//                                Grove - CO2 & Temperature & Humidity Sensor
// SDA --------------------------- SDA
// SCL --------------------------- SCL
//                                Grove - Soil Moisture Sensor
// A0  --------------------------- SIG

First of all, I connected the VOC & eCO2 gas sensor (SGP30),the CO2 & Temperature & Humidity sensor (SCD30), and the soil moisture sensor to Wio Terminal via Grove connection cables.

Then, I connected Wio Terminal and the Vision AI module to LattePanda 3 Delta via USB cables.

To observe running processes, I attached the 7'' HDMI display to LattePanda 3 Delta via a standard HDMI cable.

After printing all parts (models), I fastened all components except the Vision AI module to their corresponding slots on the main case via the hot glue gun.

Then, I attached the Vision AI module to the laterally moveable part allowing placing the module on the case's attachable trail or a separate location.

Finally, I placed the sliding back cover via the dents on the case.

Step 2: Creating a Twilio account to send MMS

https://www.hackster.io/kutluhan-aktar/iot-ai-driven-tree-disease-identifier-w-edge-impulse-mms-1b5ff6#toc-step-2--creating-a-twilio-account-to-send-mms-2

Step 3: Developing a web application in PHP to save the transferred detection results (images)

Since Twilio needs a publicly accessible URL to send media (pictures) via MMS, I developed a simple web application in PHP to save the modified images with bounding boxes after running the object detection model. LattePanda 3 Delta adds bounding boxes for each detected object and sends the detection result (modified image) to the web application.

Since I have a website (theamplituhedron.com), I utilized its server to host this web application named tree_disease_detection_web. However, you can employ a localhost tunneling service like ngrok to send images directly from your localhost via Twilio.

As shown below, the web application consists of one file:

⭐ If LattePanda 3 Delta transfers the modified image (detection result) after running an inference with the Edge Impulse model successfully:

⭐ Check whether the uploaded file extension is in the allowed file formats.

⭐ Check whether the uploaded file size exceeds the 5MB data limit.

⭐ Save the transferred image to the detections folder.

if(!empty($_FILES["captured_image"]['name'])){
    // Image File:
    $captured_image_properties = array(
        "name" => $_FILES["captured_image"]["name"],
        "tmp_name" => $_FILES["captured_image"]["tmp_name"],
        "size" => $_FILES["captured_image"]["size"],
        "extension" => pathinfo($_FILES["captured_image"]["name"], PATHINFO_EXTENSION)
    );

    // Check whether the uploaded file extension is in the allowed file formats.
    $allowed_formats = array('jpg', 'png');
    if(!in_array($captured_image_properties["extension"], $allowed_formats)){
        echo 'FILE => File Format Not Allowed!';
    }else{
        // Check whether the uploaded file size exceeds the 5MB data limit.
        if($captured_image_properties["size"] > 5000000){
            echo "FILE => File size cannot exceed 5MB!";
        }else{
            // Save the uploaded file (image).
            move_uploaded_file($captured_image_properties["tmp_name"], "./detections/".$captured_image_properties["name"]);
            echo "FILE => Saved Successfully!";
        }
    }
}

Step 4: Setting up Wio Terminal on the Arduino IDE

https://www.hackster.io/kutluhan-aktar/iot-ai-driven-tree-disease-identifier-w-edge-impulse-mms-1b5ff6#toc-step-4--setting-up-wio-terminal-on-the-arduino-ide-4

Step 5: Collecting environmental factors and sending commands to LattePanda 3 Delta w/ Wio Terminal

After setting up Wio Terminal and installing the required libraries and modules, I programmed Wio Terminal to collect environmental factors and save them to the given CSV file on the SD card by appending the current date & time:

Since I needed to send commands to LattePanda 3 Delta to capture tree images or run the object detection model, I utilized the configurable buttons integrated into Wio Terminal to choose among commands. After selecting a command, Wio Terminal sends the selected command to LattePanda 3 Delta via serial communication.

Also, Wio Terminal sends the model run command ('B') to LattePanda 3 Delta via serial communication automatically every 5 minutes.

Before programming Wio Terminal, I had to modify the Histogram library to resize histograms and adjust their colors simultaneously.

#️⃣ First, open the Histogram.cpp file and modify the shrinkShowHistogram and changeParam functions.

#️⃣ Then, open the Histogram.h file and add the new parameters to the shrinkShowHistogram function.

Or, you can download the modified files directly on Downloads.

You can download the tree_disease_detection_wio_controls.ino file to try and inspect the code for collecting environmental factors, saving information to a given CSV file on the SD card, and transferring commands via serial communication.

⭐ Include the required libraries.

#include <SPI.h>
#include <Seeed_FS.h>#include "SD/Seeed_SD.h"
#include "TFT_eSPI.h"
#include "Histogram.h"
#include "RawImage.h"
#include "sensirion_common.h"
#include "sgp30.h"
#include "SCD30.h"
#include "RTC_SAMD51.h"
#include "DateTime.h"

⭐ Define the built-in TFT screen and the histogram settings.

TFT_Histogram histogram=TFT_Histogram();TFT_eSPI tft = TFT_eSPI();

⭐ Initialize the File class and define the CSV file name.

File myFile;const char* data_file = "environmental_factors.csv";

⭐ Define the environmental factor thresholds to inform the user of potential tree disease risks.

int thresholds[3][6] = {
                        {800,38,42,435,350,1500},
                        {830,35,45,435,375,1650},
                        {950,42,60,600,485,1735}
                       };

⭐ Define the required settings for the Grove VOC & eCO2 gas sensor.

s16 err;u32 ah = 0;u16 scaled_ethanol_signal, scaled_h2_signal, tvoc_ppb, co2_eq_ppm;

⭐ Define the built-in RTC module.

RTC_SAMD51 rtc;

⭐ Initialize the built-in RTC module. Then, adjust the date & time as the compiled date & time.

rtc.begin();  DateTime now = DateTime(F(__DATE__), F(__TIME__));  rtc.adjust(now);

⭐ Check the connection status between Wio Terminal and the SD card.

if(!SD.begin(SDCARD_SS_PIN, SDCARD_SPI)) while (1);

⭐ Check the SGP probe status on the VOC and eCO2 gas sensor. Then, read the H2 and Ethanol signal.

⭐ Set the default absolute humidity value - 13.000 g/m^3.

⭐ Initiate the VOC and eCO2 gas sensor.

while(sgp_probe() != STATUS_OK){
    if(DEBUG) Serial.println("VOC and eCO2 Gas Sensor => SGP probe failed!");
    while (1);
  }
  // Read the H2 and Ethanol signal with the VOC and eCO2 gas sensor.
  err = sgp_measure_signals_blocking_read(&scaled_ethanol_signal, &scaled_h2_signal);
  // Check the VOC and eCO2 gas sensor status after reading the signal.
  if(err == STATUS_OK){ if(DEBUG) Serial.println("VOC and eCO2 Gas Sensor => Signal acquired successfully!"); }
  else{ if(DEBUG) Serial.println("VOC and eCO2 Gas Sensor => Signal reading error!"); }
  // Set the default absolute humidity value - 13.000 g/m^3.
  sgp_set_absolute_humidity(13000);
  // Initiate the VOC and eCO2 gas sensor.
  err = sgp_iaq_init();

⭐ Initialize the CO2 & Temperature & Humidity sensor.

scd30.initialize();

⭐ Initiate the built-in TFT screen.

tft.init();  tft.setTextColor(TFT_WHITE);  tft.setTextSize(2);

⭐ Create the histogram and hide the histogram axes.

histogram.initHistogram(&tft);
histogram.formHistogram("a", 1, 10, column_w, TFT_RED);
// Column 1  histogram.formHistogram("b", 2, 10, column_w, TFT_PINK);
// Column 2  histogram.formHistogram("c", 3, 10, column_w, TFT_GREEN);
// Column 3  histogram.formHistogram("d", 4, 10, column_w, TFT_BLUE);
// Column 4  histogram.formHistogram("e", 5, 10, column_w, TFT_YELLOW);  
// Column 5  histogram.formHistogram("f", 6, 10, column_w, TFT_MAGENTA); 
// Column 6  // Hide the histogram axes.  histogram.notShowAxis();

⭐ Define and display the 8-bit images saved on the SD card.

drawImage<uint8_t>("forest_disease.bmp", TFT_HEIGHT, 0);

⭐ In the get_VOC_and_eCO2 function, get the VOC (Volatile Organic Compounds) and CO2eq (Carbon dioxide equivalent) measurements evaluated by the VOC and eCO2 gas sensor.

void get_VOC_and_eCO2(){
  // Get the VOC (Volatile Organic Compounds) and CO2eq (Carbon dioxide equivalent) measurements evaluated by the VOC and eCO2 gas sensor.
  s16 err = 0;  
  u16 tvoc_ppb, co2_eq_ppm;
  err = sgp_measure_iaq_blocking_read(&tvoc_ppb, &co2_eq_ppm);
  if(err == STATUS_OK){
    tvoc_value = tvoc_ppb;
    co2_eq_value = co2_eq_ppm;
    if(DEBUG){ Serial.print("tVOC (Volatile Organic Compounds): "); Serial.print(tvoc_value); Serial.println(" ppb"); }
    if(DEBUG){ Serial.print("CO2eq (Carbon dioxide equivalent): "); Serial.print(co2_eq_value); Serial.println(" ppm\n"); }
  }else{
    if(DEBUG) Serial.println("VOC and eCO2 Gas Sensor => IAQ values reading error!\n");
  }  delay(1000);
}

⭐ In the get_co2_temp_humd function, obtain the CO2, temperature, and humidity measurements generated by the CO2 & Temperature & Humidity sensor.

void get_co2_temp_humd(){
  // Obtain the CO2, temperature, and humidity measurements generated by the CO2 & Temperature & Humidity sensor.
  float result[3] = {0};
  if(scd30.isAvailable()){    
      scd30.getCarbonDioxideConcentration(result);
      co2_value = result[0];
      temp_value = result[1];
      humd_value = result[2];
      if(DEBUG){ Serial.print("CO2 (Carbon dioxide): "); Serial.print(co2_value); Serial.println(" ppm"); }
      if(DEBUG){ Serial.print("Temperature: "); Serial.print(temp_value); Serial.println(" ℃"); } 
      if(DEBUG){ Serial.print("Humidity: "); Serial.print(result[2]); Serial.println(" %\n"); }
  }
  delay(1000);
}

⭐ In the get_moisture function, get the soil moisture measurement generated by the Grove - Soil Moisture sensor.

void get_moisture(){
  moisture_value = analogRead(moisture_sensor);
  if(DEBUG){ Serial.print("Moisture: "); Serial.print(moisture_value); Serial.println("\n"); }
}

⭐ In the check_thresholds function, notify the user via the built-in buzzer if the collected environmental factors exceed the defined thresholds.

void check_thresholds(int s){
  // If the collected environmental factors exceed the given thresholds, notify the user via the built-in buzzer.
  for(int i=0; i<3; i++){
    if(co2_value >= thresholds[i][0] && temp_value >= thresholds[i][1] && humd_value >= thresholds[i][2] && moisture_value >= thresholds[i][3] && tvoc_value >= thresholds[i][4] && co2_eq_value >= thresholds[i][5]){
      analogWrite(WIO_BUZZER, 128);
      if(DEBUG) Serial.println("\nPotential tree disease risk detected!\n");
      delay(s*1000);
      analogWrite(WIO_BUZZER, 0);
    }
  }
}

⭐ In the update_histogram function, update the histogram parameters with the collected environmental factors.

void update_histogram(){
  // Update histogram parameters with the collected data.
  histogram.changeParam(1, "a", co2_value/10, TFT_RED);
  histogram.changeParam(2, "b", temp_value, TFT_PINK);
  histogram.changeParam(3, "c", humd_value, TFT_GREEN);
  histogram.changeParam(4, "d", moisture_value/10, TFT_BLUE);
  histogram.changeParam(5, "e", tvoc_value, TFT_YELLOW);
  histogram.changeParam(6, "f", co2_eq_value/10, TFT_MAGENTA);
}

⭐ In the show_resize_histogram function, resize, place, and display the histogram on the TFT screen.

⭐ Then, set the background image for the TFT screen.

void show_resize_histogram(int text, int background){
  // Resize, place, and display the histogram on the TFT screen.
  histogram.shrinkShowHistogram(25, 45, 1.4, text, background, background);
  tft.setRotation(3);  tft.setTextSize(1);
  tft.drawString("a:CO2 b:Temp c:Humd d:Mois e:tVOC f:CO2eq", 30, 5);
  delay(5000);
  // Set the background image.
  drawImage<uint8_t>("forest_disease.bmp", 0, 0);
  delay(2000);
}

⭐ In the save_data_to_SD_Card function, open the given CSV file on the SD card in the APPEND file mode.

⭐ There are three file modes supported by Wio Terminal: WRITE, READ, and APPEND.

⭐ If the given CSV file is opened successfully, obtain the current date & time from the built-in RTC module and create the data record to be inserted as a new row.

⭐ Then, append the data record with the current date & time and close the CSV file.

⭐ After appending the given data record successfully, notify the user via the TFT screen.

void save_data_to_SD_Card(){
  // Open the given CSV file on the SD card in the APPEND file mode.
  // FILE MODES: WRITE, READ, APPEND
  myFile = SD.open(data_file, FILE_APPEND);
  // If the given file is opened successfully:
  if(myFile){
    if(DEBUG){ Serial.print("\nWriting to "); Serial.print(data_file); Serial.println("..."); }
    // Obtain the current date & time.
    DateTime now = rtc.now();
    String _date = String(now.year(), DEC) + "_" + String(now.month(), DEC) + "_" + String(now.day(), DEC) + "_" + String(now.hour(), DEC) + "_" + String(now.minute(), DEC) + "_" + String(now.second(), DEC);
    // Create the data record to be inserted as a new row:
    String data_record = String(_date)
                         + "," + String(co2_value)
                         + "," + String(temp_value)
                         + "," + String(humd_value)
                         + "," + String(moisture_value)
                         + "," + String(tvoc_value)
                         + "," + String(co2_eq_value)
                       ;
     // Append the data record:
     myFile.println(data_record);
     // Close the CSV file:
     myFile.close();
     if(DEBUG) Serial.println("Data saved successfully!\n");
     // Notify the user after appending the given data record successfully.
     tft.fillRect(0, 0, w, h, TFT_WHITE);
     tft.fillRect(offset, offset, w-2*offset, h-2*offset, TFT_BLACK);
     tft.setTextSize(2);
     tft.drawString("Data Stored!", (w-12*12)/2, 23);
  }else{
    // If Wio Terminal cannot open the given CSV file successfully:
    if(DEBUG) Serial.println("Wio Terminal cannot open the given CSV file!\n");
    tft.setTextSize(2);
    tft.drawString("Wio Terminal", 35, 10);
    tft.drawString("cannot open the file!", 35, 30);
  }
  // Exit and clear:
  delay(3000);}

⭐ Every 1 minute, update the histogram and append the collected environmental factors to the CSV file on the SD card.

⭐ Every 5 minutes, send the model run command ('B') automatically to LattePanda 3 Delta via serial communication.

if(millis() - timer > 60*1000 || timer == 0){
    // Display the histogram on the TFT screen.
    update_histogram();
    show_resize_histogram(TFT_WHITE, TFT_BLACK);
    // Save the collected environmental factors to the SD card.
    save_data_to_SD_Card();
    // Every 5 minutes, send the model run command ('B') automatically to LattePanda 3 Delta.
    if(millis() - model_timer > 5*60*1000){
      Serial.println("B"); delay(500);
      tft.fillRect(0, TFT_WIDTH-h, w, h, TFT_WHITE);
      tft.fillRect(offset, TFT_WIDTH-h+offset, w-2*offset, h-2*offset, TFT_BLACK);
      tft.setTextSize(2);
      tft.drawString("Model Running!", (w-14*12)/2, TFT_WIDTH-25-12);
      // Update the model timer.
      model_timer = millis();
    }
    // Update the timer.
    timer = millis();
  }

⭐ If the configurable button A is pressed, send the capture command ('A') to LattePanda 3 Delta via serial communication.

if(digitalRead(WIO_KEY_A) == LOW){
    Serial.println("A"); delay(500);
    tft.fillRect(0, 0, w, h, TFT_WHITE);
    tft.fillRect(offset, offset, w-2*offset, h-2*offset, TFT_BLACK);
    tft.setTextSize(2);
    tft.drawString("Image Captured!", (w-15*12)/2, 23);
}

⭐ If the configurable button B is pressed, send the model run command ('B') manually to LattePanda 3 Delta.

if(digitalRead(WIO_KEY_B) == LOW){
    Serial.println("B"); delay(500);
    tft.fillRect(0, TFT_WIDTH-h, w, h, TFT_WHITE);
    tft.fillRect(offset, TFT_WIDTH-h+offset, w-2*offset, h-2*offset, TFT_BLACK);
    tft.setTextSize(2);
    tft.drawString("Model Running!", (w-14*12)/2, TFT_WIDTH-25-12);
}

After uploading and running the tree_disease_detection_wio_controls.ino file on Wio Terminal:

🌳📲 The device displays the collected environmental factors as a histogram on the built-in TFT screen.

🌳📲 The device notifies the user via the built-in buzzer if the collected environmental factors exceed the defined thresholds.

🌳📲 Every 1 minute, the device updates the histogram and appends the collected environmental factors to the environmental_factors.csv file on the SD card.

🌳📲 If the configurable button A is pressed, the device sends the capture command ('A') to LattePanda 3 Delta via serial communication.

🌳📲 Every 5 minutes, the device transfers the model run command ('B') automatically to LattePanda 3 Delta via serial communication.

🌳📲 Alternatively, the device sends the model run command ('B') manually if the configurable button B is pressed.

🌳📲 If Wio Terminal cannot open the given CSV file successfully, the device displays the error message on the TFT screen.

🌳📲 If the DEBUG variable is set as 1, the device prints notifications and sensor measurements on the serial monitor for debugging.

Step 6: Capturing and storing images of diseased trees w/ the Grove Vision AI module

https://www.hackster.io/kutluhan-aktar/iot-ai-driven-tree-disease-identifier-w-edge-impulse-mms-1b5ff6#toc-step-6--capturing-and-storing-images-of-diseased-trees-w--the-grove-vision-ai-module-7

Step 6.1: Saving the captured pictures as samples

Since I needed to collect various infected tree images to create a data set with notable validity, I wandered a forest near my hometown to capture infected tree pictures.

I managed to find samples of different foliar and bark tree diseases:

As far as my experiments go, the device operates faultlessly while capturing infected tree images and saving them on LattePanda 3 Delta :)

After capturing numerous infected tree images denoting different foliar and bark diseases, I elicited my data set, including training and testing samples for my object detection (FOMO) model.

Step 7: Building an object detection (FOMO) model with Edge Impulse

https://www.hackster.io/kutluhan-aktar/iot-ai-driven-tree-disease-identifier-w-edge-impulse-mms-1b5ff6#toc-step-7--building-an-object-detection--fomo--model-with-edge-impulse-9

Step 8: Setting up the Edge Impulse FOMO model on LattePanda 3 Delta

https://www.hackster.io/kutluhan-aktar/iot-ai-driven-tree-disease-identifier-w-edge-impulse-mms-1b5ff6#toc-step-8--setting-up-the-edge-impulse-fomo-model-on-lattepanda-3-delta-13

Step 9: Running the FOMO model on LattePanda 3 Delta to detect tree diseases

My Edge Impulse object detection (FOMO) model scans a captured image and predicts possibilities of trained labels to recognize an object on the given captured image. The prediction result (score) represents the model's "confidence" that the detected object corresponds to each of the two different labels (classes) [0 - 1], as shown in Step 7:

After executing the main.py file on LattePanda 3 Delta:

🌳📲 If Wio Terminal sends the model run command ('B') automatically in every 5 minutes or the user presses the configurable button B to send the command manually, the device captures an image and runs an inference with the Edge Impulse object detection model.

🌳📲 After running inference, the device modifies the captured image by adding bounding boxes for each detected object to emphasize potential tree diseases.

🌳📲 Then, the device saves the resized and modified image to the detections folder and sends the saved image to the web application via an HTTP POST request.

🌳📲 Finally, the device sends an MMS, including the detected labels and the modified image, to the verified phone number via Twilio's API.

🌳📲 If the model does not detect any labels, the device sends Not Detected! Instead of the detected label list.

🌳📲 Also, the device prints notifications and the detection results on the shell for debugging.

As far as my experiments go, the device detects foliar tree diseases precisely and shows accurate bounding boxes around the detected objects :)

Videos and Conclusion

Further Discussions

By applying object detection models trained on captured infected tree images in detecting potential tree diseases, we can achieve to:

🌳📲 avoid crop yield loss, animal deaths, widespread infectious epidemics,

🌳📲 prevent land degradation due to soil erosion,

🌳📲 mitigate deforestation,

🌳📲 protect wildlife.