MinGW 기반 C++ OpenCV 영상 처리 튜토리얼
본 튜토리얼에서는 **Windows + MinGW 환경의 C++**에서 OpenCV 라이브러리를 설치하고 간단한 영상 처리 예제를 실행하는 방법을 다룹니다. 기본 이미지 입출력부터 그레이스케일 변환, 가우시안 블러, 캐니 엣지 검출 등의 순서로 설명하며, 각 단계마다 관련 코드 예제와 해설을 제공합니다. (필요에 따라 코드와 설명을 표 형식으로 정리합니다.)
OpenCV 설치 및 MinGW 연동
MinGW를 사용하는 C++ 환경에서 OpenCV를 사용하려면 먼저 OpenCV 라이브러리를 설치하고 MinGW 컴파일러와 연동해야 합니다. 일반적으로 OpenCV는 Visual Studio 용 바이너리를 제공하지만, MinGW에서는 직접 빌드하거나 미리 컴파일된 라이브러리를 구하여 설정해야 합니다. 아래는 MinGW-w64 환경에서 OpenCV를 설치 및 연동하는 방법의 개략적인 단계입니다:
-
MinGW-w64 설치: 최신 버전의 MinGW-w64 64비트 컴파일러를 설치합니다. 반드시
posix
스레드 모델의 MinGW-w64를 선택하세요. 32비트 MinGW나win32
스레드 옵션은 OpenCV 빌드시 스레드 관련 오류를 일으킬 수 있습니다. 설치 후mingw64/bin
경로를 시스템 PATH에 추가하고g++ --version
으로 정상 설치 여부를 확인합니다. -
OpenCV 소스 다운로드: OpenCV 공식 저장소나 홈페이지에서 최신 OpenCV 소스 코드를 다운로드합니다. (예: GitHub의 opencv/opencv 및 opencv_contrib 저장소의 릴리스 ZIP 파일 다운로드.) 다운로드한 압축 파일을 풀어서, 예를 들어
D:\OpenCV\opencv-4.x.x\
경로에 저장합니다. -
CMake로 OpenCV 빌드: CMake 툴을 설치한 후, CMake GUI나 명령줄을 이용하여 OpenCV 소스를 MinGW용으로 빌드합니다. CMake 설정 단계에서 Generator로 "MinGW Makefiles"를 선택해야 합니다. 또한
BUILD_EXAMPLES=OFF
,BUILD_TESTS=OFF
등 불필요한 옵션을 끄면 빌드 시간이 단축됩니다. 소스 경로와 별도의 빌드 출력 폴더를 지정한 뒤 Configure와 Generate를 수행하면 MinGW용 Makefile이 생성됩니다. -
OpenCV 컴파일 및 설치: 명령 프롬프트에서 빌드 출력 폴더로 이동하여
mingw32-make
명령을 실행하면 OpenCV 라이브러리가 컴파일됩니다. 컴파일에는 상당한 시간이 소요될 수 있습니다. 에러 없이 완료되면 이어서mingw32-make install
을 실행하여 설치를 완료합니다. 설치 완료 후 지정된 설치 경로(예:D:\OpenCV\opencv-4.x.x\install\x64\mingw\
)에bin
,lib
,include
폴더가 생성됩니다. -
환경 변수 설정: OpenCV로 만들어진 실행 파일이 DLL을 찾을 수 있도록, OpenCV 설치 디렉토리의
bin
폴더 경로 (예:...\install\x64\mingw\bin
)를 시스템 PATH 환경 변수에 추가합니다. 이렇게 해야 실행 시 필요한opencv_worldXXX.dll
또는 각 모듈별 DLL을 로드할 수 있습니다. -
MinGW에서 OpenCV 연동: 컴파일 시에 OpenCV 헤더 파일과 라이브러리를 포함하도록 설정해야 합니다. 예를 들어, 명령줄에서
g++
로 컴파일할 경우 다음과 같이 옵션을 지정합니다:g++ main.cpp -I D:\OpenCV\opencv-4.x.x\install\x64\mingw\include \ -L D:\OpenCV\opencv-4.x.x\install\x64\mingw\lib \ -lopencv_core470 -lopencv_imgproc470 -lopencv_highgui470 -lopencv_imgcodecs470 \ -o main.exe
위 명령에서
-I
옵션은 OpenCV의 헤더(include) 경로를,-L
옵션은 라이브러리(lib) 경로를 가리킵니다.-lopencv_core470
등의 옵션은 링크할 OpenCV 라이브러리의 이름을 지정합니다. (opencv_core470.dll
에 대응되는 import 라이브러리libopencv_core470.a
를 링크) 각 라이브러리 이름 뒤의 숫자는 OpenCV 버전을 나타내므로, 사용 중인 버전에 맞게 변경해야 합니다. 일반적으로 영상 입출력 및 처리를 위해서는core
,imgproc
,highgui
,imgcodecs
모듈 등을 링크하면 됩니다. (예: OpenCV 4.7.0 기준으로opencv_core470
,opencv_imgproc470
,opencv_highgui470
,opencv_imgcodecs470
등). -
IDE 통합: Visual Studio Code 등의 IDE를 사용한다면, tasks.json 또는 CMakeLists.txt에 위와 같은 include 경로와 라이브러리 경로를 설정하고,
target_link_libraries
에 OpenCV 라이브러리를 추가하면 됩니다. OpenCV를 빌드할 때OpenCVConfig.cmake
가 생성되므로 CMake를 사용할 경우find_package(OpenCV REQUIRED)
등으로 쉽게 연동할 수도 있습니다.
참고: MSYS2 환경을 사용 중이라면 pacman 패키지 관리자를 통해
mingw-w64-x86_64-opencv
패키지를 설치하여 OpenCV를 손쉽게 활용할 수도 있습니다. 이 경우 위 단계 중 빌드 과정 없이 바로 헤더/라이브러리가 제공되지만, 본 튜토리얼에서는 일반적인 수동 설치 과정을 설명합니다.
설치 및 연동을 마쳤다면, 이제 간단한 코드를 작성하여 OpenCV가 제대로 동작하는지 확인해보겠습니다.
기본 이미지 열기 및 화면 표시
OpenCV가 잘 설치되었다면, cv::imread
함수로 이미지를 불러오고 cv::imshow
로 화면에 출력할 수 있습니다. 다음은 이미지 파일을 읽어와서 윈도우에 표시하는 간단한 C++ 코드 예제입니다:
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main() {
Mat img = imread("test.jpg"); // 이미지 파일 읽기
if (img.empty()) { // 파일 읽기 오류 처리
cerr << "이미지를 불러올 수 없습니다." << endl;
return -1;
}
imshow("Display", img); // 이미지 표시 창 열기
waitKey(0); // 키 입력을 기다림 (창 유지)
return 0;
}
위 코드에서는 test.jpg
라는 이름의 이미지를 현재 작업 경로에서 읽어들여 Mat
객체(img
)에 저장합니다. imshow("Display", img)
는 "Display"
라는 이름의 창을 생성하고 그 안에 img
이미지를 출력합니다. waitKey(0)
는 키가 눌릴 때까지 프로그램을 대기시키는 함수로, 이 호출이 있어야 창이 바로 닫히지 않고 화면에 이미지가 나타난 상태로 유지됩니다.
imread
로 이미지를 불러올 때 실패할 수 있으므로, 위 코드에서는 img.empty()
를 통해 이미지가 제대로 로드되었는지 확인하고 있습니다. empty()
가 참이면 에러 메시지를 출력하고 프로그램을 종료합니다. OpenCV에서 지원하는 imread
의 두 번째 인자로 IMREAD_COLOR
, IMREAD_GRAYSCALE
등의 플래그를 줄 수 있지만, 지정하지 않으면 기본값으로 컬러(BGR) 이미지로 읽어옵니다.
팁:
imshow
로 여러 장의 이미지를 동시에 띄울 수도 있습니다. 단, 각각 다른 창 이름을 지정해야 합니다. 또한waitKey(0)
는 한 번만 호출해도 모든 창이 닫히므로, 여러 창을 띄웠을 경우 한 곳에서 대기하면 됩니다. 만약 일정 시간(ms)만큼만 창을 표시하고 자동으로 진행시키고 싶다면waitKey(5000)
처럼 밀리초 단위를 인자로 줄 수도 있습니다.
그레이스케일 변환
컬러 영상은 보통 BGR 채널로 구성되는데, 영상 처리 단계에 따라 이를 그레이스케일(흑백) 영상으로 변환하여 사용하는 경우가 많습니다. 그레이스케일로 변환하면 데이터가 단일 채널로 줄어들어 연산이 효율적이고, 노이즈에 덜 민감한 처리(에지 검출 등)에 유리합니다. OpenCV에서는 cvtColor()
함수를 사용하여 색상 공간을 변환할 수 있습니다.
예를 들어, 컬러 이미지를 그레이스케일로 변환하려면 다음과 같이 합니다:
Mat gray;
cvtColor(img, gray, COLOR_BGR2GRAY);
위 코드에서는 입력 img
(Mat 객체)를 출력 gray
에 담으면서, 색상 변환 코드로 COLOR_BGR2GRAY
를 지정했습니다. 이렇게 하면 BGR 컬러 영상이 그레이스케일 영상으로 변환됩니다. 변환 후 gray
는 한 채널로 구성된 8비트 영상이 되며, 픽셀 값은 0(검은색)~255(흰색)의 밝기 값으로 표현됩니다.
OpenCV에서는 COLOR_BGR2HSV
, COLOR_BGR2RGB
등 다양한 색 변환 코드를 제공하며, cvtColor
함수의 활용으로 손쉽게 영상의 색 공간을 바꿀 수 있습니다. 위 예제에서는 컬러로 읽은 영상을 그레이스케일로 변환했지만, 처음부터 imread("image.jpg", IMREAD_GRAYSCALE)
로 읽어오는 것도 가능합니다. 변환된 흑백 영상도 imshow
를 통해 확인할 수 있으며, 별도로 창 이름을 "Gray" 등으로 다르게 주어 원본 컬러 영상과 나란히 비교 표시할 수도 있습니다.
가우시안 블러(영상 흐리기) 적용
영상의 노이즈를 줄이거나 디테일을 완화시키기 위해 **블러링(흐리게 처리)**을 적용할 수 있습니다. OpenCV는 여러 가지 블러링 필터 함수를 제공하며, 그 종류에 따라 결과와 목적이 조금씩 다릅니다:
-
평균값 블러(Uniform Blur): 지정한 커널 영역의 픽셀 평균값으로 중앙 픽셀을 대체합니다 (
blur()
함수). 가장 단순한 블러 방법입니다. -
가우시안 블러(Gaussian Blur): 가우시안 커널(정규분포 곡선 형태의 가중치)을 이용하여 블러를 적용합니다 (
GaussianBlur()
함수). 중앙에 가까울수록 큰 가중치를 부여하여 평균내므로 자연스러운 흐림 효과를 내며, 잡음 제거에 효과적입니다. -
중값 필터(Median Blur): 커널 내 픽셀들의 중앙값으로 대체하여 노이즈를 제거합니다. 특히 염Salt-and-pepper 노이즈 제거에 효과적입니다.
-
양방향 필터(Bilateral Filter): 경계는 보존하면서 영역 내부만 흐리게 하는 고급 필터로, 노이즈 제거와 에지 보존을 동시에 노립니다.
이 중 가우시안 블러는 영상 처리에서 많이 사용되므로 여기서 다룹니다. 가우시안 블러는 저역 통과 필터의 일종으로 고주파 성분(급격한 밝기 변화, 즉 노이즈나 디테일)을 줄여줍니다. 단순 평균 필터에 비해 가장자리를 어느 정도 보존하면서 부드럽게 만드는 효과가 있어 노이즈 제거에 더 효과적입니다.
OpenCV의 GaussianBlur()
함수를 사용하여 영상을 흐리게 하는 예는 다음과 같습니다:
Mat blurred;
GaussianBlur(img, blurred, Size(5, 5), 0);
위 코드는 입력 img
에 대해 5x5 크기의 가우시안 커널을 적용하여 blurred
결과 영상을 얻습니다. 네 번째 인자인 sigmaX
를 0으로 준 것은 X방향 표준편차를 자동 계산하라는 의미입니다. Size(5,5)
와 같이 커널 크기를 홀수로 지정하면 OpenCV가 내부적으로 적절한 sigma 값을 사용하여 필터를 적용합니다. (물론 sigmaX
값을 직접 지정할 수도 있고, sigmaY
를 0으로 두면 sigmaX
와 동일하게 설정됩니다.)
커널 크기가 클수록 더 많은 이웃 픽셀을 평균하므로 영상이 더 흐릿해집니다. 아래 출력 예시처럼, 원본 대비 3x3, 5x5, 7x7 가우시안 블러를 적용한 결과를 비교해보면 커널 사이즈가 커질수록 점점 흐려지는 것을 확인할 수 있습니다. 용도에 따라 커널 크기와 sigma 값을 조절하면 됩니다.
블러 처리한 결과 영상도 마찬가지로 imshow("Blurred", blurred);
로 표시하거나 imwrite
로 파일 저장을 할 수 있습니다. 가우시안 블러를 거친 영상은 노이즈가 줄어드는 대신 가장자리 선명도도 일부 감소하므로, 후속 단계에서 에지 검출 등을 수행하면 이전보다 덜 민감하게 반응하게 됩니다.
캐니 엣지 검출
**엣지(edge)**란 영상 내 픽셀 밝기값이 급격하게 변하는 경계선을 말합니다. 엣지 검출은 이미지에서 이러한 경계선을 찾아내는 작업으로, 특징 추출 등에 널리 활용됩니다. 여러 엣지 검출 알고리즘 중 캐니(Canny) 엣지 검출기가 대표적이며, OpenCV에서 Canny()
함수로 제공됩니다. Canny 알고리즘은 노이즈 제거, 그라디언트 계산, 비최대 억제, 이력 임계(hysteresis threshold) 등의 단계를 거쳐 최종 엣지를 결정합니다.
일반적으로 컬러 영상은 그레이스케일로 변환한 후 엣지 검출을 적용합니다. 또한 검출 전에 가우시안 블러 등으로 노이즈를 감소시키면 잘못된 엣지가 검출되는 것을 줄일 수 있습니다. 앞서 가우시안 블러를 적용한 결과를 활용해도 되고, 작은 커널로 한 번 더 블러를 적용할 수도 있습니다.
OpenCV에서 Canny()
함수의 사용법은 다음과 같습니다:
Mat edges;
GaussianBlur(gray, gray, Size(3,3), 0); // 노이즈 감소를 위해 3x3 블러 적용 (선택 사항)
Canny(gray, edges, 50, 150);
위 코드에서 gray
는 입력 그레이스케일 영상이고, edges
는 출력 엣지 영상입니다. Canny(입력, 출력, 낮은임계값, 높은임계값)
형태로 호출되며, 여기서는 낮은 임계값을 50, 높은 임계값을 150으로 설정했습니다. 캐니 알고리즘의 동작은 다음과 같습니다:
-
먼저 이미지의 그라디언트(변화율)를 계산하여 에지 후보 픽셀들을 얻습니다.
-
높은 임계값(150) 이상인 그라디언트 세기를 가진 픽셀들은 강한 에지로 간주되어 결과에 포함됩니다.
-
낮은 임계값(50) 미만인 픽셀들은 에지가 아닌 것으로 간주되어 제거됩니다.
-
두 임계값 사이의 픽셀들은 애매한 상태인데, 이들은 주변에 강한 에지가 존재하는 경우에만 에지로 채택됩니다. 이 과정을 이력 임계(hysteresis) 처리라고 하며, 약한 에지가 강한 에지와 연결되어 있으면 실제 에지로 남고 그렇지 않으면 제거됩니다.
위 예시 임계값 50-150은 한 영상에 대한 설정일 뿐이며, 이미지마다 엣지 강도 분포가 다르므로 적절한 값을 실험적으로 찾아야 합니다. 일반적으로 높은 임계값을 낮은 임계값의 약 2~3배 정도로 설정하는 것이 권장됩니다. (캐니 논문에서 2:1~3:1 비율 제안) 예를 들어 낮은 임계값을 80으로 하면 높은 임계값은 160이나 240 정도로 정할 수 있습니다.
Canny()
함수의 결과 edges
는 단일 채널 이진 이미지입니다. 엣지로 판단된 픽셀은 255(흰색) 값으로, 다른 픽셀은 0(검정) 값으로 표시됩니다. imshow
로 이 이미지를 출력하면 검은 배경에 흰 선으로 에지가 나타난 것을 볼 수 있습니다. 필요하다면 원본 컬러 이미지와 합성하여 색깔 있는 에지 오버레이를 만들 수도 있지만, 여기서는 단순히 결과만 표시합니다.
아래는 전체 처리를 종합한 코드 예제입니다 (이미지 불러오기 → 그레이스케일 변환 → 블러 → 엣지 검출):
Mat img = imread("test.jpg");
Mat gray, blurred, edges;
cvtColor(img, gray, COLOR_BGR2GRAY); // 1. 그레이스케일 변환
GaussianBlur(gray, blurred, Size(5,5), 0); // 2. 가우시안 블러로 노이즈 제거
Canny(blurred, edges, 50, 150); // 3. 캐니 엣지 검출 적용
imshow("Original", img);
imshow("Edges", edges);
waitKey(0);
위 코드가 실행되면 원본 이미지와 검출된 엣지를 각각 화면에 보여줍니다. 사용된 임계값 50, 150
은 예시이므로, 이미지에 따라 선명한 에지를 얻기 위해 조절해야 합니다. 에지 결과를 보면 객체의 윤곽선 등 강한 경계만 추출되고 세부적인 질감이나 노이즈는 대부분 제거된 것을 확인할 수 있습니다.
각 단계별로 참고한 공식 문서와 튜토리얼 링크는 본문에 각주 형태로 포함되어 있으므로, 설치나 함수 사용법에 대한 추가적인 정보가 필요하면 해당 출처를 따라가 자세한 설명을 읽어보시기 바랍니다. OpenCV 공식 문서에는 이 밖에도 다양한 예제 코드와 설명이 있으므로 더 심화된 학습에 활용할 수 있습니다.
이상으로 MinGW 기반 C++ OpenCV 환경 설정과 기본적인 영상 처리 예제를 살펴보았습니다. 이제 제공된 코드를 바탕으로 직접 컴파일 및 실행해보면서 OpenCV 사용 방법을 익혀보세요. Happy Coding! 🎉
댓글
댓글 쓰기