画像内の対称領域/パターンを見つける


14

人間の背面の平均曲率を表す一連の画像があります。

私がやりたいのは、画像のその他の部分に類似した反映された「カウンターパート」を持つポイントの画像を「スキャン」することです(おそらく中央線に対して対称ですが、変形がある可能性があるため必ずしもそうではありません)。一部の画像合成技術では、これを使用して画像間の類似点を「自動検出」しますが、同じ画像の両側でそれらを検出したいです。

最終的な目標は、背中を対称的な「半分」に適応的に分割する、連続した、おそらく最も湾曲した縦線を見つけることです。

サンプル画像を下に配置します。すべての領域が対称ではないことに注意してください(具体的には、画像の中心のすぐ上で、赤い垂直「ストリップ」が右にずれています)。その領域は悪いスコアなどを受け取るはずですが、ローカル対称性は、より遠くに配置された対称点から定義されます。いずれにせよ、アルゴリズムをアプリケーションドメインに適合させる必要がありますが、私が目指しているのは、SOM相関/畳み込み/パターンマッチング戦略であり、既に何かがあるはずです。

(編集:下にさらに画像があり、さらに説明があります)

ここに画像の説明を入力してください

編集:要求に応じて、行儀が良く問題のあるより典型的な画像を含めます。しかし、カラーマップされた画像の代わりに、それらはグレースケール画像であるため、色はデータの大きさに直接関連します。これは、カラー画像では発生しませんでした(通信のためだけに提供されます)。グレーの画像はカラーの画像と比べてコントラストが欠けているように見えますが、データの勾配があり、必要に応じて適応的なコントラストで表示することができます。


1)非常に対称的な被写体の画像:

ここに画像の説明を入力してください


2)異なる瞬間の同じ被写体の画像。より多くの「機能」(より多くのグラデーション)がありますが、以前のように「対称」ではありません。

ここに画像の説明を入力してください


3)より一般的な凹型正中線の代わりに正中線に凸部(骨の突起、より明るい領域で示される)を備えた薄い若い被験者:

ここに画像の説明を入力してください


4)X線で確認された脊椎の逸脱のある若者(非対称性に注意):

ここに画像の説明を入力してください


5)典型的な「傾けられた」対象(ほとんどが湾曲した正中線の周りで対称的であり、それ自体は適切に「変形」していない):

ここに画像の説明を入力してください


どんな助けも大歓迎です!


背骨を単に仕切りとして使用しないのはなぜですか?
ジム・クレイ

@JimClay:画像の残りの部分の実際の対称軸と比較して、脊椎が測定されている部分であると思われます
エンドリス

「一部の画像合成技術では、これを使用して画像間の類似点を「自動検出」します」画像の反転コピーを作成してから、それらのいずれかを使用します。:)
エンドリス

Y軸に沿って画像を単純にミラーリングし、登録アルゴリズムを使用できませんでしたか?既に構築可能な柔軟/ノンパラメトリックな登録アルゴリズムに関する多くの研究があるためです。
ニキエストナー

JimClay、背骨は私が見つけたいものです。どこにあるのか分かりません。Endolith、私の質問には、これらのアルゴリズムのいくつかの名前を教えてくれる人が関係していますが、まだ見つかりませんでした。ニキー、それが全体のポイントですが、私はそれらのアルゴリズムのいずれも知らないので、そもそも質問をしている理由です:o)
heltonbiker

回答:


9

コメントで述べたように、医療画像の登録は多くの研究が利用可能なトピックであり、私は専門家ではありません。私が読んだことから、一般的に使用される基本的な考え方は、2つの画像(あなたの場合は画像とその鏡像)間のマッピングを定義し、マッピングが適用された場合の滑らかさと画像の類似性のエネルギー項を定義し、最後に標準の(またはアプリケーション固有の)最適化手法を使用してこのマッピングを最適化します。

これを実証するためにMathematicaで簡単なアルゴリズムをハッキングしました。これは、医療アプリケーションで使用すべきアルゴリズムではなく、基本的なアイデアのデモにすぎません。

最初に、イメージをロードし、ミラーリングして、これらのイメージを小さなブロックに分割します。

src = ColorConvert[Import["http://i.stack.imgur.com/jf709.jpg"], 
   "Grayscale"];
mirror = ImageReflect[src, Left -> Right];
blockSize = 30;
partsS = ImagePartition[src, {blockSize, blockSize}];
partsM = ImagePartition[mirror, {blockSize, blockSize}];
GraphicsGrid[partsS]

Mathematicaグラフィックス

通常、キーポイントや画像モーメントなどを使用して、おおよその厳密な登録を行いますが、画像はほぼ中央にあるため、これはスキップします。

1つのブロックを見て、それが鏡像に相当する場合:

{partsS[[6, 10]], partsM[[6, 10]]}

Mathematicaグラフィックス

それらは似ているが、シフトしていることがわかります。シフトの量と方向は、私たちが見つけようとしているものです。

一致の類似性を定量化するために、ユークリッド距離の2乗を使用できます。

ListPlot3D[
  ImageData[
   ImageCorrelate[partsM[[6, 10]], partsS[[6, 10]], 
    SquaredEuclideanDistance]]]

Mathematicaグラフィックス

悲しいことに、このデータを使用すると、最適化が直接考えられていたよりも困難であったため、代わりに2次近似を使用しました。

fitTerms = {1, x, x^2, y, y^2, x*y};

fit = Fit[
   Flatten[MapIndexed[{#2[[1]] - blockSize/2, #2[[2]] - 
        blockSize/2, #1} &, 
     ImageData[
      ImageCorrelate[partsM[[6, 10]], partsS[[6, 10]], 
       SquaredEuclideanDistance]], {2}], 1], fitTerms, {x, y}];

Plot3D[fit, {x, -25, 25}, {y, -25, 25}]

Mathematicaグラフィックス

この関数は実際の相関関数と同じではありませんが、最初のステップに十分近いものです。ブロックのすべてのペアに対してこれを計算しましょう:

distancesFit = MapThread[
   Function[{part, template},
    Fit[Flatten[
      MapIndexed[{#2[[2]] - blockSize/2, #2[[1]] - blockSize/2, #1} &,
        ImageData[
        ImageCorrelate[part, template, 
         SquaredEuclideanDistance]], {2}], 1], 
     fitTerms, {x, y}]], {partsM, partsS}, 2];

これにより、最適化の最初のエネルギー項が得られます。

variablesX = Array[dx, Dimensions[partsS]];
variablesY = Array[dy, Dimensions[partsS]];

matchEnergyFit = 
  Total[MapThread[#1 /. {x -> #2, y -> #3} &, {distancesFit, 
     variablesX, variablesY}, 2], 3];

variablesX/Y 各ブロックのオフセットが含まれています。 matchEnergyFit元の画像とオフセットが適用されたミラー化された画像との間の平方ユークリッド差近似します。

このエネルギーだけを最適化すると、悪い結果が得られます(収束した場合)。また、オフセットを滑らかにする必要があります。この場合、ブロックの類似性はオフセットについて何も伝えません(たとえば、直線に沿って、または白い背景で)。

そこで、平滑化のために2番目のエネルギー項を設定します。

smoothnessEnergy = Total[Flatten[
    {
     Table[
      variablesX[[i, j - 1]] - 2 variablesX[[i, j]] + 
       variablesX[[i, j + 1]], {i, 1, Length[partsS]}, {j, 2, 
       Length[partsS[[1]]] - 1}],
     Table[
      variablesX[[i - 1, j]] - 2 variablesX[[i, j]] + 
       variablesX[[i + 1, j]], {i, 2, Length[partsS] - 1}, {j, 1, 
       Length[partsS[[1]]]}],
     Table[
      variablesY[[i, j - 1]] - 2 variablesY[[i, j]] + 
       variablesY[[i, j + 1]], {i, 1, Length[partsS]}, {j, 2, 
       Length[partsS[[1]]] - 1}],
     Table[
      variablesY[[i - 1, j]] - 2 variablesY[[i, j]] + 
       variablesY[[i + 1, j]], {i, 2, Length[partsS] - 1}, {j, 1, 
       Length[partsS[[1]]]}]
     }^2]];

幸いなことに、制約付き最適化はMathematicaに組み込まれています。

allVariables = Flatten[{variablesX, variablesY}];
constraints = -blockSize/3. < # < blockSize/3. & /@ allVariables;
initialValues = {#, 0} & /@ allVariables;
solution = 
  FindMinimum[{matchEnergyFit + 0.1 smoothnessEnergy, constraints}, 
   initialValues];

結果を見てみましょう:

grid = Table[{(j - 0.5)*blockSize - dx[i, j], (i - 0.5)*blockSize - 
      dy[i, j]}, {i, Length[partsS]}, {j, Length[partsS[[1]]]}] /. 
   solution[[2]];
Show[src, Graphics[
  {Red,
   Line /@ grid,
   Line /@ Transpose[grid]
   }]]

Mathematicaグラフィックス

0.1前の要因smoothnessEnergyは、平滑エネルギーが画像一致エネルギー項に関連して得られる相対的な重みです。これらは異なる重みの結果です:

Mathematicaグラフィックス

可能な改善:

  • 私が言ったように、最初に厳格な登録を実行します。背景が白の場合、単純な画像の瞬間ベースの登録は正常に機能するはずです。
  • これは1つのステップにすぎません。1つのステップで見つけたオフセットを使用し、2番目のステップでそれらを改善できます。たとえば、検索ウィンドウを小さくするか、ブロックサイズを小さくします。
  • ブロックなしでこれを行う記事を読みましたが、ピクセルごとのオフセットを最適化します。
  • さまざまな平滑化機能を試す

楽しみのためだけに読むには長すぎますが、最終的な画像はかなり示唆的です。それは驚くほどに見えます:D-
ペネロペ

この答えは非常に啓発的でした。私はそれを飲み込むのにいくらかの時間を必要としますが、おそらく非剛体の登録テクニックが私が使用する必要があるものです。幸いなことに、概念的な詳細を提供してくれたので、最悪の場合、同様のアプローチを見つけることができます。それまでの間、質問をより多くの画像で更新します。どうもありがとう!
heltonbiker

4

興味深い質問。まず、関心のあるキーポイント検出器とマッチングに基づいたアプローチをお勧めします。これにはSIFTが含まれます(Scale-Invariant Feature Transform)、SURF、ORBなどが含まれます。または、ハリス演算子(csce.uark.edu/~jgauch/library/Features/Harris.1988.pdfのみに基づく単純なアプローチも含まれます。 )。あなたの投稿からあなたが何を試みたのか明確ではないので、私がここでナイーブになっているのなら申し訳ありません。

そうは言っても、数学的形態学(MM)を使ったより簡単なアプローチをお楽しみください:)すべてのステップを視覚化するための画像は最後にあります。

サンプル画像を取得し、ImageMagickを使用してL a b *色空間に変換し、L *バンドのみを使用しました。

convert x.jpg -colorspace Lab -separate %d.png

0.pngはL *バンドに対応します。今、あなたは実際の画像データを持っていると確信していますが、jpg圧縮アーティファクトとそうでないものを扱っています。この問題を部分的に処理するために、モルフォロジーオープニングに続いて半径5のフラットディスクでモルフォロジークロージングを実行しました。これは、MMでノイズを低減する基本的な方法であり、ディスクの半径はほとんど変化しません。次に、私のアイデアはこの単一のイメージに基づいていましたが、他のケースでは失敗する可能性が高いです。関心のある領域は、より暗い(カラー画像では「より暑い」)ことで視覚的に区別されるので、統計ベースの2値化機能がうまく機能すると思いました。私は大津のアプローチを使用しました。これは自動的なアプローチです。

この時点で、関心のある中心領域を明確に視覚化することができます。問題は、私のアプローチでは、閉じたコンポーネントにしたかったのですが、そうではなかったということです。まず、接続されているコンポーネントのうち、最大のものよりも小さいものをすべて破棄します(バックグラウンドはそれらの1つとして数えません)。二値化の結果が良好な場合、これは他の場合に機能する可能性が高くなります。サンプル画像では、背景に接続されているコンポーネントが1つあるため、破棄されませんが、問題は発生しません。

あなたがまだ私をフォローしている場合、私たちは実際に想定されている中央の関心領域をまだ見つけていません。ここに私の見解があります。その人がどんなに曲がっていても(実際に問題のあるケースを見ることができます)、この領域は垂直線に似ています。そのために、長さ100の垂直線でモルフォロジーオープニングを実行することで現在の画像を単純化します。この長さは純粋に任意であり、スケーリングの問題がない場合、これを決定するのは難しい値ではありません。ここで再びコンポーネントを破棄しますが、このステップではもう少し注意しました。私は小さな領域と考えていたものを破棄するために、画像の補数で領域ごとに開くことを使用しました。これは、粒度測定分析の形式で何かを実行することにより、より制御された方法で行うことができます(MMからも)

現在、画像の左部分、中央部分、画像の右部分の3つの部分があります。中央部分は3つのうちの小さいコンポーネントであると予想されるため、簡単に取得できます。

これが最終結果です。右下の画像は、元の画像と左に重ねた画像です。個々の数字がすべて揃っているわけではありません。急いで申し訳ありません。

http://i.imgur.com/XRhYv.png


あなたの親切な関心に非常に感謝しますが、あなたのアプローチは私のデータの特定の特性を考慮する必要があります(苦情ではなく、単なる詳細):1)実際のデータは、発散する赤黄色Pythonのmatplotlibの緑色のカラーマップ。色データを扱うことは概念的に正しいとは思いません。画像はコミュニケーションの目的でのみ表示されます。2)実際のデータは表面の曲率(凸面と凹面)に関連しており、赤い部分は凹面で、緑の部分は凸面です。対称軸は必ずしも凹面領域に収まるわけではありません。
heltonbiker

すぐにいくつかの画像を追加し(そしてこれをグレースケール画像に置き換えます)、画像自体をテストに使用して、色によるダイナミックレンジの歪みの危険性を排除します。
-heltonbiker

残念ながら、データはまだ利用できません。グレースケール画像はせいぜいその近似です。
mmgp

おそらく近似で十分だと思いますが、実際のデータを提供しても構いません。いくつかのパブリックDropBoxダウンロードリンクを投稿できますが、どのファイル形式かはわかりません。
heltonbiker
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.