この記事の例では、参考のために画像スティッチング用のpythonopencvの特定のコードを共有しています。具体的な内容は次のとおりです。
アイデアと方法
アイデア
1、 スプライスする2つの画像の特徴点と特徴記述子を抽出します。
2、 2つの写真で対応するポイントを見つけて、それらを一致させます。
3、 十分な一致点が見つかった場合、2つの画像を一緒に接合できます。接合する前に、2番目の画像を遠近法で回転させ、見つかったキーポイントを使用して2番目の画像を1つと最初の画像に回転させる必要があります。同じ写真でつなぎ合わせることができる角度;
4、 スプライシング
5、 ステッチ後の処理により、効果が良くなります。
実装
1、 画像の特徴点と記述子を抽出するには、opencvを使用してSIFTオブジェクトを作成します。SIFTオブジェクトはDoGメソッドを使用してキーポイントを検出し、各キーポイントの周囲の領域の特徴ベクトルを計算します。実装では、SIFTよりも高速なSURFメソッドを使用でき、Hessianアルゴリズムを使用してキーポイントを検出できます。パノラマステッチ専用なので、SURFを使用する場合は、パラメータを調整したり、要点を減らしたり、128次元のベクトルではなく64次元のベクトルを取得したりすることもできます。
2、 2つの画像のキーポイントと特徴ベクトルをそれぞれ抽出した後、それらを使用して2つの画像を一致させることができます。スプライシング画像では、マッチングにKnnを使用できますが、FLANN高速マッチングライブラリを使用する方が高速であり、画像スプライシングにはFLANNのホモグラフィマッチングが必要です。
3、 ホモグラフィが一致した後、遠近法変換H行列を取得できます。この逆行列を使用して、2番目の画像で遠近法変換を実行し、最初の画像と同じ遠近法に変換して、次のステッチの準備をします。
4、 透視変換後の画像のサイズは最終的なパノラマのサイズ、右側は透視変換後の画像、左側は情報のない黒です。スプライシングプロセスは比較的簡単です。numpy配列を選択すると、最初の画像が左側に直接追加され、重なり合った部分が覆われ、スプライシングされた画像が取得されます。これは非常に高速ですが、最終的な効果はあまり良くありません。中央にセグメンテーションマークがあります。非常に明白です。 opencvガイドの画像ピラミッドコードを使用して、ステッチされた画像を処理します。画像全体が滑らかになり、中央の継ぎ目は特に急激です。
5、 ダイレクトスペルの効果はあまり良くありません。最初の画像を左側に重ねることはできますが、最初の画像とその重なり合う領域に重みを付けます。重なり合う部分は左側の画像に近く、左側の画像の重みが大きくなります。右側に近いほど、右側の回転画像の重みが大きくなり、2つが足し合わされて遷移がスムーズになり、見栄えが良くなり、遅くなります。 SURFを使用して行う場合、時間は主に特徴点の抽出とマッチングではなくスムージングに費やされます。
**python_opencv **で使用される主な関数
0、 python3.7および対応するpython-opencvに基づく
1、cv2.xfeatures2d.SURF_create ([hessianThreshold[, nOctaves[, nOctaveLayers[, extended[, upright]]]]])
この関数は、SURFオブジェクトを生成するために使用されます。使用中、速度を上げるために、hessianThresholdを適切に増やして、検出されるキーポイントの数を減らすことができます。Extended= Falseを使用すると、128次元ではなく64次元記述子のみを生成できるため、直立します。 = True、キーポイントの方向を検出しません。
2、cv2.SURF.detectAndCompute(image, mask[, descriptors[, useProvidedKeypoints]])
この関数は、画像のキーポイントと記述子を計算するために使用され、両方の画像を計算する必要があります。
3、flann=cv2.FlannBasedMatcher(indexParams,searchParams)** match=flann.knnMatch(descrip1,descrip2,k=2)**
フランファストマッチャーには2つのパラメーターがあります。1つはindexParamsで、もう1つはsearchParamsです。マニュアルで提案されている値を使用できます。一致する配列の一致を取得するためにマッチャーを作成した後、Loweによって指定されたパラメーターを参照して、一致をフィルター処理し、不良一致をフィルターで除外できます。戻り値の一致には、2つの画像の記述子距離距離、トレーニング画像(2番目の画像)の記述子インデックスtrainIdx、および照会された画像(最初の画像)の記述子インデックスqueryIdxが含まれます。
4、M,mask=cv2.findHomography(srcPoints, dstPoints[, method[, ransacReprojThreshold[, mask]]])
この関数はホモグラフィマッチングを実装します。返されるMは行列です。つまり、キーポイントsrcPointsはM変換によってdstPointsの位置に変換できます。
5、warpImg=cv2.warpPerspective(src,np.linalg.inv(M),dsize[,dst[,flags[,borderMode[,borderValue]]]])
この関数を使用して、パースペクティブ変換を実行し、パースペクティブを変更します。 srcは変換する画像、np.linalg.inv(M)は④のMの逆行列で、同じ方向の画像を取得します。
6、**a = b.copy()**ディープコピーを実現します。Pythonのデフォルトは参照によるコピーです。a= bはaがbを指すメモリです。
7、**draw_params = dict(matchColor = (0,255,0),singlePointColor = (255,0,0),matchesMask = matchMask,flags = 2),img3 = cv2.drawMatches(img1,kp1,img2,kp2,good,None,draw_params)
drawMatchesを使用して、一致の適切なキーポイントを描画します。matchMaskは、緑色の線で接続された、より適切な一致ポイントです。
コアコード
import cv2
import numpy as np
from matplotlib import pyplot as plt
import time
MIN =10
starttime=time.time()
img1 = cv2.imread('1.jpg') #query
img2 = cv2.imread('2.jpg') #train
# img1gray=cv2.cvtColor(img1,cv2.COLOR_BGR2GRAY)
# img2gray=cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)
surf=cv2.xfeatures2d.SURF_create(10000,nOctaves=4,extended=False,upright=True)
# surf=cv2.xfeatures2d.SIFT_create()#SIFTに変更できます
kp1,descrip1=surf.detectAndCompute(img1,None)
kp2,descrip2=surf.detectAndCompute(img2,None)
FLANN_INDEX_KDTREE =0
indexParams =dict(algorithm = FLANN_INDEX_KDTREE, trees =5)
searchParams =dict(checks=50)
flann=cv2.FlannBasedMatcher(indexParams,searchParams)
match=flann.knnMatch(descrip1,descrip2,k=2)
good=[]for i,(m,n)inenumerate(match):if(m.distance<0.75*n.distance):
good.append(m)iflen(good) MIN:
src_pts = np.float32([kp1[m.queryIdx].pt for m in good]).reshape(-1,1,2)
ano_pts = np.float32([kp2[m.trainIdx].pt for m in good]).reshape(-1,1,2)
M,mask=cv2.findHomography(src_pts,ano_pts,cv2.RANSAC,5.0)
warpImg = cv2.warpPerspective(img2, np.linalg.inv(M),(img1.shape[1]+img2.shape[1], img2.shape[0]))
direct=warpImg.copy()
direct[0:img1.shape[0],0:img1.shape[1]]=img1
simple=time.time()
# cv2.namedWindow("Result", cv2.WINDOW_NORMAL)
# cv2.imshow("Result",warpImg)
rows,cols=img1.shape[:2]for col inrange(0,cols):if img1[:, col].any() and warpImg[:, col].any():#オーバーラップの左端
left = col
breakfor col inrange(cols-1,0,-1):if img1[:, col].any() and warpImg[:, col].any():#オーバーラップの右端の列
right = col
break
res = np.zeros([rows, cols,3], np.uint8)for row inrange(0, rows):for col inrange(0, cols):if not img1[row, col].any():#元の画像がない場合は、回転させて塗りつぶします
res[row, col]= warpImg[row, col]
elif not warpImg[row, col].any():
res[row, col]= img1[row, col]else:
srcImgLen =float(abs(col - left))
testImgLen =float(abs(col - right))
alpha = srcImgLen /(srcImgLen + testImgLen)
res[row, col]= np.clip(img1[row, col]*(1-alpha)+ warpImg[row, col]* alpha,0,255)
warpImg[0:img1.shape[0],0:img1.shape[1]]=res
final=time.time()
img3=cv2.cvtColor(direct,cv2.COLOR_BGR2RGB)
plt.imshow(img3,),plt.show()
img4=cv2.cvtColor(warpImg,cv2.COLOR_BGR2RGB)
plt.imshow(img4,),plt.show()print("simple stich cost %f"%(simple-starttime))print("\ntotal cost %f"%(final-starttime))
cv2.imwrite("simplepanorma.png",direct)
cv2.imwrite("bestpanorma.png",warpImg)else:print("not enough matches!")
運用結果
元の画像1.jpg
元の画像2.jpg
特徴点マッチング
ダイレクトステッチと滑らかなコントラスト
効果
この記事はトピック「python画像処理操作」に含まれています。クリックして、よりエキサイティングなコンテンツを学ぶことを歓迎します。
以上が本稿の内容ですので、皆様のご勉強に役立てていただければ幸いです。
Recommended Posts