UGeunJi / MNIST_Streamlit_Project

:open_file_folder: MNIST 데이터 기반 streamlit 배포 프로젝트

Repository from Github https://github.comUGeunJi/MNIST_Streamlit_ProjectRepository from Github https://github.comUGeunJi/MNIST_Streamlit_Project

🔢 MNIST Streamlit Project 🎰

image

개요

  • Deep Learning
  • Streamlit
  • Canvas

MNIST 데이터를 가지고 모델에 학습시켜 예측하는 결과를 가지고 하는 숫자놀이 페이지 만들기

image

💾 Mini Project (2023/01/27 ~ 2023/01/30) 📅

👪 팀명: 숫자놀이

팀원 역할(Code Link)
강동엽 Calculator
이상훈 Phone Number
지우근 Main Page
최세현 Lottery

시연 영상

Main Page 시연 영상

Calculator 시연 영상

Lottery 시연 영상

Phone Number 시연 영상


Trouble Shooting

  1. Teachable Machine Link - 마스크, 로고, 가위바위보를 실험해 봤지만 정확도가 높지 않아서 기각
  2. MNIST-Canvas 버전 문제 (Terminal Settings로 해결), 배포 문제 (packages.txt file로 해결)
  3. 코딩하면서의 시행착오
  • columns 안에 columns 코딩 불가능!
  • 버튼을 누를 때마다 계속 페이지가 초기화됨 😢 (session.state로 해결)
  1. 배포한 사이트에서 사이드바에 다른 페이지가 표시되지 않음 (streamlit을 최신버전으로, photobuf의 버전을 그에 맞게 바꿔서 해결)
  2. Keyerror DISPLAY (pyautogui 모듈을 없애줌으로써 해결)
  3. encode('ANSI') (('utf-8-sig')로 바꿔줌으로써 해결)

더 구현하고 싶은 기능

  • emoji rain
  • stoggle
  • 효과음
  • linebar
  • Mention
  • streamlit.extras 모듈에서 실행되지 않았던 기능들

‼️ Terminal Settings

    # 아래 단계를 차례로 실행해 주세요
    # 1. python -m pip install --upgrade pip
    # 2. conda create -n tensorflow python=3.7
    # 3. activate tensorflow
    # 4. pip install tensorflow
    # 5. pip install keras
    # 6. pip install opencv-python
    # 7. pip install streamlit_drawable_canvas
    # 8. 모듈이 없다고 오류뜨면 pip install <module name>
    # 9. pip install -r requirements.txt

Code

Main Page
Calculator
Lottery
Phone Number

Main Page

import cv2
from keras.models import load_model
import streamlit as st
from streamlit_drawable_canvas import st_canvas
import numpy as np
from streamlit_vertical_slider import vertical_slider
from utils import set_bg

set_bg('images/mnist2.png')

st.sidebar.image('./images/sidebar_main.jpg')

st.image('./images/title.png')

st.write('### :star: :red[특별 체험]')


calculator = st.checkbox('Calculator')
if calculator:
    st.write('좋아요!')
lottery = st.checkbox('Lottery')
if lottery:
    st.image('./images/따봉1.png')
phone_number = st.checkbox('Phone Number')
if phone_number:
    st.image('./images/따봉2.png')


st.write('### :mag: :blue[기본 체험]')

@st.cache(allow_output_mutation=True)         # 모델을 한 번만 load하기 위해서 Rerun을 안하도록 만들어줌
def load():
    return load_model('./model.h5')
model = load()

CANVAS_SIZE = 340

col1, col2 = st.columns(2)

with col1:
    canvas = st_canvas(
        fill_color='#000000',
        stroke_width=20,
        stroke_color='#FFFFFF',
        background_color='#000000',
        width=CANVAS_SIZE,
        height=CANVAS_SIZE,
        drawing_mode='freedraw',
        key='canvas'
    )

if canvas.image_data is not None:
    img = canvas.image_data.astype(np.uint8)
    img = cv2.resize(img, dsize=(28, 28))
    preview_img = cv2.resize(img, dsize=(CANVAS_SIZE, CANVAS_SIZE), interpolation=cv2.INTER_NEAREST)

    col2.image(preview_img)

    x = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    x = x.reshape((-1, 28, 28, 1))
    y = model.predict(x).squeeze()

    st.write('## :dart: 예측 결과: %d' % np.argmax(y))

st.write('### :green[예쁜 사진으로 보기]')
[col3, col4, col5] = st.columns([2, 2, 1])
with col3:
    if st.button('일치'):
        if np.argmax(y) == 0:
            st.image('./images/zero.jpg')
            with open("./images/zero.jpg", "rb") as file:
                btn = st.download_button(
                        label="이미지 소장하기",
                        data=file,
                        file_name="zero.jpg",
                        mime="image/jpg"
                    )
        elif np.argmax(y) == 1:
            st.image('./images/one.jpg')
            with open("./images/one.jpg", "rb") as file:
                btn = st.download_button(
                        label="이미지 소장하기",
                        data=file,
                        file_name="one.jpg",
                        mime="image/jpg"
                    )
        elif np.argmax(y) == 2:
            st.image('./images/two.jpg')
            with open("./images/two.jpg", "rb") as file:
                btn = st.download_button(
                        label="이미지 소장하기",
                        data=file,
                        file_name="two.jpg",
                        mime="image/jpg"
                    )
        elif np.argmax(y) == 3:
            st.image('./images/three.jpg')
            with open("./images/three.jpg", "rb") as file:
                btn = st.download_button(
                        label="이미지 소장하기",
                        data=file,
                        file_name="three.jpg",
                        mime="image/jpg"
                    )
        elif np.argmax(y) == 4:
            st.image('./images/four.jpg')
            with open("./images/four.jpg", "rb") as file:
                btn = st.download_button(
                        label="이미지 소장하기",
                        data=file,
                        file_name="four.jpg",
                        mime="image/jpg"
                    )
        elif np.argmax(y) == 5:
            st.image('./images/five.jpg')
            with open("./images/five.jpg", "rb") as file:
                btn = st.download_button(
                        label="이미지 소장하기",
                        data=file,
                        file_name="five.jpg",
                        mime="image/jpg"
                    )
        elif np.argmax(y) == 6:
            st.image('./images/six.jpg')
            with open("./images/six.jpg", "rb") as file:
                btn = st.download_button(
                        label="이미지 소장하기",
                        data=file,
                        file_name="six.jpg",
                        mime="image/jpg"
                    )
        elif np.argmax(y) == 7:
            st.image('./images/seven.jpg')
            with open("./images/seven.jpg", "rb") as file:
                btn = st.download_button(
                        label="이미지 소장하기",
                        data=file,
                        file_name="seven.jpg",
                        mime="image/jpg"
                    )
        elif np.argmax(y) == 8:
            st.image('./images/eight.jpg')
            with open("./images/eight.jpg", "rb") as file:
                btn = st.download_button(
                        label="이미지 소장하기",
                        data=file,
                        file_name="eight.jpg",
                        mime="image/jpg"
                    )
        elif np.argmax(y) == 9:
            st.image('./images/nine.jpg')
            with open("./images/nine.jpg", "rb") as file:
                btn = st.download_button(
                        label="이미지 소장하기",
                        data=file,
                        file_name="nine.jpg",
                        mime="image/jpg"
                    )

with col4:
    if st.button('불일치'):
        st.image('./images/불일치.png')
        st.write('#### 다시 그려주세요')
        
with col5:
    st.write("##### 내 만족도")
    vertical_slider(
        key="slider",
        default_value=10,
        step=1,
        min_value=0,
        max_value=100,
        track_color="gray",
        thumb_color="blue", 
        slider_color="red",
    )
    
st.write("### :bluepurple[그래프로 보기]")
st.write("해당 숫자일 확률을 나타냅니다.")
st.bar_chart(y)

st.write('### BGM :musical_score:')
st.write('Fantasie Impromptu')
st.audio('./audios/Fantasie Impromptu.mp3')
st.write('He is a Perate')
st.audio('./audios/He is a Perate.mp3')
st.write('Merry Christmas Mr-Laurence')
st.audio('./audios/Merry Christmas Mr-Laurence.mp3')
st.write('River flows in your')
st.audio('./audios/River flows in your.mp3')
st.write('Summer')
st.audio('./audios/Summer.mp3')

Main Page 시연 영상

main_page3

Calculator

import cv2
from keras.models import load_model
import streamlit as st
from streamlit_drawable_canvas import st_canvas
import numpy as np
import random
from utils import set_bg

set_bg('images/mnist2.png')

@st.cache(allow_output_mutation=True)
def load():
    return load_model('./model.h5')
model = load()

st.image('./images/title.png')

st.write('# 계산기 :computer:')
st.write('숫자 두개를 그려주세요')
CANVAS_SIZE = 340
STROKE_SIZE =16 

# 숫자 확인
def model_predict(canvas1, canvas2) :
        img1 = canvas1.image_data.astype(np.uint8)
        img1 = cv2.resize(img1, dsize=(28, 28))
        preview_img = cv2.resize(img1, dsize=(CANVAS_SIZE, CANVAS_SIZE), interpolation=cv2.INTER_NEAREST)
        x1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
        x1 = x1.reshape((-1, 28, 28, 1))
        y1 = model.predict(x1).squeeze()

        
        img2 = canvas2.image_data.astype(np.uint8)
        img2 = cv2.resize(img2, dsize=(28, 28))
        x2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
        x2 = x2.reshape((-1, 28, 28, 1))
        y2 = model.predict(x2).squeeze()

        return np.argmax(y1), np.argmax(y2) 

# 계산
def calculation() :
    operator = st.radio('operator', ["+", "-", "%", "*"]) 

    st.write("## 계산 결과는...")
    if operator == "+" : 
        st.write('## %d + %d = %d' % (z1,z2,z1+z2))

    elif operator == "-" : 
        st.write('## %d - %d = %d' % (z1,z2,z1-z2))

    elif operator == "%" : 
        st.write('## %d / %d = %d' % (z1,z2,z1/ z2))

    else : 
        st.write('## %d * %d = %d' % (z1,z2,z1*z2))

# canvas 설정
col1, col2 = st.columns(2)

with col1:
    canvas1 = st_canvas(
        fill_color='#000000',
        stroke_width=STROKE_SIZE,
        stroke_color='#FFFFFF',
        background_color='#000000',
        width=CANVAS_SIZE,
        height=CANVAS_SIZE,
        drawing_mode='freedraw',
        key='canvas1'
    )

with col2:
    canvas2 = st_canvas(
        fill_color='#000000',
        stroke_width=STROKE_SIZE,
        stroke_color='#FFFFFF',
        background_color='#000000',
        width=CANVAS_SIZE,
        height=CANVAS_SIZE,
        drawing_mode='freedraw',
        key='canvas2'
    )
   

# 숫자 에측 
if canvas1.image_data is not None and canvas2.image_data is not None:
    z1, z2 = model_predict(canvas1, canvas2)


# 그린 숫자가 맞는지 확인
st.write("## 입력하신 숫자가 맞나요?? %d, %d" % (z1 ,z2) )
[col1, col2] =st.columns(2) 


if 'button_clicked' not in st.session_state:
    st.session_state.button_clicked = False

def callback():
    st.session_state.button_clicked = True

# 맞을 경우  
with col1 :
    if (st.button("Yes", on_click=callback) or st.session_state.button_clicked): 
        st.write("## 연산자를 골라주세요!")
        calculation()


with col2 : 
    if st.button("NO")  :
        st.write('#### 새로고침을 눌러주세요.')

Calculator 시연 영상

calculator시연영상

Lottery

import cv2
from keras.models import load_model
import streamlit as st
from streamlit_drawable_canvas import st_canvas
import numpy as np
import tensorflow as ts
import random  
from utils import set_bg

set_bg('images/mnist2.png')


disable_btn=False

@st.cache(allow_output_mutation=True)
def load():
    return load_model('./model.h5')
model = load()
st.image('./images/title.png')

st.title('행운의 숫자 뽑기')

col1, col2,col3,col4 = st.columns(4)
CANVAS_SIZE = 192
yes_btn=False
no_btn=False

with col1:
    st.write("숫자를 그려주세요")
    canvas1 = st_canvas(
        fill_color='#000000',
        stroke_width=20,
        stroke_color='#FFFFFF',
        background_color='#000000',
        width=CANVAS_SIZE,
        height=CANVAS_SIZE,
        drawing_mode='freedraw',
        key='canvas1'
    )
with col2:
    st.write("숫자를 그려주세요")
    canvas2 = st_canvas(
        fill_color='#000000',
        stroke_width=20,
        stroke_color='#FFFFFF',
        background_color='#000000',
        width=CANVAS_SIZE,
        height=CANVAS_SIZE,
        drawing_mode='freedraw',
        key='canvas2'
    )    
    


# 브라우저가 가진 session을 이용하여 화면이 새로 렌더링 되더라도 계속 내 데이터를 가지고 갑니다.
if 'key' not in st.session_state:
    st.session_state['key'] = set()
if 'sort' not in st.session_state:
    st.session_state['sort'] = []
if 'rn' not in st.session_state:
    st.session_state['rn'] = random.sample(range(1,100),4)   

def lottery_check (check,win):
    same=0
    for i in check :
        if i in win:
             same+=1
    return same
    
    
if len(st.session_state.key)>3 :
    disable_btn=True
    with col1:
        st.write('뽑은 숫자들')
        st.session_state.sort=list(st.session_state.key)
        sorted_number=sorted(st.session_state.sort)
        st.write(sorted_number)
    with col2:    
        st.write('당첨번호 확인하기')
        check_number=st.button('과연 몇개?')
        st.write('나온 숫자입니다')
        lottery_num=sorted(st.session_state.rn)
        st.write(lottery_num)
        txt=lottery_check(sorted_number,lottery_num)
        st.write('%d 개 맞았습니다 ' %(txt))

    

def get_2number (c1,c2):
    img = canvas1.image_data.astype(np.uint8)
    img = cv2.resize(img, dsize=(28, 28))
    x1 = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    x1 = x1.reshape((-1, 28, 28, 1))
    y1 = model.predict(x1).squeeze()
    get_number1=np.argmax(y1)
    
    img = canvas2.image_data.astype(np.uint8)
    img = cv2.resize(img, dsize=(28, 28))
    x2 = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    x2 = x2.reshape((-1, 28, 28, 1))
    y2 = model.predict(x2).squeeze()
    get_number2=np.argmax(y2)
    return int(get_number1)*10+int(get_number2)

if (canvas1.image_data is not None) & (canvas2.image_data is not None):
    with col3:

        get_number=get_2number(canvas1,canvas2)
        st.subheader('쓰신 숫자가: %d 맞나요?' % get_number)

        with st.container() :
            yes_btn= st.button('yes',disabled=(disable_btn))
            no_btn= st.button('no')

        # 바뀐 부분
        if yes_btn:
            st.session_state.key.add(int(get_number))
            

        if no_btn:
            with col2:
                st.write("숫자를 다시 입력해주세요")
        st.text('중복숫자는 불가능')
# 바뀐부분
with col4:
    st.text(" 총 4개의\n 숫자를 입력\n 하세요")
    if st.session_state:
        str_set=''
        for i in st.session_state.key :
           str_set+=str(i)+' '
        st.subheader(str_set)
    with col4:
        refresh_btn=st.button("regame?")
        if refresh_btn==True:
            st.write('#### 새로고침을 눌러주세요.')

Lottery 시연 영상

lottery시연영상

Phone Number

import cv2
from keras.models import load_model
import streamlit as st
from streamlit_drawable_canvas import st_canvas
import numpy as np
import pandas as pd
from io import BytesIO
from utils import set_bg

set_bg('images/mnist2.png')

@st.cache(allow_output_mutation=True)
def load():
    return load_model('./model.h5')
model = load()

st.image('./images/title.png')

name_input = st.text_input('이름을 입력하세요')

st.subheader(" '010'을 제외한 휴대폰 번호 8자리를 입력해주세요.")

CANVAS_SIZE = 160
STROKE_SIZE = 12
st.text('중간 번호 4자리')

col1, col2, col3, col4 = st.columns(4)

with col1:
    canvas1 = st_canvas(
        fill_color='#000000',
        stroke_width=STROKE_SIZE,
        stroke_color='#FFFFFF',
        background_color='#000000',
        width=CANVAS_SIZE,
        height=CANVAS_SIZE,
        drawing_mode='freedraw',
        key='canvas1'
    )

with col2:
    canvas2 = st_canvas(
        fill_color='#000000',
        stroke_width=STROKE_SIZE,
        stroke_color='#FFFFFF',
        background_color='#000000',
        width=CANVAS_SIZE,
        height=CANVAS_SIZE,
        drawing_mode='freedraw',
        key='canvas2'
    )

with col3:
    canvas3 = st_canvas(
        fill_color='#000000',
        stroke_width=STROKE_SIZE,
        stroke_color='#FFFFFF',
        background_color='#000000',
        width=CANVAS_SIZE,
        height=CANVAS_SIZE,
        drawing_mode='freedraw',
        key='canvas3'
    )

with col4:
    canvas4 = st_canvas(
        fill_color='#000000',
        stroke_width=STROKE_SIZE,
        stroke_color='#FFFFFF',
        background_color='#000000',
        width=CANVAS_SIZE,
        height=CANVAS_SIZE,
        drawing_mode='freedraw',
        key='canvas4'
    )

st.text('마지막 번호 4자리')
col5, col6, col7, col8 = st.columns(4)
with col5:
    canvas5 = st_canvas(
        fill_color='#000000',
        stroke_width=STROKE_SIZE,
        stroke_color='#FFFFFF',
        background_color='#000000',
        width=CANVAS_SIZE,
        height=CANVAS_SIZE,
        drawing_mode='freedraw',
        key='canvas5'
    )

with col6:
    canvas6 = st_canvas(
        fill_color='#000000',
        stroke_width=STROKE_SIZE,
        stroke_color='#FFFFFF',
        background_color='#000000',
        width=CANVAS_SIZE,
        height=CANVAS_SIZE,
        drawing_mode='freedraw',
        key='canvas6'
    )

with col7:
    canvas7 = st_canvas(
        fill_color='#000000',
        stroke_width=STROKE_SIZE,
        stroke_color='#FFFFFF',
        background_color='#000000',
        width=CANVAS_SIZE,
        height=CANVAS_SIZE,
        drawing_mode='freedraw',
        key='canvas7'
    )

with col8:
    canvas8 = st_canvas(
        fill_color='#000000',
        stroke_width=STROKE_SIZE,
        stroke_color='#FFFFFF',
        background_color='#000000',
        width=CANVAS_SIZE,
        height=CANVAS_SIZE,
        drawing_mode='freedraw',
        key='canvas8'
    )


if canvas1.image_data is not None:
    img1 = canvas1.image_data.astype(np.uint8)
    img1 = cv2.resize(img1, dsize=(28, 28))

    img2 = canvas2.image_data.astype(np.uint8)
    img2 = cv2.resize(img2, dsize=(28, 28))

    img3 = canvas3.image_data.astype(np.uint8)
    img3 = cv2.resize(img3, dsize=(28, 28))

    img4 = canvas4.image_data.astype(np.uint8)
    img4 = cv2.resize(img4, dsize=(28, 28))

    img5 = canvas5.image_data.astype(np.uint8)
    img5 = cv2.resize(img5, dsize=(28, 28))

    img6 = canvas6.image_data.astype(np.uint8)
    img6 = cv2.resize(img6, dsize=(28, 28))

    img7 = canvas7.image_data.astype(np.uint8)
    img7 = cv2.resize(img7, dsize=(28, 28))

    img8 = canvas8.image_data.astype(np.uint8)
    img8 = cv2.resize(img8, dsize=(28, 28))

    x1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
    x1 = x1.reshape((-1, 28, 28, 1))
    y1 = model.predict(x1).squeeze()

    x2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
    x2 = x2.reshape((-1, 28, 28, 1))
    y2 = model.predict(x2).squeeze()

    x3 = cv2.cvtColor(img3, cv2.COLOR_BGR2GRAY)
    x3 = x3.reshape((-1, 28, 28, 1))
    y3 = model.predict(x3).squeeze()

    x4 = cv2.cvtColor(img4, cv2.COLOR_BGR2GRAY)
    x4 = x4.reshape((-1, 28, 28, 1))
    y4 = model.predict(x4).squeeze()

    x5 = cv2.cvtColor(img5, cv2.COLOR_BGR2GRAY)
    x5 = x5.reshape((-1, 28, 28, 1))
    y5 = model.predict(x5).squeeze()

    x6 = cv2.cvtColor(img6, cv2.COLOR_BGR2GRAY)
    x6 = x6.reshape((-1, 28, 28, 1))
    y6 = model.predict(x6).squeeze()

    x7 = cv2.cvtColor(img7, cv2.COLOR_BGR2GRAY)
    x7 = x7.reshape((-1, 28, 28, 1))
    y7 = model.predict(x7).squeeze()

    x8 = cv2.cvtColor(img8, cv2.COLOR_BGR2GRAY)
    x8 = x8.reshape((-1, 28, 28, 1))
    y8 = model.predict(x8).squeeze()

    st.write('#### Number: 010-%d%d%d%d-%d%d%d%d' %(np.argmax(y1),np.argmax(y2),np.argmax(y3),np.argmax(y4),
                            np.argmax(y5),np.argmax(y6),np.argmax(y7),np.argmax(y8)),' 이 번호가 맞습니까?')
    
if 'number' not in st.session_state:
    st.session_state.number = '010-'

if 'Phone_Number' not in st.session_state:
    st.session_state.Phone_Number = []

if 'Name' not in st.session_state:
    st.session_state.Name = []

def phone_number_covert():
    num = str(np.argmax(y1))+str(np.argmax(y2))+str(np.argmax(y3))+str(np.argmax(y4))+'-'+str(np.argmax(y5))+str(np.argmax(y6))+str(np.argmax(y7))+str(np.argmax(y8))
    st.session_state.number += num
    return st.session_state.number
    
col_1, col_2 = st.columns(2)
with col_1:
    if st.button('Yes'):
        st.session_state.number = phone_number_covert()

        st.session_state.Phone_Number += [st.session_state.number]
        st.session_state.Name += [name_input]

        df = pd.DataFrame(
            {
                "Name" : st.session_state.Name,
                "Phone_Number": st.session_state.Phone_Number
            }
        )
        st.session_state.number = '010-'
        st.dataframe(df)

        st.button('추가 입력')

        csv = df.to_csv().encode('utf-8-sig')
        st.download_button(
            label="CSV 파일 다운로드",
            data=csv,
            file_name='휴대폰 번호 정보.csv'
        )

        excel_data = BytesIO()  
        df.to_excel(excel_data)
        st.download_button(
            label="엑셀 파일 다운로드",
            data=excel_data,
            file_name='휴대폰 번호 정보.xlsx'
        )

with col_2:
    if st.button('No'):
        st.error('번호를 다시 입력하세요', icon="🚨")

Phone Number 시연 영상

전화번호시연영상

About

:open_file_folder: MNIST 데이터 기반 streamlit 배포 프로젝트


Languages

Language:Python 100.0%