본문 바로가기
푸닥거리

온디바이스 기반 인공지능 비전인식 모델 학습

by ┌(  ̄∇ ̄)┘™ 2026. 4. 12.
728x90

 

peak-I

 

MicroPython

 

https://hyenc.net/product/82916acf-fbd2-470c-b733-b3d1825ae957-18-21

 

인공지능 비전인식 실습장치

 

hyenc.net

 

 

 

Maixpy IDE

 

 

 

 

CP210xVCP

https://www.silabs.com/software-and-tools/usb-to-uart-bridge-vcp-drivers?tab=downloads

 

CP210x USB to UART Bridge VCP Drivers - Silicon Labs

The CP210x USB to UART Bridge Virtual COM Port (VCP) drivers are required for device operation as a Virtual COM Port to facilitate host communication with CP210x products. These devices can also interface to a host using the direct access driver.

www.silabs.com

 

 

Kflash GUI 설치

-> K210 펌웨어 플래시 / erase 도구

 

 

 

https://github.com/sipeed/kflash_gui

 

GitHub - sipeed/kflash_gui: Cross platform GUI wrapper for kflash.py (download(/burn) tool for k210)

Cross platform GUI wrapper for kflash.py (download(/burn) tool for k210) - sipeed/kflash_gui

github.com

 

 

https://github.com/sipeed/kflash_gui/releases/tag/v1.8.1

 

Release v1.8.1 · sipeed/kflash_gui

Sorry, something went wrong. No results found

github.com

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

from Maix import GPIO
from fpioa_manager import fm

fm.register(6, fm.fpioa.GPIO0)

LED = GPIO(GPIO.GPIO0, GPIO.OUT)
LED.value(0)

while True:
    pass

 

 

 

 

from Maix import GPIO
from fpioa_manager import fm
import utime

# io pin 을 gpio에 mapping
fm.register(9, fm.fpioa.GPIO0)
fm.register(10, fm.fpioa.GPIO1)
fm.register(11, fm.fpioa.GPIO2)

# gpio 초기
LED_B = GPIO(GPIO.GPIO0, GPIO.OUT,value=1)
LED_G = GPIO(GPIO.GPIO1, GPIO.OUT,value=1)
LED_R = GPIO(GPIO.GPIO2, GPIO.OUT,value=1)

# 효율적인 반복을 위해 배열 선언
LED=[LED_B, LED_G, LED_R]

while True:

    for i in range(0,3):

        LED[i].value(0)
        utime.sleep(1)
        LED[i].value(1)
        utime.sleep(1)

 

 

 

from machine import Timer, PWM
import time

tim = Timer(Timer.TIMER0, Timer.CHANNEL0, mode=Timer.MODE_PWM)
LED_R = PWM(tim, freq=100, duty=0, pin=11)
# RED = 9 RED , 10 GREEN , 11 BLUE

while True:
    i=range(0, 100, 1)
    for n in i:
        LED_R.duty(n)
        time.sleep(0.01)
        print(n)

 

 

import sensor, image, lcd

sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.skip_frames()
sensor.run(1)
sensor.set_vflip(True) # set_vflip() >> 상하반전 // set_hmirror() >> 좌우반전

lcd.init()
lcd.mirror(True)

while(True):
    lcd.display(sensor.snapshot())

 

import sensor,lcd,time

sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.set_hmirror(0)

lcd.init(freq=15000000)
sensor.skip_frames(time = 2000)

clock=time.clock()

# https://ko.rakko.tools/tools/30/    <lab 컬러 변환 툴>

thresholds = [(60, 90, 40, 90, 5, 70), # 빨간색 임계값
              (30, 100, -60, -20, -30, 50), # 녹색 임계값
              (0, 30, 0, 64, -128, -20)] # 파란색 임계값

while True:
    img=sensor.snapshot()
    blobs = img.find_blobs([thresholds[1]]) # 0, 1, 2는 각각 빨강, 초록, 파랑
    if blobs:
        for b in blobs:
            tmp=img.draw_rectangle(b[0:4])
           #tmp=img.draw_cross(b[5], b[6])

    lcd.display(img)
print(clock.fps())

 

 

import sensor,lcd,time

sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.set_vflip(1)
sensor.skip_frames(30)

lcd.init()

clock = time.clock()

while True:
    clock.tick()

    img = sensor.snapshot()

    res = img.find_qrcodes()
    if len(res) > 0:
        img.draw_rectangle(res[0].rect())
        img.draw_string(2,2, res[0].payload(), color=(255,255,255), scale=2)
        print(res[0].payload())

    lcd.display(img)
    print(clock.fps())

 

 

 

 

import sensor, image, time, lcd
from Maix import GPIO
from fpioa_manager import fm

fm.register(21, fm.fpioa.GPIO0)
btn = GPIO(GPIO.GPIO0, GPIO.IN)

lcd.init()

sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.set_vflip(1)
sensor.skip_frames(time=2000)
sensor.run(1)

cnt = 1

while True:
    img = sensor.snapshot()

    if btn.value() == 0:
        img = sensor.snapshot()
        fileName = "/sd/test_{:02d}.jpg".format(cnt)  # 수정됨
        img.save(fileName)
        lcd.draw_string(50, 70, "Save snapshot to SDcard", lcd.WHITE)
        print("Save snapshot to SDcard:", fileName)
        cnt += 1
        time.sleep(1)

    lcd.display(img)

 

https://maixhub.com/

 

MaixHub

 

maixhub.com

 

 

 

 

 

 

 

 

 

 

 

 

 

# generated by maixhub, tested on maixpy3 v0.4.8
# copy files to TF card and plug into board and power on
import sensor, image, lcd, time
import KPU as kpu
from machine import UART
import gc, sys
from fpioa_manager import fm

input_size = (224, 224)
labels = ['bird', 'cat']
anchors = [1.5, 1.34, 2.19, 3.25, 3.19, 2.47, 1.63, 2.19, 1.97, 2.0]

def lcd_show_except(e):
    import uio
    err_str = uio.StringIO()
    sys.print_exception(e, err_str)
    err_str = err_str.getvalue()
    img = image.Image(size=input_size)
    img.draw_string(0, 10, err_str, scale=1, color=(0xff,0x00,0x00))
    lcd.display(img)

class Comm:
    def __init__(self, uart):
        self.uart = uart

    def send_detect_result(self, objects, labels):
        msg = ""
        for obj in objects:
            pos = obj.rect()
            p = obj.value()
            idx = obj.classid()
            label = labels[idx]
            msg += "{}:{}:{}:{}:{}:{:.2f}:{}, ".format(pos[0], pos[1], pos[2], pos[3], idx, p, label)
        if msg:
            msg = msg[:-2] + "\n"
        self.uart.write(msg.encode())

def init_uart():
    fm.register(10, fm.fpioa.UART1_TX, force=True)
    fm.register(11, fm.fpioa.UART1_RX, force=True)

    uart = UART(UART.UART1, 115200, 8, 0, 0, timeout=1000, read_buf_len=256)
    return uart

def main(anchors, labels = None, model_addr="/sd/model-262409.kmodel", sensor_window=input_size, lcd_rotation=0, sensor_hmirror=False, sensor_vflip=True):
    sensor.reset()
    sensor.set_pixformat(sensor.RGB565)
    sensor.set_framesize(sensor.QVGA)
    sensor.set_windowing(sensor_window)
    sensor.set_hmirror(sensor_hmirror)
    sensor.set_vflip(sensor_vflip)
    sensor.run(1)

    lcd.init(type=1)
    lcd.rotation(lcd_rotation)
    lcd.clear(lcd.WHITE)

    if not labels:
        with open('labels.txt','r') as f:
            exec(f.read())
    if not labels:
        print("no labels.txt")
        img = image.Image(size=(320, 240))
        img.draw_string(90, 110, "no labels.txt", color=(255, 0, 0), scale=2)
        lcd.display(img)
        return 1
    try:
        img = image.Image("startup.jpg")
        lcd.display(img)
    except Exception:
        img = image.Image(size=(320, 240))
        img.draw_string(90, 110, "loading model...", color=(255, 255, 255), scale=2)
        lcd.display(img)

    uart = init_uart()
    comm = Comm(uart)

    try:
        task = None
        task = kpu.load(model_addr)
        kpu.init_yolo2(task, 0.5, 0.3, 5, anchors) # threshold:[0,1], nms_value: [0, 1]
        while(True):
            img = sensor.snapshot()
            t = time.ticks_ms()
            objects = kpu.run_yolo2(task, img)
            t = time.ticks_ms() - t
            if objects:
                for obj in objects:
                    pos = obj.rect()
                    img.draw_rectangle(pos)
                    img.draw_string(pos[0], pos[1], "%s : %.2f" %(labels[obj.classid()], obj.value()), scale=2, color=(255, 0, 0))
                comm.send_detect_result(objects, labels)
            img.draw_string(0, 200, "t:%dms" %(t), scale=2, color=(255, 0, 0))
            img.draw_string(0, 2, "Upgrade to MaixCAM to use YOLOv8", scale=1.2, color=(255, 0, 0))
            img.draw_string(0, 30, "wiki.sipeed.com/maixcam", scale=1.2, color=(255, 0, 0))
            lcd.display(img)
    except Exception as e:
        raise e
    finally:
        if not task is None:
            kpu.deinit(task)


if __name__ == "__main__":
    try:
        # main(anchors = anchors, labels=labels, model_addr=0x300000, lcd_rotation=0)
        main(anchors = anchors, labels=labels, model_addr="/sd/model-262409.kmodel")
    except Exception as e:
        sys.print_exception(e)
        lcd_show_except(e)
    finally:
        gc.collect()

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

https://nodered.org/

 

Low-code programming for event-driven applications : Node-RED

Node-RED's goal is to enable anyone to build applications that collect, transform and visualize their data; building flows that can automate their world. Its low-code nature makes it accessible to users of any background, whether for home automation, indus

nodered.org

 

 

npm install -g node-red

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

from Maix import GPIO
from fpioa_manager import fm
from machine import UART
import time

# 1. 하드웨어 핀 등록 (교재 39p 기반 및 UART 핀 추가)
fm.register(9, fm.fpioa.GPIO0)   # Red LED
fm.register(10, fm.fpioa.GPIO1)  # Green LED
fm.register(11, fm.fpioa.GPIO2)  # Blue LED

fm.register(18, fm.fpioa.GPIO3)  # 물리 버튼 R (IO18)
fm.register(19, fm.fpioa.GPIO4)  # 물리 버튼 G (IO19)
fm.register(20, fm.fpioa.GPIO5)  # 물리 버튼 B (IO20)
fm.register(21, fm.fpioa.GPIO6)  # 물리 버튼 Y (IO21)

# PEAK-i의 USB 시리얼 통신을 위한 RX/TX 핀 강제 할당 (중요)
fm.register(4, fm.fpioa.UART1_RX, force=True)
fm.register(5, fm.fpioa.UART1_TX, force=True)

# 2. GPIO 객체 초기화 (1: OFF, 0: ON)
LED_R = GPIO(GPIO.GPIO0, GPIO.OUT, value=1)
LED_G = GPIO(GPIO.GPIO1, GPIO.OUT, value=1)
LED_B = GPIO(GPIO.GPIO2, GPIO.OUT, value=1)

KEY_R = GPIO(GPIO.GPIO3, GPIO.IN)
KEY_G = GPIO(GPIO.GPIO4, GPIO.IN)
KEY_B = GPIO(GPIO.GPIO5, GPIO.IN)
KEY_OFF = GPIO(GPIO.GPIO6, GPIO.IN)

# 3. UART 초기화 (기본 USB 포트 통로 사용, 속도 115200)
uart = UART(UART.UART1, 115200, 8, 1, 0, timeout=1000, read_buf_len=4096)

def all_off():
    LED_R.value(1); LED_G.value(1); LED_B.value(1)

print("Serial System Ready")

while True:
    # [방향 1] 기기 물리 버튼 입력 -> Node-RED로 알림 전송
    if KEY_R.value() == 0:
        all_off(); LED_R.value(0)
        print("BTN_RED")
        time.sleep(0.3)
    elif KEY_G.value() == 0:
        all_off(); LED_G.value(0)
        print("BTN_GREEN")
        time.sleep(0.3)
    elif KEY_B.value() == 0:
        all_off(); LED_B.value(0)
        print("BTN_BLUE")
        time.sleep(0.3)
    elif KEY_OFF.value() == 0:
        all_off();
        time.sleep(0.3)


    # [방향 2] Node-RED 명령 수신 처리
    if uart.any():
        # 들어온 데이터를 읽고 문자열로 변환
        data = uart.read().decode()

        # 'in' 연산자를 사용하여 데이터에 해당 문자가 포함되어 있는지 확인 (오동작 방지)
        if "R" in data:
            all_off(); LED_R.value(0)
        elif "G" in data:
            all_off(); LED_G.value(0)
        elif "B" in data:
            all_off(); LED_B.value(0)
        elif "OFF" in data:
            all_off()

    time.sleep(0.05)

 

 

 

 

 

 

 

 

 

 

 

 

KakaoTalk_20260412_104525650.mp4
2.78MB

 

 

 

 

KakaoTalk_20260412_105127954.mp4
1.15MB

 

 

 

 

 

 

 

 

 

 

 

 

 

728x90

 

 

 

 

 

 

 

 

 

https://search.naver.com/search.naver?where=nexearch&sm=top_hty&fbm=0&ie=utf8&query=%EC%83%89%EC%83%81%EC%BD%94%EB%93%9C&ackey=5geichf9

 

 

 

http://127.0.0.1:1880/ui

 

 

 

 

 

KakaoTalk_20260412_114404983.mp4
1.48MB

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

from Maix import GPIO
from fpioa_manager import fm
from machine import UART
import time

# 1. 하드웨어 핀 등록 (교재 39p 기반 및 UART 핀 추가)
fm.register(9, fm.fpioa.GPIO0)   # Red LED
fm.register(10, fm.fpioa.GPIO1)  # Green LED
fm.register(11, fm.fpioa.GPIO2)  # Blue LED

fm.register(18, fm.fpioa.GPIO3)  # 물리 버튼 R (IO18)
fm.register(19, fm.fpioa.GPIO4)  # 물리 버튼 G (IO19)
fm.register(20, fm.fpioa.GPIO5)  # 물리 버튼 B (IO20)
fm.register(21, fm.fpioa.GPIO6)  # 물리 버튼 Y (IO21)

# PEAK-i의 USB 시리얼 통신을 위한 RX/TX 핀 강제 할당 (중요)
fm.register(4, fm.fpioa.UART1_RX, force=True)
fm.register(5, fm.fpioa.UART1_TX, force=True)

# 2. GPIO 객체 초기화 (1: OFF, 0: ON)
LED_R = GPIO(GPIO.GPIO0, GPIO.OUT, value=1)
LED_G = GPIO(GPIO.GPIO1, GPIO.OUT, value=1)
LED_B = GPIO(GPIO.GPIO2, GPIO.OUT, value=1)

KEY_R = GPIO(GPIO.GPIO3, GPIO.IN)
KEY_G = GPIO(GPIO.GPIO4, GPIO.IN)
KEY_B = GPIO(GPIO.GPIO5, GPIO.IN)
KEY_OFF = GPIO(GPIO.GPIO6, GPIO.IN)

# 3. UART 초기화 (기본 USB 포트 통로 사용, 속도 115200)
# uart = UART(UART.UART1, 115200, 8, 1, 0, timeout=1000, read_buf_len=4096)
uart = UART(UART.UART1, 115200, 8, 0, 1, timeout=1000, read_buf_len=4096)

def all_off():
    LED_R.value(1); LED_G.value(1); LED_B.value(1)

print("Serial System Ready")

while True:
    # [방향 1] 기기 물리 버튼 입력 -> Node-RED로 알림 전송
    if KEY_R.value() == 0:
        all_off(); LED_R.value(0)
        print("BTN_RED")
        time.sleep(0.3)
    elif KEY_G.value() == 0:
        all_off(); LED_G.value(0)
        print("BTN_GREEN")
        time.sleep(0.3)
    elif KEY_B.value() == 0:
        all_off(); LED_B.value(0)
        print("BTN_BLUE")
        time.sleep(0.3)
    elif KEY_OFF.value() == 0:
        all_off();
        time.sleep(0.3)


    # [방향 2] Node-RED 명령 수신 처리
    if uart.any():
        # 들어온 데이터를 읽고 문자열로 변환
        data = uart.read().decode()

        # 'in' 연산자를 사용하여 데이터에 해당 문자가 포함되어 있는지 확인 (오동작 방지)
        if "R" in data:
            all_off(); LED_R.value(0)
        elif "G" in data:
            all_off(); LED_G.value(0)
        elif "B" in data:
            all_off(); LED_B.value(0)
        elif "OFF" in data:
            all_off()

    time.sleep(0.05)

 

 

 

 

 

 

import sensor, image, time, lcd
import ubinascii

# 1. LCD 및 카메라 초기화
lcd.init()
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.skip_frames(30)

sensor.set_vflip(True)

print("Camera System Ready")

while True:
    img = sensor.snapshot()
    lcd.display(img)

    # 2. JPEG 압축 (속도 중요) >> quality 값이 높아질수록 화질 good + 속도 slow
    img_buf = img.compress(quality=30)

    # 3. Base64 변환
    img_64 = ubinascii.b2a_base64(img_buf)

    # 4. USB 시리얼로 전송 (핵심)
    print("START_IMG")
    print(img_64.decode())   # decode 필수
    print("END_IMG")

    time.sleep(0.2)  # 없으면 데이터 터짐

 

 

 

 

 

 

 

 




// ----------------------
// 설정
// ----------------------
let START_TAG = "START_IMG";
let END_TAG = "END_IMG";


// ----------------------
// 버퍼 누적
// ----------------------
let buffer = context.get("buffer") || "";
buffer += msg.payload.toString();


// ----------------------
// 이미지 추출 루프 (여러 프레임 대응)
// ----------------------
let start = buffer.indexOf(START_TAG);
let end = buffer.indexOf(END_TAG);


if (start !== -1 && end !== -1 && end > start) {


   // 이미지 데이터만 추출
   let base64 = buffer.substring(
       start + START_TAG.length,
       end
   ).replace(/\s/g, "");  // 줄바꿈 제거


   // 사용한 데이터 제거 (다음 프레임 대비)
   buffer = buffer.substring(end + END_TAG.length);
   context.set("buffer", buffer);


   // Dashboard 이미지 형식으로 변환
   msg.payload = "data:image/jpeg;base64," + base64;


   return msg;
}


// ----------------------
// 버퍼 저장
// ----------------------
context.set("buffer", buffer);


// ----------------------
// 아직 데이터 부족
// ----------------------
return null;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

import sensor, image, lcd, time
import KPU as kpu
import ubinascii

try:
    print("BOOT START")

    # -------------------------------
    # 1. 초기화
    # -------------------------------
    lcd.init()

    sensor.reset()
    sensor.set_pixformat(sensor.RGB565)
    sensor.set_framesize(sensor.QVGA)
    sensor.set_vflip(1)
    sensor.set_hmirror(1)
    sensor.skip_frames(30)

    clock = time.clock()

    print("Camera OK")

    # -------------------------------
    # 2. YOLO 설정
    # -------------------------------
    classes = ['aeroplane','bicycle','bird','boat','bottle','bus','car',
               'cat','chair','cow','diningtable','dog','horse','motorbike',
               'person','pottedplant','sheep','sofa','train','tvmonitor']

    try:
        task = kpu.load("/sd/20class.kmodel")
    except:
        task = kpu.load(0x500000)

    anchor = (1.889, 2.5245, 2.9465, 3.94056, 3.99987,
              5.3658, 5.155437, 6.92275, 6.718375, 9.01025)

    kpu.init_yolo2(task, 0.5, 0.3, 5, anchor)

    print("YOLO INIT OK")

    frame_count = 0

    # -------------------------------
    # 3. 메인 루프
    # -------------------------------
    while True:
        clock.tick()
        frame_count += 1

        img = sensor.snapshot()

        # YOLO 실행
        code = kpu.run_yolo2(task, img)

        detect_results = []

        if code:
            for i in code:
                img.draw_rectangle(i.rect(), color=(255, 0, 0))

                label = classes[i.classid()]
                confidence = i.value()

                img.draw_string(i.x(), i.y(), label, color=(255,0,0), scale=1)
                img.draw_string(i.x(), i.y()+10, "%.2f" % confidence, color=(255,0,0), scale=1)

                detect_results.append("{}:{:.2f}".format(label, confidence))

        lcd.display(img)

        # -------------------------------
        # 🔥 핵심: 텍스트 항상 출력
        # -------------------------------
        print("[TXT_START]")

        if detect_results:
            print(",".join(detect_results))
        else:
            print("No Detect")   # 👈 이거 때문에 이제 항상 뜸

        print("[TXT_END]")

        # -------------------------------
        # 이미지 전송
        # -------------------------------
        if frame_count % 3 == 0:
            try:
                img_buf = img.compress(quality=10)
                img_64 = ubinascii.b2a_base64(img_buf)

                print("[IMG_START]")
                print(img_64.decode())
                print("[IMG_END]")

            except:
                print("IMG ERROR")

            time.sleep(0.5)

except Exception as e:
    print("FATAL ERROR:", e)

 

 

 

 

 

 

[결과값 가져오기 함수]

let buffer = context.get("buffer") || "";
buffer += msg.payload.toString();

let start = buffer.indexOf("[TXT_START]");
let end = buffer.indexOf("[TXT_END]");

if (start !== -1 && end !== -1 && end > start) {

    let text = buffer.substring(start + 11, end).trim();

    buffer = buffer.substring(end + 9);
    context.set("buffer", buffer);

    return { payload: text };
}

context.set("buffer", buffer);
return null;

 

 

[name-score split 함수]

let text = msg.payload;

// 예외 처리
if (!text || text === "No Detect") {
   msg.payload = {
       name: "No Detect",
       score: "-"
   };
   return msg;
}

// 첫 번째 객체만 사용
let first = text.split(",")[0];
let parts = first.split(":");

let name = parts[0];
let score = Math.round(parseFloat(parts[1]) * 100) + "%";

//payload를 객체로 변경
msg.payload = {
   name: name,
   score: score
};

return msg;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

728x90

댓글