컴퓨터 비전(OpenCV) 스터디

230515-21 스터디

2023. 5. 18. 15:15

< OpenCV 4로 배우는 컴퓨터 비전과 머신 러닝 > 교재 3, 4장 공부

 

 

- 3장 OpenCV 주요 클래스

3.1 기본 자료형 클래스

<Point_ 클래스>

    픽셀의 좌표를 표현, 2차원 좌표를 나타내는 x, y를 멤버 변수로 가져 2차원 평면 상의 점의 좌표를 표현

    Point_<int>와 같이 자료형을 명시해야하지만 클래스 이름 재정의해 사용도 가능 (Point2i 클래스, Point2f 클래스 ...)

    .dot() 함수를 통해 두 점의 내적을 구할 수 있음 ( .dot(), .ddot(), .cross(), inside() )

    Point 객체끼리 ==, != 연산자를 이용하여 두 점이 같은지 다른지도 알 수 있음 (결과는 bool)

    Point 객체를 cout으로 출력하면 그 점의 좌표가 출력됨

 

<Size_ 클래스>

    영상 또는 사각형 영역의 크기를 표현

    가로와 세로 크기를 나타내는 width, height를 멤버변수로 가짐 (역시 기본 생성자로는 0으로 초기화)

    area(), empty() 함수

    역시 다양한 자료형 존재

 

<Rect_ 클래스>

    사각형 위치와 크기 정보를 표현

    좌측 상단 점의 좌표 x, y와 width, height가 멤버변수

    tl(), br(), size():사각형 크기 정보, area(), empty(), contains() 함수가 존재

    역시 다양한 자료형에 대해 이름 재정의 되어있음

    Size_ 클래스, Point_ 클래스와 산술 연산자 재정의가 돼있어 산술 연산 가능 

    Rect_ 객체끼리 논리 연산도 가능 (&: 겹치는 직사각형 반환, |: 두 사각형으로 만들 수 있는 최소의 직사각형 반환)

    객체 출력시 x, y, width, height 출력됨

 

<RotatedRect 클래스>

    회전된 사각형을 표현

    center, size, angle을 멤버변수로 가짐 (회전된 사각형의 중심 좌표, 사각형의 크기, 회전 각도 정보)

    points(): 회전된 사각형의 네 꼭지점 좌표,

    boundingRect(): 회전된 사각형을 감싸는 최소 크기의 사각형 정보,

    BoundingRect2f(): 사각형 좌표 정보를 실수로 알고 싶을 때 사용 

    앞선 클래스들과 달리 템플릿 클래스가 아니라서 모든 정보를 float 자료형으로 표현 

 

<Range 클래스>

    범위 또는 구간을 표현

    start, end를 멤버변수로 가짐 (start <= x < end, end는 범위에 포함되지 않음)

    size(): end-start, 범위의 크기를 반환

    empty(): start와 end가 같으면 true를 반환

    all(): start, end를 자료형이 가질 수 있는 최대, 최소 범위로 설정

 

<String 클래스>

    문자열 표현

    std: string 클래스 사용방식과 유사하게 사용가능

    " " 로 string 표현 가능

    compare(), ==연산자 가능

    .format() 함수를 통해 문자열 생성 가능

 

3.2 Mat 클래스

<Mat 클래스 개요>

- 행렬을 표현하는 클래스

- 2차원 뿐만 아니라 고차원 행렬도 표현 가능, 한 개 이상의 채널을 가질 수 있음

- 행렬, 벡터, 그레이스케일, 컬러 영상도 Mat 클래스에 저장 가능, 2차원 영상 데이터 저장하고 처리하는 용도로 가장 많이 사용

- 멤버 변수: dims-차원, rows-행 개수, cols-열 개수, data-행렬의 데이터, size-행렬 크기 표현

모두 public 으로 접근 가능

(rows와 cols는 2차원 상에서만 의미있는 값을 갖고 3차원 이상에서는 -1을 가짐, 여기서부터는 size로 행렬 정보를 알 수 있음)

- Mat 행렬의 깊이(자료형)는 매크로 상수를 이용해 표현

    ex. 행렬의 원소를 float로 표현하려면 깊이가 CV_32F인 행렬을 사용해야함

- 새로운 행렬을 생성할 때는 행렬 타입 정보를 명시적으로 지정해주어야 함

 

<행렬의 생성과 초기화>

- 세로 크기, 가로 크기, type 순으로 입력 

Mat img( Size(640, 480), CV_8UC3 );

- Scalar도 입력 가능 (rbg값을 입력해 색상을 지정가능)

- Zeros() 함수: 모든 원소가 0으로 초기화된 행렬 만드는 함수

- ones() 함수: 모든 원소가 1로 초기화된 행렬 만드는 함수

- eye() 함수

- create() 함수: 이미 있는 Mat 객체에 새로운 행렬 할당

- setTo() 함수: 원소 값 한번에 설정가능

 

<행렬의 복사>

- "=": 얕은 복사

- clone(), copyTo() 함수: 깊은 복사, 메모리 공간을 새로 할당해 픽셀 데이터를 복사하고 싶을때

 

<부분 행렬 추출>

- 부분 행렬 추출 시에는 얕은 복사가 됨

- 깊은 복사 하고 싶다면 식 뒤에 .clone()을 붙이기

- 부분을 추출하고 싶을 땐 Rect()함수로 원하는 부분을 선택

-----

- rowRange(), colRange(): 행 또는 열을 부분행렬로 추출하고자 할 때

- row(), col(): 행 또는 열을 추출해 1행짜리 또는 1열짜리 행렬을 만듦

위에 네 함수는 모두 얕은 복사, 깊은 복사 하고 싶다면 식 뒤에 .clone()을 붙이기

 

<행렬의 원소 값 참조>

- 영상의 픽셀 값을 참조하고 (행렬 원소 값을 참조하고) 값을 변경할 수 있음

1. at(행, 열): 행렬의 값에 접근 가능, 템플릿 함수라 자료형 지정해야함

2. ptr(행): Mat 행렬에서 특정 행의 첫 번째 원소 주소를 반환, 템플릿 함수라 자료형 지정해야함, 포인터로 반환함

3. MatIterator_클래스: 행렬 크기에 상관 없이 행렬 전체 원소를 차례대로 참조하는 방식

    -> begin(), end()

 

<행렬 정보 참조하기>

- .rows: 행 개수, .cols: 열 개수, .channels()

- type(): 그레이스케일 영상인지 3채널 컬러 영상인지 확인 가능

 

<행렬 연산>

- 행렬끼리 +, -, /, * 연산 가능

- mul(): 곱셈연산

- inv(): 역행렬 구하기

- t(): 전치행렬 구하기

 

<크기 및 타입 변환 함수>

- convertTo(): 행렬 원소의 타입을 다른 타입으로 변경하고 추가적으로 모든 원소에 일정한 값을 더하거나 곱할 수 있음

    ex. img1.convertTo(img2, 바꾸고 싶은 타입);

- reshape(): 행렬의 모양을 변경함, 기존 행렬 원소 데이터를 복사해 새 행렬을 만드는 게 아니라 행렬 원소 데이터를 같이 참조하는 행렬을 반환 (즉 얕은 복사가 됨)

    ex. mat2 = mat1.reshape(0, 1);  기존 행렬을 1xn으로 바꿈

- resize(): 행렬의 모양을 변경시키는 것이 아니라 단순히 행렬의 크기를 변경하고 싶을 때

    ex. mat1.resize(5, 100);  행을 5(줄)까지 추가하고 그 값들을 모두 100으로 채움

- push_back(): 기존 행렬에 인자로 받은 행렬을 밑에 추가

- pop_back(): 아래에 있는 행 제거

 

3.3 Vec과 Scalar 클래스

- Vec 템플릿 클래스: 작은 개수의 원소로 구성된 벡터를 표현함

- Scalar 클래스: Vec 클래스의 특별한 형태

 

<Vec 클래스>

- 행 벡터, 열 벡터를 합쳐 벡터 행렬이라 부름, 벡터는 같은 자료형을 가진 원소 몇 개로 이루어진 데이터라고 볼 수 있음

    ex. Vec<자료형 타입, 생성하고 싶은 데이터 수> p1(0,0,255);

- 컬러 영상의 픽셀 값을 표현하고 싶을 때

    ex. Vec3b p1(0,0,255);

 

<Scalar 클래스>

- 4채널 이하의 영상에서 픽셀 값을 표현하는 용도로 자주 사용됨

- Scalar(밝기)

- Scalar(파, 녹, 빨)

- Scalar(파, 녹, 빨, 투명도)

- yellow.val[0] == yellow[0] 로 yellow 변수의 0번찌 원소 값을 참조 가능

 

3.4 InputArray와 OutputArray 클래스

<InputArray 클래스>

- OpenCV 함수의 입력으로 주로 사용됨

- noArray(), Mat(): 비어있는 행렬 전달

- getMat(): Mat 객체 타입으로 변환

- pringMat(): Mat 행렬의 원소 값 출력

- InputArrayOp()

 

<OutputArray 클래스>

- OpenCV 함수의 출력으로 주로 사용됨, 영상 처리 수행 후 결과를 다시 영상으로 생성해 반환

- return이 아닌 클래스의 참조를 함수 인자로 사용해 결과를 전달함

- InputArray 클래스를 상속받음, create()함수만 새로 있음

- 결과 영상을 저장할 새로운 행렬 먼저 생성 후 영상처리 결과를 저장해 반환

- InputOutputArray 클래스는 클래스 이름에서 알 수 있듯이 입력과 출력의 역할을 동시에 수행할 때 사용

 

 

- 4장 OpenCV 주요 기능

4.1 카메라와 동영상 파일 다루기

<VideoCapture 클래스>

- 동영상: 일련의 정지영상(프레임)을 압축해 파일로 저장한 형태

- 카메라, 동영상 파일로부터 정지 영상 프레임을 받아올 수 있는 클래스

- protected 모드라 사용자가 직접 접근할 수 는 없음

- open() 함수: 객체 생성후 open함수로 동영상 파일 호출해야 파일 불러올 수 있음, VideoCaptureAPIs 열거형 상수 지정

카메라 장치를 열 때도 사용

- isOpened(): 제대로 열기 작업이 수행됐는지 확인

- release(): 사용하던 자원 해제 및 동영상 파일 닫힘

- read(): 정상적으로 열고 한 프레임을 받아오는 함수, Mat 클래스의 변수에 저장

- get(): 열린 파일로부터 여러 가지 정보를 받아옴, VideoCaptureProperties 열거형 상수를 함수 인자로 사용가능

-  cvRound(): 반올림

- set(): get과 반대로 열려있는 파일에 속성 값을 설정할 때 사용, VideoCaptureProperties 열거형 상수를 지정해 사용

 

<카메라 입력 처리하기>

- VideoCapture 클래스를 사용하여 컴퓨터에 연결된 카메라로부터 프레임을 받아 와서 처리

1. VideoCapture 클래스 객체를 생성

2.  VideoCapture::open() 멤버 함수를 이용하여 사용할 카메라 장치를 열기, 컴퓨터에 연결되어 있는 기본 카메라를 사용하려면 VideoCapture::open() 함수의 인자에 0을 지정

3. VideoCapture::isOpened() 멤버 함수를 이용하여 카메라 장치가 사용 가능한 상태로 열렸는지 확인

4. 카메라 장치를 사용할 수 있는 상태라면 이제 카메라 장치로부터 프레임을 받아 올 수 있음 (받아와  Mat 클래스 객체에 저장 가능)

(이렇게 각 프레임을 가져와 다양한 영상기법을 적용해 출력할 수 있음)

 

<동영상 파일 처리하기>

-  동영상 파일은 고유의 코덱(codec)을 이용하여 압축된 형태로 저장됨

- 코덱은 복잡한 알고리즘을 이용하여 대용량 동영상 데이터를 압축하거나, 반대로 압축을 해제하여 프레임을 받아 오는 기능을 제공

-  VideoCapture 클래스를 사용하면 동영상 파일을 쉽게 불러와서 사용 가능

- 동영상 파일은 모두 초당 프레임 수 FPS를 갖고, 동영상을 적절한 속도로 재생하려면 동영상의 FPS값을 참고해야함

1.  VideoCapture 객체를 생성

2. VideoCapture::open() 멤버 함수를 이용하여 동영상 파일을 여는 작업을 수행(동영상 파일 이름은 문자열로 받음)

3. FPS 값을 이용해 매 프레임 사이의 시간 간격 계산, 이를 이용해 적절한 속도로 영상이 출력될 수 있도록 함

4. 동영상을 불러와 원하는 대로 처리

 

<동영상 파일 저장하기>

- OpenCV는 카메라 및 동영상 파일의 프레임을 받아 오는 기능뿐만 아니라 일련의 프레임을 동영상 파일로 저장하는 기능도 제공

- 영상 파일을 생성하고 프레임을 저장하기 위해서는 VideoWriter 클래스를 사용

1. 새로운 동영상 파일을 만들기 위해 VideoWriter 클래스 객체를 생성 => VideoWriter video;

2.  VideoWriter::open() 멤버 함수를 이용하여 저장할 동영상 파일을 쓰기 모드로 열기

(fourcc()로 코덱 표현가능)

3. 열려 있는 동영상 파일에 새로운 프레임을 추가하기 위해서 VideoWriter::write() 함수를 이용하여 프레임을 추가

4. 프레임 저장이 완료되었으면 열려 있던 파일을 닫는 VideoWriter::release() 함수를 호출

+ VideoCapture 클래스를 이용하여 카메라 장치를 열고, VideoWriter 클래스를 이용하여 반전된 동영상 파일을 생성

 

4.2 다양한 그리기 함수

- 영상을 불러와 영상위에 그리기 함수를 통해 정보 표현 가능

 

<직선 그리기>

- line() 함수: img 영상 위에 pt1 좌표부터 pt2 좌표까지 직선을 그림. color, 선 두께, 선 타입 지정 가능

- arrowedLine() 함수: 화살표 직선, tiplength도 지정 가능

- drawMarker() 함수: 직선 그리기 함수를 이용하여 다양한 모양의 마커(marker) 그림

 

<도형 그리기>

- rectangle(): 영상에 사각형을 그리는 함수, 사각형의 정보는 두 꼭지점 좌표를 이용하거나 또는 Rect 클래스 타입의 객체를 이용하여 전달할 수 있음, 두께 등으 인자값은 기본값이 있어 생략가능

- circle(): 원을 그리는 함수, 원의 중심점 좌표와 반지름을 지정해야함

ellipse() 함수: 타원을 그리는 함수, 타원 또는 호를 그릴 수 있음, 호는 startAngle endAngle 인자를 적절하게 이용하면 그릴 수 있음

- polylines() 함수: 임의의 다각형을 그리는 함수, 다각형의 꼭지점 좌표를 전달해야함

- drawPolys() 함수: 도형을 영상에 그려 화면에 출력하는 함수

<문자열 출력하기>

- 영상에 직접 영상 처리 결과 또는 추가적인 정보를 문자열 형태로 나타내야 할 때 사용하면 편리

-  putText() 함수: 영상 위에 정해진 폰트로 문자열 출력. 폰트 종류, 크기 등을 설정 가능. 한글은 출력 불가

- getTextSize() 함수: 문자열 출력을 위해 필요한 사각형 영역 크기를 가늠 가능, 이 함수를 잘 이용하면 문자열이 한쪽으로 치우치지 않고 적당한 위치에 출력되도록 설정할 수 있음

함수 실행 시, 지정한 문자열, 폰트 종류, 폰트 크기 등을 이용하여 문자열을 출력할 때 차지할 사각형 영역 크기 정보를 반환. putText 실행 전에 사용해 위치 확인 후 적절한 곳에 문자열 출력하도록 할 수 있음

 

4.3 이벤트 처리

-  잘 사용하면 프로그램 동작 시 사용자 입력을 실시간으로 처리 가능. 

- 프로그램 실행 중 특정 범위의 값을 사용자가 선택하여 프로그램 동작을 제어 가능

 

<키보드 이벤트 처리>

- waitKey() 함수:  프로그램에서 키 입력을 확인하기 위해 사용하는 함수. 키보드 입력을 처리하는 기본적인 OpenCV 함수

delay 시간 동안 키 입력을 기다리다가 키 입력이 있으면 해당 키의 아스키 코드(ASCII code) 값을 반환

키 입력 없으면 -1 반환

waitKey() 함수의 인자를 지정하지 않거나 0 또는 음수로 설정하면 키 입력이 있을 때까지 무한히 기다리고, 사용자가 키보드를 누르면 눌린 키의 아스키 코드를 반환하면서 함수가 종료

 

<마우스 이벤트 처리>

- OpenCV에 의해 만들어진 창에서 마우스 클릭에 반응하거나 마우스를 드래그하여 영상에 그림을 그리는 등의 동작을 수행 가능

1. setMouseCallback() 함수를 이용해 마우스 콜백 함수를 등록

2. 마우스 콜백 함수에 마우스 이벤트를 처리하는 코드를 추가

 

<트랙바 사용하기>

- 새 창에 영상만 출력하는 것이 아니라 프로그램 동작 중에 사용자 입력을 받을 수 있는 그래픽 사용자 인터페이스, 즉 GUI(Graphical User Interface)를 추가 가능

- 새 창에 영상만 출력하는 것이 아니라 프로그램 동작 중에 사용자 입력을 받을 수 있는 그래픽 사용자 인터페이스, 즉 GUI(Graphical User Interface)를 추가 가능

- createTrackbar() 함수: 트랙바 생성 가능

- getTrackbarPos() 함수: 트랙바의 현재 위치 알 수 있음

- setTrackbarPos() 함수: 트랙바 위치 강제로 옮기기 가능

 

4.4 OpenCV 데이터 파일 입출력

<FileStorage 클래스>

-  FileStorage 클래스는 Mat 클래스 객체뿐만 아니라 일반적인 C/C++ 자료형 데이터를 XML, YAML, JSON 등 파일 형식으로 저장하는 기능을 제공

- 데이터 파일 입출력을 담당

1. FileStorage 객체를 생성

2. FileStorage::open() 함수를 이용하여 실제 사용할 파일을 열기 -> 데이터 파일 이름 지정, mode 열거형 상수 지정

3. FileStorage::isOpened() 함수로 파일이 정상적으로 열렸는지를 따로 확인

4. FileStorage 객체를 이용하여 파일 입출력 작업이 완료되면 FileStorage::release() 함수를 호출

 

<데이터 파일 저장하기>

- FileStorage 클래스를 이용하여 데이터를 파일에 저장할 때에는 보통 << 연산자 재정의 함수를 사용

- FileStorage 클래스를 이용하여 파일에 여러 개의 데이터를 저장할 때에는 데이터의 구분을 위한 문자열 형식의 이름을 함께 저장

- writeData() 함수: FileStorage 클래스를 이용하여 C/C++ 기본 자료형, STL 벡터, OpenCV 자료형 등을 JSON 파일 형식으로 저장. 프로그램 실행 폴더에 mydata.json 파일이 생성됨

 

<데이터 파일 불러오기>

- FileStorage 클래스를 이용하여 XML/YAML/JSON 형식의 파일로부터 데이터를 읽어 오는 방법

1. FileStorage 객체를 생성

2. 실제 사용할 데이터 파일을 읽기 모드로 열기

3. FileNode 객체에 접근하려면 FileStorage::operator[]() 연산자 재정의 함수를 사용

4. 노드 이름을 이용하여 FileNode 객체를 얻어 온 후에는 FileNode 클래스의 >> 연산자 재정의 함수를 이용하여 노드에 저장된 데이터 값을 받아올 수 있음

5. 다 사용하면 fs release하기

+ readData() 함수: FileStorage 클래스를 이용하여 파일로부터 C/C++ 기본 자료형, STL 벡터, OpenCV 자료형 등을 읽어옴

 

4.5 유용한 OpenCV 기능

<마스크 연산>

- 일부 영역에 대해서만 특정 연산을 수행, 이 기능을 활용하면 두 영상을 합성할 수 있음

- 앞에서 사각형 ROI를 설정했었지만, 꼭 사각형이 아닌 임의의 모양을 갖기 위해서도 ROI를 사용할 수 있음

- 두개의 함수가 마스크 연산 지원

1.  Mat::setTo() 멤버 함수: 행렬의 픽셀 값을 설정하는데 사용했었지만 마스크 연산을 지원하는 함수,

 번째 인자 mask에 마스크 영상을 지정 가능

2. Mat::copyTo() 함수: 마스크 연산도 지원

 

<연산 시간 측정>

- 최적화 작업에서 유용하게 사용 가능. 정밀한 시간 측정 방법을 제공.

1. 

-  OpenCV에서는 getTickCount() 함수와 getTickFrequency() 함수를 사용하여 특정 연산의 수행 시간을 측정.

1단계. getTickCount() 함수: (tick) 횟수를 반환, 틱 횟수는 컴퓨터 시스템에서 발생하는 클럭(clock)처럼 매우 빠르게 증가하는 성능 측정 계수를 의미, 컴퓨터 성능에 따라 조금씩 달라짐. 반환형은 int64.

특정 연산 수행 전에 getTickCount() 함수 반환값을 저장해 놓고, 연산 후에 다시 getTickCount() 함수 반환값을 구하여 그 차이를 계산

2단계. getTickFrequency(): 1초 동안 발생하는 틱 횟수인 틱 주파수(tick frequency)로 나누는 작업을 통해 시스템 틱 주파수를 구함

2. 

- TickMeter 클래스: 안에 있는 시간 측정 멤버 함수를 이용해 시간 측정 가능. start(), stop(), time_inverse(), getTimeMilli() 등의 함수를 이용해 시간 측정 가능.

 

<유용한 OpenCV 함수 사용법>

- OpenCV 주요 함수들

- sum() 함수: Mat 행렬의 원소 합, 반환형이 Scalar

- mean() 함수: Mat 행렬의 원소 평균, 마스크 연산을 지원하므로 필요한 경우 mask 영상을 지정하여 특정 영역의 원소 평균을 구할 수 도 있음, 반환형이 Scalar

- minMaxLoc() 함수: 행렬의 최솟값, 최댓값을 찾음, 그 위치를 찾을 수도 있음

- normalize() 함수: 행렬의 노름(norm) 값을 정규화하거나 또는 원소 값 범위를 특정 범위로 정규화할 때 사용

- cvRound() 함수: 실수 값의 반올림 연산

- cvFloor() 함수: 실수의 내림을 수행

- cvCeil() 함수: 실수의 올림을 수행

 

 

 

 

 

'컴퓨터 비전(OpenCV) 스터디' 카테고리의 다른 글

230626-230702 스터디  (0) 2023.06.28
230619-25 스터디  (0) 2023.06.22
230619-25 스터디  (0) 2023.06.22
230612-18 스터디  (0) 2023.06.18
230522-28 스터디  (0) 2023.05.27