OpenCV
cv::Mat
OpenCV의 Mat자료구조에 대해서 살펴보도록 하겠습니다.
먼저 간단한 예제를 통해 이미지를 읽어 Mat에 어떻게 저장되는지 확인해보겠습니다.
opencv를 이용하여 imread를 할 시 RGB로 순서가 아닌 BGR로 읽게됩니다. 따라서, 채널별로 조작을 하고 싶다면 cv::cvtColor()를 통해 BGR2RGB를 하거나 채널 순서를 헷갈리지 않고 작업을 해야합니다.
1 |
|
위와 같은 사진이 저장된 img_color의 저장방식을 살펴보도록하겠습니다.
1 | int main(int, char**) |
1 | Region of (5,5,5,5) : [167, 166, 168, 167, 166, 168, 167, 166, 168, 167, 166, 170, 168, 167, 171; |
cv::Rect(5,5,5,5)는 point(5,5)로부터 width, height가 각각 5인 직사각형 영역을 의미합니다.
즉, 25개의 픽셀값이 들어가는데 출력시 75개의값이 반환되는 것을 볼 수 있습니다.
이는, RGB채널마다 픽셀값을 가지고 있기 때문입니다.
따라서, 5,5라는 점에서의 가로 5 세로 5의 사각형은 아래와 같습니다.
이해를 돕기위해 width, height = 100으로 증가시켰습니다.
Mat 생성 방법
C++: Mat::Mat()
C++ : Mat::Mat(int rows, int cols, int type)
C++ : Mat::Mat(Size size, int type)
C++ : Mat::Mat(int rows, int cols, int type, const Scalar& s)
C++ : Mat::Mat(Size size, int type, const Scalar& s)
C++ : Mat::Mat(const Mat& m)
C++ : Mat::Mat(int rows, int cols, int type, void* data, size_t step = AUTO_STEP)
C++ : Mat::Mat(Size size, int type, void* data, size_t step = AUTO_STEP)
C++ : Mat::Mat(const Mat& m, const Range& rowRange, const Range& colRange = Range::all())
C++ : Mat::Mat(const Mat& m, const Rect& roi)
C++ : Mat::Mat(const CvMat* m, bool copyData = false)
C++ : Mat::Mat(const IplImage* img, bool copyData = false)출처: https://nextus.tistory.com/14 [ReStartAllKill]
위의 다양한 생성자에서 type
이라는 변수가 있는데 아래와 같은 상수를 통해 값을 설정합니다.
CV_8UC1 : 8 - bit unsigned integer : uchar(0..255)
CV_8SC1 : 8 - bit signed integer : schar(-128..127)
CV_16UC1 : 16 - bit unsigned integer : ushort(0..65535)
CV_16SC1 : 16 - bit signed integer : short(-32768..32767)
CV_32SC1 : 32 - bit signed integer : int(-2147483648..2147483647)
CV_32FC1 : 32 - bit floating - point number : float(-FLT_MAX..FLT_MAX, INF, NAN)
CV_64FC1 : 64 - bit floating - point number : double(-DBL_MAX..DBL_MAX, INF, NAN)출처: https://nextus.tistory.com/14 [ReStartAllKill]
CV_64FC1으로 살펴보면 다음과 같습니다.
- 64 : bit단위를 말하며 위의 예시는 64bit를 의미합니다. 즉, 0~2^64를 의미합니다.
- F : 부호 결정자로 F는 Floating, S는 Signed, U는 Unsigned를 의미합니다.
- C1: Channel의 약자로 C1의 경우 생략이 가능하며 그 외는 C1~C8범위가 가능합니다.
가장 처음 살펴본 강아지의 경우 RGB값이 있는 3 channel의 8bit image이므로 CV_8UC3의 데이터타입을 갖게 됩니다.
위와같은 데이터타입을 생성할 수도 있는데
1 | //mat.hpp |
위와 같이 입력할 경우 CV_32FC5이라는 상수명으로 5 + 4 << 3 = 69라는 값이 저장되게 됩니다.
OpenCV 핸드북 - 다크프로그래머님 - https://darkpgmr.tistory.com/46
using namespace cv;
이미지 읽기 및 저장
- imread()를 통한 이미지 읽기
Mat img_color = imread(“sample.jpg”); // color load
Mat img_gray = imread(“sample.jpg”, 0); // gray load
Mat img_16bit = imread(“sample.jpg”, cv::IMREAD_ANYDEPTH); // 원본 depth로 읽기
imwrite()를 통한 이미지 저장
imwrite(“fname.jpg”, img);
이미지 생성, 복사, 형변환, 색상변환, roi 설정
int w = 320;// width
int h = 240;// height
- 생성자를 통한 변수 생성
Mat img(h,w,CV_8UC1);//1채널 unsigned char
Mat img(h,w,CV_8UC3);//3채널 unsigned char
Mat img = Mat::zeros(h,w,CV_32FC1);//1채널 float
Mat img = Mat::ones(h,w,CV_64FC3);//3채널 double
unsigned char * img_buffer;// 이미지버퍼 포인터
Mat img(h, w, CV_8UC3, img_buffer);//메모리 공유
- Scalar()를 통한 원소 초기화
Mat img(h,w,CV_8UC1);
img = Scalar(3); // img 모든 원소값 3으로 초기화
- 이미지 참조 및 복사
Mat img2 = img; // 메모리 공유
Mat img2 = img.clone(); // 별도 메모리
Mat img2; img.copyTo(img2);//별도 메모리
- 형변환을 통한 복사
Mat img1(h,w,CV_32FC1);
Mat img2;
img1.convertTo(img2, CV_8U);
- gray-color 변환
cvtColor(color, gray, CV_BGR2GRAY);
cvtColor(gray, color, CV_GRAY2BGR);
- ROI(Region Of Interst) 설정
Rect roi;
Mat sub_img = img(roi);//메모리공유
Mat sub_img = img(roi).clone();//별도메모리
행렬 원소접근 및 생성초기화
Mat A = (Mat_
Mat B = (Mat_
A.at
B.at
Mat C(h, w, CV_8UC3);
C.at
C.at
C.at
영상 크기변경 및 상하좌우 반전
- 크기 변경
Mat dst;
resize(img, dst, cv::Size(new_w,new_h));
resize(img, dst, cv::Size(), 0.5, 0.5);//scalex, scaley
- 영상 반전(flip)
flip(img, dst, 0);// vertical flip
flip(img, dst, 1);// horizontal flip
flip(img, dst, -1);// vertial & horizontal flip
이미지에 그리기 (drawing)
Rect rc(x,y,w,h);
Scalar color(B,G,R);
int thickness=1; // line thickness
line(img, Point(x1,y1), Point(x2,y2), color, thickness);
rectangle(img, rc, color, thickness);
rectangle(img, rc.tl(), rc.br(), color, thickness); // tl = TopLeft, br = BottomRight
rectangle(img, rc, color, CV_FILLED); // filled rectangle
Point center(rc.x+rc.width/2, rc.y+rc.height/2);
Size radius(rc.width/2, rc.height/2);
double rot_deg = 0; // rotation of ellipse
double s_deg = 0; // start angle of arc
double e_deg = 360; // end angle of arc
ellipse(img,center,radius,rot_deg,s_deg,e_deg,color,thickness);
ellipse(img,center,radius,rot_deg,s_deg,e_deg,color,CV_FILLED);
int circle_radius = 10;
circle(img, center, circle_radius, color, thickness);
circle(img, center, circle_radius, color, CV_FILLED);
putText(img, “text”, Point(x,y), FONT_HERSHEY_SIMPLEX, 1., color, thickness);
putText(img, “text”, Point(x,y), FONT_HERSHEY_DUPLEX, 1., color, thickness);
이미지 디스플레이하기 (display)
namedWindow(“name”); // auto resized
namedWindow(“name”,CV_WINDOW_NORMAL); // manual resize
imshow(“name”, img);
char ch = waitKey(); // 무한 대기
char ch = waitKey(10); // 10 msec 대기
if(ch == 27) … // ESC key
if(ch == 32) … // SPACE key
destroyWindow(“name”);
destroyAllWindows();
웹캠 연결하기
VideoCapture vc(0);
if (!vc.isOpened()) return; // 연결실패
vc.set(CV_CAP_PROP_FRAME_WIDTH, 640);
vc.set(CV_CAP_PROP_FRAME_HEIGHT, 480);
Mat img;
while(1){
vc >> img;
if(img.empty()) break;
imshow(“cam”,img);
if(waitKey(10)==27) break; //ESC
}
destroyAllWindows();
avi 비디오 파일 읽어오기
VideoCapture vc(“sample.avi”);
if (!vc.isOpened()) return; // 불러오기 실패
Mat img;
while(1){
vc >> img;
if(img.empty()) break;
imshow(“video”,img);
if(waitKey(10)==27) break; //ESC
}
destroyAllWindows();
avi 비디오 녹화하기
double fps = 15;
int fourcc = CV_FOURCC(‘X’,’V’,’I’,’D’); // codec (opencv3.0이하)
int fourcc = VideoWriter::fourcc(‘X’,’V’,’I’,’D’); // opencv3.0이상
bool isColor = true;
VideoWriter *video = new VideoWriter;
if(!video->open(“result.avi”, fourcc, fps, Size(img_w, img_h), isColor)){
delete video;
return;
}
Mat img;
while(1){
// …
*video << img;
// …
}
delete video;
※ 코덱 목록: http://www.fourcc.org/codecs.php
창에 Trackbar 붙이기
int threshold = 10;
cv::namedWindow(“display”);
cv::createTrackbar(“thr:”, “display”, &threshold, 1000);