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! 🎉
댓글
댓글 쓰기