이전 게시글: 문과생AI 2주차 과제 + 개인 프로젝트 질문
goyangfa.mp4이전에 축구협회에 있을 때, AI 카메라를 사용해서 자동으로 공을 따라다니는 영상을 만든적이 있습니다.
사실은 공을 따라다니는게 아닌 축구장 전체를 찍고 그 중 공의 움직임에 따라 자동으로 편집화면을 내놓는 방식입니다.
저는 이 방법을 이용해서 만들고 싶은 프로그램이 생겼습니다.
파이썬으로 라이브아이돌 공연 영상에서 멤버 별 영상 추출하기
요즘 지하공연장에 서 공연하는 지하아이돌에 푹 빠졌습니다. 서비스도 만들었고 보완해줄 기능도 찾고 있었는데요, 제가 만들고자 하는 프로그램의 흐름은 다음과 같습니다.
구글 드라이브에 아이돌 풀영상 업로드
멤버별 하이라이트 영상 추출 (3명이면 영상이 3개)
추출 영상이 특정 구글드라이브 폴더에 저장
서비스는 간단하면서도 코딩을하려니 참 막막했지만 파트너님과 말씀 나누면서 몇 가지 힌트를 얻었습니다.
설치해서 쓰는 pycharm이 아닌 구글 Colab을 사용하면 구글 드라이브와의 연동이 편해진다. (코랩은 구글에서 제공하는 설치없이 온라인으로 코딩할 수 있는 툴)
마찬가지로 Colab을 사용하면 GPU를 빌려쓸 수 있다. (제 노트북은 너무 힘들어해요..)
그래서 파트너님께 피드백을 받고 Colab으로 환경 셋팅 후 클로드로 코딩 시도를 했었습니다.
파트너님께서도 피드백을 주시면 결과물을 보여주셨는데, 여기서 확인
친절 하게 설명해주시기도 했고 트래킹을 하면서 보는것과 아닌 것 구분을 해주셔서 이해하기가 좋았습니다.
아래는 아이돌을 연속적으로 인식하지 못하고 개별 사람으로 카운팅하는 문제를 해결하기 위한 저의 프롬프트 입니다.
너는 세계 최고의 파이썬 개발자이다.
노트북의 리소스는 최소한으로 사용해야한다.
Colab을 사용하여 개발한다.
아이돌 풀라이브영상을 mp4 파일로 가지고 있다.
Yolo를 사용해서 아이돌 라이브공연에서 아이돌이 5명이라면 각각의 아이돌에 대한 tracking 영상 5개가 추출되어야 한다.
각각의 아이돌 멤버가 누군지 학습될 필요는 없고 각각의 사람이 구분되어서 tracking 하여 zoom in, zoom out 하면서 편집된 영상을 추출해야한다.
칼만필터를 적용해서 영상의 멤버에 대한 객체가 연속적으로 인식이 되어야한다.
구글 드라이브의 /content/drive/MyDrive/idol_video/input_video.mp4 경로 비디오를 사용한다.
결과인 편집된 하이라이트 영상은 구글드라이브 /content/drive/MyDrive/highlights 에 에 저장된다
위 내용을 참고해서 코딩 입문자에게 바로 따라할 수 있을 정도로 쉽게 환경셋팅을하는 방법을 제시해주고 이후에 하이라이트 영상을 만들기 위한 코드를 바로 복사 붙여넣기로 따라할 수 있도록 순서대로 알려주고 그 기능과 코드에대한 이유와 근거를 상세한 주석과 함께 제시해줘
이렇게해서 아래와 같이 코드를 받았습니다.
이전에 로컬에서 pycharm으로 실행하면서 아이돌 객체인식의 연속성이 없는 문제가 있어서 칼만필터 (오차보정 하는 공식) 적용을 요청했습니다.
하지만 욕심이 과해서인지 칼만필터 쪽에서 계속 문제가 발생하더라구요..
클로드 할당량을 3번 써버려서 이후에 추가는 못했습니다.
+업데이트 내용
클로드 할당량이 다시 생겨서 칼만필터 부분을 해결하고 사람 객체인식을 하는지 확인을 위한 YOLO8s 로 실행한 결과입니다.
화면 기록 2024-04-13 오전 2.38.26.mp4혹시 궁금하실 분들을 위해 pycharm에서 돌릴 코드를 공유드립니다.
아마 그대로 돌리면 실행이 안될 것인데,
!pip install ~~ 를 통해 라이브러리를 설치하고
.py로 끝나는 프로젝트 파일과 동일한 위치에 input_video.mp4 파일이 있어야 합니다.
무슨 라이브러리를 설치해야하는지는 에러근육을 키우기 위해서 에러코드를 클로드나 지피티씨에게 물어보셔요
import torch
import cv2
import os
import numpy as np
from ultralytics import YOLO
from filterpy.kalman import KalmanFilter
def compute_iou(bbox1, bbox2):
"""
두 개의 상자가 얼마나 겹치는지 계산하는 함수예요.
겹치는 정도를 0에서 1 사이의 숫자로 알려줍니다.
"""
x1, y1, x2, y2 = bbox1
x3, y3, x4, y4 = bbox2
x_left = max(x1, x3)
y_top = max(y1, y3)
x_right = min(x2, x4)
y_bottom = min(y2, y4)
if x_right < x_left or y_bottom < y_top:
return 0.0
intersection_area = (x_right - x_left) * (y_bottom - y_top)
bbox1_area = (x2 - x1) * (y2 - y1)
bbox2_area = (x4 - x3) * (y4 - y3)
union_area = bbox1_area + bbox2_area - intersection_area
iou = intersection_area / union_area
return iou
def assign_id(bbox, prev_bboxes, threshold=0.5):
"""
새로운 상자에 ID를 부여하는 함수예요.
이전 상자들과 비교해서 가장 비슷한 상자의 ID를 가져옵니다.
"""
if not prev_bboxes:
return len(prev_bboxes)
ious = [compute_iou(bbox, prev_bbox) for prev_bbox in prev_bboxes]
max_iou = max(ious)
if max_iou >= threshold:
return ious.index(max_iou)
else:
return len(prev_bboxes)
def create_kalman_filter():
"""
칼만 필터라는 것을 만드는 함수예요.
칼만 필터는 상자의 움직임을 부드럽게 예측하는 데 사용됩니다.
"""
kf = KalmanFilter(dim_x=4, dim_z=2)
kf.F = np.array([[1, 0, 1, 0],
[0, 1, 0, 1],
[0, 0, 1, 0],
[0, 0, 0, 1]])
kf.H = np.array([[1, 0, 0, 0],
[0, 1, 0, 0]])
kf.P *= 1000
kf.R *= 100
kf.Q *= 0.01
return kf
def update_kalman_filter(kf, bbox):
"""
칼만 필터를 업데이트하는 함수예요.
상자의 새로운 위치를 칼만 필터에 알려줍니다.
"""
x, y, w, h = bbox
center_x, center_y = x + w // 2, y + h // 2
kf.predict()
kf.update(np.array([center_x, center_y]))
return kf.x[:2]
# 입력 비디오 경로와 출력 폴더 경로를 지정해 주세요.
video_path = "input_video.mp4"
highlight_path = "highlights"
# YOLOv8 모델을 불러옵니다. 이 모델은 사람을 찾는 데 사용될 거예요.
model = YOLO('yolov8s.pt')
# 비디오를 불러옵니다.
video = cv2.VideoCapture(video_path)
# 비디오 파일이 열렸는지 확인합니다.
if not video.isOpened():
print("비디오 파일을 열 수 없습니다.")
exit()
# 사람을 추적하기 위한 변수들을 초기화합니다.
person_detections = {}
prev_bboxes = []
kalman_filters = {}
frame_num = 0
while True:
# 비디오에서 이미지를 한 장씩 읽어옵니다.
ret, frame = video.read()
if not ret:
break
# YOLOv8 모델을 사용하여 이미지에서 사람을 찾습니다.
results = model(frame)
# 찾은 사람들 중에서 정말 사람인 것만 골라냅니다.
person_info = results[0].boxes.cls == 0
# 검출된 사람 객체의 수를 출력합니다.
print(f"검출된 사람 객체 수: {len(results[0].boxes.cls[person_info])}")
# 사람 주변에 초록색 상자를 그립니다.
curr_bboxes = []
for box in results[0].boxes.xyxy[person_info]:
x1, y1, x2, y2 = map(int, box.tolist())
curr_bboxes.append((x1, y1, x2, y2))
cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2)
# 칼만 필터를 사용하여 사람을 부드럽게 추적합니다.
for bbox in curr_bboxes:
person_id = assign_id(bbox, prev_bboxes)
if person_id not in person_detections:
person_detections[person_id] = []
kalman_filters[person_id] = create_kalman_filter()
person_detections[person_id].append((frame_num, bbox))
prev_center = update_kalman_filter(kalman_filters[person_id], bbox)
prev_center_x, prev_center_y = map(int, prev_center)
cv2.circle(frame, (prev_center_x, prev_center_y), 5, (0, 0, 255), -1)
prev_bboxes = curr_bboxes
# 처리된 이미지를 화면에 보여줍니다.
cv2.imshow('frame', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
frame_num += 1
video.release()
cv2.destroyAllWindows()
# 하이라이트 영상을 저장할 폴더를 만듭니다.
os.makedirs(highlight_path, exist_ok=True)
# 각 사람별로 하이라이트 영상을 만듭니다.
for person_id, detections in person_detections.items():
highlight_frames = []
for frame_num, bbox in detections:
x1, y1, x2, y2 = bbox
video.set(cv2.CAP_PROP_POS_FRAMES, frame_num)
ret, frame = video.read()
if ret:
# 사람 주변을 크게 잘라냅니다.
margin = 50
x1, y1, x2, y2 = x1 - margin, y1 - margin, x2 + margin, y2 + margin
x1, y1 = max(0, x1), max(0, y1)
x2, y2 = min(frame.shape[1], x2), min(frame.shape[0], y2)
person_frame = frame[y1:y2, x1:x2]
# 잘라낸 이미지를 줌인/줌아웃 효과를 주어 강조합니다.
zoom_ratio = 1.5
zoom_in_frame = cv2.resize(person_frame, None, fx=zoom_ratio, fy=zoom_ratio)
zoom_out_frame = cv2.resize(zoom_in_frame, (person_frame.shape[1], person_frame.shape[0]))
highlight_frames.append(zoom_out_frame)
# 하이라이트 영상을 저장합니다.
if highlight_frames:
highlight_filename = os.path.join(highlight_path, f"person_{person_id}.mp4")
height, width, _ = highlight_frames[0].shape
fourcc = cv2.VideoWriter_fourcc(*"mp4v")
out = cv2.VideoWriter(highlight_filename, fourcc, 30.0, (width, height))
for frame in highlight_frames:
out.write(frame)
out.release()
print(f"사람 {person_id}의 하이라이트 영상이 {highlight_filename}에 저장되었습니다.")
else:
print(f"사람 {person_id}의 하이라이트 영상이 없습니다.")
video.release()
print("하이라이트 영상 생성이 완료되었습니다!")
(서비스 자랑)
끝
#AI문과생