고등학교/제3회 SW융합 학생 해커톤

제3회 SW융합 학생 해커톤 (2021.10.22~2021.10.23)

MSHUN 2022. 1. 18.
반응형

제작 동기

친구들과 함께 이번 해커톤에 참가하게 되었다.

<심심풀이로 앨버트로스>라는 책을 함께 읽고 책 속에서 문제를 발견한 후 창의적인 해결 방안을 찾아야 했다.

그리고 그것을 피지컬 컴퓨팅으로 구현하는 것이 목표였다.

 

우리는 <심심풀이로 앨버트로스>에서 쓰레기로 뒤덮인 섬에서 해양으로 배출되는 쓰레기의 심각성을 느끼고 이를 해결하기 위해 기존에 비해 보다 편리한 분리수거 쓰레기통을 활용하여 플라스틱 등의 쓰레기 재활용률을 높여 자연으로 유출되는 쓰레기의 양을 줄이는 방법을 선택했다.

설계 및 계획

설계도

웹캠을 통해 들고 있는 쓰레기를 인식하면, 그 쓰레기가 어떤 쓰레기인지 판단한 후 판단된 쓰레기에 따라 각각의 신호를 아두이노에 전달하고 소리파일을 재생한다. 그러면 아두이노는 그 신호에 따라 플라스틱, 캔, 종이, 인식 안됨을 파악하여 스텝 모터와 LCD를 제어한다.

인공지능은 티쳐블 머신을, 이미지 인식은 웹캠과 OpenCV, 쓰레기통 투입구 회전은 아두이노를 활용했다.

인공지능 학습

우리는 인공지능을 학습시키기 위해 머신러닝 모델을 쉽고 빠르게 만들 수 있는 티쳐블 머신을 사용하기로 했다.

우선 플라스틱, 종이, 캔, 없음의 사진들을 각각 1000장 정도 찍은 후 그 사진들을 사용해 학습시켰다.

 

 

Teachable Machine

Train a computer to recognize your own images, sounds, & poses. A fast, easy way to create machine learning models for your sites, apps, and more – no expertise or coding required.

teachablemachine.withgoogle.com

 

 

소리 안내

쓰레기를 인식하면 어떤 쓰레기인지 음성으로 안내하기 위해 타입 캐스트를 이용해 음성 파일을 만들었다.

sound.zip
0.03MB

 

파이썬 코딩

import tensorflow.keras
import numpy as np
import cv2
import serial
import time
import pygame
pygame.init()
arduino = serial.Serial('com13',9600)

maxcnt = 10

count_plastic = 0
count_paper = 0
count_can = 0
count_none = 0
var = 'N'
last = ''
Plastic_Sound = pygame.mixer.Sound("Plastic.mp3")
Can_Sound = pygame.mixer.Sound("Can.mp3")
Paper_Sound = pygame.mixer.Sound("Paper.mp3")
# 모델 위치
model_filename ='keras_model.h5'

# 케라스 모델 가져오기
model = tensorflow.keras.models.load_model(model_filename)

#레이블 가져오기
fp = open('labels.txt', 'r')
lines = fp.readlines()
label = []
for itr in lines:
    label.append(itr.split())
fp.close()

# 카메라를 제어할 수 있는 객체
capture = cv2.VideoCapture(0)

# 카메라 길이 너비 조절
capture.set(cv2.CAP_PROP_FRAME_WIDTH, 320)
capture.set(cv2.CAP_PROP_FRAME_HEIGHT, 240)

# 이미지 처리하기
def preprocessing(frame): 
    #frame_fliped = cv2.flip(frame, 1) #좌우/상하 반전
    # 사이즈 조정 티쳐블 머신에서 사용한 이미지 사이즈로 변경해준다.
    size = (224, 224) #TM2의 이미지 크기
    frame_resized = cv2.resize(frame, size, interpolation=cv2.INTER_AREA)
    
    # 이미지 정규화
    # astype : 속성
    frame_normalized = (frame_resized.astype(np.float32) / 127.0) - 1

    # 이미지 차원 재조정 - 예측을 위해 reshape 해줍니다.
    # keras 모델에 공급할 올바른 모양의 배열 생성
    frame_reshaped = frame_normalized.reshape((1, 224, 224, 3))
    #print(frame_reshaped)
    return frame_reshaped

# 예측용 함수
def predict(frame):
    prediction = model.predict(frame)
    return prediction

while True:
    ret, frame = capture.read()
    
    if cv2.waitKey(100) > 0: 
        break
    
    preprocessed = preprocessing(frame) #이미지 전처리
    prediction = predict(preprocessed) #추론 [0.1,0,0.9,0]플라스틱 10%, 종이 0%, 캔 90%, 없음 0%

    #추론 결과 표시
    idx = np.argmax(prediction) #최대값의 index 반환
#플라스틱
    if (idx == 0):
        count_plastic = count_plastic +1
        count_paper = 0
        count_can = 0
        count_none = 0
        var = 'P'
        var = var.encode('utf-8')
        
        if (count_plastic>=maxcnt and last != 'Plastic'):
            print(label[idx][1])
            count_plastic = 0 
            last = 'Plastic'
            arduino.write(var)
            Plastic_Sound.play()
#종이
    if (idx == 1):
        count_plastic = 0
        count_paper = count_paper +1
        count_can = 0
        count_none = 0
        var = 'J'
        var = var.encode('utf-8')
        if (count_paper>=maxcnt and last != 'Paper'):
            print(label[idx][1])
            count_paper = 0
            last = 'Paper'
            arduino.write(var)
            Paper_Sound.play()
#캔
    if (idx == 2):
        count_plastic = 0
        count_paper = 0
        count_can = count_can +1
        count_none = 0
        var = 'C'
        var = var.encode('utf-8')
        
        if (count_can>=maxcnt and last != 'Can'):
            print(label[idx][1])
            count_can = 0
            last = 'Can'
            arduino.write(var)
            Can_Sound.play()
#없음
    if (idx == 3):
        count_plastic = 0
        count_paper = 0
        count_can = 0
        count_none = count_none +1
        var = 'N'
        var = var.encode('utf-8')
        
        if (count_none>=20 and last != 'None'):
            print(label[idx][1])
            count_none = 0
            last = 'None'
            arduino.write(var)

    cv2.imshow("VideoFrame", frame)

정확성을 위해 10번 정도 동일한 추론 결과가 나올 때와, 여러 번 같은 신호를 보내지 않기 위해 마지막 신호와 다를 때만 신호를 보내도록 했다.

플라스틱은 P, 종이는 J, 캔은 C, 없음은 N으로 신호를 보낸다.

 

소감

친구들과 함께 주어진 과제에서 문제 상황을 발견하고 해결방안을 찾는 것이 재밌었다. 그리고 만드는 과정이 완벽하진 않았지만, 문제를 하나씩 해결해나가는 과정에서 깨닫는 점이 많았고 팀원들과 각자 역할을 맡아 수행하며 서로의 장단점을 보완해나갈 수 있었다. 아쉬운 점은 시간 분배를 잘하지 못해서 시간이 부족했었다. 하지만 짧은 시간에도 팀원들과 함께 좋은 추억과 많은 깨달음을 얻을 수 있어서 좋았다.

 

처음 이 대회에 나가기로 생각했을 때는 이틀 만에 작품을 만들어야 한다는 조건에 집중하여 최대한 시간을 활용하며 의미 있는 것을 만들려 계획했다. 분명 제작을 머릿속에서 생각했음에도 불구하고 당일에는 순식간에 많은 것들을 변경해야 했었다. 생각했던 것보다도 시간은 촉박했고 이 제작과정 중에 순간적으로 상황을 대처하는 능력이 매우 발전했다고 느꼈다. 구상 단계에서 스스로 문제 해결 과정을 더욱 복잡하게 만들었다고 생각이 들었다. 처음 몸체를 스스로 제작하려 했지만 있던 것을 꾸며서 사용하는 과정에서 너무 새로운 것이 아니더라도 응용과 활용이 또 다른 창조를 만들 수 있다는 것을 깨달았다. 3명이서 역할분담을 하여 주어진 역할을 충실히 하는 것이 프로젝트의 시간 대비 효율을 극대화했었다. 공동체 사회에서도 자신이 맡은 일을 충실히 하는 것이 사회의 유지에 기여하는 것뿐 아니라 자신을 좀 더 능동적으로 성장시키는 일이라 생각한다. 이번 프로젝트에서 내가 미처 생각하지 못했던 부분에 대해 다른 팀원이 이의제기를 해주고 수정해 나가는 과정이 작품의 완성도를 올리는데 도움을 주었다. 나의 부족한 점을 보완해주고 나 또한 다른 사람들의 부족한 점을 보완해주는 것에서 긍정적인 발전을 이룰 수 있다고 느꼈다.

 

이번  햬커톤을 하며 정말 많은 것들을 배우게 되었다. 첫 번째로는 나의 코딩 실력이며 두 번째는 협동 프로젝트에 익숙해지게 되었다는 것이다. 이번에 나는 아두이노 코딩을 담당하게 되었는데 이때 이틀간의 대회 기간 동안 약 몇 달간에 맞먹는 지식을 습득한 것 같다. 그리고 난 보통 혼자서 코딩을 하고 공부하던 편인지라 여럿이 같이 함께 프로젝트를 하는 데는 미숙하였다. 하지만 이번에 서로 의견을 조율하고, 방향을 잡아가며, 서로 모르는 것을 알려주며 프로젝트를 진행함으로써 팀 프로젝트에도 어느 정도 익숙해진 거 같다.

반응형

댓글