João Vitor Yukio Bordin Yamashita
Published © CC BY-ND

Coffee disease classification with ML

Classification of coffee diseases using images of coffee leaves and convolutional networks embedded in a $14 board powered by batteries.

IntermediateFull instructions provided1,280
Coffee disease classification with ML

Things used in this project

Hardware components

Seeed Studio Maix Bit
×1

Software apps and online services

aXeleRate
Seeed Studio Maix Py
Google Colab

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)

Story

Read more

Custom parts and enclosures

Stl base

Stl files used to print a case for the board

Stl cover

Stl files used to print a case for the board

Schematics

System workflow

How the code is going to "thing"

Code

MaixPy Inference

MicroPython
MaixPy code used to inference data in the board
import sensor, image, lcd, time
import KPU as kpu
import gc

lcd.init()
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.set_windowing((224, 224))
sensor.set_brightness(2)
sensor.set_auto_gain(1)
sensor.set_vflip(1)
lcd.clear()

labels_stage1 = ['Rust', 'Brown_Spots', 'Sooty_Molds', 'healthy']
labels_stage2 = ['Cercospora', 'Phoma', 'Leaf_Miner','Red_Spider_Mite']
task_stage1 = kpu.load(0x300000)
task_stage2 = kpu.load(0x500000)

kpu.set_outputs(task_stage1, 0, 1, 1, 4)

kpu.set_outputs(task_stage2, 0, 1, 1, 4)

while(True):
    kpu.memtest()
    img = sensor.snapshot()
    #img = img.rotation_corr(z_rotation=90.0)   uncomment if need rotation correction - only present in full maixpy firmware
    #a = img.pix_to_ai()

    #primeiro estgio
    fmap1 = kpu.forward(task_stage1, img)
    plist=fmap1[:]
    pmax=max(plist)
    max_index=plist.index(pmax)
    if labels_stage1[max_index] == 'Brown_Spots':
        #segundo estgio
        fmap2 = kpu.forward(task_stage2, img)
        plist2=fmap2[:]
        pmax2=max(plist2)
        max_index2=plist2.index(pmax2)
        a = img.draw_string(0,0, str(labels_stage2[max_index2].strip()), color=(255,0,0), scale=2)
        a = img.draw_string(0,20, str(pmax2), color=(255,0,0), scale=2)
    else:
        a = img.draw_string(0,0, str(labels_stage1[max_index].strip()), color=(255,0,0), scale=2)
        a = img.draw_string(0,20, str(pmax), color=(255,0,0), scale=2)

    a = lcd.display(img)
    gc.collect()

a = kpu.deinit(task_stage1)
a = kpu.deinit(task_stage2)

Data Acquisition

MicroPython
Code used to take pictures and save them in a sd card inside the board.
'''
    image caupture tool, capture images to SD card with directory switch support
    @usage 1. Change camera and lcd configs according to your hardware like `lcd.rotation`
           2. Prepare a SD card with SPI mode support, and format to FAT32 with MBR(msdos) partition
           3. Copy this boot.py to your SD card root directory
           4. Power off board, then insert SD card to board
           5. Power on, it will automatically create a directory like `cap_images_1`,
                the next time will be `cap_images_2` to avoid rewrite
           6. Capture images for one class,
                push `boot` button on board and release to capture one image,
                this will save images as `cap_images_1/0/0.jpg`,
                the name of image will automaitcally increase, like `0.jpg` `1.jpg` ...
           7. Long push `boot` botton on board to switch class,
                this will create a new directory like `cap_images_1/1/`,
                and later captured images will be saved to this directory like `cap_images_1/1/0.jpg`
           8. Power off board, pop out SD card, mount on your PC, now you get your images in your file brower
    @update https://github.com/sipeed/MaixPy_scripts
    @author neucrack@sipeed
    @license MIT
'''

import sensor, lcd
from Maix import GPIO
from fpioa_manager import fm
from board import board_info
import os, sys
import time
import image

#### image size ####
set_windowing = (224, 224)

#### sensor config ####

sensor.reset(freq=22000000, dual_buff=False)
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA) # 320x240
try:
    sensor.set_jb_quality(95)         # for IDE display quality
except Exception:
    pass # no IDE support
if set_windowing:
    sensor.set_windowing(set_windowing)
# sensor.set_auto_gain(False)
# sensor.set_auto_whitebal(False, rgb_gain_db=(0x52,0x40,0x4d))
# sensor.set_saturation(0)
# sensor.set_brightness(4)
# sensor.set_contrast(0)
# sensor.set_hmirror(True)        # image horizonal mirror
# sensor.set_vflip(True)          # image vertical flip
# sensor.set_auto_whitebal(False)
sensor.set_hmirror(True)
sensor.set_auto_gain(1)
sensor.set_vflip(True)

sensor.skip_frames()

#### lcd config ####
lcd.init(type=1, freq=15000000)
#lcd.rotation(2)

#### boot key ####
boot_pin = 16 # board_info.BOOT_KEY
fm.register(boot_pin, fm.fpioa.GPIOHS0)
key = GPIO(GPIO.GPIOHS0, GPIO.PULL_UP)

######################################################

#### main ####
def capture_main(key):
    def draw_string(img, x, y, text, color, scale, bg=None , full_w = False):
        if bg:
            if full_w:
                full_w = img.width()
            else:
                full_w = len(text)*8*scale+4
            img.draw_rectangle(x-2,y-2, full_w, 16*scale, fill=True, color=bg)
        img = img.draw_string(x, y, text, color=color,scale=scale)
        return img

    def del_all_images():
        os.chdir("/sd")
        images_dir = "cap_images"
        if images_dir in os.listdir():
            os.chdir(images_dir)
            types = os.listdir()
            for t in types:
                os.chdir(t)
                files = os.listdir()
                for f in files:
                    os.remove(f)
                os.chdir("..")
                os.rmdir(t)
            os.chdir("..")
            os.rmdir(images_dir)

    # del_all_images()
    os.chdir("/sd")
    dirs = os.listdir()
    images_dir = "cap_images"
    last_dir = 0
    for d in dirs:
        if d.startswith(images_dir):
            if len(d) > 11:
                n = int(d[11:])
                if n > last_dir:
                    last_dir = n
    images_dir = "{}_{}".format(images_dir, last_dir+1)
    print("save to ", images_dir)
    if images_dir in os.listdir():
        img = image.Image()
        img = draw_string(img, 2, 200, "please del cap_images dir", color=lcd.WHITE,scale=1, bg=lcd.RED)
        lcd.display(img)
        sys.exit(1)
    os.mkdir(images_dir)
    last_cap_time = 0
    last_btn_status = 1
    save_dir = 0
    save_count = 0
    os.mkdir("{}/{}".format(images_dir, save_dir))
    while(True):
        img0 = sensor.snapshot()
        if set_windowing:
            img = image.Image()
            img = img.draw_image(img0, (img.width() - set_windowing[0])//2, img.height() - set_windowing[1])
        else:
            img = img0.copy()
        # img = img.resize(320, 240)
        if key.value() == 0:
            time.sleep_ms(30)
            if key.value() == 0 and (last_btn_status == 1) and (time.ticks_ms() - last_cap_time > 500):
                last_btn_status = 0
                last_cap_time = time.ticks_ms()
            else:
                if time.ticks_ms() - last_cap_time > 5000:
                    img = draw_string(img, 2, 200, "release to change type", color=lcd.WHITE,scale=1, bg=lcd.RED)
                else:
                    img = draw_string(img, 2, 200, "release to capture", color=lcd.WHITE,scale=1, bg=lcd.RED)
                    if time.ticks_ms() - last_cap_time > 2000:
                        img = draw_string(img, 2, 160, "keep push to change type", color=lcd.WHITE,scale=1, bg=lcd.RED)
        else:
            time.sleep_ms(30)
            if key.value() == 1 and (last_btn_status == 0):
                if time.ticks_ms() - last_cap_time > 5000:
                    img = draw_string(img, 2, 200, "change object type", color=lcd.WHITE,scale=1, bg=lcd.RED)
                    lcd.display(img)
                    time.sleep_ms(1000)
                    save_dir += 1
                    save_count = 0
                    dir_name = "{}/{}".format(images_dir, save_dir)
                    os.mkdir(dir_name)
                else:
                    draw_string(img, 2, 200, "capture image {}".format(save_count), color=lcd.WHITE,scale=1, bg=lcd.RED)
                    lcd.display(img)
                    f_name = "{}/{}/{}.jpg".format(images_dir, save_dir, save_count)
                    img0.save(f_name, quality=95)
                    save_count += 1
                last_btn_status = 1
        img = draw_string(img, 2, 0, "will save to {}/{}/{}.jpg".format(images_dir, save_dir, save_count), color=lcd.WHITE,scale=1, bg=lcd.RED, full_w=True)
        lcd.display(img)
        del img
        del img0


def main():
    try:
        capture_main(key)
    except Exception as e:
        print("error:", e)
        import uio
        s = uio.StringIO()
        sys.print_exception(e, s)
        s = s.getvalue()
        img = image.Image()
        img.draw_string(0, 0, s)
        lcd.display(img)
main()

Credits

João Vitor Yukio Bordin Yamashita

João Vitor Yukio Bordin Yamashita

3 projects • 4 followers

Comments