コンピュータービジョンを使用して、複数の写真を1つの長い写真に接着します

以前の記事では、ラベルをアンラップするための6ポイントの方法、ニューラルネットワークトレーニングする方法について説明しましたこの記事では、さまざまな角度から作成されたフラグメントを1つの長い画像に接着する方法について説明します。





ラベルは、前の記事で説明したニューラルネットワークによって事前にセグメント化され、展開されます。







接着は一般的にどのように機能しますか? 2枚の重なり合う写真を撮り、相互シフトを計算し、一方を他方の上に重ねる必要があります。非常に単純に聞こえますが、各手順を見ていきましょう。



相互シフトを計算するには、両方の画像に存在するいくつかのオブジェクトを見つけて、ある画像から別の画像へのポイントの変換を何らかの方法で計算する必要があります。このシフトは、変換マトリックスで表すことができます。変換マトリックスでは、マトリックスの要素が、スケーリング、変換、回転など、一度に複数の変換をエンコードします。ウィキペディアには、どの要素がどのように変換に影響するかを示す優れた表



があります



下の図でわかるように、十分な数の一般的なオブジェクト







があります。ただし、選択したオブジェクトに問題があります。アルゴリズムで検出するのは困難です。代わりに、より単純なオブジェクト、いわゆる「コーナー」を探すのが通例です。これらは記述子(「記述子」、「機能」)でもあります。



OpenCVのドキュメントには、コーナーの理由に関するすばらしい記事があります。つまり、線の定義は簡単ですが、座標は1つしかありません。したがって、2番目の(平行ではない)線も検出する必要があります。それらが一点に収束する場合、この場所は記述子を見つけるのに理想的であり、コーナーでもあります(実際の記述子は単語の幾何学的な意味でのコーナーではありませんが)。



記述子を見つけるためのアルゴリズムの1つは、SIFT(Scale-Invariant Feature Transform)です。1999年に発明されたという事実にもかかわらず、そのシンプルさと信頼性のために非常に人気があります。このアルゴリズムは特許を取得していますが、この春(2020年)に特許が失効しました。ただし、メインのOpenCVビルドに転送できなかったため、特別な非フリービルドを使用する必要があります。



それでは、両方の画像で同様のコーナーを見つけましょう。



sift = cv2.xfeatures2d.SIFT_create()
features_left = sift.detectAndCompute(left_image, None)






features_right = sift.detectAndCompute(left_image, None)






フランマッチャーを使用してみましょう。記述子の数が多くてもパフォーマンスは良好です。



KNN = 2
LOWE = 0.7
TREES = 5
CHECKS = 50

matcher = cv2.FlannBasedMatcher({'algorithm': 0, 'trees': TREES}, {'checks': CHECKS})
matches = matcher.knnMatch(left_descriptors, right_descriptors, k=KNN)

logging.debug("filtering matches with lowe test")

positive = []
for left_match, right_match in matches:
    if left_match.distance < LOWE * right_match.distance:
        positive.append(left_match)


黄色の線は、マッチャーがどのように一致を見つけたかを示しています。







はっきりとわかるように、正しい一致は約半分しかありません。ただし、正しい一致が常に同じ変換を行う場合、正しくない一致は無秩序に新しい方向を示します。それら。理論的には、それらはどういうわけか互いに分離することができ







ます。正​​しい変換を見つけるためのアルゴリズムの1つはRANSACです。このアルゴリズムは、適切な値をノイズから分離したい場合に最適です-これはまさにその通りです。



幸い、OpenCVには、RANSACを使用した一致によって変換マトリックスを検索する関数がすでにあります。実際、何も書く必要はありません。



次の変換を探すestimateAffinePartial2D関数を使用してみましょう:回転、スケーリング、および変換(4自由度)。



H, _ = cv2.estimateAffinePartial2D(right_matches, left_matches, False)


変換マトリックスが見つかったら、接着のために適切な画像を変換できます。



左のフラグメント:





右のフラグメント:







最初に、交差点の各ピクセルが平均として計算されるときに、フラグメントを接着する最も簡単な方法を使用しましょう。残念ながら、結果はまあまあです-特に接着線の近くで、画像が著しく2倍になります。







アニメーションでは、2つのフレームの違いがより明確に表示されます。







これは驚くべきことではありません。写真はさまざまな角度から撮影され、ニューラルネットワークもわずかに異なって向きを変え、その結果、わずかな差異がありました。



シームレスに接着するには、非線形歪みを補正する必要があります。歪みは、元の画像と同じ解像度のベクトルフィールドとして表すことができますが、色の代わりに、シフトが各ピクセルにエンコードされます。このベクトルフィールドは「オプティカルフロー」と呼ばれます。



一般に、光の流れを計算する方法はいくつかあります。それらのいくつかはOpenCVに直接組み込まれており、特別なニューラルネットワークもあります。



この場合、特定の手法は省略しますが、結果を公開します。







ただし、補償は両方のフラグメントに比例して実行する必要があります。これを行うには、2つのマトリックスに分割します。







左側のフラグメントは左から右に増加する方法で補正され、右側のフラグメントはその逆に補正されます。



これで、両方のフラグメントがほぼ完全に重なり合います。







これでオーバーレイは幾何学的に正しいですが、継ぎ目の明るさの非常に顕著なジャンプが見られます:







この問題は、平均値の代わりに勾配でオーバーレイされている場合、簡単に修正できます:







このアプローチでは、継ぎ目はまったく表示されません:







原則として、他の接着技術もあります。 、マルチバンドブレンディング。パノラマのステッチに使用されますが、テキストではうまく機能しません。光の流れの補正だけで、テキストのゴーストを完全に取り除くことができます。



今、私たちは完全な画像を接着します:







最終バージョン:







さらなる改善は、影の効果(画像の右側)の補正、または色とコントラストの後処理である可能性があります。また、グローバルジオメトリがわずかに影響を受けていることもわかります。右側の線は、わずかに上になっています。理論的には、この問題はグローバルスケーリング補正を追加することでも修正できますが、これも完全に簡単な作業ではありません。



接着がどのように機能するかを調べました。既製のソリューションがRESTAPIの形式でここにあります。また、次のリンクを確認することをお勧めします。






All Articles