2024. 12. 20. 18:55ㆍMemorizing/Qt
문제 상황
Python, PyQT에서 dlib을 사용해서 얼굴 인식을 했을 때, fps가 30 정도 나오는데, C++, QT에서 dlib을 사용해서 얼굴 인식을 진행하면 fps가 5-6정도 나오는 문제가 있었음. 분명 동일한 코드인데?
그래서 우선 dlib을 사용하지 않은 경우 fps를 측정해보았다.
문제를 간단하게 생각하기 위해 아래와 같은 코드를 작성하였다.
#include <opencv2/opencv.hpp>
#include <iostream>
#include <chrono>
int main() {
// 화면 캡쳐를 위한 VideoCapture 객체
cv::VideoCapture cap(0); // 0은 기본 카메라 장치, 화면 캡처 시에는 다른 방법이 필요할 수 있습니다
if (!cap.isOpened()) {
std::cerr << "카메라를 열 수 없습니다!" << std::endl;
return -1;
}
// FPS 측정을 위한 변수 설정
auto lastTime = std::chrono::high_resolution_clock::now();
int frameCount = 0;
// 화면을 캡쳐하고, FPS를 측정
while (true) {
cv::Mat frame;
cap >> frame; // 화면 캡쳐
cv::resize(frame, frame, cv::Size(320, 240));
if (frame.empty()) {
std::cerr << "프레임을 읽을 수 없습니다!" << std::endl;
break;
}
frameCount++;
// FPS 계산
auto currentTime = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> elapsed = currentTime - lastTime;
if (elapsed.count() >= 1.0) {
double fps = frameCount / elapsed.count();
std::cout << "FPS: " << fps << std::endl;
frameCount = 0;
lastTime = currentTime;
}
// 화면에 캡쳐된 이미지 표시
cv::imshow("Screen Capture", frame);
// 키 입력이 'q'이면 종료
if (cv::waitKey(1) == 'q') {
break;
}
}
// 캡쳐 종료 후 리소스 해제
cap.release();
cv::destroyAllWindows();
return 0;
}
import cv2
import time
# 화면 캡쳐를 위한 VideoCapture 객체 (0은 기본 카메라)
cap = cv2.VideoCapture(0)
if not cap.isOpened():
print("카메라를 열 수 없습니다!")
exit()
# FPS 측정을 위한 변수 설정
frame_count = 0
last_time = time.time()
while True:
ret, frame = cap.read()
if not ret:
print("프레임을 읽을 수 없습니다!")
break
frame_count += 1
# FPS 계산
current_time = time.time()
elapsed_time = current_time - last_time
if elapsed_time >= 1.0:
fps = frame_count / elapsed_time
print(f"FPS: {fps:.2f}")
frame_count = 0
last_time = current_time
# 화면에 캡쳐된 이미지 표시
cv2.imshow("Screen Capture", frame)
# 'q'를 누르면 종료
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 캡쳐 종료 후 리소스 해제
cap.release()
cv2.destroyAllWindows()
위와 같이 작성했을 때 동일한 문제가 발생한다는 것을 발견했다. 캡쳐를 해올 때, 너무 큰 이미지를 가져와서 프로그램이 늦어지는 건가 싶어서 캡쳐해오는 이미지의 크기를 아래과 같이 변경해주었다.
int main() {
// 화면 캡쳐를 위한 VideoCapture 객체
cv::VideoCapture cap(0); // 0은 기본 카메라 장치, 화면 캡처 시에는 다른 방법이 필요할 수 있습니다
if (!cap.isOpened()) {
std::cerr << "카메라를 열 수 없습니다!" << std::endl;
return -1;
}
int frameWidth = 320;
int frameHeight = 240;
cap.set(cv::CAP_PROP_FRAME_WIDTH, frameWidth);
cap.set(cv::CAP_PROP_FRAME_HEIGHT, frameHeight);
...
캡쳐를 해올 때, 이미지를 작은 사이즈로 고정해오니 fps가 정상적으로 돌아온다는 것을 확인했다.
하지만 의문은 왜 파이썬은 적당한 크기로 잘 읽어오느냐는 문제..
놀라운 사실을 발견했는데, 기본적으로 파이썬에서 OpenCV를 사용하는 경우, width는 640으로 height는 480으로 읽어온다.. 아래의 코드로 확인 가능했다.
cap = cv2.VideoCapture(0)
if not cap.isOpened():
print("카메라를 열 수 없습니다!")
exit()
# FPS 측정을 위한 변수 설정
frame_count = 0
last_time = time.time()
while True:
ret, frame = cap.read()
print(f"width: {cap.get(cv2.CAP_PROP_FRAME_WIDTH)}, height: {cap.get(cv2.CAP_PROP_FRAME_HEIGHT)}")
결론
C++, OpenCV에서 프레임을 얻어오면, 따로 설정해주지 않으면 카메라의 해상도 그대로 읽어오는데, Python, OpenCV에서 프레임을 얻어오면 따로 설정해주지 않아도 기본적으로 640, 480 해상도로 읽어온다!!
추가적으로 리눅스에서 카메라의 해상도를 확인할 수 있는데, 이때, 사용할 수 있는 FPS도 같이 알려준다.
$ v4l2-ctl --device=/dev/video0 --list-formats-ext
ioctl: VIDIOC_ENUM_FMT
Type: Video Capture
[0]: 'MJPG' (Motion-JPEG, compressed)
Size: Discrete 1920x1080
Interval: Discrete 0.033s (30.000 fps)
Interval: Discrete 0.040s (25.000 fps)
Interval: Discrete 0.050s (20.000 fps)
Interval: Discrete 0.067s (15.000 fps)
Interval: Discrete 0.100s (10.000 fps)
Interval: Discrete 0.200s (5.000 fps)
Size: Discrete 320x240
Interval: Discrete 0.033s (30.000 fps)
Interval: Discrete 0.040s (25.000 fps)
Interval: Discrete 0.050s (20.000 fps)
Interval: Discrete 0.067s (15.000 fps)
Interval: Discrete 0.100s (10.000 fps)
Interval: Discrete 0.200s (5.000 fps)
Size: Discrete 640x360
Interval: Discrete 0.033s (30.000 fps)
Interval: Discrete 0.040s (25.000 fps)
Interval: Discrete 0.050s (20.000 fps)
Interval: Discrete 0.067s (15.000 fps)
Interval: Discrete 0.100s (10.000 fps)
Interval: Discrete 0.200s (5.000 fps)
Size: Discrete 1280x720
Interval: Discrete 0.033s (30.000 fps)
Interval: Discrete 0.040s (25.000 fps)
Interval: Discrete 0.050s (20.000 fps)
Interval: Discrete 0.067s (15.000 fps)
Interval: Discrete 0.100s (10.000 fps)
Interval: Discrete 0.200s (5.000 fps)
Size: Discrete 1280x800
Interval: Discrete 0.033s (30.000 fps)
Interval: Discrete 0.040s (25.000 fps)
Interval: Discrete 0.050s (20.000 fps)
Interval: Discrete 0.067s (15.000 fps)
Interval: Discrete 0.100s (10.000 fps)
Interval: Discrete 0.200s (5.000 fps)
Size: Discrete 640x480
Interval: Discrete 0.033s (30.000 fps)
Interval: Discrete 0.040s (25.000 fps)
Interval: Discrete 0.050s (20.000 fps)
Interval: Discrete 0.067s (15.000 fps)
Interval: Discrete 0.100s (10.000 fps)
Interval: Discrete 0.200s (5.000 fps)
[1]: 'YUYV' (YUYV 4:2:2)
Size: Discrete 1920x1080
Interval: Discrete 0.200s (5.000 fps)
Size: Discrete 320x240
Interval: Discrete 0.033s (30.000 fps)
Interval: Discrete 0.040s (25.000 fps)
Interval: Discrete 0.050s (20.000 fps)
Interval: Discrete 0.067s (15.000 fps)
Size: Discrete 640x360
Interval: Discrete 0.033s (30.000 fps)
Interval: Discrete 0.040s (25.000 fps)
Interval: Discrete 0.050s (20.000 fps)
Interval: Discrete 0.067s (15.000 fps)
Size: Discrete 1280x720
Interval: Discrete 0.100s (10.000 fps)
Interval: Discrete 0.200s (5.000 fps)
Size: Discrete 1280x800
Interval: Discrete 0.100s (10.000 fps)
Interval: Discrete 0.200s (5.000 fps)
Size: Discrete 640x480
Interval: Discrete 0.033s (30.000 fps)
Interval: Discrete 0.040s (25.000 fps)
Interval: Discrete 0.050s (20.000 fps)
Interval: Discrete 0.067s (15.000 fps)
그리고 파이썬 기준 아래의 코드로 어떤 포맷으로 읽어오는지 확인할 수 있는데 나의 경우 16이 나왔는데, 16은 YUYV 포맷이다.
camera_format = cap.get(cv2.CAP_PROP_FORMAT)
print(f"format: {camera_format}")