이전 글에서 Tab1과 Tab2의 소켓 연동 과제를 구현해봤습니다.
이번 글에서는 Tab7, Tab6 카메라 탭 구현에 앞서 ubuntu05 환경에 OpenCV 4.12.0을 소스 빌드하고, Qt + OpenCV 연동 예제인 CamViewerThread를 실행해 카메라 영상 출력을 확인하는 과정을 정리합니다.


빌드에 앞서 기존에 설치된 OpenCV가 있다면 제거합니다.
opencv_version
sudo apt-get purge libopencv* python-opencv
sudo apt-get autoremove
sudo find /usr/local/ -name "*opencv*" -exec rm -rf {} \;
sudo find명령은 직접 소스 빌드로 설치한 경우에만 실행합니다.
sudo apt update
sudo apt upgrade
sudo apt install build-essential cmake git pkg-config \
libjpeg-dev libtiff-dev libpng-dev \
libavcodec-dev libavformat-dev libswscale-dev libv4l-dev \
v4l-utils libxvidcore-dev libx264-dev libgtk-3-dev \
libatlas-base-dev gfortran python3-dev opencl-headers \
ffmpeg libxine2-dev libgstreamer1.0-dev \
libgstreamer-plugins-base1.0-dev mesa-utils \
libgl1-mesa-dri libgtkgl2.0-dev libgtkglext1-dev \
libeigen3-dev python3-numpy
opencv와 opencv_contrib를 함께 다운로드합니다.
contrib 모듈은 SIFT, SURF 등 추가 알고리즘을 포함합니다.
mkdir openCV && cd openCV
wget -O opencv.zip https://github.com/opencv/opencv/archive/4.12.0.zip
wget -O opencv_contrib.zip https://github.com/opencv/opencv_contrib/archive/4.12.0.zip
unzip opencv.zip
unzip opencv_contrib.zip
cd opencv-4.12.0
mkdir build && cd build
cmake -D CMAKE_BUILD_TYPE=RELEASE \
-D CMAKE_INSTALL_PREFIX=/usr/local \
-D WITH_TBB=OFF \
-D WITH_IPP=OFF \
-D WITH_1394=OFF \
-D BUILD_WITH_DEBUG_INFO=OFF \
-D BUILD_DOCS=OFF \
-D INSTALL_C_EXAMPLES=ON \
-D INSTALL_PYTHON_EXAMPLES=ON \
-D BUILD_EXAMPLES=OFF \
-D BUILD_PACKAGE=OFF \
-D BUILD_TESTS=OFF \
-D BUILD_PERF_TESTS=OFF \
-D WITH_QT=OFF \
-D WITH_GTK=ON \
-D WITH_OPENGL=ON \
-D BUILD_opencv_python3=ON \
-D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib-4.12.0/modules \
-D WITH_V4L=ON \
-D WITH_FFMPEG=ON \
-D WITH_XINE=ON \
-D OPENCV_ENABLE_NONFREE=ON \
-D BUILD_NEW_PYTHON_SUPPORT=ON \
-D OPENCV_SKIP_PYTHON_LOADER=ON \
-D OPENCV_GENERATE_PKGCONFIG=ON \
../
OPENCV_GENERATE_PKGCONFIG=ON옵션을 설정해야 이후pkg-config opencv4 --cflags --libs명령으로 경로를 확인할 수 있습니다.
make -j4 # 약 35분 소요
sudo make install
sudo ldconfig
설치 완료 후 버전 및 경로를 확인합니다.
opencv_version
pkg-config opencv4 --cflags --libs
설치가 정상적으로 완료됐는지 간단한 예제로 확인합니다.
first.cpp는 지정한 크기의 단색 이미지를 화면에 출력하는 예제입니다.
#include <opencv2/highgui.hpp>
using namespace::cv;
int main(void)
{
Mat image(300, 400, CV_8UC1, Scalar(128));
imshow("영상보기", image);
waitKey(0);
return 0;
}
Scalar(128) 값을 수정해 이미지 밝기가 바뀌는 것을 확인하며 OpenCV가 정상적으로 동작함을 확인했습니다.


위 캡쳐에서 밝은 회색 → 어두운 회색으로 변경되는 것을 확인할 수 있습니다.
OpenCV 설치를 확인한 후, Qt와 OpenCV를 연동해 카메라 영상을 Qt 화면에 출력하는 예제 프로젝트를 진행했습니다.
| 파일 | 역할 |
|---|---|
mainwidget.h/cpp | 메인 위젯, 버튼 이벤트 처리 |
webcamthread.h/cpp | QThread 상속, OpenCV 카메라 루프 |
Qt 프로젝트에서 OpenCV 헤더를 사용하려면 .pro 파일에 경로를 추가해야 합니다.
ubuntu05는 소스 빌드 설치이므로 경로가 /usr/local 하위에 위치합니다.
INCLUDEPATH += /usr/local/include/opencv4
LIBS += `pkg-config opencv4 --cflags --libs`
카메라 루프는 UI 스레드와 분리하기 위해 QThread를 상속한 WebCamThread 클래스로 구현합니다.
#ifndef WEBCAMTHREAD_H
#define WEBCAMTHREAD_H
#include <QThread>
#include <QLabel>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
class WebCamThread : public QThread
{
Q_OBJECT
void run();
int cnt;
string fname;
Mat frame;
void put_string(Mat &frame, string text, Point pt, int value);
public:
WebCamThread(QObject *parent = nullptr);
bool camViewFlag;
QLabel *pCamView;
void snapShot();
};
#endif // WEBCAMTHREAD_H
run() 안에서 VideoCapture로 카메라를 열고, 프레임을 읽어 QLabel에 표시합니다.
cv::Mat 데이터를 QImage로 변환한 뒤 QPixmap으로 설정하는 방식입니다.
#include "webcamthread.h"
WebCamThread::WebCamThread(QObject *parent)
: QThread(parent)
{
cnt = 0;
camViewFlag = false;
}
void WebCamThread::run()
{
VideoCapture capture(0);
if (!capture.isOpened())
{
cout << "카메라가 연결되지 않았습니다." << endl;
exit(1);
}
while(camViewFlag)
{
capture.read(frame);
put_string(frame, "Count: ", Point(10, 40), cnt);
fname = "cam_" + to_string(cnt++);
fname += ".jpg";
QImage qImage(frame.data, frame.cols, frame.rows, QImage::Format_BGR888);
pCamView->setPixmap(QPixmap::fromImage(qImage));
}
capture.release();
pCamView->setPixmap(QPixmap("initDisplay.png"));
}
void WebCamThread::put_string(Mat &frame, string text, Point pt, int value)
{
text += to_string(value);
Point shade = pt + Point(2, 2);
int font = FONT_HERSHEY_SIMPLEX;
putText(frame, text, shade, font, 0.7, Scalar(0, 0, 0), 2);
putText(frame, text, pt, font, 0.7, Scalar(120, 200, 90), 2);
}
void WebCamThread::snapShot()
{
imwrite(fname, frame);
}
QImage::Format_BGR888을 사용하면 OpenCV의 BGR 포맷을 별도 변환 없이 바로 Qt에서 표시할 수 있습니다. 이후 Tab7에서는cvtColor로 RGB 변환 후Format_RGB888을 사용하는 방식으로 변경됩니다.
#ifndef MAINWIDGET_H
#define MAINWIDGET_H
#include <QWidget>
#include <QDebug>
#include "webcamthread.h"
namespace Ui {
class MainWidget;
}
class MainWidget : public QWidget
{
Q_OBJECT
public:
explicit MainWidget(QWidget *parent = nullptr);
~MainWidget();
private slots:
void on_pPBcamStart_clicked(bool checked);
void on_pPBsnapShot_clicked();
private:
Ui::MainWidget *ui;
WebCamThread *pWebCamThread;
};
#endif // MAINWIDGET_H
생성자에서 WebCamThread를 생성하고 pCamView에 QLabel 포인터를 전달합니다.
CamStart 버튼은 checkable 버튼으로, 클릭 시 bool 값을 받아 스레드를 시작/정지합니다.
#include "mainwidget.h"
#include "ui_mainwidget.h"
MainWidget::MainWidget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::MainWidget)
{
ui->setupUi(this);
setWindowTitle("CamViewer");
ui->pPBsnapShot->setEnabled(false);
pWebCamThread = new WebCamThread(this);
pWebCamThread->pCamView = ui->plabelCamView;
}
MainWidget::~MainWidget()
{
delete ui;
}
void MainWidget::on_pPBcamStart_clicked(bool checked)
{
if(checked)
{
pWebCamThread->camViewFlag = true;
if(!pWebCamThread->isRunning())
{
pWebCamThread->start();
ui->pPBcamStart->setText("CamStop");
ui->pPBsnapShot->setEnabled(true);
}
}
else
{
pWebCamThread->camViewFlag = false;
ui->pPBcamStart->setText("CamStart");
ui->pPBsnapShot->setEnabled(false);
}
}
void MainWidget::on_pPBsnapShot_clicked()
{
pWebCamThread->snapShot();
}
빌드 후 실행하면 카메라 영상이 Qt 위젯에 실시간으로 출력됩니다. 좌측 상단에 프레임 카운트가 함께 표시되며, SnapShot 버튼을 클릭하면 cam_[count번호].jpg로 사진이 저장됩니다.


OpenCV 4.12.0 소스 빌드 (의존성 설치 → cmake → make -j4 → make install → ldconfig)
↓
first.cpp로 설치 확인 (단색 이미지 출력, Scalar 값 변경으로 동작 검증)
↓
.pro 파일에 OpenCV 경로 추가 (INCLUDEPATH, LIBS)
↓
CamViewerThread 프로젝트 구현
↓
WebCamThread (QThread) - VideoCapture → Mat → QImage → QPixmap → QLabel
↓
CamStart/CamStop 토글 버튼으로 스레드 제어, Snapshot 저장 확인