アイソフォースを見つける

私はかつて等射線(画像内で同じ強度の線)を計算する必要がありましたが、既製のライブラリは見つかりませんでしたが、他の人のコード(同じOctaveやIrafなど)を掘り下げたくはありませんでした。 最も単純なアルゴリズムとして、Walking Square Methodを見つけまし 。 ただし、この方法では、アイソフォトノードを計算するときに空間解像度が大幅に低下するため、これをわずかに変更して正方形をオーバーラップさせることにしました。

最初の実装 (ところで、非常に高速)は失敗しました。 すべてのレベルに共通するマスクを作成しました。特定のレベルについては、いくつかの等値線が通る点で個別に数え直しましたが、ギャップがありました。 コードをいじると、デッドロックとフラグの数が増えたため、パフォーマンスを犠牲にし、強度レベルごとにマスクを個別に計算することにしました。



だから、「正方形を歩く」方法を簡単に繰り返します。 レベルI iの等値線を作成するために、特別なマスクが最初に作成されます。画像内の各ピクセルに対して、「隣人」の相対位置が右、下、右下にエンコードされます。 これをさまざまな方法でエンコードできます。ビットマスク000abcdの形式でコードを提示しました。a、b、c、dは対応するピクセルの相対的な強度です(aは画像の現在のピクセル)

ビルドマスク

ピクセルの値が輪郭のレベルより大きい場合、対応するビットに1が割り当てられ、それ以外の場合はゼロが割り当てられます。 wが画像の幅で、* inがピクセルaへのポインターである場合、このピクセルのマスク値(* out)は次のように計算されます。

*out = (unsigned char) ((in[0]>lvl)<<3) | ((in[1]>lvl)<<2) | ((in[w]>lvl)<<1) | (in[w+1]>lvl);
      
      





その結果、ピクセルの構成に応じて、16の値のいずれかを取得します。

マスク値

マスクのサイズは、画像のサイズよりも両次元で1つ小さくなります。



次のステップでは、マスクのすべてのピクセルを1つずつ調べて、不等式が0と15であるかどうかを確認します。そのようなピクセルが見つかるとすぐに、そこから輪郭を作成し始めます。 輪郭を正しく構築するには、このピクセルに近づいた方向を覚えておく必要があります。 上の図では、矢印はマスクの各ピクセルからの「下降」経路を示しています。 禁止された方向(元の方向)を考慮しない場合、マスクの余分なピクセルを確認するか、(特別なポイント6と9の場合、少し後で)次のアイソショットポイントの位置を誤って選択する可能性があります。

マスクのピクセルを見ると(左上から右、上から下、左上隅で画像の原点を数える場合)、空のセルのみが見つかりますが、「禁止」方向は「左」方向です。 輪郭のセクションを含むセルを見つけるとすぐに、事前に準備された「方向」の配列に従って、次の方向を選択し、「禁止」を切り取ります。 このような方向が2つある場合、時計回りに移動する場合は右または下(「右」を優先)に、反時計回りに移動する場合は左または上(「上」を優先する)を選択します(これについては後で詳しく説明します)。

その後、特定のピクセルの輪郭ノードの位置を計算します。 これは、このピクセルのマスクの値に従って、関数の配列の1つを使用して行われます。 次の図は、この位置の計算方法を説明しています。

ポイント計算

したがって、画像に図に示す強度(セル内の数値)を持たせてください。 レベル30で等値線を実行します。隣接ピクセル(x i 、y i )の構成は、マスク値7に対応します。 対応する関数を呼び出します。この関数は、右の2つのピクセルを垂直に接続し、下の2つのピクセルを水平に接続する線で線形補間法により輪郭線の制御点の座標を計算します。 対応するドットは、赤い丸でマークされています。 それらを直線で接続し、その中心を見つけると、目的のアイソフォテートノード(緑色の塗りつぶしを持つ赤い円でマークされた「Our point」)が得られます。 もちろん、これはあまり正しい方法ではありませんが、ほとんどのタスクでは十分です。 各ノードは、対応するリストの末尾に追加されます。

対応するマスク値が使用されると、ゼロにリセットされ、マスクの次の隣接ピクセルに移動します。 その内容が等値線の次のノードに対応する場合、計算を続行します;それ以外の場合、等値線を「閉じます」。 isophoteの「クロージャ」の直後に、まず、それが短すぎるかどうか(たとえば、1ピクセル程度)をチェックし、次に、その近さをチェックします:isophotesの始まりと終わりが、 、2ピクセル離れているため、閉じていると見なします。

アイソフォテートを「閉じる」手順は、「念のため」、アイソフォテートが最初のポイントから反対方向に続くかどうかをチェックすることです。 これを行うには、マスクの最初のピクセルの一番下に移動して、上に移動することを禁止します。 そこに等音線の継続が見つかった場合、リストの「先頭」にノードを追加し、優先順位として反時計回りの方向を選択して、右端まで移動します。



6と9の特別なピクセルを「つまずく」まで、上記のすべてが当てはまります。2つのアイソフォティックラインがマスクのこれらのピクセルを通過するため、「禁止」方向に基づいて、正しい次の方向を選択する必要があります。 したがって、たとえば、値6を左に「つまずく」と、次の方向は「上」になります。

次のパスで別の輪郭点を「忘れない」ように、特別な値を「特別ではない」に置き換えます。単に、既に使用されているピクセルを「塗りつぶす」だけです(たとえば、左側の「6」を押すと、 「左上のピクセルにペイントします。つまり、6を7に置き換えます。 残念ながら、この方法は、強度の「こぶ」に単一ピクセルの「くぼみ」が存在する場合に「見落とし」を引き起こします。 しかし、残念なことに、これの修正は非常に複雑なアルゴリズムタスクであり、アイソフォースを構築するのにコンピューター時間がかかりすぎます。 そして、ほとんどの画像について、説明されている方法は正常に機能します。

したがって、「特別な」ピクセルは2回使用され、2回目のパスの後でのみゼロになります。 特別なポイントでのノードの計算は、他の方法で実行されます。このため、使用されるピクセルとは反対のピクセルの「シェーディング」を使用して関数が取得されます。



次の図に示すように、2つのピクセルの「ピーク」をバイパスする例によって、アルゴリズムの動作を説明します。

例

4x4ピクセル画像の特定のセクションは、3x3ピクセルマスクに対応します(右側)。 画像の左上のピクセルから移動を開始します。 なぜなら マスクでは、これはゼロに対応し、マスクの次の右ピクセルに移動します(「右」方向に「禁止」があることを覚えています)。 禁止されている方向を図に示します。 右側の赤い矢印、黒い矢印の付いた「空の」遷移、緑色の矢印の付いた等値線ノードの計算による遷移。

したがって、8つを「つまずき」、対応する関数を使用して、最初の等電点ノードの位置を計算します。 次に、事前に準備された配列を見て、現在のピクセルからの「下降」の方向が「右」または「下」であることがわかります。 「右へ」の方向を選択し、次のピクセル(4)に進みます。マスクの既に使用されているピクセルをリセットすることを忘れません(ピクセルのゼロ化は、ピクセルの右上隅に赤いゼロでマークされます)。

次に、値1に移動し、その後、値6の特異点に移動します。 右側に移動すると、ノード値は7に等しいマスク値の関数によって計算され、マスク上の6は14に置き換えられます。その後、統一性に移行します。

ユニット2と8を通過した後、「特別な」ピクセルに戻りますが、すでに14の値があります。 「何も起こらなかったように」さらに計算が行われ、その後、上に移動する必要があります。 しかし、一番上でゼロに遭遇します。 ノードのリストの「ヘッド」にも何も追加できません。 輪郭の開始ピクセルの下の値もゼロにリセットされます。 したがって、ラインの開始ノードと終了ノードの近接性を確認します。 それらは非常に近く、この輪郭を閉じているとマークできます。



ここでアルゴリズムのすべてのソースを見つけることができます 。 異なるレベルの輪郭の計算の並列化を追加して、少なくとも4..8の並列スレッドを開始する予定です。 これまでのところ、1つのストリームで、3000x3000ピクセルのテスト画像の場合、16レベルでのアイソフォイトの構築には約1.2秒かかります。



All Articles