[2023-05-01] 2. OpenCV 특징점 검출과 기술
OpenCV 특징점 검출과 기술
OpenCV 특징점 클래스
- Feature2D 클래스와 파생 클래스
- Feature2D 클래스가 전체적인 특징점 클래스의 부모 클래스 역할을 수행함
- detect() : 특징점 검출
- compute() : 기술자 계산
- detectAndCOmpute() : 특징점 검출과 기술자 계산을 한번에 진행
- Feature2D 클래스를 사용하는 것이 아닌, Feature2D 클래스를 상속받은 다양한 클래스들에서 위 3가지 함수를 호출해서 사용
- Feature2D 클래스가 전체적인 특징점 클래스의 부모 클래스 역할을 수행함
- 특징점 표현을 위한 KeyPoint 클래스
- 특징점 클래스 객체 생성 함수
- Feature2D 상속 클래스들은 모두 create() 라는 이름의 정적 멤버 함수를 제공
- Ptr은 OpenCV에서 구현한 스마트 포인터 클래스
- 각각의 create() 함수는 다수의 인자를 가지지만, 디폴트 인자가 정의되어 있음
- 예를 들어 SIFT 같은 경우
영상에서 특징점 검출 함수
virtual void Feature2D::detect(InputArray image, std::vector<KeyPoint>& keypoints, InputArray mask = noArray());
- image : 입력 영상
- keypoints : (출력) 검출된 특징점 정보 (vector
자료형) - mask : 마스크 영상
검출된 특징점 그리기 함수
void drawKeyPoints(InputArray image, const std::vector<KeyPoint>& keypoints, InputOutputArray outImage, const Scalar& color = Scalar::all(-1), int flags = DrawMatchesFlags::DEFAULT);
- image : 입력영상
-
keypoints : 입력 영상에서 검출된 특징점
-
outImage : 출력 영상
- color : 특징점 색상
- flags : 특징점 그리기 방법
- DrawMatchesFlags::DEFAULT : 특징점 위치만을 표현한 작은 크기의 원
- DrawMatchesFlags::DRAW_RICH_KEYPOINTS : 특징점의 크기와 방향을 반영한 원
특징점 검출 예제 코드
#include <iostream>
#include "opencv2/opencv.hpp"
#include "opencv2/core/ocl.hpp"
using namespace std;
using namespace cv;
int main()
{
ocl::setUseOpenCL(false); // for ORB time check
Mat src = imread("lenna.bmp", IMREAD_GRAYSCALE);
if (src.empty()) {
cerr << "Image load failed!" << endl;
return -1;
}
TickMeter tm;
tm.start();
Ptr<Feature2D> detector = SIFT::create(); // SIFT, KAZE, AKAZE, ORB
// detector 변수는 SIFT 알고리즘의 객체라고 보면됨
vector<KeyPoint> keypoints; // KeyPoint 벡터 keypoints
detector->detect(src, keypoints); // 입력영상 src의 모든 SIFT 특징점을 keypoints에 저장
// detector 객체를 이용해서 특징점을 검출하기 위해서는 화살표 연산자를 사용하고 detect 함수를 입력하면 됨
tm.stop();
cout << "Elapsed time: " << tm.getTimeMilli() << "ms." << endl;
cout << "keypoints.size(): " << keypoints.size() << endl; // size()를 이용해 몇 개나 검출했는지 확인할 수 있음
Mat dst;
drawKeypoints(src, keypoints, dst, Scalar::all(-1), DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
// src 영상의 알록달록한 색으로 keypoints의 크기와 방향을 반영한 원을 표시한 것을 dst 영상에 저장함
/* for(int i = 0; i < keypoints.size(); i++) {
keypoints[i].pt // 점들의 좌표를 사용해 동그라미를 그려서 어느 위치에 특징점이 검출되었는지 확인가능
} */
imshow("dst", dst);
waitKey();
}
특징점 기술자 구하기
- 기술자 : 각각의 특징점 근방의 부분 영상을 표현하는 실수 또는 이진 벡터
- OpenCV에서는 Mat 객체로 표현
- 행 개수 : 특징점 개수
- 열 개수 : 특징점 기술자 알고리즘에 의해 정의됨
실수 기술자
- 주로 특징점 부근 부분 영상의 방향 히스토그램을 사용
- 보통 float 자료형을 사용하여 실수 정보를 저장하는 방식
- SIFT, SURF, KAZE 등의 알고리즘이 실수 기술자를 사용
- 보통 L2 norm을 사용하여 유사도를 판단함
이진 기술자(binary descriptor)
-
이진 테스트(binary test)를 이용하여 부분 영상의 특징을 기술
-
보통 uchar(8bit) 자료형을 사용하여 비트 단위로 영상 특징 정보를 저장
-
AKAZE, ORB, BRIEF 등의 알고리즘이 이진 기술자를 사용
-
이진 기술자는 해밍 거리(Hamming Distance)를 사용하여 유사도를 판단함
e.g. d1 = 1011101, d2 = 1001001 인 경우 해밍 거리는 2
특징점에서 기술자(특징 벡터) 계산 함수
virtual void Feature2D::compute(InputArray images, std::vector<KeyPoint>& keypoints, OutputArrays descriptors);
- image : (입력) 입력 영상
- keypoints : (입력) 검출된 특징점 정보(vector
자료형) - descriptors : (출력) 특징점 기술자 행렬(Mat 자료형)
특징점 검출 및 기술자(특징 벡터) 계산 함수
virtual void Feature2D::detectAndCompute(InputArray images, InputArray mask, std::vector<KeyPoint>& keypoints, OutputArrays descriptors);
- image : (입력) 입력 영상
- mask : (입력) 마스크 영상
- keypoints : (출력) 검출된 특징점 정보(vector
자료형) - descriptors : (출력) 특징점 기술자 행렬(Mat 자료형)
- useProvidedKeypoints : 인자로 전달된 keypoints 정보 사용 여부
특징점 기술자 계산 예제 코드
#include <iostream>
#include "opencv2/opencv.hpp"
#include "opencv2/core/ocl.hpp"
using namespace std;
using namespace cv;
int main()
{
ocl::setUseOpenCL(false); // for ORB time check
Mat src = imread("lenna.bmp", IMREAD_GRAYSCALE);
if (src.empty()) {
cerr << "Image load failed!" << endl;
return -1;
}
TickMeter tm;
tm.start();
Ptr<Feature2D> feature = SIFT::create(); // SIFT, KAZE, AKAZE, ORB
vector<KeyPoint> keypoints;
Mat desc;
feature->detectAndCompute(src, Mat(), keypoints, desc);
tm.stop();
cout << "Elapsed time: " << tm.getTimeMilli() << "ms." << endl;
cout << "keypoints.size(): " << keypoints.size() << endl;
cout << "desc.size(): " << desc.size() << endl;
Mat dst;
drawKeypoints(src, keypoints, dst, Scalar::all(-1), DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
imshow("dst", dst);
waitKey();
}
- SIFT 결과
- 128개의 열로 구성됨
- KAZE 결과
- 64개의 열로 구성됨
- ORB 결과
- 32개의 열로 구성됨
주요 특징점 알고리즘과 기술자 특성
- 속도가 중요하면 ORB
- 속도와 성능이 중요하면 AKAZE
- 성능이 중요하면 SIFT