주요 콘텐츠

opticalFlowRAFT

RAFT 딥러닝 알고리즘을 사용하여 광학 흐름 추정

R2024b 이후

    설명

    opticalFlowRAFT 객체를 사용하여 RAFT(Recurrent All-pairs Field Transforms) 알고리즘으로 이전 및 현재 비디오 프레임 간의 모션 방향과 속도를 추정합니다. 이 알고리즘은 Kubric[3] 데이터셋에서 훈련된 딥러닝 신경망을 사용합니다. RAFT 광학 흐름 추정 알고리즘은 특히 텍스처가 거의 없는 영역이나 모션 블러가 있는 영역, 그리고 카메라 움직임이 복잡한 경우에서도 정확도가 높아 Farneback과 같은 방식보다 더 뛰어난 성능을 보입니다. 이 알고리즘은 픽셀당 밀도가 높고 매우 정확한 추정값을 제공하지만 더 많은 시간과 메모리가 필요합니다. 더 빠르지만 정확도가 낮은 고밀도 광학 흐름 추정을 위해서는 딥러닝에 의존하지 않는 기존의 비전 알고리즘인 opticalFlowFarneback을 선택하십시오.

    참고

    이 기능을 사용하려면 Deep Learning Toolbox™와 Computer Vision Toolbox™ Model for RAFT Optical Flow Estimation이 필요합니다. 애드온 탐색기에서 Computer Vision Toolbox Model for RAFT Optical Flow Estimation을 설치할 수 있습니다. 애드온 설치에 대한 자세한 내용은 애드온을 받고 관리하기를 참조하십시오.

    생성

    설명

    flowModel = opticalFlowRAFT는 이전 및 현재 비디오 프레임 간의 모션 방향과 속도를 추정하는 optical flow 객체를 반환합니다.

    예제

    객체 함수

    estimateFlowEstimate optical flow between two frames
    resetReset the internal state of the optical flow estimation object

    예제

    모두 축소

    RAFT optical flow 객체를 만듭니다.

    flowModel = opticalFlowRAFT;

    입력 비디오 파일을 읽을 객체를 만듭니다.

    vidReader = VideoReader("visiontraffic.avi",CurrentTime=11);

    광학 흐름 벡터를 시각화하는 사용자 지정 Figure 창을 생성합니다.

    h = figure;
    movegui(h);
    hViewPanel = uipanel(h, Position=[0 0 1 1], Title="Plot of Optical Flow Vectors");
    hPlot = axes(hViewPanel);

    광학 흐름을 추정하기 위해 연속적인 영상 프레임을 읽습니다. 현재 프레임을 표시하고 퀴버 플롯을 사용하여 광학 흐름 벡터를 겹쳐 표시합니다. estimateFlow 함수는 연속적인 두 프레임 간의 광학 흐름을 계산합니다.

    이 함수는 내부적으로 이전 프레임을 저장하고 광학 흐름 추정에 묵시적으로 활용합니다. 따라서 프레임 시퀀스에서 이 함수를 처음 호출하면 흐름이 0으로 반환됩니다. 이는 실제 이전 프레임이 없기 때문에 초기 프레임이 현재 프레임과 이전 프레임 모두로 간주되며, 그 결과 두 프레임 사이에서 검출할 수 있는 모션이 없기 때문입니다. 이는 opticalFlowFarneback과 같은 기존 광학 흐름 추정 방법의 인수 구조체 및 동작과 일치합니다.

    while hasFrame(vidReader)
        frame = readFrame(vidReader);
        flow = estimateFlow(flowModel,frame);
    
        imshow(frame)
        hold on
        plot(flow,DecimationFactor=[10 10],ScaleFactor=0.45,Parent=hPlot,color="g");
        hold off
        pause(10^-3)
    end

    비디오 처리가 완료된 후 opticalFlowRAFT 객체를 재설정합니다. 이렇게 하면 저장된 이전 프레임을 포함하여 객체의 내부 상태가 삭제됩니다.

    reset(flowModel);

    RAFT는 정확한 광학 흐름 추정을 제공하지만, 크기가 큰 영상에 적용하거나 메모리가 제한된 GPU에서 실행할 경우 메모리 사용량이 많아질 수 있습니다. 이러한 경우 고해상도 프레임을 직접 처리하면 메모리 부족(OOM: out-of-memory) 오류가 발생할 수 있습니다. 실질적인 해결 방법은 입력 영상을 RAFT 모델에 전달하기 전에 다운스케일링하고, 축소된 해상도에서 광학 흐름을 계산한 다음, 결과로 생성된 흐름 필드(flow field)를 다시 영상의 원래 크기로 재스케일링하는 것입니다. 이 예제에서는 이러한 메모리 효율적인 전략을 적용하는 방법을 보여주며, 이를 통해 유의미한 흐름 추정값을 유지하면서 더 큰 영상이나 리소스가 제한된 하드웨어에서 RAFT를 사용할 수 있도록 합니다.

    영상 쌍 불러오기

    두 개의 영상을 불러온 다음 카메라 움직임으로 인한 픽셀별 차이를 빨강색-녹청색(red-cyan) 합성 영상을 사용하여 시각화합니다.

    I1 = imread("yellowstone_left.png");
    I2 = imread("yellowstone_right.png");
    
    figure
    imshow(stereoAnaglyph(I1, I2))
    title("Composite Image (Red - Left Image, Cyan - Right Image)")

    Figure contains an axes object. The hidden axes object with title Composite Image (Red - Left Image, Cyan - Right Image) contains an object of type image.

    영상의 공간 차원을 표시합니다.

    disp(size(I1, [1 2]))
       480   640
    

    opticalFlowRAFT 객체 만들기

    두 영상 간 광학 흐름을 계산하기 위한 opticalFlowRAFT 객체를 만듭니다.

    raft = opticalFlowRAFT;

    전체 해상도 영상에서 광학 흐름 추정하기

    원래 해상도의 영상에서 광학 흐름을 추정합니다. 이 방법은 가장 정확한 결과를 제공하지만 실행 속도가 느려지고 메모리 사용량이 증가할 수 있습니다.

    estimateFlow(raft, I1);
    flowFull = estimateFlow(raft, I2);

    다운샘플링된 영상에서 광학 흐름 추정하기

    다운스케일링된 영상 만들기

    설명을 돕기 위해, 영상 차원을 0.5배율로 스케일링합니다. 해상도가 낮은 영상을 사용하면 광학 흐름 계산 속도를 높이고 메모리 사용량을 줄일 수 있습니다.

    I1Small = imresize(I1, 0.5);
    I2Small = imresize(I2, 0.5);

    크기가 조정된 영상 차원을 표시합니다.

    disp(size(I1Small, [1 2]))
       240   320
    

    다운스케일링된 영상에서 흐름 추정하기

    다운스케일링된 영상에서 광학 흐름을 계산합니다. 앞에서 인스턴스화한 opticalFlowRAFT 모델을 재설정한 후에 사용합니다.

    reset(raft);
    estimateFlow(raft, I1Small);
    flowLowRes = estimateFlow(raft, I2Small);

    추정된 흐름을 원래 해상도로 스케일링하기

    저해상도의 광학 흐름을 업샘플링하고 다시 원래 영상 해상도로 스케일링합니다.

    origDims = size(I1, [1 2]);
    scaleX = origDims(2) / size(flowLowRes.Magnitude, 2);
    scaleY = origDims(1) / size(flowLowRes.Magnitude, 1);
    
    flowX = imresize(flowLowRes.Vx, origDims, "bilinear") * scaleX;
    flowY = imresize(flowLowRes.Vy, origDims, "bilinear") * scaleY;
    
    flowUpscaled = opticalFlow(flowX, flowY);

    원래 해상도와 다운스케일링된 해상도의 광학 흐름 비교하기

    원래 고해상도 영상에서 직접 계산된 광학 흐름과, 다운스케일링된 영상에서 계산된 후 다시 원래 크기로 재스케일링된 광학 흐름을 시각적으로 비교합니다. 이 비교는 다운스케일링–업스케일링 워크플로가 메모리 사용량을 줄이면서 원래 광학 흐름을 어떻게 근사하는지 보여줍니다.

    figure
    subplot(1,2,1)
    imshow(I1)
    hold on
    plot(flowFull, DecimationFactor=[40 40], ScaleFactor=0.75, Color="g");
    hold off
    title("Optical Flow at Full Resolution")
    
    subplot(1,2,2)
    imshow(I1)
    hold on
    plot(flowUpscaled, DecimationFactor=[40 40], ScaleFactor=0.75, Color="g");
    hold off
    title("Optical Flow at Half Resolution")

    Figure contains 2 axes objects. Hidden axes object 1 with title Optical Flow at Full Resolution contains 2 objects of type image, quiver. Hidden axes object 2 with title Optical Flow at Half Resolution contains 2 objects of type image, quiver.

    영상 크기 조정 작업에서 쌍선형 보간을 사용하면 업스케일링된 광학 흐름에서 수치상의 부정확성과 과도하게 평활화된 결과를 초래할 수 있습니다. 이 같은 정확도 저하는 저해상도 영상에서 광학 흐름 계산을 수행할 때 메모리 사용량을 줄이는 대신 감수해야 할 단점입니다.

    참고 문헌

    [1] Teed, Zachary, and Jia Deng. RAFT: Recurrent All-Pairs Field Transforms for Optical Flow. Proceedings of the 16th European Conference on Computer Vision. 2020.

    [2] Shah, Neelay, Prajnan Goswami, and Huaizu Jiang. EzFlow: A modular PyTorch library for optical flow estimation using neural networks. 2021. Web. https://github.com/neu-vi/ezflow.

    [3] Greff, Klaus, Francois Belletti, Lucas Beyer, Carl Doersch, Yilun Du, Daniel Duckworth, David J. Fleet et al. Kubric: A scalable dataset generator. In Proceedings of the IEEE/CVF conference on computer vision and pattern recognition, pp. 3749-3761. 2022.

    버전 내역

    R2024b에 개발됨