[OpenCV] 05-10. Feature Matching + Homography to find Objects
🐍Python/OpenCV

[OpenCV] 05-10. Feature Matching + Homography to find Objects

728x90
반응형

< Feature Matching + Homography to find Objects >

이번 장에서는

  • Feature matching 과 calib3 모듈의 findHomography를 섞어서 복합적인 이미지에서 알고있는 객체를 찾아 볼 것이다.

Basics

이전 장에서는, queryImage를 사용해서 특성 포인트들을 찾고, 다른 이미지인 trainImage에서도 있는 특성 포인트를 찾고 가장 잘 맞는 매칭을 찾아냈다. 요약하자면, 객체 일부분의 위치를 찾아서 다른 뒤섞인 이미지 속에서 이를 찾아내는 것이다. 이 정보는 trainImage에서 객체를 찾기에 충분하다.

그래서 우리는 calib3d 모듈에 있는 cv2.findHomography() 를 사용할 수 있다. 만약 우리가 두 이미지로부터의 포인트 집합을 입력한다면, 이는 관점이 변환되었을 때 객체를 찾아낼 것이다. (관점이 다른 이미지에서 그 특성점을 찾아낸다는 것) 그리고 cv2.perspectiveTransform() 을 사용해서 객체를 찾을 수 있다. 변환된 것을 찾기 위해 최소 4개의 정확한 포인트를 필요로 한다.

우리는 결과에 영향을 미칠 수 있는 매칭하는 와중에 발생할 수 있는 몇 가지 오류가 있다는 것을 알았다. 이 문제를 해결하기 위해서, 알고리즘은 RANSAC 또는 LEAST_MEDIAN(flags에 의해 결정된다)를 사용한다. 정확한 판단을 제공하는 좋은 매칭은 “inlier”라고 부르고 나머지 것들은 “outlier”라고 불린다. cv2.findHomography() 는 inlier 점인지 outlier 점인지를 지정하는 마스크를 반환한다.

Code

먼저, 이미지내의 SIFT 특성을 찾고 ratio test에 적용해서 최고의 매칭을 찾는다.

import cv2
import numpy as np

qimg = cv2.imread('./images/maface1.jpg',0)   #queryImage
timg = cv2.imread('./images/ma.jpg',0)   # trainImage

sift = cv2.xfeatures2d.SIFT_create()

kp1, des1 = sift.detectAndCompute(qimg,None)
kp2, des2 = sift.detectAndCompute(timg,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)

good = []
for m,n in matches:
    if m.distance < 0.7*n.distance:
        good.append(m)

이제 우리는 객체를 찾기위해 최소 10개의 매칭(MIN_MATCH_COUNT로 설정)이 있어야한다고 조건을 설정한다. 그렇지 않다면 매칭이 부족하다는 메세지를 보여줘라.

만약 충분한 매칭이 발견되면, 두 이미지의 매칭된 키포인트들의 위치를 추출한다. 이 위치는 관점이 변환된것을 찾이 위해 사용된다. 3X3 변환 매트릭스를 얻으면, queryImage에서의 코너를 trainImage에 대응하는 코너로 변환해주기위해 사용한다. 그리고 이를 그린다!

MIN_MATCH_COUNT = 10
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 = qimg.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)

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

else:
    print("발견된 매칭이 부족합니다 - %d/%d" % (len(good),MIN_MATCH_COUNT))
    matchesMask = None

마지막으로 inliers를 그리거나(만약 객체를 성공적으로 찾았다면) 키포인트들을 매칭(객체 찾는데 실패)한다.

draw_params = dict(matchColor = (0,255,0),
                  singlePointColor = None,
                  matchesMask=matchesMask, # inliers만 그리기
                  flags=2)
res=None
res = cv2.drawMatches(qimg,kp1,timg,kp2,good,res,**draw_params)

cv2.imshow("Res",res)
cv2.waitKey(0)
cv2.destroyAllWindows()

아래 결과를 보자. 두 번째 이미지에서 객체는 흰 선으로 표시되었다.


하지만 여기서 중요한 점은 객체와 아주 똑같은 사진을 입력해야 찾을 수 있다는 점!

방향을 돌려도 인식한다는 것!


아래의 예시를 보자!


위의 예시같이 기존 trainImages내의 인물의 얼굴은 당연히 기가막히게 잘 찾는다.



하지만, 같은 인물이지만 다른 사진을 넣는다면 알지 못한다. 따라서 정말 그 이미지의 특성으로만 판단하는 것이지 사람의 얼굴을 인식한다거나 하지는 않는다. 당연한 말인게 한 장의 사진의 특성으로 수 많은 다른 인물사진을 보여주고 매칭시켜라! 라는 것이 이 방법으로는 무리인 것 같다.

인물을 인식하고 얼굴의 특성점을 찾으려면 얼굴인식쪽으로 다른 방법을 사용해야 할 것 같다. 대량의 다양한 사진으로 얼굴을 학습시켜 인식하도록 하는 것이 방법이 될 것 같다.

728x90
반응형