画像パノラマステッチには、特徴点の抽出とマッチング、画像の登録、画像の融合の3つの部分が含まれます。
1、 SIFTベースの特徴点の抽出とマッチング
Siftを使用して、画像の局所的な特徴を抽出し、スケールスペース内の極値を見つけ、その位置、スケール、および方向の情報を抽出します。
具体的な手順:
1 )ガウス差分ピラミッド(DOGピラミッド)を生成し、スケールスペースを構築します
2 )。空間極値検出(キーポイントの予備調査)
3). 安定したキーポイントの正確な配置
4 )。安定したキーポイント方向情報の配布
5). キーポイントの説明
6). 特徴点マッチング
2、 画像登録
画像レジストレーションは、ステッチする画像間のオーバーラップ領域とオーバーラップ位置を決定する技術であり、画像ステッチ全体の中核です。このセクションでは、特徴点に基づく画像登録方法を使用します。つまり、画像シーケンス間の変換マトリックスは、パノラマ画像のモザイクを完成させるために点のペアを照合することによって構築されます。
変換行列Hの解は画像レジストレーションの中核であり、その解のアルゴリズムフローは次のとおりです。
1 )各画像の特徴点を検出します。
2 )特徴点間のマッチングを計算します。
3 )画像間の変換行列の初期値を計算します。
4 )H変換マトリックスを繰り返し改良します。
5 )ブートマッチング。推定されたHを使用して、エピポーラ線の近くの検索領域を定義し、特徴点の対応をさらに決定します。
6 )対応するポイントの数が安定するまで、繰り返し4)と5)を繰り返します。
画像シーケンス間の変換を投影変換とします
Hマトリックスの8つのDOFパラメーターhi =(i = 0,1、...、7)は、4セットの最適なマッチングを使用して計算でき、これを初期値として使用します。
このセクションでは、画像登録の精度を向上させるために、RANSACアルゴリズムを使用して画像変換マトリックスを解決および改良し、より優れた画像モザイク効果を実現します。 RANSACアルゴリズムのアイデアはシンプルで巧妙です:最初に、2つのポイントがランダムに選択され、これらの2つのポイントが直線を決定し、直線の特定の範囲内のポイントはこの直線のサポートと呼ばれます。このランダムな選択を数回繰り返し、サンプルポイントセットのフィッティングとしてサポートセットが最大の直線を確認します。フィッティングの誤差距離内のポイントは内部ポイントと見なされ、一貫したセットを構成します。それ以外の場合は、外部ポイントです。アルゴリズムの説明によると、外側の点の数が少ない場合、外側の点を含むランダムに選択された初期点セットによって決定された線はあまりサポートされないことがすぐに判断できます。外側の点の割合が多すぎると、 RANSACアルゴリズムが失敗しました。直線フィッティングの例では、ポイントセットから直線を決定するために少なくとも2つのポイントが必要です。遠近法変換の場合、このような最小セットには4つのポイントが必要です。
3、 画像融合
カメラと光の強さの違いにより、画像内や画像間で明るさが不均一になり、スプライスされた画像が明暗に切り替わるため、観察に大きな不便が生じます。明るさとカラーバランスの処理、通常の処理方法は、カメラの照明モデルを介して画像内の照明の不均一性を修正し、次に2つの隣接する画像の重なり合う領域間の関係を介して隣接する2つの画像間の関係を確立することですヒストグラムマッピングテーブル、マッピングテーブルを介して、2つの画像の全体的なマッピング変換を実行し、最終的に全体的な明るさと色の一貫性を実現します。
実装:
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
if __name__ =='__main__':
top, bot, left, right =100,100,0,500
img1 = cv.imread('1.jpg')
img2 = cv.imread('2.jpg')
srcImg = cv.copyMakeBorder(img1, top, bot, left, right, cv.BORDER_CONSTANT, value=(0,0,0))
testImg = cv.copyMakeBorder(img2, top, bot, left, right, cv.BORDER_CONSTANT, value=(0,0,0))
img1gray = cv.cvtColor(srcImg, cv.COLOR_BGR2GRAY)
img2gray = cv.cvtColor(testImg, cv.COLOR_BGR2GRAY)
sift = cv.xfeatures2d_SIFT().create()
# find the keypoints and descriptors with SIFT
kp1, des1 = sift.detectAndCompute(img1gray, None)
kp2, des2 = sift.detectAndCompute(img2gray, None)
# FLANN parameters
FLANN_INDEX_KDTREE =1
index_params =dict(algorithm=FLANN_INDEX_KDTREE, trees=5)
search_params =dict(checks=50)
flann = cv.FlannBasedMatcher(index_params, search_params)
matches = flann.knnMatch(des1, des2, k=2)
# Need to draw only good matches, so create a mask
matchesMask =[[0,0]for i inrange(len(matches))]
good =[]
pts1 =[]
pts2 =[]
# ratio test as per Lowe's paper
for i,(m, n)inenumerate(matches):if m.distance <0.7*n.distance:
good.append(m)
pts2.append(kp2[m.trainIdx].pt)
pts1.append(kp1[m.queryIdx].pt)
matchesMask[i]=[1,0]
draw_params =dict(matchColor=(0,255,0),
singlePointColor=(255,0,0),
matchesMask=matchesMask,
flags=0)
img3 = cv.drawMatchesKnn(img1gray, kp1, img2gray, kp2, matches, None,**draw_params)
plt.imshow(img3,), plt.show()
rows, cols = srcImg.shape[:2]
MIN_MATCH_COUNT =10iflen(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 = cv.findHomography(src_pts, dst_pts, cv.RANSAC,5.0)
warpImg = cv.warpPerspective(testImg, np.array(M),(testImg.shape[1], testImg.shape[0]), flags=cv.WARP_INVERSE_MAP)for col inrange(0, cols):if srcImg[:, col].any() and warpImg[:, col].any():
left = col
breakfor col inrange(cols-1,0,-1):if srcImg[:, 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 srcImg[row, col].any():
res[row, col]= warpImg[row, col]
elif not warpImg[row, col].any():
res[row, col]= srcImg[row, col]else:
srcImgLen =float(abs(col - left))
testImgLen =float(abs(col - right))
alpha = srcImgLen /(srcImgLen + testImgLen)
res[row, col]= np.clip(srcImg[row, col]*(1-alpha)+ warpImg[row, col]* alpha,0,255)
# opencv is bgr, matplotlib is rgb
res = cv.cvtColor(res, cv.COLOR_BGR2RGB)
# show the result
plt.figure()
plt.imshow(res)
plt.show()else:print("Not enough matches are found - {}/{}".format(len(good), MIN_MATCH_COUNT))
matchesMask = None
**実験結果: **
1、 屋内シーン:
元の画像1
元の画像2
接合後:
2、 屋外シーン:
シーン1:
元の画像1
元の画像2
接合後:
シーン2:
元の画像1
元の画像2
接合後:
シーン3:
元の画像1
元の画像2
接合後:
総括する:
この論文では、2つの画像を屋内と屋外の状況でパノラマビューでステッチし、屋内の状況でステッチ効果が優れていることがわかりました。屋外シーン1の場合、2つの画像は近距離と遠距離の組み合わせです。2つの画像をスプライスした後、近くの画像をある程度拡大して傾けます。シーン2では、2つの画像は両方とも遠景であり、スプライス効果は変わりません。悪くはありませんが、ステッチ画像の中央と上部にステッチシームがあります。シーン3は、さまざまな輝度レベルでの画像のステッチです。ステッチ画像には明らかな明暗のギャップがあり、ステッチシームは明らかに良くありません。一緒に接合すると、重ならない場所がたくさんあります。
この実験では、最初はopencv-contrib 3.4.5バージョンを使用しましたが、siftの特許制限のために使用できず、opencv-contriv3.4.2コードを問題なく実行できます。方法:最初にopencvの現在のバージョンをアンインストールし、以下をインストールします。
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple opencv-contrib-python==3.4.2.16
この記事はトピック「python画像処理操作」に含まれています。クリックして、よりエキサイティングなコンテンツを学ぶことを歓迎します。
以上が本稿の内容ですので、皆様のご勉強に役立てていただければ幸いです。
Recommended Posts