4.3.cube.pyでsiftモジュールが使われているが、VLfeatから提供されているsiftバイナリがもはや動かないのでOpenCVに書き換える必要がある。
ChatGPTの協力も得て書き直したのが以下。
4.3.cube.py
#!/usr/bin/python # -*- coding: utf-8 -*- from PIL import Image from pylab import * import homography import camera import cv2 import numpy as np def my_calibration(sz): row,col = sz fx = 2555.0*col/2592 fy = 2586.0*row/1936 K = diag([fx,fy,1]) K[0,2] = 0.5*col K[1,2] = 0.5*row return K def process_image(image_name, output_name): # 画像を読み込み、グレースケールに変換 image = cv2.imread(image_name) gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # SIFT機能を初期化 sift = cv2.SIFT_create() # 特徴点と記述子を検出 keypoints, descriptors = sift.detectAndCompute(gray, None) # 特徴点をファイルに保存 with open(output_name, 'wb') as f: np.save(f, descriptors) return keypoints, descriptors def match_twosided(desc1, desc2): # BFMatcherを使用して記述子間のマッチングを行う bf = cv2.BFMatcher(cv2.NORM_L2) matches = bf.knnMatch(desc1, desc2, k=2) # Lowe's ratio testを適用して良いマッチングを選択 good_matches = [] for m, n in matches: if m.distance < 0.75 * n.distance: good_matches.append(m) return good_matches # 特徴量を計算する l0, d0 = process_image('../data/book_frontal.JPG','im0.sift') l0 = np.array([l.pt for l in l0]) l1, d1 = process_image('../data/book_perspective.JPG','im1.sift') l1 = np.array([l.pt for l in l1]) # 特徴量を対応づけホモグラフィーを推定する matches = match_twosided(d0,d1) ndx = [m.queryIdx for m in matches] fp = homography.make_homog(l0[ndx,:2].T) ndx2 = [m.trainIdx for m in matches] tp = homography.make_homog(l1[ndx2,:2].T) model = homography.RansacModel() H = homography.H_from_ransac(fp,tp,model)[0] def cube_points(c,wid): """plotで立方体を描画するための頂点のリストを生成する。 最初の5点は底面の正方形であり、辺が繰り返されます """ p = [] # 底面 p.append([c[0]-wid,c[1]-wid,c[2]-wid]) p.append([c[0]-wid,c[1]+wid,c[2]-wid]) p.append([c[0]+wid,c[1]+wid,c[2]-wid]) p.append([c[0]+wid,c[1]-wid,c[2]-wid]) p.append([c[0]-wid,c[1]-wid,c[2]-wid]) # 描画を閉じるため第一点と同じ # 上面 p.append([c[0]-wid,c[1]-wid,c[2]+wid]) p.append([c[0]-wid,c[1]+wid,c[2]+wid]) p.append([c[0]+wid,c[1]+wid,c[2]+wid]) p.append([c[0]+wid,c[1]-wid,c[2]+wid]) p.append([c[0]-wid,c[1]-wid,c[2]+wid]) # 描画を閉じるため第一点と同じ # 垂直の辺 p.append([c[0]-wid,c[1]-wid,c[2]+wid]) p.append([c[0]-wid,c[1]+wid,c[2]+wid]) p.append([c[0]-wid,c[1]+wid,c[2]-wid]) p.append([c[0]+wid,c[1]+wid,c[2]-wid]) p.append([c[0]+wid,c[1]+wid,c[2]+wid]) p.append([c[0]+wid,c[1]-wid,c[2]+wid]) p.append([c[0]+wid,c[1]-wid,c[2]-wid]) return array(p).T # カメラのキャリブレーション K = my_calibration((747,1000)) # z=0の平面上の辺の長さ0.2の立方体の3Dの点 box = cube_points([0,0,0.1],0.1) # 第1の画像の底面の正方形を射影する cam1 = camera.Camera( hstack((K,dot(K,array([[0],[0],[-1]])) )) ) # 最初の点群は、底面の正方形 box_cam1 = cam1.project(homography.make_homog(box[:,:5])) # Hを使って第2の画像に点を変換する box_trans = homography.normalize(dot(H,box_cam1)) # cam1とHから第2のカメラ行列を計算する cam2 = camera.Camera(dot(H,cam1.P)) A = dot(linalg.inv(K),cam2.P[:,:3]) A = array([A[:,0],A[:,1],cross(A[:,0],A[:,1])]).T cam2.P[:,:3] = dot(K,A) # 第2のカメラ行列を使って射影する box_cam2 = cam2.project(homography.make_homog(box)) # テスト:z=0上の点を射影を変換すると同じになるはず point = array([1,1,0,1]).T print(homography.normalize(dot(dot(H,cam1.P),point))) print(cam2.project(point)) im0 = array(Image.open('../data/book_frontal.JPG')) im1 = array(Image.open('../data/book_perspective.JPG')) # 底面の正方形を2Dに射影 figure() imshow(im0) plot(box_cam1[0,:],box_cam1[1,:],linewidth=3) # Hで変換されたものを2Dに射影 figure() imshow(im1) plot(box_trans[0,:],box_trans[1,:],linewidth=3) # 3Dの立方体 figure() imshow(im1) plot(box_cam2[0,:],box_cam2[1,:],linewidth=3) show() import pickle print(K) print(f) with open('ar_camera.pkl','wb') as f: pickle.dump(K,f) pickle.dump(dot(linalg.inv(K),cam2.P),f)