Programming/Qt

[도서 실습] Qt 5 and OpenCV 4 Computer Vision – The GazerW Application (FPS 계산하기)

변화의 물결1 2024. 4. 19. 00:06

 

 

 안녕하세요.

 

  FPS라고 하면 게임에서 많이 볼 단어이지만 영상에 처리 많이 사용하는 용어이기도 합니다. 그래서 간단하게 정의를 찾아보고 테스트해 보겠습니다.

 


 

 

1. FPS란

 

  동영상을 물리적으로 환원하면 시간상 연속된 정지 사진들의 모음으로 볼 수 있는데, 이 각각의 정지 사진 하나를 '프레임'이라 부른다. 이런 사진 토막들이 1초에 몇 장 보이느냐, 즉 프레임이 보이는 속도를 가리켜 'Frame Rate', 우리말로 옮기면 프레임률이라 하며, 단위로는 'fps' 혹은 국제 표준인 'Hz'를 쓴다. 간혹 모니터 주사율(refresh rate)과 헷갈리는 일이 있는데, 이는 단위가 같지만 완전히 별개의 개념이다. 모니터 주사율의 단위는 'Hz'로 표기하고, '화면 재생 빈도'라고 하며 모니터가 그래픽 카드에서 제공한 프레임을 얼마나 자주 새 프레임으로 교체하는지의 수치이다.

 <나무 위키, FPS>

 

  보통 영화나 애니메이션은 24 fps가 나온다고 합니다. 이 수치로 화면을 출력하는 이유는 사람 눈으로 보았을 때 적당하게 끊기지 않고 자연스럽게 보이기 때문이라고 합니다.

 

 

2. 소스 추가

 

<capture_thread.h>

 

  - 시간 계산을 하기 위해서 QTime 클래스를 include 합니다.

  - 계산중인지, fps 수치가 얼마인지 저장할 수 있는 변수를 선언합니다.

  - fps를 계산을 위한 함수와 계산완료가 되었다는 시그널 함수를 선언해 줍니다.

 

 

private:
...
    bool    fps_calculating;
    float   fps;
...    
private :
    void calculateFPS(cv::VideoCapture &cap);

signals:
    void frameCaptured(cv::Mat *data);
    void fpsChanged(float fps);

 

 

<capture_thread.cpp>

 

  - fps 변수를 Thread 생성자에서 초기화해 줍니다.

  - startCalcFPS 함수 경우 변수를 True로 해주는 것뿐이기 때문에 inline 함수로 간단하게 처리할 수 있지만, 함수를 정의하였습니다.

   - 카메라 영상을 100 프레임을 읽는 동안, 읽기 전 시간과 다 처리한 시간을 간격을 구해서 프레임 수로 나누고 다시 초당 수치로 나누면 FPS 값을 확인할 수 있습니다. 그리고 계산 완료되었다는 flag(fps_calculating)를 false로 해주고 fpsChanged 시그널을 발생시킵니다.

  - 영상 캡처하는 CaptureThread 안의 무한루프 안에 calculateFPS(cap) 통해 영상 프로그램을 전달받습니다.

 

 

void CaptureThread::run() {
...
       if(fps_calculating) {
            calculateFPS(cap);
        }
    }
    cap.release();
    running = false;
}

void CaptureThread::startCalcFPS()
{
    fps_calculating = true;
}


void CaptureThread::calculateFPS(cv::VideoCapture &cap)
{
    const int count_to_read = 100;
    cv::Mat tmp_frame;
    QTime timer;
    timer.start();

    for(int i=0;i<count_to_read;i++)
    {
        cap >> tmp_frame;
    }//for

    int elapsed_ms = timer.elapsed();
    fps = count_to_read / (elapsed_ms / 1000.0); //1000.0 is 1sec
    fps_calculating = false;

    emit fpsChanged(fps);
}

 

 

<mainwindow.h>

 

  - 메뉴를 클릭에 이벤트와 fps 계산 후 UI를 업데이트를 위한 함수들을 선언합니다.

   

private slots:
  ...
    void calculateFPS();
    void updateFPS(float);

 

 

<mainwindow.cpp>

 

  - "Calculate FPS" Action을 만들고 calculateFPS() 함수와 연결해 줍니다. 그리고 카메라가 영상 Thread가 생성되어 있다면 startCalcFPS() 호출해서 계산을 시작하라고 flag를 true로 만들어줍니다.

  - 최종적으로 계산이 끝나면 fpsChaged 시그널이 발생하고 이 시점에 fps 값을 화면에 출력할 수 있도록 updateFPS() 슬롯 함수를 호출합니다.

  

 

void MainWindow::openCamera()
{
 ...
    if(capturer != nullptr) {
        // if a thread is already running, stop it
        capturer->setRunning(false);
        disconnect(capturer, &CaptureThread::frameCaptured, this, &MainWindow::updateFrame);
        connect(capturer, &CaptureThread::finished, capturer, &CaptureThread::deleteLater);
        disconnect(capturer, &CaptureThread::fpsChanged, this, &MainWindow::updateFPS);
    }

    connect(capturer, &CaptureThread::frameCaptured, this, &MainWindow::updateFrame);
    connect(capturer, &CaptureThread::fpsChanged, this, &MainWindow::updateFPS);
...
}

...

void MainWindow::calculateFPS()
{
  if(capturer != nullptr) {
      capturer->startCalcFPS();
  }
}

void MainWindow::updateFPS(float fps)
{
    mainStatusLabel->setText(QString("FPS of current camera is %1").arg(fps));
}

 

 

 

3. 최종 결과

 

  - 정상적으로 컴파일해서 실행되었다면 화면 하단에 FPS가 출력되고 수치는 계산할 때마다 다를 수 있습니다.

  - 참고로 이전 GazerW.pro의 DEFINES += GAZER_USE_QT_CAMERA=1을 주석 처리했거나 변경했어도 크게 문제는 없지만, 가끔 .pro 파일 내용을 변경했는데 반영되지 않을 때가 있으므로 그럴 때는 "Build -> Clean Project GazerW" 해고 다시 필드 해서 테스트해 보시기 바랍니다.

 

 

 

 

 

감사합니다.

  

 

<참고자료>

1. [BOOK] Qt-5-and-OpenCV-4-Computer-Vision-Projects

2. FPS

https://namu.wiki/w/FPS    

 

GazerW_day5.zip
0.01MB

반응형