Open CV 다운로드
Releases
OpenCV Releases Are Brought To You By Intel Intel is a multinational corporation known for its semiconductor products, including processors that power a wide range of computing devices, from personal computers to servers and embedded systems. Read More Qua
opencv.org
환경변수 설정 (OpenCV 다운받은 폴더에 opencv\build\x64\vc16\bin 경로)

프로젝트 만들기
프로젝트 경로 설정: C:\OpenCV\opencv\build\include

추가 라이브러리 디렉터리 C:\OpenCV\opencv\build\x64\vc16\lib

추가 종속성 opencv_world4120d.lib

레나 이미지 로드하기
- imread: 저장 장치에서 이미지 파일을 읽어 메모리(cv::Mat)에 올린다.
- empty(): 파일이 없거나 형식이 잘못되어 로딩에 실패했는지 검사한다.
- namedWindow: 이미지를 보여줄 빈 창을 생성한다.
- imshow: 특정 창에 메모리의 이미지 데이터를 시각화한다.
- destroyAllWindows: 사용한 시스템 자원을 반납하고 창을 닫는다.
#include "opencv2/opencv.hpp"
#include <iostream>
int main()
{
std::cout << "Hello OpenCV" << CV_VERSION << std::endl;
cv::Mat img;
img = cv::imread("lenna.png");
if (img.empty()) {
std::cerr << "Image load failed!" << std::endl;
return -1;
}
cv::namedWindow("image");
cv::imshow("image", img);
cv::waitKey();
return 0;
}
참고로 [파일 탐색기에서 열기] 경로에 lenna.png 을 넣어야 이미지가 로드된다

C++은 cv::Mat img;라고 선언하는 즉시 스택 메모리에 객체가 생성되고 기본 생성자가 호출된다. Java나 C#처럼 new 키워드를 명시적으로 사용하지 않아도 된다는 점이 C++의 특징이다.
std::cout vs std::cerr
- std::cout: 표준 출력 스트림. 버퍼링을 사용하므로 효율적이지만, 프로그램이 비정상 종료될 때 출력 내용이 유실될 가능성이 있다.
- std::cerr: 표준 오류 스트림. 버퍼를 거치지 않고 즉시 출력(unbuffered)하므로 에러 발생 시 상황을 즉각 확인해야 하는 디버깅 용도에 적합하다.
cv::waitKey(1000)
- 단순히 1초를 기다리는 기능 외에도, 이 함수는 이벤트를 처리하는 역할을 한다.
- imshow로 창을 띄웠을 때 화면이 갱신되려면 반드시 waitKey가 호출되어야 한다. 아무것도 안 넣으면 키 입력이 있을 때까지 무한정 대기한다.
Mat imread, Mat imwrite 예제
| 함수 | 설명 | 주요 옵션 (Flags) |
| cv::imread() | 이미지 파일을 읽어 cv::Mat 객체로 반환 | IMREAD_COLOR (컬러), IMREAD_GRAYSCALE (그레이스케일) |
| cv::imwrite() | cv::Mat 객체를 파일로 저장 | 포맷은 파일 확장자(.jpg, .png)에 따라 자동 결정 |
#include "opencv2/opencv.hpp"
#include <iostream>
int main() {
// 1. 이미지 읽기 (컬러 모드)
cv::Mat img = cv::imread("lenna.png", cv::IMREAD_COLOR);
if (img.empty()) {
std::cerr << "이미지를 찾을 수 없습니다." << std::endl;
return -1;
}
// 2. 이미지 처리 (예: 컬러를 그레이스케일로 변환)
cv::Mat grayImg;
cv::cvtColor(img, grayImg, cv::COLOR_BGR2GRAY);
// 3. 이미지 저장
// 성공 시 true, 실패 시 false 반환
bool isSaved = cv::imwrite("lenna_gray.jpg", grayImg);
if (isSaved) {
std::cout << "이미지가 성공적으로 저장되었습니다." << std::endl;
}
else {
std::cerr << "이미지 저장에 실패했습니다." << std::endl;
}
// 4. 화면 출력 확인
cv::imshow("Original", img);
cv::imshow("Gray", grayImg);
cv::waitKey(0);
cv::destroyAllWindows();
return 0;
}
mwrite 에는 압축률을 지정할 수 있다
std::vector<int> params;
params.push_back(cv::IMWRITE_JPEG_QUALITY);
params.push_back(95); // 95% 화질로 저장
cv::imwrite("high_quality.jpg", grayImg, params);
윈도우 창 제어 함수 예제
#include "opencv2/opencv.hpp"
#include <iostream>
int main() {
cv::Mat img = cv::imread("lenna.png");
if (img.empty()) {
std::cerr << "Image load failed!" << std::endl;
return -1;
}
// 1. 기본 창 생성 및 출력
cv::namedWindow("First");
cv::moveWindow("First", 50, 50); // 화면 좌상단 (50, 50) 위치로 이동
cv::imshow("First", img);
// 2. 크기 조절이 가능한 창 생성
cv::namedWindow("Second", cv::WINDOW_NORMAL);
cv::resizeWindow("Second", 300, 300); // 창 크기를 300x300으로 강제 조정
cv::moveWindow("Second", 600, 50); // 첫 번째 창 옆으로 이동
cv::imshow("Second", img);
std::cout << "아무 키나 누르면 'First' 창만 닫힙니다." << std::endl;
cv::waitKey(0);
// 3. 특정 창만 닫기
cv::destroyWindow("First");
std::cout << "아무 키나 누르면 모든 창이 닫히고 종료됩니다." << std::endl;
cv::waitKey(0);
// 4. 모든 창 닫기
cv::destroyAllWindows();
return 0;
}
| 함수 | 기능 | 특징 |
| namedWindow() | 새로운 윈도우 창 생성 | WINDOW_AUTOSIZE(기본값) 또는 WINDOW_NORMAL(크기 조절 가능) 설정 가능 |
| imshow() | 윈도우에 이미지 출력 | 첫 번째 인자인 창 이름이 없으면 namedWindow를 내부적으로 호출함 |
| moveWindow() | 윈도우의 위치 변경 | 모니터 좌측 상단을 (0, 0) 기준으로 좌표 지정 |
| resizeWindow() | 윈도우의 크기 변경 | WINDOW_NORMAL로 생성된 창에서만 동작함 |
| destroyWindow() | 특정 윈도우 파괴 | 인자로 전달한 이름의 창만 닫음 |
| destroyAllWindows() | 모든 윈도우 파괴 | 프로그램 종료 전 열려 있는 모든 창을 한꺼번에 닫음 |
Point_ 클래스
2차원 평면 위의 점을 나타내는 템플릿 클래스
#include "opencv2/opencv.hpp"
#include <iostream>
int main() {
// 1. 다양한 생성 방식
cv::Point pt1; // (0, 0)으로 초기화
pt1.x = 10; pt1.y = 20;
cv::Point pt2(100, 200); // 생성과 동시에 초기화
// 2. 연산자 오버로딩 활용
cv::Point pt3 = pt1 + pt2; // (110, 220)
cv::Point pt4 = pt2 * 2; // (200, 400)
// 3. 비교 및 관계 연산
bool isEqual = (pt1 == pt2); // false
// 4. 점 정보를 이용한 실습 (이미지에 점 그리기)
cv::Mat img(400, 400, CV_8UC3, cv::Scalar(255, 255, 255)); // 흰색 배경
cv::Point center(200, 200);
// 점 위치에 반지름 5인 빨간색 원 그리기
cv::circle(img, center, 5, cv::Scalar(0, 0, 255), -1);
// 좌표 정보 출력
std::cout << "pt1: " << pt1 << std::endl;
std::cout << "pt3 (pt1 + pt2): " << pt3 << std::endl;
std::cout << "dot product: " << pt1.dot(pt2) << std::endl; // 내적 연산
cv::imshow("Point Example", img);
cv::waitKey(0);
return 0;
}
Size_ 클래스
Size_ 템플릿 클래스는 2차원 영역의 크기를 나타내기 위해 사용된다. 보통 너비(width)와 높이(height)를 멤버 변수로 가진다.
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main() {
// 1. 다양한 초기화 방법
Size sz1(320, 240); // 정수형 (Size2i)
Size2f sz2(10.5f, 20.5f); // 실수형 (float)
Size sz3 = sz1; // 복사 생성
// 2. 멤버 변수 접근 및 출력
cout << "sz1: " << sz1.width << "x" << sz1.height << endl;
// 3. area() 메서드를 이용한 면적 계산
cout << "sz1의 면적: " << sz1.area() << endl;
// 4. 산술 연산
Size sz4 = sz1 * 2; // 모든 요소에 2를 곱함
Size sz5 = sz1 + Size(10, 10); // 너비와 높이에 각각 10을 더함
// 5. 비교 연산
if (sz1 == sz3) {
cout << "sz1과 sz3의 크기는 같다." << endl;
}
// 6. empty() 확인 (너비나 높이가 0 이하인 경우 true)
Size sz6(0, 100);
if (sz6.empty()) {
cout << "sz6는 비어있는 크기다." << endl;
}
return 0;
}
Rect_ 클래스
Rect_ 클래스는 2차원 평면에서 사각형의 위치(좌표)와 크기(너비, 높이)를 나타내는 클래스다. Point_와 Size_ 클래스의 기능을 합친 형태라고 볼 수 있다.
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main() {
// 1. 다양한 초기화 방법
Rect rc1(10, 10, 100, 100); // (x, y, width, height)
Rect rc2(Point(20, 20), Size(50, 50)); // Point와 Size 이용
Rect rc3(Point(0, 0), Point(100, 100)); // 두 대각 점 이용
// 2. 주요 멤버 변수 및 메서드
cout << "rc1의 우측 하단 좌표: " << rc1.br() << endl; // Bottom-Right (110, 110)
cout << "rc1의 좌측 상단 좌표: " << rc1.tl() << endl; // Top-Left (10, 10)
cout << "rc1의 면적: " << rc1.area() << endl; // 10000
// 3. 사각형 포함 관계 확인
Point pt(50, 50);
if (rc1.contains(pt)) {
cout << "점 pt는 rc1 내부에 있음" << endl;
}
return 0;
}
RotatedRect 클래스
RotatedRect 클래스는 중심점, 가로·세로 크기, 그리고 회전 각도를 이용해 회전된 사각형을 표현하는 클래스다. 일반적인 Rect_가 좌표축에 평행한 사각형만 다루는 것과 대조적이다.
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main() {
// 1. 객체 생성
RotatedRect rr(Point2f(100, 100), Size2f(100, 50), 30.0f);
// 2. 정점 좌표 추출
Point2f pts[4];
rr.points(pts);
// 3. 이미지 생성 및 그리기
Mat img = Mat::zeros(200, 200, CV_8UC3);
// 회전된 사각형 그리기 (초록색)
for (int i = 0; i < 4; i++) {
line(img, pts[i], pts[(i + 1) % 4], Scalar(0, 255, 0), 2);
}
// 바운딩 박스 그리기 (빨간색)
Rect br = rr.boundingRect();
rectangle(img, br, Scalar(0, 0, 255), 1);
// --- 추가된 부분: 화면 출력 ---
imshow("RotatedRect Test", img); // 창을 띄워 이미지 표시
waitKey(0); // 키 입력이 있을 때까지 대기 (이게 없으면 창이 바로 닫힘)
// ----------------------------
return 0;
}
Range 클래스
cv::Range 클래스는 행렬(cv::Mat)의 특정 행이나 열의 범위를 지정하여 **ROI(Region of Interest, 관심 영역)**를 추출할 때 주로 사용된다.
#include <opencv2/opencv.hpp>
#include <iostream>
int main() {
// 1. 10x10 크기의 0으로 채워진 행렬 생성
cv::Mat mat = cv::Mat::zeros(10, 10, CV_8UC1);
// 2. 2행부터 4행까지, 3열부터 7열까지 범위를 지정하여 부분 행렬 생성
// (5행과 8열은 포함되지 않음)
cv::Range row_range(2, 5);
cv::Range col_range(3, 8);
cv::Mat sub_mat = mat(row_range, col_range);
// 3. 부분 행렬의 값을 255로 변경 (원본 mat에도 반영됨)
sub_mat.setTo(255);
std::cout << "Sub-matrix size: " << sub_mat.size() << std::endl;
return 0;
}
String 클래스
OpenCV에서 과거에는 자체적인 cv::String 클래스를 사용했으나, 최신 버전(C++11 이후)에서는 표준 라이브러리인 std::string을 그대로 사용하도록 통합되었다. 따라서 OpenCV에서 문자열을 다루는 것은 일반적인 C++ 문자열 처리와 거의 동일하다.
#include <opencv2/opencv.hpp>
#include <string>
int main() {
// 1. 400x600 크기의 검은색 배경 생성 (3채널 컬러 이미지)
cv::Mat img = cv::Mat::zeros(400, 600, CV_8UC3);
// 2. 사용할 문자열 정의 (std::string 사용)
std::string text = "Hello, OpenCV!";
// 3. 이미지 위에 문자열 그리기
// cv::putText(대상이미지, 문자열, 시작좌표, 폰트종류, 폰트크기, 색상, 두께)
cv::putText(img,
text,
cv::Point(100, 200), // 좌측 하단 시작점 (x, y)
cv::FONT_HERSHEY_SIMPLEX, // 폰트 스타일
1.5, // 폰트 크기 비율
cv::Scalar(0, 255, 0), // 색상 (B, G, R) -> 초록색
2); // 선 두께
// 4. 결과 확인
cv::imshow("String Example", img);
cv::waitKey(0);
return 0;
}
Mat 클래스의 기본적인 생성, 복사, 속성 확인 및 출력 방법
- image1.dims: 행렬의 차원을 나타낸다. 일반적인 2D 이미지는 2가 출력된다.
- image1.cols / image1.rows: 영상의 가로(열)와 세로(행) 크기다.
- image1.clone(): **깊은 복사(Deep Copy)**를 수행한다. image3은 image1과 동일한 데이터를 가지지만, 메모리 공간이 완전히 분리된 별개의 행렬이 된다.
- cv::Scalar(i, i, i): B, G, R 값을 모두 동일하게 주면 검은색(0)에서 흰색(255)까지 변하는 그레이스케일 효과가 나타난다.
- cv::waitKey(10): 밀리초(ms) 단위로 대기한다. 이 숫자가 작을수록 색상 변화가 빠르게 진행된다.
- std::abs(255 - i): 수학적인 계산을 통해 밝기가 부드럽게 밝아졌다가 다시 어두워지는 왕복 효과를 구현했다.
Code1.cpp
#include "opencv2/opencv.hpp"
void show1() {
cv::Mat image1 = cv::imread("lenna.png");
cv::Mat image2 = cv::imread("dog.bmp");
cv::Mat image3;
if (image1.empty() or image2.empty()) {
std::cerr << "파일들이 없습니다" << "\\n";
return;
}
image3 = image1.clone();
std::cout << "lena 는 몇 차원?: " << image1.dims << "\\n";
std::cout << "lena 는 몇 컬럼?: " << image1.cols << "\\n";
std::cout << "lena 는 몇 행?: " << image1.rows << "\\n";
std::cout << "dog 는 몇 차원?: " << image2.dims << "\\n";
std::cout << "dog 는 몇 컬럼?: " << image2.cols << "\\n";
std::cout << "dog 는 몇 행?: " << image2.rows << "\\n";
std::cout << "lena clone 는 몇 차원?: " << image3.dims << "\\n";
std::cout << "lena clone 는 몇 컬럼?: " << image3.cols << "\\n";
std::cout << "lena clone 는 몇 행?: " << image3.rows << "\\n";
cv::namedWindow("LENA");
cv::imshow("LENA", image1);
cv::namedWindow("LENA CLONE");
cv::imshow("LENA CLONE", image3);
cv::namedWindow("DOG");
cv::imshow("DOG", image2);
cv::waitKey();
cv::destroyAllWindows();
}
void show2() {
cv::namedWindow("Color");
for (int i = 0; i <= 255; ++i) {
// cv::Mat image(512, 512, CV_8UC3, cv::Scalar(0, 0, i)); // 빨강
cv::Mat image(512, 512, CV_8UC3, cv::Scalar(i, i, i));
cv::imshow("Color", image);
cv::waitKey(10);
}
cv::waitKey(0);
}
void show2_gray() {
// cv::Mat image2(1024, 1024, CV_8UC1); // 회색
// cv::Mat image2(1024, 1024, CV_8UC3); // 회색
cv::Mat image2(cv::Size(512, 512), CV_8UC3); // 회색
cv::imshow("Color", image2);
cv::waitKey(0);
cv::destroyAllWindows();
}
void show2_smooth() {
cv::namedWindow("Color");
// 0부터 510까지 순회 (255까지 내려갔다가 255만큼 다시 올라오는 거리)
for (int i = 0; i <= 510; ++i) {
// 255에서 i를 뺀 값의 절댓값을 취하면 255 -> 0 -> 255로 바뀜
int brightness = std::abs(255 - i);
cv::Mat image(512, 512, (CV_8U, 3), cv::Scalar(0, 0, brightness)); // 빨간색 왕복
cv::imshow("Color", image);
if (cv::waitKey(5) == 27) break;
}
}
OpenCvProject.cpp
extern void show1();
extern void show2();
extern void show2_gray();
extern void show2_smooth();
#include <iostream>
int main()
{
std::cout << "OpenCV!\\n";
// show1();
show2_gray();
// show2_smooth();
}
Mat 클래스
1. Mat 클래스 정의
cv::Mat은 **n차원 행렬(Matrix)**을 표현하는 클래스다. 주로 2차원 이미지를 저장하는 용도로 쓰이지만, 일반적인 수치 데이터를 다루는 행렬로도 사용된다.
- 헤더(Header): 행렬 크기, 행렬의 타입, 주소 등 정보를 담고 있다.
- 데이터 포인터(Data Pointer): 실제 픽셀 값이나 수치 데이터가 저장된 메모리 공간을 가리킨다.
- Mat은 헤더만 복사하는 얕은 복사를 기본으로 하여 대용량 이미지 처리 시 메모리 낭비를 줄인다.
2. 행렬의 깊이 (Depth)
행렬의 원소 하나가 사용하는 비트 수와 자료형을 의미한다. 이미지 처리에서 어떤 정밀도로 데이터를 저장할지 결정한다.
| 기호 | 데이터 타입 | 범위 | 용도 |
| CV_8U | 8비트 부호 없는 정수 | 0 ~ 255 | 일반적인 이미지 (uchar) |
| CV_8S | 8비트 부호 있는 정수 | -128 ~ 127 | |
| CV_16U | 16비트 부호 없는 정수 | 0 ~ 65,535 | 고해상도 의료 영상 등 |
| CV_32F | 32비트 실수 | $-\infty$ ~ $\infty$ | 정밀 연산, 필터링 (float) |
| CV_64F | 64비트 실수 | $-\infty$ ~ $\infty$ | 고정밀 수치 계산 (double) |
3. 채널 (Channel)
행렬의 한 칸(Pixel)이 몇 개의 성분으로 구성되어 있는지를 뜻한다.
- 1채널 (C1): 그레이스케일(Grayscale) 이미지. 한 칸에 밝기 값 하나만 있음.
- 3채널 (C3): 컬러 이미지. 한 칸에 B, G, R 세 가지 색상 값이 있음.
- 4채널 (C4): 컬러 이미지 + 알파 채널(투명도).
4. 행렬 타입 (Type)
위에서 설명한 **깊이(Depth)**와 **채널(Channel)**을 합쳐서 하나의 상수로 표현한 것이다.
표기법: CV_<비트수><자료형>C<채널수>
- CV_8UC1: 8비트 부호 없는 정수, 1채널 (일반 흑백 이미지)
- CV_8UC3: 8비트 부호 없는 정수, 3채널 (일반 컬러 이미지 - BGR)
- CV_32FC1: 32비트 실수, 1채널 (정밀한 계산용 데이터)
마스크
마스크 영상은 보통 **0(검은색)**과 **255(흰색)**로만 구성된 이진 영상(Binary Image)을 의미한다.
- 1(혹은 255, 흰색): 연산을 수행할 부분 (관심 영역, ROI)
- 0 (검은색): 무시할 부분
"곱하기"와 "모따기" (누끼 따기)
이미지 프로세싱에서 마스크를 곱한다는 것은 특정 영역만 남기고 나머지는 지워버리는 과정을 뜻한다.
- 원리: 원본 이미지의 픽셀 값에 마스크의 값을 곱한다.
- (원본 픽셀 값) $\times$ 1 (흰색) = 원본 유지
- (원본 픽셀 값) $\times$ 0 (검은색) = 0 (검은색으로 변함)
- 모따기(누끼 따기): 사과 사진에서 사과 모양의 마스크(흰색)를 만들어서 원본에 곱하면, 사과만 남고 배경은 모두 검은색(0)이 된다. 이렇게 **임의의 부분 영역(ROI)**만 골라내는 것을 "모따기" 혹은 "마스크 연산을 통한 ROI 추출"이라고 한다.
인식
- 객체 검출: 영상 안에서 자동차, 컵, 키보드 같은 물체를 찾아내고 사각형(Bounding Box)으로 표시.
- 얼굴 및 문자 인식: 사람의 얼굴을 찾거나(Face Detection), 이미지 속 글자를 읽어내는(OCR) 기술들이 모두 이 분야에 해당.
'OpenCV' 카테고리의 다른 글
| OpenCV - 색 공간(Color Space)의 이해와 활용, 영상 전처리, 모폴로지 (1) | 2025.12.29 |
|---|---|
| OpenCV - Mat, 간단한 영상 처리 (0) | 2025.12.19 |