ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [OpenCV] Epipolar Geometry
    Image Geometry 2018. 2. 1. 18:57

    에피폴라 기하


    목표

    다중시점 기하의 기본이론에 관해 학습합니다.

    에피폴, 에피폴라 라인, 에피폴라 제약등에 대해 알 수 있습니다.


    기본개념

    핀홀 카메라를 사용하여 이미지를 얻을 때, 우리는 중요한 정보 즉, 이미지의 깊이를 잃어버립니다. 또는 3D에서 2D로의 변환이기 때문에 카메라에서 이미지의 각 포인트까지의 거리. 따라서 이러한 카메라를 사용하여 깊이 정보를 찾을 수 있는지 여부는 매우 중요한 질문입니다. 대답은 하나 이상의 카메라를 더 사용하는 것입니다. 우리의 눈은 스테레오 비전이라 불리는 두 개의 카메라(두 눈)를 사용하는 비슷한 방법으로 움직입니다. 이 영역에 대해 OpenCV가 제공하는 것을 살펴보겠습니다.


    (Learning OpenCV by Gary Bradsky 는 이 영역에 대해 많은 정보를 포함하고 있습니다.)


    깊이영상에 대해 진행하기전에, 먼저 다중시점 기하의 기본 개념을 이해해보겠습니다. 이 영역에서 우리는 에피폴라 기하를 다룹니다. 아래의 이미지에서 두 개의 카메라를 사용하여 동일한 장면의 이미지를 획득하는 기본 설정을 볼 수 있습니다.




    만약 우리가 왼쪽 카메라 하나만 사용한다면, OX 선위의 모든 점들이 이미지 평면상의 동일한 포인트에 투영되기 때문에 이미지에서 x에 대응하는 3D 포인트를 찾을 수 없습니다. 그러나 오른쪽 이미지를 함께 고려하면, OX 선상의 다른 포인트들이 우측 평면에서 다른점 (x')으로 투영됩니다. 따라서 이러한 두 이미지를 사용하여, 정확한 3D 포인트를 삼각화할 수 있습니다. 이것이 전반적인 아이디어 입니다.


    OX상의 다른 점들의 투영은 우측 평면에 선(l')을 형성합니다. 우리는 이것을 포인트 x에 대응하는 에피라인(epiline)이라고 부릅니다. 

    즉, 오른쪽 이미지에서 포인트 x를 찾기위해, 에피라인을 따라 검색합니다. 그것은 이 라인상의 어딘가에 있어야 합니다. (이 방법으로 색가하면, 다른 이미지에서 매칭 포인트를 찾기위해, 전체 이미지를 검색할 필요가 없고, 오직 에피라인을 따라 검색하면됩니다. 따라서 더 나은 정확도와 성능을 제공합니다.) 이것을 에피폴라 제약(epipolar constraint) 라고 부릅니다. 유사하게 모든 포인트들은 그것에 대응하는 에피라인을 다른 이미지에 가지고 있습니다. 평면 XOO' 는 에피폴라 평면(epipolar plane)이라고 불립니다.


    O와 O'은 카메라 중심입니다. 위의 설정으로부터, 우측 카메라 O'의 투영이 왼쪽이미지에서 포인트 e 상에 보여지는 것을 알 수 있습니다.

    그것은 에피폴(epipole)이라고 부릅니다. 에피폴은 카메라 중심과 이미지 평면을 통과하는 라인의 교차점입니다. 유사하게 e'은 좌측 카메라의 에피폴 입니다. 몇몇 경우에, 이미지에 에피폴이 존재하지 않을 수 있고, 이미지 밖에 존재할 수 있습니다.(한 쪽 카메라에서 다른 카메라를 볼 수 없음을 의미합니다.)


    모든 에피라인들은 에피폴을 통과합니다. 따라서 에피폴의 위치를 찾기위해, 우리는 많은 에피라인을 찾고 그들의 교차점을 찾을 수 있습니다.


    따라서 이 세션에서, 에피폴라라인과 에피폴을 찾는것에 초점을 맞춥니다. 그러나 그들을 찾기위해, 우리는 두 가지의 성분 Fundamental Matrix (F) 와 Essential Matrix (E)  더 필요합니다. Essential Matrix는 두번째 카메라의 위치를 설명하는 이동과 회전에 관한 정보를 포함합니다. 전역 좌표에서 첫 번째 카메라를 기준으로 두번째 카메라의 위치를 설명합니다. 아래의 이미지를 보세요.

    (이미지 제공: Learning OpenCV by Gary Bradsky)




    그러나 우리는 픽셀 좌표로 수행되는 측정을 선호합니다. 그렇죠? 


    Fundamental Matrix는 두 카메라의 내장 함수에 대한 정보 이외에 Essential Matrix와 동일한 정보가 포함되어 있으므로 두 카메라를 픽셀 좌표로 연결할 수 있습니다. 

    Fundamental Matrix contains the same information as Essential Matrix in addition to the information about the intrinsics of both cameras so that we can relate the two cameras in pixel coordinates. 

    (만약 우리가 rectified 이미지를 사용하고 초점거리(focal length)로 나누어 포인트를 정규화하면, F=E 입니다)

    간단히 말하면, Fundamental Matrix F는, 한 이미지의 한 점을 다른 이미지의 한 선(에피라인)으로 맵핑합니다. 

    이것은 두 이미지의 매칭포인트에서 계산됩니다. 

    Fundamental Matrix를 찾기위해 최소한 8개의 포인트가 필요합니다. (8-포인트 알고리즘을 사용하므로..)

    더 많은 포인트가 선호되고, RANSAC을 사용하여 더 강건한 결과를 얻을 수 있습니다.




    코드

    먼저 우리는 Fundamental Matrix를 찾기위해 두 이미지 사이에서 가능한한 많은 매칭을 찾아야 합니다. 이를 위해, 매쳐와 비율 테스트에 기반한 FLANN과 함께 SIFT 기술자를 사용합니다.


    이제 두 이미지로부터 최적 매치의 목록을 얻었으며, Fundamental Matrix를 찾아보도록 하겠습니다.


    다음으로 에피라인을 찾습니다. 에피라인은 첫번째 이미지의 점이 두 번째 이미지에 그려지는 것에 대응합니다. 따라서 정확한 이미지를 언급하는 것이 중요합니다. 우리는 라인들의 배열을 얻습니다. 따라서 우리는 이 라인을 이미지 상에 그리기 위한 새로운 함수를 정의합니다. 


    def drawlines(img1,img2,lines,pts1,pts2):
        ''' img1 - image on which we draw the epilines for the points in img2
            lines - corresponding epilines '''
        r,c = img1.shape
        img1 = cv2.cvtColor(img1,cv2.COLOR_GRAY2BGR)
        img2 = cv2.cvtColor(img2,cv2.COLOR_GRAY2BGR)
        for r,pt1,pt2 in zip(lines,pts1,pts2):
            color = tuple(np.random.randint(0,255,3).tolist())
            x0,y0 = map(int, [0, -r[2]/r[1] ])
            x1,y1 = map(int, [c, -(r[2]+r[0]*c)/r[1] ])
            img1 = cv2.line(img1, (x0,y0), (x1,y1), color,1)
            img1 = cv2.circle(img1,tuple(pt1),5,color,-1)
            img2 = cv2.circle(img2,tuple(pt2),5,color,-1)
        return img1,img2


    이제 우리는 두 이미지에서 에피라인을 찾고 그립니다.


    # Find epilines corresponding to points in right image (second image) and
    # drawing its lines on left image
    lines1 = cv2.computeCorrespondEpilines(pts2.reshape(-1,1,2), 2,F)
    lines1 = lines1.reshape(-1,3)
    img5,img6 = drawlines(img1,img2,lines1,pts1,pts2)
    
    # Find epilines corresponding to points in left image (first image) and
    # drawing its lines on right image
    lines2 = cv2.computeCorrespondEpilines(pts1.reshape(-1,1,2), 1,F)
    lines2 = lines2.reshape(-1,3)
    img3,img4 = drawlines(img2,img1,lines2,pts2,pts1)
    
    plt.subplot(121),plt.imshow(img5)
    plt.subplot(122),plt.imshow(img3)
    plt.show()


    아래는 결과물입니다.




    왼쪽 이미지의 모든 에피라인이 우측면에서 이미지의 바깥 점에 수렴되는 것을 볼 수 있습니다. 그것들이 만나는 포인트가 에피폴입니다. 더 나은 결과를 위해, 좋은 해상도의 이미지와 다른 비-평면 위치들이 사용될 수 있습니다.


    연습

    1. 한가지 중요한 주제는 카메라의 전방 이동입니다. 그러면 에피폴은 하나의 고정된 포인트에서 나타나는 에피라인들과 함께 동일한 위치에서 보여질 것입니다. See this discussion.

    2. Fundamental Matrix 추정은 매치들의 퀄리티와 아웃라이어등에 민감합니다. 모든 선택된 매치들이 동일한 평면상에 놓여 있을 때 성능이 나빠집니다. Check this discussion.



    Reference

    [1] https://docs.opencv.org/3.0-beta/doc/py_tutorials/py_calib3d/py_epipolar_geometry/py_epipolar_geometry.html#epipolar-geometry

Designed by Tistory.