data.fl [union CvMat::<unnamed> CvMat::data ]이라는 것이 나왔다.. 이건 뭔가 싶어서 찾아봄.
접기
공용체(union)란 C언어 문법 책 뒷쪽에, 구조체(structure) 다음에 꼽사리로 나오는 데이터 구조. 예를 들어, 아래와 같은 공용체가 정의되어있다고 하자. typedef union _data { char a; int b; float c; } data; 이 경우, 이 공용체는 전체 8바이트의 크기를 갖는다. 이 8바이트 중에서 첫 번째 바이트는 a 변수가 사용하고, 처음 네 개의 바이트는 b가 사용하고, 처음부터 끝까지 여덟 바이트는 c가 사용한다. 즉, 세 멤버 변수 a, b, c 는 중첩된 메모리 공간을 같이 사용한다. 그러므로, a 변수에 값을 저장하면, b와 c에 저장된 값은 전혀 다른 값으로 바뀌게 된다. "도대체 이런 구조를 왜 써야할까???" 하는 의문을 바로 몇 달전 C 프로그래밍을 가르치면서 다시금 떠올렸었다. 그러다가 OpenCV 책을 번역하면서 발견한, union의 효과적인 사용 예를 기록해보려고 한다. OpenCV의 행렬 구조체의 정의는 다음과 같다. typedef struct CvMat { int type; int step; int* refcount; // 내부적 용도로만 사용됨. int hdr_refcount; union { uchar* ptr; short* s; int* i; float* fl; double* db; } data; union { int rows; int height; }; union { int cols; int width; }; } CvMat; CvMat 라는 구조체 내부에 union이 두루 사용된 것을 볼 수 있다. 먼저 아래쪽 두 개의 union을 보면 rows 와 height 두 개를 union으로 감싸고 있다. 이 경우, rows 와 height 는 같은 메모리 공간을 지칭하는 변수 가 된다. 즉, 행렬의 행의 크기를 나타내는 값을 rows 라는 변수로도 접근할 수 있고, height 라는 변수로도 접근할 수가 있는 것이다. 이건, 꽤 괜찮다. ^^; 두 번째, 위 구조체 정의 중간에 있는 data 라는 이름을 할당한 union은 5 가지 종류의 포인터 변수를 가지고 있는데, 이 또한 꽤 그럴싸하다. 어차피 포인터 형 변수라면 항상 4바이트(win32 환경의 경우)를 갖게 되니까 data 변수는 결과적으로 4바이트를 갖는다. 그런데 data.ptr 을 사용할 수도 있고, data.s, data.i, data.fl, data.db 를 사용할 수도 있다. 즉, CvMat 행렬이 실제 저장하고 있는 값이 무슨 타입이냐에 따라 실제 데이터가 저장된 메모리 공간을 가리키는 변수를 선택적으로 사용할 수 있는 것이다. 그러면 뭐가 좋을까??? 포인터 연산을 통해 주변 원소로 이동할 때 캐스팅을 따로 하지 않아도 되는 장점이 생긴다. (물론 주의해서 사용해야 하는 점은 존재한다.) 음... 어려울려나?? 암튼 좋은거다. ^^; 암튼, union을 사용해서 도움이 되는 예제를 처음 보다시피하여 기록해보았다. 도움이 될라나.. 흠..
접기 http://yeahhappyday.tistory.com/entry/CvMat-%ED%96%89%EB%A0%AC-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0
[opencv] cv::Mat 클래스에 대한 것. Tip??
접기
Mat에 대해 다시 한번 보자.
cv:Mat - 행렬을 나타내기 위한 클래스, 주로 영상 데이터를 담고, 연산하기 위해 쓰이는 녀석.
[멤버 변수]
- data : 실제 영상 데이터를 저장하고 있는 메모리 블록의 시작 주소를 담고 잇는 포인터 변수
- cols : 열의 수(열의 개수)
- rows : 행의 수(행의 개수)
- step : 한 행의 원소 수
- refcount : 참조 카운터(reference count), 0이 되면 data가 가리키는 메모리 해제
[멤버 메소드]
- at() : 템플릿 메소드로 특정 화소에 접근할 때 사용
- ptr() : 영상의 특정 열의 주소를 가져올때 사용
- channels() : 채널의 수
- elemSize() : 화소의 크기를 반환 -> 채널수 * 화소 당 byte 수 (CV_16SC3인 경우 : 3채널*2byte=6,
따라서 elemSize()의 반환 값은 6)
- total() : 행렬 내 원소의 수
- create() : 새로운 크기와 타입을 갖는 행렬을 할당할 때 사용, 만약 동일한 크기와 타입을 갖는 행렬이 이미 할당되어 있는 경우 아무런 동작도 하지 않음
- type() : 할당되어 있는 타입(ex : CV_8UC1, CV16SC3 등)
- reshape() : 임의의 메모리 복사나 재할당 없이 행렬의 차원 수를 변경
- isContinuous() : 할당된 데이터가 연속적인지를 반환 (연속적이면 true, 불연속적이면 false 반환)
- col() : 데이터의 특정 열에 접근
- row() : 데이터의 특정 행에 접근
- convertTo() : type을 변경
opencv February 24, 2014
접기 접기
아래 내용은 다크pgmr ( http://darkpgmr.tistory.com/46 ) 님의 블로그에서 복사한 내용입니다.
내용에 내가 필요료 하는 것들 추가로 기록할 예정입니다.
====================================================================================
using namespace cv;
1. 이미지 읽기 & 저장
Mat img_color = imread("sample.jpg"); // color load
Mat img_gray = imread("sample.jpg", 0);// gray load
imwrite("fname.jpg", img);
2. 이미지 생성, 복사, 형변환, 색상변환, 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);//메모리 공유
// 원소 초기화
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 설정
Rect roi;
Mat sub_img = img(roi); //메모리공유
Mat sub_img = img(roi).clone(); //별도메모리
3. 영상 크기변경 및 상하좌우 반전
// 크기 변경
Mat dst;
resize(img, dst, Size(new_w,new_h));
resize(img, dst, 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
4. 이미지에 그리기 (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);
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);
5. 이미지 디스플레이하기 (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();
6. 웹캠 연결하기
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();
7. avi 비디오 파일 읽어오기
VideoCapture vc("sample.avi");
if (!vc.isOpened()) return; // 불러오기 실패
Mat img;
while(1){
vc >> img;
if(img.emplty()) break;
imshow("video",img);
if(waitKey(10)==27) break; //ESC
}
destroyAllWindows();
8. avi 비디오 녹화하기
double fps = 15;
int fourcc = CV_FOURCC('X','V','I','D'); // codec
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;
9. Mat <--> IplImage
Mat --> IplImage
Mat matimg;
IplImage* iplimh;
iplimg = &IplImage(matimg);
IplImage --> Mat
IplImage* iplimg;
Mat matimg;
matimg(iplimg);
10. 픽셀 접근법
Mat image;
// 3 channel Image
for ( int j= 0 ; j < image.rows ; j++ )
{
for ( int i= 0 ; i < image.cols ; i++ )
{
image.at < Vec3b> ( j,i) [ 0 ] + = 30 ;
image.at < Vec3b> ( j,i) [ 1 ] + = 20 ;
image.at < Vec3b> ( j,i) [ 2 ] + = 20 ;
}
}
이때 Vec3b 는 unsigned char 형이다
b(unsigned char) 외에도 s(short), i(int), f(float), d(double) 형의 벡터가 존재한다.
* 추가사항 *
cv::Mat클래스의 at메소드를 사용한다면 가끔은 성가실 수 있다. 행렬 타입을 알고 있다면 cv::Mat의 템플릿 하위 클래스인 cv::Mat_ 클래스를 사용할 수 있다.
cv::Mat_<uchar> im2 = image; //im2는 image를 참조
im2(50,100) = 0; // 50행 100열 화소에 접근
접기