File size: 14,584 Bytes
63a28f6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
import cv2 as cv
import streamlit as st
import tempfile
import time
from moviepy.editor import VideoClip
from moviepy.editor import AudioFileClip
import datetime

@st.cache_resource
def yolov4(names, weights, config, Conf_threshold, NMS_threshold):
    Conf_threshold = Conf_threshold
    NMS_threshold = NMS_threshold
    COLORS = [(0, 255, 0), (0, 0, 255), (255, 0, 0),
            (255, 255, 0), (255, 0, 255), (0, 255, 255)]

    class_name = []
    with open(names, 'r') as f:
        class_name = [cname.strip() for cname in f.readlines()]
    # Инициализация нейросети YOLOv4 
    net = cv.dnn.readNet(weights, config)
    net.setPreferableBackend(cv.dnn.DNN_BACKEND_CUDA)
    net.setPreferableTarget(cv.dnn.DNN_TARGET_CUDA_FP16)

    model = cv.dnn_DetectionModel(net)
    model.setInputParams(size=(416, 416), scale=1/255, swapRB=True)
    return model, COLORS, class_name


def temp_file(data):    
    # Сохранение видеофайла во временный файл
    temp_file = tempfile.NamedTemporaryFile(delete=False)
    temp_file.write(data.read())
    temp_file_path = temp_file.name
    
    # Захват видео
    cap = cv.VideoCapture(temp_file_path)
    temp_file.close()
    return cap, temp_file_path

def image_process(model, cap, Conf_threshold, NMS_threshold, COLORS, class_name):
    
    ret, frame = cap.read()
    # Обнаружение объектов с использованием YOLOv4
    classes, scores, boxes = model.detect(frame, Conf_threshold, NMS_threshold)
    for (classid, score, box) in zip(classes, scores, boxes):
        color = COLORS[int(classid) % len(COLORS)]
        label = "%s : %f" % (class_name[classid], score)
        cv.rectangle(frame, box, color, 1)
        cv.putText(frame, label, (box[0], box[1]-10),
                cv.FONT_HERSHEY_COMPLEX, 0.3, color, 1)
    frame = cv.resize(frame,(0,0), fx=0.8, fy=0.8)
    return frame       
    
def video_process(model, cap, Conf_threshold, NMS_threshold, COLORS, class_name):
    starting_time = time.time()
    frame_counter = 0
    total_frames = int(cap.get(cv.CAP_PROP_FRAME_COUNT))
    remaining_time = datetime.timedelta(seconds=0)
    remaining_time_container = st.empty()
    video_frames = []
    while True:
        ret, frame = cap.read()
        frame_counter += 1
        if ret == False:
            break
        # Обнаружение объектов с использованием YOLOv4
        classes, scores, boxes = model.detect(frame, Conf_threshold, NMS_threshold)
        for (classid, score, box) in zip(classes, scores, boxes):
            color = COLORS[int(classid) % len(COLORS)]
            label = "%s : %f" % (class_name[classid], score)
            cv.rectangle(frame, box, color, 1)
            cv.putText(frame, label, (box[0], box[1]-10),
                    cv.FONT_HERSHEY_COMPLEX, 0.3, color, 1)
        if app_mode == 'Видео':
            endingTime = time.time() - starting_time
            fps = frame_counter/endingTime
            remaining_frames = total_frames - frame_counter
            remaining_time = datetime.timedelta(seconds=int(remaining_frames / fps))
            
        # Преобразование кадра в формат RGB для отображения в Streamlit
        frame = cv.cvtColor(frame, cv.COLOR_BGR2RGB)
        video_frames.append(frame.copy())
        remaining_time_container.markdown('Оставшееся время выполнения: ' + str(remaining_time))           
        
        if stop:
            break
    return video_frames

def concotinate_video(video_frames, data):
    cap = cv.VideoCapture(data)
    # Считывание видео для получения FPS
    fps_original = cap.get(cv.CAP_PROP_FPS)
    total_frames_original = int(cap.get(cv.CAP_PROP_FRAME_COUNT))
    # Создание функции для извлечения кадров из списка video_frames
    def get_frame(t):
        index = int(t * fps_original)

        if index < total_frames_original:
            return video_frames[index]
        else:
            return video_frames[-1]
    # Считывание аудио для получения длительности
    audio_clip = AudioFileClip(data)
    st.markdown('Сборка видео')
    video_clip = VideoClip(get_frame, duration=total_frames_original / fps_original)
    video_clip = video_clip.set_audio(audio_clip)
    output_file_path = 'processed_video.mp4'
    video_clip.write_videofile(output_file_path, codec="libx264", audio_codec="aac", fps=fps_original)
        
    return output_file_path

st.set_page_config(layout="wide", page_title="Детекция с YOLO v4")
st.title("Детекция с YOLO v4")

st.sidebar.title('Информация и выбор режима')

app_mode = st.sidebar.selectbox(
    'Параметры',
    ['О сервисе', 'Изображение', 'Видео']
)

# About Page
if app_mode == 'О сервисе':
    st.markdown('''Проект создан с использованием фреймворка Streamlit и библиотеки OpenCV, при этом в его основе лежит сверточная нейросеть YOLOv4. 
    Проект предоставляет демонстрацию возможностей данной нейросети.    
#### YOLOv4 с обученными весами:
- Проект включает в себя готовую модель YOLOv4 с предварительно обученными весами. Эта модель способна обнаруживать объекты из 80 различных классов, что обеспечивает широкий спектр применения для определения различных объектов на изображениях.

#### Переобученная модель YOLOv4-tiny:
- Кроме того, представлена переобученная модель YOLOv4-tiny, которая была адаптирована для специфической задачи - определения наличия надетой каски на человеке. В ходе этого процесса были взяты веса базовой модели YOLOv4-tiny, проведена разметка данных и выполнено обучение на домашнем компьютере с использованием технологии CUDA от NVIDIA. Обучение велось по двум классам: "helmet" (каска) и "head" (голова).

Этот проект не только демонстрирует работу нейросети, но и подчеркивает его возможности в адаптации к конкретным задачам и обучению на собственных данных.
    ''')
    with st.expander("Пример видео на выходе после обработки"):
        st.video('processed_test1.mp4')
        st.video('processed_test2.mp4')

# Image Page
elif app_mode == 'Изображение':
    genre = st.sidebar.radio(
    "Выбор модели",
    ["yolov4", "helmet"],
    index=0,
    )
    if genre == 'yolov4':
        names = 'coco.names'
        weights = 'yolov4-tiny.weights'
        config = 'yolov4-tiny-custom.cfg'
    elif genre == 'helmet':
        names = 'helmet.names'
        weights = 'helmet_final.weights'
        config = 'helmet.cfg'
            
    st.sidebar.markdown('---')

    st.markdown("#### Определение объектов на изображении")

    st.sidebar.markdown('---')
    detection_confidence = st.sidebar.slider('Порог уверенности', min_value=0.0, max_value=1.0, value=0.5)
    with st.sidebar.expander("Назначение:"):
        st.markdown('''Определяет, насколько уверенной должна быть модель в том, что объект обнаружен, прежде чем результат будет рассматриваться как положительный. 
                 Если уверенность модели ниже этого порога, объект не будет считаться детектированным.
                 Обычно устанавливается в диапазоне 0.1-0.9 в зависимости от ваших требований к уверенности. 
                 Более низкие значения приведут к более широкому набору детекций, но с большим числом ложных срабатываний.''')
    tracking_confidence = st.sidebar.slider('Порог подавления', min_value=0.0, max_value=1.0, value=0.5)
    with st.sidebar.expander("Назначение:"):
        st.markdown('''Используется для подавления (фильтрации) дублирующих детекций. 
                 Когда модель обнаруживает несколько прямоугольных областей, перекрывающихся с высокой уверенностью, порог подавления помогает выбрать только одну из них. 
                 Это предотвращает появление множественных детекций для одного и того же объекта.
                 Обычно устанавливается в диапазоне 0.1-0.5. 
                 Более высокие значения делают алгоритм более консервативным, выбирая более уверенные детекции, но при этом может пропустить менее уверенные детекции.''')
    st.sidebar.markdown('---')
    
    img_file_buffer = st.sidebar.file_uploader("Загрузите изображение", type=["jpg", "jpeg", "png"])
    
    
    st.sidebar.text('Исходное изображение')
    if img_file_buffer:
        st.sidebar.image(img_file_buffer)
    if img_file_buffer:
        start = st.button("Запуск обработки", type="primary")
        stframe = st.empty()
        if start:
            model, COLORS, class_name = yolov4(names, weights, config, detection_confidence, tracking_confidence)
            cap, temp_file_path = temp_file(img_file_buffer)
            frame = image_process(model, cap, detection_confidence, tracking_confidence, COLORS, class_name)
            stframe.image(frame,channels='BGR', use_column_width="auto")
# Video Page
elif app_mode == 'Видео':
    st.set_option('deprecation.showfileUploaderEncoding', False)
    
    genre = st.sidebar.radio(
    "Выбор модели",
    ["yolov4", "helmet"],
    index=0,
    )
    
    if genre == 'yolov4':
        names = 'coco.names'
        weights = 'yolov4-tiny.weights'
        config = 'yolov4-tiny-custom.cfg'
    elif genre == 'helmet':
        names = 'helmet.names'
        weights = 'helmet_final.weights'
        config = 'helmet.cfg'
    
    st.sidebar.markdown('---')
    detection_confidence = st.sidebar.slider('Порог уверенности', min_value=0.0, max_value=1.0, value=0.5)
    with st.sidebar.expander("Назначение:"):
        st.markdown('''Определяет, насколько уверенной должна быть модель в том, что объект обнаружен, прежде чем результат будет рассматриваться как положительный. 
                 Если уверенность модели ниже этого порога, объект не будет считаться детектированным.
                 Обычно устанавливается в диапазоне 0.1-0.9 в зависимости от ваших требований к уверенности. 
                 Более низкие значения приведут к более широкому набору детекций, но с большим числом ложных срабатываний.''')
    tracking_confidence = st.sidebar.slider('Порог подавления', min_value=0.0, max_value=1.0, value=0.5)
    with st.sidebar.expander("Назначение:"):
        st.markdown('''Используется для подавления (фильтрации) дублирующих детекций. 
                 Когда модель обнаруживает несколько прямоугольных областей, перекрывающихся с высокой уверенностью, порог подавления помогает выбрать только одну из них. 
                 Это предотвращает появление множественных детекций для одного и того же объекта.
                 Обычно устанавливается в диапазоне 0.1-0.5. 
                 Более высокие значения делают алгоритм более консервативным, выбирая более уверенные детекции, но при этом может пропустить менее уверенные детекции.''')
    st.sidebar.markdown('---')

    ## Get Video
    
    video_file_buffer = st.sidebar.file_uploader("Загрузите видео", type=['mp4', 'mov', 'avi', 'asf', 'm4v'])
    
    st.sidebar.text('Исходное видео')
    if video_file_buffer:
        st.sidebar.video(video_file_buffer)
        
    st.markdown("#### Определение объектов на видео")
    
    if video_file_buffer:
        start = st.button("Запуск обработки", type="primary")
        stop = st.button("Остановка обработки")
        stframe = st.empty()
        if start:
            model, COLORS, class_name = yolov4(names, weights, config, detection_confidence, tracking_confidence)
            cap, temp_file_path = temp_file(video_file_buffer)
            video_frames = video_process(model, cap, detection_confidence, tracking_confidence, COLORS, class_name)
            output_file_path = concotinate_video(video_frames, temp_file_path)
            st.markdown('### Обработанное видео')
            st.video(output_file_path)