Upload 9 files
Browse files- .gitattributes +2 -0
- app.py +73 -0
- data/breakfast.mp4 +3 -0
- data/table.jpg +3 -0
- models/yolov8n.pt +3 -0
- models/yolov8n_openvino_model/metadata.yaml +93 -0
- models/yolov8n_openvino_model/yolov8n.bin +3 -0
- models/yolov8n_openvino_model/yolov8n.xml +0 -0
- utils/game_classes.txt +27 -0
- utils/object_detection_brainai.py +84 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,5 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
data/breakfast.mp4 filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
data/table.jpg filter=lfs diff=lfs merge=lfs -text
|
app.py
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
import cv2
|
| 3 |
+
from utils import object_detection_brainai as odb
|
| 4 |
+
object_detection = odb.ObjectDetectionModel()
|
| 5 |
+
|
| 6 |
+
st.set_page_config(
|
| 7 |
+
page_title = "객체 인식",
|
| 8 |
+
page_icon = ":black_cat:",
|
| 9 |
+
layout = "wide")
|
| 10 |
+
|
| 11 |
+
st.title(":blue[Object Detection] :black_cat:")
|
| 12 |
+
st.sidebar.header("메뉴")
|
| 13 |
+
source_radio = st.sidebar.radio("선택하세요", ["IMAGE", "VIDEO", "GAME"])
|
| 14 |
+
|
| 15 |
+
if source_radio == "IMAGE":
|
| 16 |
+
st.write(":green[왼쪽 메뉴 'Browse files' 버튼을 클릭하여 이미지 파일을 선택하면 AI 추론이 시작됩니다.]" )
|
| 17 |
+
st.sidebar.header("이미지 파일 업로드")
|
| 18 |
+
input_img = st.sidebar.file_uploader("이미지 파일을 선택하세요.", type=("jpg", "png"))
|
| 19 |
+
|
| 20 |
+
if input_img is not None:
|
| 21 |
+
result_img, detected_object = object_detection.process_image(input_img)
|
| 22 |
+
col1, col2 = st.columns(2)
|
| 23 |
+
with col1:
|
| 24 |
+
st.image(result_img)
|
| 25 |
+
with col2:
|
| 26 |
+
st.write(detected_object)
|
| 27 |
+
else:
|
| 28 |
+
col1, col2 = st.columns(2)
|
| 29 |
+
with col1:
|
| 30 |
+
st.image("data/table.jpg")
|
| 31 |
+
with col2:
|
| 32 |
+
st.write("Objects detected: chair, potted plant, vase, dining table")
|
| 33 |
+
|
| 34 |
+
elif source_radio == "VIDEO":
|
| 35 |
+
st.write(":green[왼쪽 메뉴 'Browse files' 버튼을 클릭하여 비디오 파일을 선택하면 AI 추론이 시작됩니다.]" )
|
| 36 |
+
st.sidebar.header("비디오 파일 업로드")
|
| 37 |
+
input_video = st.sidebar.file_uploader("비디오 파일을 선택하세요..", type=("mp4"))
|
| 38 |
+
print(input_video)
|
| 39 |
+
if input_video is not None:
|
| 40 |
+
temp_file = object_detection.play_video(input_video)
|
| 41 |
+
st.video(temp_file)
|
| 42 |
+
else:
|
| 43 |
+
st.video("data/breakfast.mp4")
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
elif source_radio == "GAME":
|
| 47 |
+
input_img = st.sidebar.file_uploader("이미지 파일을 선택하세요.", type=("jpg", "png"))
|
| 48 |
+
if input_img is None:
|
| 49 |
+
st.session_state.random_class = object_detection.call_class()
|
| 50 |
+
col1, col2 = st.columns([3, 1]) # Adjust the column widths as needed
|
| 51 |
+
|
| 52 |
+
with col1:
|
| 53 |
+
st.title(f':{st.session_state.random_class}: 있는 이미지를 업로드') # Display the header
|
| 54 |
+
|
| 55 |
+
with col2:
|
| 56 |
+
if st.button('새로운 객체'):
|
| 57 |
+
st.session_state.random_class = object_detection.call_class()
|
| 58 |
+
else:
|
| 59 |
+
result_img, detected_object = object_detection.process_image(input_img)
|
| 60 |
+
if st.session_state.random_class in detected_object:
|
| 61 |
+
st.header(f':{st.session_state.random_class}: 찾습니다!')
|
| 62 |
+
|
| 63 |
+
else:
|
| 64 |
+
st.header(f':{st.session_state.random_class}: 찾을 수 없습니다')
|
| 65 |
+
|
| 66 |
+
st.image(result_img)
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
|
data/breakfast.mp4
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:e76a8a373151d85b48c8c3d3d441927ee98316b9ead06b22a172db9e1bd72afe
|
| 3 |
+
size 2034760
|
data/table.jpg
ADDED
|
Git LFS Details
|
models/yolov8n.pt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:f59b3d833e2ff32e194b5bb8e08d211dc7c5bdf144b90d2c8412c47ccfc83b36
|
| 3 |
+
size 6549796
|
models/yolov8n_openvino_model/metadata.yaml
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
description: Ultralytics YOLOv8n model trained on coco.yaml
|
| 2 |
+
author: Ultralytics
|
| 3 |
+
date: '2024-11-27T09:26:37.990600'
|
| 4 |
+
version: 8.3.34
|
| 5 |
+
license: AGPL-3.0 License (https://ultralytics.com/license)
|
| 6 |
+
docs: https://docs.ultralytics.com
|
| 7 |
+
stride: 32
|
| 8 |
+
task: detect
|
| 9 |
+
batch: 1
|
| 10 |
+
imgsz:
|
| 11 |
+
- 640
|
| 12 |
+
- 640
|
| 13 |
+
names:
|
| 14 |
+
0: person
|
| 15 |
+
1: bicycle
|
| 16 |
+
2: car
|
| 17 |
+
3: motorcycle
|
| 18 |
+
4: airplane
|
| 19 |
+
5: bus
|
| 20 |
+
6: train
|
| 21 |
+
7: truck
|
| 22 |
+
8: boat
|
| 23 |
+
9: traffic light
|
| 24 |
+
10: fire hydrant
|
| 25 |
+
11: stop sign
|
| 26 |
+
12: parking meter
|
| 27 |
+
13: bench
|
| 28 |
+
14: bird
|
| 29 |
+
15: cat
|
| 30 |
+
16: dog
|
| 31 |
+
17: horse
|
| 32 |
+
18: sheep
|
| 33 |
+
19: cow
|
| 34 |
+
20: elephant
|
| 35 |
+
21: bear
|
| 36 |
+
22: zebra
|
| 37 |
+
23: giraffe
|
| 38 |
+
24: backpack
|
| 39 |
+
25: umbrella
|
| 40 |
+
26: handbag
|
| 41 |
+
27: tie
|
| 42 |
+
28: suitcase
|
| 43 |
+
29: frisbee
|
| 44 |
+
30: skis
|
| 45 |
+
31: snowboard
|
| 46 |
+
32: sports ball
|
| 47 |
+
33: kite
|
| 48 |
+
34: baseball bat
|
| 49 |
+
35: baseball glove
|
| 50 |
+
36: skateboard
|
| 51 |
+
37: surfboard
|
| 52 |
+
38: tennis racket
|
| 53 |
+
39: bottle
|
| 54 |
+
40: wine glass
|
| 55 |
+
41: cup
|
| 56 |
+
42: fork
|
| 57 |
+
43: knife
|
| 58 |
+
44: spoon
|
| 59 |
+
45: bowl
|
| 60 |
+
46: banana
|
| 61 |
+
47: apple
|
| 62 |
+
48: sandwich
|
| 63 |
+
49: orange
|
| 64 |
+
50: broccoli
|
| 65 |
+
51: carrot
|
| 66 |
+
52: hot dog
|
| 67 |
+
53: pizza
|
| 68 |
+
54: donut
|
| 69 |
+
55: cake
|
| 70 |
+
56: chair
|
| 71 |
+
57: couch
|
| 72 |
+
58: potted plant
|
| 73 |
+
59: bed
|
| 74 |
+
60: dining table
|
| 75 |
+
61: toilet
|
| 76 |
+
62: tv
|
| 77 |
+
63: laptop
|
| 78 |
+
64: mouse
|
| 79 |
+
65: remote
|
| 80 |
+
66: keyboard
|
| 81 |
+
67: cell phone
|
| 82 |
+
68: microwave
|
| 83 |
+
69: oven
|
| 84 |
+
70: toaster
|
| 85 |
+
71: sink
|
| 86 |
+
72: refrigerator
|
| 87 |
+
73: book
|
| 88 |
+
74: clock
|
| 89 |
+
75: vase
|
| 90 |
+
76: scissors
|
| 91 |
+
77: teddy bear
|
| 92 |
+
78: hair drier
|
| 93 |
+
79: toothbrush
|
models/yolov8n_openvino_model/yolov8n.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:48b86fce278a5a6833dc015b7af8cbcb7174004a5f9b6ff7ec724f753f361681
|
| 3 |
+
size 12708656
|
models/yolov8n_openvino_model/yolov8n.xml
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
utils/game_classes.txt
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
cat
|
| 2 |
+
dog
|
| 3 |
+
bus
|
| 4 |
+
train
|
| 5 |
+
boat
|
| 6 |
+
bird
|
| 7 |
+
horse
|
| 8 |
+
sheep
|
| 9 |
+
cow
|
| 10 |
+
elephant
|
| 11 |
+
bear
|
| 12 |
+
umbrella
|
| 13 |
+
handbag
|
| 14 |
+
kite
|
| 15 |
+
skateboard
|
| 16 |
+
banana
|
| 17 |
+
apple
|
| 18 |
+
sandwich
|
| 19 |
+
broccoli
|
| 20 |
+
carrot
|
| 21 |
+
pizza
|
| 22 |
+
chair
|
| 23 |
+
cake
|
| 24 |
+
bed
|
| 25 |
+
toilet
|
| 26 |
+
tv
|
| 27 |
+
keyboard
|
utils/object_detection_brainai.py
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from ultralytics import YOLO
|
| 2 |
+
import cv2
|
| 3 |
+
import numpy as np
|
| 4 |
+
import PIL
|
| 5 |
+
import io
|
| 6 |
+
import tempfile
|
| 7 |
+
import streamlit as st
|
| 8 |
+
import moviepy.editor as mpy
|
| 9 |
+
import random
|
| 10 |
+
|
| 11 |
+
class ObjectDetectionModel():
|
| 12 |
+
|
| 13 |
+
def __init__(self):
|
| 14 |
+
self.model = YOLO("models/yolov8n_openvino_model", task = "detect")
|
| 15 |
+
self.class_names = self.model.names
|
| 16 |
+
|
| 17 |
+
with open("utils/game_classes.txt", "r") as file:
|
| 18 |
+
self.game_classes = [line.strip() for line in file if line.strip()]
|
| 19 |
+
|
| 20 |
+
def process(self, img):
|
| 21 |
+
result = self.model(img)
|
| 22 |
+
img_plot = result[0].plot()
|
| 23 |
+
|
| 24 |
+
return img_plot
|
| 25 |
+
|
| 26 |
+
def process_image(self, img):
|
| 27 |
+
|
| 28 |
+
if isinstance(img, np.ndarray):
|
| 29 |
+
uploaded_img_cv = img
|
| 30 |
+
else:
|
| 31 |
+
uploaded_img = PIL.Image.open(img)
|
| 32 |
+
uploaded_img_cv = np.array(uploaded_img)
|
| 33 |
+
|
| 34 |
+
result = self.model(uploaded_img_cv, verbose=False)
|
| 35 |
+
img_plot = result[0].plot()
|
| 36 |
+
|
| 37 |
+
detected_classes = set()
|
| 38 |
+
for box in result[0].boxes:
|
| 39 |
+
class_id = int(box.cls[0]) # Class ID
|
| 40 |
+
class_name = self.class_names[class_id] # Get class name
|
| 41 |
+
detected_classes.add(class_name)
|
| 42 |
+
|
| 43 |
+
return img_plot, f'Objects Detected: {", ".join(detected_classes) if detected_classes else "No objects detected"}'
|
| 44 |
+
|
| 45 |
+
def play_video(self, input_video):
|
| 46 |
+
g = io.BytesIO(input_video.read())
|
| 47 |
+
temporary_location = "upload.mp4"
|
| 48 |
+
with open(temporary_location, "wb") as out:
|
| 49 |
+
out.write(g.read())
|
| 50 |
+
out.close()
|
| 51 |
+
|
| 52 |
+
camera = cv2.VideoCapture(temporary_location)
|
| 53 |
+
fps = camera.get(cv2.CAP_PROP_FPS)
|
| 54 |
+
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.mp4')
|
| 55 |
+
video_row=[]
|
| 56 |
+
total_frames = int(camera.get(cv2.CAP_PROP_FRAME_COUNT))
|
| 57 |
+
progress_bar = st.progress(0)
|
| 58 |
+
frame_count = 0
|
| 59 |
+
|
| 60 |
+
st_frame = st.empty()
|
| 61 |
+
while(camera.isOpened()):
|
| 62 |
+
ret, frame = camera.read()
|
| 63 |
+
|
| 64 |
+
if ret:
|
| 65 |
+
img_plot, _ = self.process_image(frame)
|
| 66 |
+
st_frame.image(img_plot, channels = "BGR")
|
| 67 |
+
video_row.append(cv2.cvtColor(img_plot,cv2.COLOR_BGR2RGB))
|
| 68 |
+
frame_count +=1
|
| 69 |
+
progress_bar.progress(frame_count/total_frames, text = None)
|
| 70 |
+
|
| 71 |
+
else:
|
| 72 |
+
camera.release()
|
| 73 |
+
st_frame.empty()
|
| 74 |
+
progress_bar.empty()
|
| 75 |
+
break
|
| 76 |
+
clip = mpy.ImageSequenceClip(video_row,fps=fps)
|
| 77 |
+
clip.write_videofile(temp_file.name)
|
| 78 |
+
|
| 79 |
+
return temp_file.name
|
| 80 |
+
|
| 81 |
+
def call_class(self):
|
| 82 |
+
random_class = random.choice(list(self.game_classes))
|
| 83 |
+
return random_class
|
| 84 |
+
|