15장. 비디오 처리와 실시간 영상처리
동영상은 사진 묶음
플립북은 장마다 그림이 조금씩 다르고, 엄지로 빠르게 넘기면 움직이는 것처럼 보입니다. 넘기는 빠르기가 느리면 뚝뚝 끊기고, 빠르면 매끈합니다. 동영상 파일 안에도 사진이 차례로 들어 있고, 1초에 몇 장을 넘길지가 함께 적혀 있습니다.
그림은 이 장의 실습 동영상(ch15_conveyor.mp4, 컨베이어 벨트 위로 상자가 지나가는 가상 동영상)에서 20장마다 한 장씩 꺼낸 것입니다. 장 번호가 커질수록 상자가 오른쪽으로 옮겨 갑니다. 여기서 플립북의 한 장이 프레임이고, 넘기는 빠르기가 FPS 이고, 엄지로 한 번 넘기는 사이의 시간이 프레임 간격입니다. 비유와 다른 점도 있습니다. 동영상 파일은 사진을 그대로 쌓아 두지 않고 코덱으로 작게 묶어 저장합니다.
손으로 계산해 보기
이 장의 컨베이어 동영상은 10fps, 80프레임입니다.
| 묻는 것 | 계산 | 답 |
|---|---|---|
| 한 장이 보이는 시간 | 1초 ÷ 10장 = 0.1초 | 100ms |
| 동영상 길이 | 80장 ÷ 10장 | 8초 |
| 한 장의 숫자 개수 | 320 × 240 × 3 | 230,400개(바이트) |
| 80장을 모두 펼친 크기 | 230,400 × 80 | 18,432,000바이트(약 18MB) |
같은 계산을 더 큰 동영상에 해 보면 금방 커집니다.
| 해상도 | FPS | 길이 | 프레임 수 | 모두 펼친 크기 |
|---|---|---|---|---|
| 320×240 | 10 | 8초 | 80장 | 약 18MB |
| 640×480 | 30 | 10초 | 300장 | 약 276MB |
| 1920×1080 | 30 | 60초 | 1,800장 | 약 11.2GB |
# 해상도, FPS, 길이로 프레임 수와 펼친 크기를 계산한다
width, height, channels = 320, 240, 3
fps, seconds = 10, 8
frames = fps * seconds # 1초에 10장 × 8초
one = width * height * channels # uint8 이므로 숫자 하나가 1바이트
print("프레임 수:", frames) # 결과: 80
print("한 장이 보이는 시간:", 1000 / fps, "ms") # 결과: 100.0 ms
print(f"한 장: {one:,}바이트") # 결과: 230,400바이트
print(f"모두 펼치면: {one * frames:,}바이트") # 결과: 18,432,000바이트주의할 점
- 동영상을 통째로 리스트에 담으면 메모리가 금방 찹니다. 이 장의 동영상은 작아서 담아도 되지만, 큰 동영상은 한 장씩 읽고 처리한 뒤 버리는 쪽으로 짭니다.
- 파일 크기와 펼친 크기는 다릅니다. 컨베이어 동영상의 파일은 80KB 쯤인데, 펼치면 18MB 가 넘습니다. 코덱이 그만큼 줄여 담았기 때문입니다.