Shared memory를 이용한 OpenCV 영상 스트리밍

Garam·2025년 6월 6일
0

Shared Memory란?

공유 메모리(Shared Memory)는 둘 이상의 프로세스 또는 스레드가 동일한 메모리 공간을 접근할 수 있도록 허용하는 메커니즘으로, 운영체제 또는 하드웨어 수준에서 지원되는 효율적인 IPC(Inter-Process Communication) 방식이다.

공유 메모리는 일반적으로 운영체제가 제공하는 시스템 콜 또는 API를 통해 생성되고 매핑된다. 공유 메모리 객체는 생성된 후 특정 이름을 가지며, 이 이름을 통해 다른 프로세스도 동일한 메모리 공간에 접근할 수 있다.

공유 메모리가 하나의 프로세스에 의해 생성된 후, 다른 프로세스는 해당 공유 메모리를 매핑하여 해당 내용을 실시간으로 공유할 수 있다. 이 과정은 커널 공간에 위치한 물리적 메모리를 각 프로세스의 가상 주소 공간에 연결하는 방식으로 이루어진다. 결과적으로 별도의 복사 과정 없이 데이터가 전달되므로 매우 빠른 통신 수단으로 간주된다.

해당 Python 예제에서는 multiprocessing.shared_memory 모듈을 사용해 tx, rx 두 파일로 구성하였다. tx에서는 영상을 OpenCV로 캡쳐하여 실시간으로 이미지를 공유 메모리에 쓰고, rx에서는 해당 메모리에서 데이터를 읽어와 imshow로 띄운다.


코드 예제

tx.py

import cv2
import numpy as np
from multiprocessing import shared_memory

# 장치 및 프레임 설정
DEVICE = 0
WIDTH = 640
HEIGHT = 480
CHANNEL = 3

# 공유 메모리 생성 (이름: 'frame_shm')
shm = shared_memory.SharedMemory(
    name='frame_shm', 
    create=True,  # 새로 생성
    size=WIDTH * HEIGHT * CHANNEL  # 필요한 바이트 크기 계산
)

# OpenCV 비디오 캡처 초기화
cap = cv2.VideoCapture(DEVICE)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, WIDTH)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, HEIGHT)
frame_idx = 0

try:
    while True:
        ret, frame = cap.read()
        if not ret:
            print("Could not read frame")
            continue

        # 공유 메모리 버퍼를 NumPy 배열로 생성
        shm_frame = np.ndarray(frame.shape, dtype=frame.dtype, buffer=shm.buf)

        # 프레임 데이터를 공유 메모리에 복사
        shm_frame[:] = frame
        print(f"Wrote frame {frame_idx}")
        frame_idx += 1

except KeyboardInterrupt:
    print("Exiting")

finally:
    # 공유 메모리 및 비디오 자원을 해제한다
    shm.close()
    shm.unlink()
    cap.release()

rx.py

import cv2
import numpy as np
from multiprocessing import shared_memory

# 프레임 정보 정의
WIDTH = 640
HEIGHT = 480
CHANNEL = 3

# 이미 생성된 공유 메모리에 연결한다 (create=False 옵션)
shm = shared_memory.SharedMemory(name='frame_shm', create=False)

# 공유 메모리 버퍼를 NumPy 배열로 매핑한다
shm_frame = np.ndarray((HEIGHT, WIDTH, CHANNEL), dtype=np.uint8, buffer=shm.buf)

try:
    while True:
        print("imshow")

        # 공유 메모리에 저장된 최신 프레임을 화면에 출력한다
        cv2.imshow('Video Player', shm_frame)

        # 1ms 대기 후 키 입력을 확인한다 (ESC 키 입력 시 종료)
        if cv2.waitKey(1) & 0xFF == 27:
            break

except KeyboardInterrupt:
    print("Exiting")

finally:
    # 모든 OpenCV 윈도우를 제거한다
    cv2.destroyAllWindows()

실행 결과


주의할 점

공유 메모리 사용은 일반적으로 동기화 문제를 수반하지만 본 예제에서는 Reader와 Writer의 역할이 명확히 분리되어 있으며, 중복 읽기가 발생하더라도 영상 스트리밍의 품질에 큰 영향을 미치지 않기 때문에 별도의 동기화 장치 없이 간단하게 구성하였다. (단 동기화가 생략된 경우에는 Reader가 Writer의 쓰기 도중 데이터를 읽어 손상된 프레임을 수신할 가능성도 존재한다.)

또한 공유 메모리는 unlink()를 호출하여 운영체제에서 명시적으로 제거해야 한다는 점에 유의해야 한다. 이를 누락할 경우 공유 메모리가 시스템에 잔존하여 리소스 누수로 이어질 수 있다. 다만 해당 자원이 해제되지 않았더라도 시스템을 재부팅하면 커널 메모리가 초기화되면서 공유 메모리는 자동으로 정리된다.


requirements.txt

numpy==2.2.6
opencv-python==4.11.0.86

0개의 댓글