728x90

 

 

 

 

내가 어쩌다 이분을 찾았는지 잘 생각은 안나지만

 

회사 생활에 필요한 노하우들을 되게 잘 설명해주시는 분이다.

 

사고법, 말하는법, 정치법 등

 

 

 

공부만 하다보니

 

정치질에 대해서 이해가 안되는 부분들이 많았는데

 

이분 영상을 보면서 많이 정리되더라 

 

 

 

 

 

 

 

300x250
728x90

 이번에는 피처 매칭과 호모그래피 탐색을 이용하여 복잡한 이미지상에 있는 물체를  찾아보겠습니다.

 

 

 지난 시간는 쿼리 이미지를 사용해서 다른 훈련 이미지상에 존재하는 특징점들을 찾았습니다. 정리하자면 다른 이미지에 존재하는 물체 일부의 위치를찾은것이라 볼수 있겠습니다. 이 정보가 있으면 훈련 이미지 상에 존재하는 물체를 찾기에 충분합니다.

 

 그러기 위해서 이번에는 calib3d 모듈에서 cv2.findHomography() 함수를 사용해보겠습니다. 두 이미지 상에서 점집합을 찾았다면 이제 그 물체의 원근 변환을 얻을수 있습니다. 그러고나서 cv2.perspectiveTransform()으로 물체를 찾겠습니다. 이 변환을 얻기 위해서는 4개의 올바른 점들이 필요합니다.

 

 매칭하는 중에 결과에 영향을 주는 에러들이 존재할수도 있지만, 이 부분은 RANSAC이나 LEAST_MEDIAN(플래그로 설정가능)을 사용해서 해결하겠습니다. 좋은 매치를 인라이어라 하고, 아닌것을 아웃라이어라 부르겠습니다. cv2.findHomography()는 인라이어와 아웃라이어 포인트들을 정리하는 마스크를 반환해줍니다.

 

 

 

import numpy as np
import cv2
from matplotlib import pyplot as plt

MIN_MATCH_COUNT = 10

img1 = cv2.imread('./res/box.png',0)          # queryImage
img2 = cv2.imread('./res/box_in_scene.png',0) # trainImage

# Initiate SIFT detector
sift = cv2.SIFT_create()

# find the keypoints and descriptors with SIFT
kp1, des1 = sift.detectAndCompute(img1,None)
kp2, des2 = sift.detectAndCompute(img2,None)

FLANN_INDEX_KDTREE = 0
index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)
search_params = dict(checks = 50)

flann = cv2.FlannBasedMatcher(index_params, search_params)

matches = flann.knnMatch(des1,des2,k=2)

# store all the good matches as per Lowe's ratio test.
good = []
for m,n in matches:
    if m.distance < 0.7*n.distance:
        good.append(m)

if len(good)>MIN_MATCH_COUNT:
    src_pts = np.float32([ kp1[m.queryIdx].pt for m in good ]).reshape(-1,1,2)
    dst_pts = np.float32([ kp2[m.trainIdx].pt for m in good ]).reshape(-1,1,2)

    M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC,5.0)
    matchesMask = mask.ravel().tolist()

    h,w = img1.shape
    pts = np.float32([ [0,0],[0,h-1],[w-1,h-1],[w-1,0] ]).reshape(-1,1,2)
    dst = cv2.perspectiveTransform(pts,M)

    img2 = cv2.polylines(img2,[np.int32(dst)],True,255,3, cv2.LINE_AA)

else:
    print("Not enough matches are found - %d/%d" % (len(good),MIN_MATCH_COUNT))
    matchesMask = None

draw_params = dict(matchColor = (0,255,0), # draw matches in green color
                   singlePointColor = None,
                   matchesMask = matchesMask, # draw only inliers
                   flags = 2)

img3 = cv2.drawMatches(img1,kp1,img2,kp2,good,None,**draw_params)

plt.imshow(img3, 'gray'),plt.show()

 

 우선 찾은 물체에 존재하는 10개의 매치들을 구합니다. 충분히 매치들을 찾았다면, 두이미지에 존재하는 매치된 키포인트의 위치들을 추출하겠습니다.

 

 

  이제 이 매치들을 사용해서 원근 변환을 찾아보겠습니다. 3 x3 크기의 변환 행렬을 얻을건데, 이 행렬을 사용해서 쿼리 이미지의 키포인트(코너)들을 훈련 이미지 상에 대응지점으로 변환시킬수 있습니다. 

 

 findHomography로 변환 행렬을 구하고, 쿼리 이미지의 코너들을 원근 변환 행렬로 훈련 이미지 상에 나타내고 이를 직선으로 이어줍시다.

 

마지막으로

 

매치들을 그리면

 

 

 

 

 

 

300x250
728x90

시간이 지났으니

 

오늘이 아니라 어재 oj tube님이 실시간 방송을 하시는걸 잠깐 봤다.

 

 

 

중간에 어느 학생이 프로젝트를 해야할지 이론 공부를 해야할지 질문 하더라

 

나도 학교를 다니는동안 그런 고민은 했지만

 

급한마음에 뭔가에 만드는데 급급했지 이론공부를 (하려고했으나) 잘 하지는 못했었다.

 

 

 

 

일단 oj tube님의 답은

 

프로젝트를 시작하려고해도 이론을 모르면 할수있는게 없으니

 

이론을 공부해야한다고 말씀하셨던것 같다.

 

 

 

 

이는 특히 피신 과정을 거치면서

 

나는 삽질만 많이했지 제대로 알지 못했다는 생각을 많이하겠다.

 

학교를 다니는동안 뭔가 만들어보겠다고 (+주위의 심한 압박) 열심히 삽질했지만

 

삽질만했지 빌드하나하는데 몇주간의 시간을 소모한적도 있엇고

 

 

 

 

 

 

 

그렇게 시간을 많이 낭비 하고보다보니 공감되는 부분이 많았다.

 

 

 

 

그런 이유로 이렇게 이론 공부를 많이하고 있는데

 

이제 좀 프로젝트를 시작해보고 싶지만

 

이론에 끝이없으니 어느정도 공부해야하는가가 문제다.

 

 

300x250
728x90

이번 시간에는

 

하나의 이미지가 주어질때 다른것과 어떻게 특징을 매치시키는지 배워봅시다.

 

또, 브루트포스 매처와 플란 매처를 사용해 봅시다.

 

 

 

브루트 포스 매처의 기본 basic of brute-force matcher

 

 브루트 포스 매처는 단순합니다. 첫 집합에서 하나의 특징 기술자를 주어지면 거리 계산 방법으로 두번째 집합에 존재하는 모든 특징들과 매치시켜봅니다. 그리고 가장 가까운것을 반환해줘요.

 

 BF 매처에서는 처음 BF매처를 생성시키고 (cv2.BFMatcher())) 여기서 2개의 옵션 파라미터를 줄수 있습니다. 첫번째 옵션은 거리 측정 방법을 명시해주는데 넘어가고, 두번쨰 파라미터는 교차 검증을 하는것으로 기본적으로 false로 되어있습니다.

 

  매처에서는 A 집합에서 i번째 기술자와 B 집합에서 j번째 기술자가 서로 잘맞는지 매치 결과를 반환해주는데, 같은 집합에 대해 두 특징을 한다면 서로 잘 될거고 일관된 결과를 보여줄겁니다.

 

  일단 매처가 만들어지고 나면, 두 중요한 방법으로 BFMatcher.match()와 BFMatcher.knnMatch()가 있습니다. 첫번째는 최적의 매치를 반환하고, 두번째는 사용자가 지정한 k개만큼의 최적의 매치를 반환해줍니다. 하고싶은 데로 하시면 되겠습니다.

 

 그 다음 키포인트를 그리기 위해서 cv2.keypoints()를 사용했지만 cv2.drawMatches()를 사용해서 매치를 그릴수가 있겠습니다. 이걸 사용하면 두 이미지가 평행하게 놓여지고, 첫번쨰 이미지에서 두번째 이미지로 최적의 매치를 하는 선을 그려줄겁니다. k개의 최적 매치에 대해서 cv2.drawMatchsKnn도 사용할수 있겠습니다.

 

 이제 SURF와 OR의 예시를 한번 보겠습니다

 

 

 

 

 

 

ORB 기술자를 이용한 브루트포스 매칭

 

 두 이미지 사이 피처를 매칭시키는 간단한 예시를 보겠습니다. 이 경우에서 쿼리 이미지와 훈련 이미지가 있는데요. 피처 매칭을 사용해서 트레이닝 이미지에 쿼리 이미지가 어디있는지 찾겠습니다.

 

 우선 시프트 기술자를 사용해서 피처를 매치시켜보겠씁니다. 여기서 이미지를 읽고 기술자를 찾겠습니다.

 

 

 다음으로 할일은 BFMatcher 객체를 생성해서 거리는 cv2.NORM_HAMMING그리고, 더나은 결과를 얻도록 crossCheck를 해줍시다.

 

 10개를 찾아 띄워주면 아래의 결과를 얻을수 있겠습니다.

 

import numpy as np
import cv2
from matplotlib import pyplot as plt

img1 = cv2.imread('./res/box.png',0)          # queryImage
img2 = cv2.imread('./res/box_in_scene.png',0) # trainImage
img3 = img1
# Initiate SIFT detector
orb = cv2.ORB_create()

# find the keypoints and descriptors with SIFT
kp1, des1 = orb.detectAndCompute(img1,None)
kp2, des2 = orb.detectAndCompute(img2,None)

# create BFMatcher object
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)

# Match descriptors.
matches = bf.match(des1,des2)

# Sort them in the order of their distance.
matches = sorted(matches, key = lambda x:x.distance)

# Draw first 10 matches.
img3 = cv2.drawMatches(img1,kp1,img2,kp2,matches[:10], img3,flags=2)

plt.imshow(img3),plt.show()

 

 

 

 

 

플란 기반 매처 FLANN based Matcher

 

 FLANN은 Fast Library for Approximate Nearest Neighbors를 말하며, 크고 고차원 데이터에서 고속 최근접 탐색을 위해 최적화된 알고리즘들의 집합을 가지고 있습니다. 많은 데이터셋에서 BFMatcher보다 더 빠르게 동작하므로 이번에는 플란 기반 매처를 사용해보겠습니다.

 

 

 플란 기반 매처를 사용하려면, 어떤 알고리즘을 사용할지 명시하는 딕셔너리 두개가 필요합니다. 첫번째는 인덱스 파라미터로 FLANN 문서에 자세히 설명되어있습니다. 

 

import numpy as np
import cv2
from matplotlib import pyplot as plt

img1 = cv2.imread('./res/box.png',0)          # queryImage
img2 = cv2.imread('./res/box_in_scene.png',0) # trainImage

# Initiate SIFT detector
sift = cv2.SIFT_create()

# find the keypoints and descriptors with SIFT
kp1, des1 = sift.detectAndCompute(img1,None)
kp2, des2 = sift.detectAndCompute(img2,None)

# FLANN parameters
FLANN_INDEX_KDTREE = 0
index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)
search_params = dict(checks=50)   # or pass empty dictionary

flann = cv2.FlannBasedMatcher(index_params,search_params)

matches = flann.knnMatch(des1,des2,k=2)

# Need to draw only good matches, so create a mask
matchesMask = [[0,0] for i in range(len(matches))]

# ratio test as per Lowe's paper
for i,(m,n) in enumerate(matches):
    if m.distance < 0.7*n.distance:
        matchesMask[i]=[1,0]

draw_params = dict(matchColor = (0,255,0),
                   singlePointColor = (255,0,0),
                   matchesMask = matchesMask,
                   flags = 0)

img3 = cv2.drawMatchesKnn(img1,kp1,img2,kp2,matches,None,**draw_params)

plt.imshow(img3,),plt.show()

 

 

300x250
728x90

드디어 ORB 특징을 정리하게 되었다.

 

이전에 비주얼 슬램을 공부할떄 ORB 특징을 사용한다고 했는데

 

ORB 특징에 대해 이해하기가 힘들더라

 

다시한번보자

 

 

 

ORB Oriented Fast and Rotated BRIEF

 

 OpenCV 연구자로서 가장 중요한 것중 하나로 ORB를 꼽을수 있겠습니다. 이 알고리즘은 Ethan Rublee이 ORB: SIFT나 SURF의 효율적 대안(ORB:An efficient alternative to SIFT or SURF) 이라는 논문에서 2011년에 소개되었습니다.

 

 이 논문 내용은 SIFT나 SURF보다 비용 계산과 매칭 성능 측면에서 좋은 대안임을 보여주고 있습니다. 특히 SIFT와 SURF는 특허로 되어있어 비용을 지불해야되지만 ORB는 그런게 없슴다.

 

 ORB는 기본적으로 FAST 키포인트 검출기와 BRIEF 기술자를 조합하여 성능을 개선한 변형물이라 할수 있겠습니다. 먼저 FAST로 키포인트를 찾아내고, 그다음 맨 위에 있는 N개의 점들을 찾기위해 해리스 코너를 사용하겠습니다. 여기서 멀티 스케일 피처를 만들도록 피라미드를 사용할수도 있겠습니다.

 

 여기서 문제는 FAST는 방향을 계산하지 않는것인데 어떻게 회전 불변이 가능할까요? 저자는 여기서 변형을 해주었습니다.

 

 ORB에서는 코너를 가진 패치 중심의 가중화된 강도를 계산하고, 이 코너점에서 중앙으로 향하는 벡터의 방향을 방위로 보고 있습니다. 회전 불변량을 개선하기 위해서, 반지름의 r인 원형 공간에 존재하는 x와 y에 대한 모멘트를 계산하겠습니다. 

 

 이제 기술자를 넘어와서보면 ORB는 BRIEF 기술자를 사용하고 있습니다. 하지만 BRIEF는 회전 변화에 좋지 않은 성능을 보이고 있어, 키포인트의 방향에 따라 브리프를 회전시켜줍니다.

 

 위치 (x_i, y_i)에서 n개의 이진 특징 집합에 대해 테스트를 하기 위해 2 x n 형태의 행렬 S(이 픽셀들의 좌표)를 정의하겠습니다. 

 

 ORB는 각도를 2pi/30 (12개)로 이산화시키고, 미리 계산한 BIREF 패턴의 룩업 테이블을 만들어 줍니다. 키포인트 방향 theta가 일관될수록 올바른 점들의 집합 S_theta가 이 기술자를 계산하는데 사용되겠습니다.

 

 BRIEF는 각 비트 특징들이 고분산과 평균이 0.5정도 되는 특성을 가지고 있습니다.  하지만 키포인트 방향으로 향하면 기존의 속성을 잃어버리고 더 분산됩니다. 여기서 고 분산인 경우 입력에 대해 다르게 반응하여 특징을 더 차별하게 만들어 버립니다.

 

 다른 바람직한 특성은 각 테스트들은 결과에 영향을 주기 때문에 테스트의 상관관계를 해재하여야 합니다. 이를 위하여 ORB는 탐욕 탐색을 하여 모든 가능한 이진 시험을 수행하여 고분산과 평균이 0.5, 상관관계가 없는 값들을 찾으며 이를 rBRIEF라 합니다.

 

 

import numpy as np
import cv2
from matplotlib import pyplot as plt

img = cv2.imread('./res/simple.jpg',0)
img2 = img

# Initiate STAR detector
orb = cv2.ORB_create()

# find the keypoints with ORB
kp = orb.detect(img,None)

# compute the descriptors with ORB
kp, des = orb.compute(img, kp)


img = cv2.drawKeypoints(img,kp,img)

# draw only keypoints location,not size and orientation
img2 = cv2.drawKeypoints(img2,kp,img2, flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)

plt.subplot(121), plt.imshow(img)
plt.subplot(122), plt.imshow(img2)
plt.show()

 

300x250
728x90

BRIEF Binary Robust Independent Elementary Feature

 

 지난 시간에 SIFT 기술자가 128차원의 벡터로 되어있다고 했습니다. 한 키포인터의 경우 여기서 부동 소수점을 사용하기 떄문에 기본적으로 512바이트를 차지하고 있고, SURF의 경우 (64차원이므로) 256바이트를 차지하게 됩니다.

 

 그렇다보니 수천개의 특징 백터를 생성하는경우 많은 공간을 차지하게되고 제한된 자원을 가진 경우 실행하기 힘든 문제가 있습니다. 그리고 메모리가 더 많이 필요할수록 매칭하는데 더 많은 시간이 걸리게 되기도 하구요.

 

 하지만 이런 모든 차원들이 실제 매칭하는데 필요한건 아닙니다.  주성분 분석 PCA나 선형 판별 분석 LDA같은 방법으로 그걸 압축시킬수도 있고, LSH Locality Sensitive Hashing을 사용하여 SIFT 기술자를 이진 문자열로 만들수도 있겠습니다. 이러한 이진 문자열들은 해밍 거르로 피처 매칭하는데 사용되기도 하는데 이를 통해 고속화가 될수 있기 때문입니다. 하지만 우선 기술자를 찾아야 해싱이 가능하니 메모리 문제를 해결한다고는 하기 어렵습니다.

 

 BRIEF는 이 개념을 사용한건데, 기술자를 찾지 않은 상태에서 바로 이진 문자열을 찾아내는 방법이라 할수 있습니다. 이 방법에서는 스무스해진 이미지 패치를 가지고 위치 쌍 n_d(x, y)집합에서 선택합니다. 그러고 나서 일부 픽셀 강도 비교가 됩니다.

 

 예를 들자면 첫 위치 쌍을 p, q라 하겠습니다. 만약 I(p) < I(q)이면 결과를 1 아니면 0으로 하겠습니다. n_d 위치쌍에 존재하는 모든 픽셀들에다가 사용하면 n_d 차원의 비트문자열을 얻게 됩니다.

 

 n_d는 128, 256, 512바이트(길이로 16, 32, 64)가 될수 있으며 opencv에서는 모두 사용가능합니다. 하지만 기본 값으로는 256으로 설정되어있어요. 이 비트스트링을 얻으면 이 기술자들을 매칭시키는데 해밍 거리를 사용할수 있겠습니다.

 

 중요한 점은 BRIEF는 특징 기술자이지, 특징을 찾는데 어떠한 방법을 제공하고 있지는 않습니다. 그래서 SIFT, SURF 같은 다른 특징 검출기를 사용해야 합니다.

 

 정리하자면 BRIEF는 빠른 특징기술자를 계산하고 매칭하는 방법이라 할수 있겠고, 큰 이미지 회전만 아니라면 좋은 인식성능을 얻을수가 있겠습니다.

 

 

 

 

정리하면

- 일단 BRIEF는 특징 기술자 종류 중 하나

- SIFT나 SURF 기술자들은 너무 커서 실시간으로 돌리기힘듬

- 알고리즘 이해하기는 어려우나 키포인트에 대한 이진 문자열을 만드는데, 키포인트 주위 쌍으로 이진값을 할당

- 이렇게 만든 비트스트링으로 나중에 매칭시 해밍 거리를 구하는데 사용 가능

 

 

import numpy as np
import cv2
from matplotlib import pyplot as plt

img = cv2.imread('./res/home.jpg',0)
img2 = np.copy(img)
img3 = np.copy(img)

# Initiate FAST object with default values
surf = cv2.SIFT_create()

#find keypoints and descriptors directly
surf_kp, surf_desc = surf.detectAndCompute(img, None)
# Initiate BRIEF extractor
brief = cv2.xfeatures2d.BriefDescriptorExtractor_create()

img2= cv2.drawKeypoints(img2, surf_kp, img2,flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)

print("surf_desc.shape : ", surf_desc.shape)

# compute the descriptors with BRIEF
brief_kp, brief_desc = brief.compute(img, surf_kp)

img3= cv2.drawKeypoints(img3, brief_kp, img3,flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)

print("brief_desc.shape : ", brief_desc.shape)

plt.subplot(121), plt.imshow(img2)
plt.subplot(122), plt.imshow(img3)

plt.show()

본 코드에서는 기존 예제와는 달리

 

SIFT를 이용해 키포인트들을 검출하고

 

SIFT 기술자와 BRIEF 기술자를 띄워봤다

 

 

 

 

 

 

 

이미 서프로 찾은 키포인트에서 기술자를 해선지

 

 

확대해서 봐도

 

서프의 기술자와 브리프의 기술자 사이의 차이를 모르겠더라

 

대신 기술자의 형태를 출력해보니

 

기존의 서프 기술자가 128차원인것에 비해

브리프의 기술자는 32차원밖에 소모되지 않는다.

 

잘은 모르겟지만 크기는 많이 줄은듯 하다.

 

 

300x250
728x90

이전에 공부하면서

 

전기를 측정하는 이상한 기계를 자주보곤했지만

 

이게 뭘하는지 몰랐다.

 

 

 

그러다보니 이계 전압같은 신호를 측정하는 장치라고 하더라

 

기계들은 0101 기계어 신호로 동작하는데

 

이게 전압으로 이렇게 보내는거고 

 

이런 신호를 측정하는 장치가 오실로스코프라 하더라

 

 

 

 

 

 

하지만 전기전자를 만질 일이 잘없으니

 

오실로스코프라는게 있구나 하고

 

그냥 넘어가고 말았다.

 

 

 

 

 

 

그러다가 요즘 프로토타이핑을 하면서

 

아두이노로 신호를 빵빵 쏴주는데 이거를 볼수 없으니까 답답하더라

 

그래서 이걸 보고싶은 마음에 오실로스코프를 한번 사봐야되겠다 그래서

 

 

 

 

 

 

찾던중 휴대용 오실로스코프를 찾게 되었고

 

저렴한 제품으로

DSO FNIRSI PRO

을 찾았다.

 

 

 

 

 

 

 

더 저렴한 제품도 있지만 측정 가능한 범위도 짧고 일반 어댑터로 충전하지만

 

그래도 조금은 대역폭도 크고, 

 

usb로 충전된다!

 

https://ko.aliexpress.com/item/32973233356.html?spm=a2g0o.productlist.0.0.17a76e9fDh9Zuj&algo_pvid=df8874ff-07a8-4a40-9d85-9a6bf2e0c041&algo_expid=df8874ff-07a8-4a40-9d85-9a6bf2e0c041-0&btsid=0ab6fa7b15974972955122825e49ed&ws_ab_test=searchweb0_0,searchweb201602_,searchweb201603_

 

 

 

 

 

 

300x250
728x90

지금은 프로그래밍이라기 보단

 

컴퓨터 과학 전반을 공부하는 꾸준히 공부하고 있다.

 

하지만 공부만 하면서 내가 인정받는 사람이 될수 있을까 확신이 안될때가 많다

 

그러다가 가끔 오제이 튜브님의 영상을 가끔보는대

 

 

 

 

오늘 찾은 와닫는 영상

 

"방법을 알려줘도 인정 받는 프로그래머가 되지 못하는 이유"

 

결론부터 푸시업 10번을 5년만 할수 있으면 좋은 개발자가 수 있다.

 

작은 일도 꾸준히 해야된다고한다

 

그런 점에서는 현재 잘하고 있는중이다.

 

지금 블로그에다가 아무리 짧은 내용이라도 조금이라도 (엉터리 글이나마) 올리지 않는다면

 

불편한 정도로 습관이 들고 말았다.

 

 

 

내용은 아래와 같다.

 

 

 

 

 

1. 실력이 있어야 된다

 -> 절대적 시간의 투자

  - 재능에 따라서 시간 량이 바뀔수 있으나. 힘듬

  => 부자들이 부자가 되는 방법을 알려줘도 알수없음

 

2. 습관 처럼 들이기 힘듬

중략

 

 

 

 

 

괜찬은 프로그래머가 될 사람은 정해져 있다.

- 가장 추천받은 덧글. 내용 정리

 

 

 

300x250
728x90

이전에 본 특징 검출기들은 대부분 좋지만, 실시간 어플에서 사용하기에는 충분히 빠르지는 않습니다. 그래서 SLAM에서 사용하기 좋은 알고리즘으로 FAST가 있습니다.

 

 FAST Feature from Accelerated Segment Test 알고리즘은 에드워드 로스텐과 톰 드루몬드가 2006년에 재안했는데요.  이알고리즘을 간략하게 정리해보겠습니다.

 

 

FAST를 이용한 특징검출

 

1. 관심점 특정 픽셀 p를 선택하고, 이 픽셀의 강도를 I_p라 합시다.

2. 적절한 임계치 t를 설정해 줍시다.

3. 테스트할 p 주위의 16개의 픽셀을 선정합니다.

4. 위 이미지의 원에서 I_p +t보다 더 밝은 n개의 연결된 픽셀들이 존재하거나 I_p - t 보다 어두운 n개의 연결댜ㅚㄴ 픽셀들이 존재한다면 픽셀 p는 코너라고 판단하겠습니다. 위 예시에서 n은 12가 됩니다.

5. 여기다가 코너가 아닌경우를 제거하기 위해서 고속의 테스트가 진행됩니다. 이 테스트에서는 4개의 픽셀만 조사하는데요 1, 9, 5, 13번 픽셀을 보고, 이들이 더 밝은지 어두운지 보겠습니다. p가 코너라면 적어도 3개는 I_p + t보다 밝거나 I_p -t보다 어두울 겁니다. 하지만 아니라면 p는 코너가 아니라고 할수 있겠습니다. 이 점 p주위의 모든 픽셀들에대해서 수행할수도 있겠지만 고성능을 내기에는 부족하지만 이렇게 사용합니다.

 

import numpy as np
import cv2
from matplotlib import pyplot as plt

img = cv2.imread('./res/home.jpg',0)
img2 = img
# Initiate FAST object with default values
fast = cv2.FastFeatureDetector_create()

# find and draw the keypoints
kp = fast.detect(img,None)
img2 = cv2.drawKeypoints(img, kp,img2, color=(255,0,0))

plt.subplot(121), plt.imshow(img, cmap="gray")
plt.subplot(122), plt.imshow(img2)
plt.show()

 

 

 

300x250
728x90

 지난번에는 키포인트를 검출하고, 기술하는 SIFT 알고리즘을 살펴보았습니다. 문제는 이 알고리즘이 매우 느리다는 점인데 2006년에 이를 개선한 SURF: Speed Up Robust Feature라는 논문이 나왔는데, 이름 그대로 SIFT의 가속화된 버전이라 할수 있겠습니다.

 

 SIFT에서는 다양한 스케일 공간에대해서 LoG를 근사한 가우시안 차 영상을 사용합니다. SUFT는 여기서 더 나아가 LOG를 박스 필터로 근사해서 사용합니다. 아래의 그림이 근사한 예시를 보여주고 있는데요. 이 근사의 가장 큰 이점은 박스 필터를 컨볼루션하면 적분 영상 계산이 매우 쉬워집니다. 그리고 다른 스케일에서 적용할수 있겠습니다.

 

 

 

 방향을 배정하기 위해서 SURF는 수평과 수직 방향에 대해 크기가 6s인 웨이블릿 응답을 사용하는데요.

 

* 웨이블릿이란?

- 0을 중심으로 증가 감소를 반복하는 진동. 아래의 그림과 같이 짧은 형태로 기존의 신호에 컨볼루션하여 모르는 정보를 추출하는데 사용할 수 있음.

https://ko.wikipedia.org/wiki/%EC%9B%A8%EC%9D%B4%EB%B8%94%EB%A6%BF

 

 이들을 아래의 이미지에 플로팅시키면 주 방향 dorminant orientation은 60도의 방향의 윈도우를 슬라이딩하여 모든 응답의 합으로 구할수 있는데요, 여기서 주의깊게 볼점은 적분 영상으로 웨이블릿 응답을 얻을수 있다는 점입니다.

 

 많은 어플리케이션에서 회전 불변이 요구되지는 않고 있으니 SURF에서는  방향을 계산하지 않고 속도를 더 높일수 있도록 하는 기능도 제공하고 있습니다.

 

 

 특징 기술에 있어서 SURF는 수직, 수평 방향에 대해 웨이블릿 응답을 사용하고 있습니다.  키포인트 주위로 20 x 20형태의 이웃을 가지며, 이들을 4 x 4 형태의 하부 영역으로 나눕니다. 각 하부영역에 대해서 수평, 수직 방향 웨이블릿 응답을 얻고, 그 결과를 아래의 형태를 가진 백터로 만들어 줍시다.

 

 

 이 벡터는 SURF 특징 기술자로 총 64개으 ㅣ차원이 되겠습니다. 차원도 작고, 고속 계산과 매칭이 가능하나 구분 하기 좋은 특징들을 만들어 줍니다.

 

 

 

import cv2
from matplotlib import pyplot as plt

img = cv2.imread("./res/home.jpg", 0)
#set hessian threshold to 400
surf = cv2.SIFT_create()

#find keypoints and descriptors directly
kp, desc = surf.detectAndCompute(img, None)

img2 = cv2.drawKeypoints(img, kp, None, (255, 0, 0), 4)
plt.imshow(img2)
plt.show()

 

 

 

 

300x250

+ Recent posts