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)