ベイジアン研究所

技術(人工知能、数学等)と心理の話をしています。

【opencv-python】エピポーラ線の描画

1. 記事の目的
参考文献[2]のエピポーラ線の描画において、opencv-python 4.4.0に対応していなかったので、対応するコードを提供する。また、サンプルコードを使いやすいです形にまとめた。

2. 実行確認済み環境
Mac OS Catalina 10.15.7
Python 3.8.5
opencv-python 4.4.0.46
numpy 1.19.1
matplotlib 3.3.1

3. 実装コード
まず、図1を"lef.jpg"、図2を"right.jpg"と言う名前で、以下のコードを書いたpythonファイルと同じ場所に保存する(参考文献[2]からも入手できる)。

f:id:camelsan:20201226112251j:plain
図1 1lef.jpg
f:id:camelsan:20201226112340j:plain
図2 right.jpg
実装コードを記す。

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

def drawlines(img1, img2, lines, pts1, pts2):
    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

def main():
    img1 = cv2.imread('./left.jpg',0)
    img2 = cv2.imread('./right.jpg',0)

    sift = cv2.SIFT_create()
    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)

    good = []
    pts1 = []
    pts2 = []

    for i, (m,n) in enumerate(matches):
        if m.distance < 0.8*n.distance:
            good.append(m)
            pts2.append(kp2[m.trainIdx].pt)
            pts1.append(kp1[m.queryIdx].pt)

    pts1 = np.int32(pts1)
    pts2 = np.int32(pts2)
    F, mask = cv2.findFundamentalMat(pts1,pts2,cv2.FM_LMEDS)

    pts1 = pts1[mask.ravel()==1]
    pts2 = pts2[mask.ravel()==1]

    lines1 = cv2.computeCorrespondEpilines(pts2.reshape(-1,1,2),2,F)
    lines1 = lines1.reshape(-1,3)
    img5,img6 = drawlines(img1,img2,lines1,pts1,pts2)

    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()

if __name__ == "__main__":
    main()

pythonファイルを"fund_mat.py"と言う名前にした場合、次のコマンドで実行が可能である。

python3 fund_mat.py

4. 実行結果
次の画像が出力される。

f:id:camelsan:20201226113125p:plain
図3 出力結果

5. 参考文献
[1] OpenCV-Pythonチュートリアル/カメラキャリブレーションと3次元復元/エピポーラ幾何
エピポーラ幾何 — OpenCV-Python Tutorials 1 documentation
[2] OpenCV github
opencv/samples/data at master · opencv/opencv · GitHub