본문 바로가기

영상처리

Opencv를 이용한 디지털 영상처리 Chapter03 정리 및 연습문제

※ 개인적으로 공부하면서 남긴 기록이라 잘못된 내용이 있을수있어서, 잘못된 내용은 댓글로 알려주세욥


1. Mat 클래스

Opencv에서 영상을 처리하기위해서는 Matrix형태로 데이터를 처리하게되는데 행렬을 쉽게 구현해놓은 것이 

Mat클래스입니다.          교수님께서는 대학원시절에 이걸 2차원 배열로 직접 구현했다는데 ㄷㄷㄷㄷ

 


2. Mat 클래스 기본 구조

 

Mat클래스 생성자 기본형:

Mat (int rows, int cols, int type, const Scalar &s); 

or Mat (size(int rows,int cols), int type, const Scalar &s);

  1. rows: 영상의 행 개수
  2. cols: 영상의 열
  3. type:화소값을 저장하는데 쓰는 자료형(아래에서 자세히 설명)
  4. s:화소의 초기값(밝기)

출처:https://slidesplayer.org/slide/17751217/

Mat::Type():
           가장 대표적으로 많이 쓰는 type인  CV_8UC3로 설명하겠습니다.

CV_8U는 화소값이 8bit unsigned integer 바로 uchar 를 의미 합니다. (범위는 0~255)

CV_8S=????(정답은 댓글에)

 

다음은 C3인데 이건  channel의 개수를 의미합니다.  예를 들어 Mat m1(3 , 4 ,CV_8UC3, 0~255)라면

3x4 사이즈이고 각각의  element값은 0~255인 행렬이 3개있다고보면 됩니다. 

 

                                               근데 왜 channel를 여러개 하냐하면은 빛의 특성때문입니다.

 

아시다시피 빛은 3원소로 빨강,초록,파랑으로 모든색을 표현할수있습니다. 그러면 아래 그림처럼 영상은 red, green,blue로 나누어 세가지를 

합치면 아래와같이 우리가 아는 영상이 나오게됩니다. 물론 뒷부분에서는 grayscale 등 다양한 방법으로 영상의 색을 표현합니다.

 

출처:http://blog.comart.io/

 

그러면 각각 화소의 밝기는 Scalar(Blue,Green,Red)를 0~255사이의 값을 넣으면 됩니다.

그래서 영상처리에서 CV_8UC3를 많이 사용하는 이유가  RGB를 다루기 위함입니다.

 


                                         Mat 클래스 깊은 복사 & 얇은 복사

얇은 복사 :

Mat A(3,3,CV_8UC3,Scalar(0,0,0));

Mat B=A;

일반적인 C/C++에서는 A의 값을 복사해서 B라는 새롭게 할당된 메모리에 write하면서 A와 B는 값만 같은 아예 다른 주소의 메모리에 할당되어있습니다. 하지만 Mat 클래스는 위에서 본 것 처럼 데이터가 매우 크기 때문에 메모리 효율 문제로 B를 위한 새로운 공간을 할당하지않고 A의 메모리주소를 같게합니다.

즉 이렇게하고 B를 통해 뭔가 연산을 해서 B를 수정하면 A의 값도 바뀌게 됩니다.

두개의 변수가 같은 주소를 가리킵니다.

깊은 복사:

 파이썬에서는 커퓨터 자체에서 이부분을 관리를 해주지만 c/c++은 그렇지 않기에 아래와 같이 clone() 혹은 copyTo()를 사용하여 깊은 복사를 수행

Mat A;

Mat B=A.clone();
Mat A,B;
B.copyTo(A);//B:복사시킬 원본 이미지, A:복사본이 저장되는 위치

이렇게 하면 A와 B는 서로 독립적인 존재가 됩니다.

서로 다른 주소에 할당이 되었지만 그안에 있는 VALUE만 같습니다.

 


                                                    Mat 클래스 생성 방법

1. 이미지 파일을 통한 Mat 생성

#include "opencv2/opencv.hpp"
#include <iostream>
using namespace cv;
using namespace std;

int main()
{
	Mat img=imread("파일명");
    
    cout <<rows값 << img.rows<< endl;
    cout <<coloum값 << img.cols << endl;
    cout <<Mat 크기 << img.size() << endl;
    cout << 전체 화소 개수 << img.total() << endl;
    cout << 한 화소의 크기 << img.total() << endl;
    cout << 타입 << img.type() << endl;
    cout << 채널 << img.channels() << endl;
    waitKey();
    return 0;
    
}

 

2. zeros(), ones(),eye() 통한 생성

3. randu()를 통한 화소값을 난수로 설정

int main()
{
	Mat R=Mat(3,6, CV_8UC1);
   	randu(R, Scalar::all(0), Scalar::all(255)); 0~255사이의 난수 
    	return 0;
}

                                             관심영역 지정하기(ROI)

                                                    아래 그림처럼 영상의 특정영역만 데이터를 뽑아옵니다.

int main()
{
	Mat A;
	A = imread("d:/lenna.jpg", IMREAD_COLOR);

	Rect r(10, 10, 100, 100); //
	Mat D = A(r); //A영상의 일부를 D에 얕은복사로 저장 D는 현재 위의 이미지에서 Subimage(ROI)를 가리킴
	D = Scalar(0, 0, 0);//영상 A의 ROI부분의 화소값 변경	
	imshow("src", A);
	waitKey();
	return 0;
}

Rect 클래스를 통해 사각형을 만들어내어 영역을 만들어냅니다.

Rect(cols 시작점, rows시작점, cols크기(가로크기),rows(세로크기));

 


                                                          도전문제(p92)

1. Mat B=A.clone()은 깊은 복사로 A,B는 서로 독립적임

      :FALSE

2. copyTo()함수 또한 clone()함수와 마찬가지로 깊은복사 함수로

:FALSE


                                                                  Exercise

 

01. Mat 클래스

02.Size

03.

Mat A(3,4,CV_8CU3,Scalar(0,0,0));//명시적 생성

Mat A;
Mat B=A; //얕은복사를 통한 Mat클래스 생성
Mat B=A.clone();//깊은복사를 통한 Mat클래스 생성

04. 문제에서는 아래의 데이터는 1x25사이즈의 2차원 행렬입니다.

아마도 {10, 20, 30 , 40 ,50} 이란 1x5 matrix 생성후 resize로 1x25로 만든게 아닌가 합니다.

 { 10 , 20, 30, 40, 50,

 10 , 20, 30, 40, 50,

 10 , 20, 30, 40, 50,

 10 , 20, 30, 40, 50,

 10 , 20, 30, 40, 50     }

#include <iostream>
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;

int main()
{
    Mat A=(Mat_<int>(1,5) << 10,20,30,40,50);
    resize(A,A,Size(1,25));
    cout << A << endl;
    return 0;
}

05.

#include <iostream>
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;

int main()
{
    vector<Point> points;
    for (int j = 0; j < 10; j++)
	{
		 points.push_back(int(rand() % 100));        
	}
    return 0;
}

06

#include <iostream>
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;

int main()
{
   Mat img=imread("~~~~",IMREAD_COLOR);
   
   imshow("windows",img);
   waitKey();
   return 0;
}

07. 이거 같은경우는 HSV영역으로 변환하거나 아니면 Mat클래스에 직접 접근해야되서 다음장에 쓰겠습니다.

///