1

私はバイナリ画像(白黒のピクセルのみ)からsvgのようなパスを作成する方法を探しています。画像そのものは、それに穴ができる不規則な形をしたブロブになります。ブロブのような画像の(内側と外側の)エッジからのパスを作成

穴がない場合、境界線が必要なのは、ブロブの境界線を再作成することだけです。ブロブに穴があるとき、私は追加のパスを使っても問題ありません(1つのパスだけでこれを再現することはできません)。最後に、どちらのパスが外側のパスであり、どちらがホールであるかを知る必要があります。

私はすでに、これらが見つかりました:また、私は穴の検出を必要とする

を。結果がポリゴンかパスかどうかは、私にとっては重要なことではありません。私は曲線が曲がっているのに十分高い精度のポイントが必要です。

誰かがアイデアを持っていたり、それ以上の情報源があれば素晴らしいことでしょう。

PS:違いがあれば、私はキャンバスとjavascript(fabricJS)で作業しています。

答えて

1

最良の選択肢

あなたのコードでブロブを描いた場合、最も簡単な&最良の方法は、それがコンポーネントベジェ曲線だに各ブロブ(およびサブブロブ)を分解することです。 FabricJSはオープンソースなので、カーブをどのように作成するのか、カーブをどのように分解できるのかが分かります。結果は、再描画またはナビゲートが容易なベイズ曲線が12個ほどになります。ベジェ曲線をナビゲートするためのヘルプが必要な場合は、このチュートリアルのNavigating along a Pathを参照してください。

その他のオプション

あなたはネイティブのキャンバスにあなたのファブリックのBlobをcontext.drawImageとピクセル情報を取得するためにcontext.getImagedataを使用する必要がありますので、あなたは、ピクセル情報を取得する必要があります。

仮定:

  • すべての画素が白または黒のいずれかです。
  • ブロブは黒:BLOB外RGBA(0,0,0,255)
  • は白である:BLOBにRGBA(255255255255)
  • 穴が白色である:RGBA(255255255255)

ブロブ&ホール経路見つける計画:

  1. ロード画像データ:context.getImageData(0,0,canvas.width,canvas.height)

  2. 画像の周囲に白い画素があります。

  3. FloodFillアルゴリズム(FFA)を使用して、外側の白を透明に置き換えます。

  4. マーチング・スクエア・アルゴリズム(MSA)を使用して、最も外側のブロブ境界を見つけて、そのブロブ・パスを保存します。

  5. #4で見つかったブロブを透過で塗りつぶすには、Floodfill Algorithmを使用します。これにより、外側の小塊はMSAの次のラウンドに「不可視」になります。この時点では、白い穴しかありません。それ以外は透明です。

  6. マーチングスクエアアルゴリズム(MSA)を使用して、次のホワイトホールの周囲を見つけ、そのホールパスを保存します。

  7. Floodfillアルゴリズムを使用して、#6のホワイトホールを透明にします。これにより、この穴はMSAの次のラウンドには見えなくなります。

  8. リピート#6 &#7残りのホワイトホールをそれぞれ見つける。

  9. MSAがピクセルを報告していない場合は、完了です。

効率を上げるために、次の手順のステップ1のimageDataを繰り返し使用できます。すべての手順を完了したら、imageDataを放棄できます。

ブロブはカーブなので、ブロブパスには多くのポイントが含まれています。パスポイント低減アルゴリズムを使用して、それらの多くのポイントをより少ないポイントに単純化することができます。

+0

こんにちは、私は現時点で構築しようとしている技術です。あなたの答えは、私が正しい道にいることを示しています。私は既にMSAとFFAを稼働させています。今私は物事をまとめようとしています。私がやったとすぐに私はフィドルを投稿します。 – Fidel90

+1

クール - 喜んで助けてください! 1つの追加の考え:純粋な白黒ピクセルの問題は少なくなりますが、キャンバスはまだアンチエイリアスカーブになる可能性があります。したがって、フラッドフィルでパスの内部がすべてクリアされないことがあります。特に、パスの周りにアンチエイリアスのポケットがある可能性があります。パス内部の大部分をfloodfillした後に、 'globalCompositeOperation = 'destination-out''で発見されたパスを撫でることで、パス境界のアンチエイリアスを排除します。ストロークライン幅4を使用すると、アンチエイリアシングビットがクリアされます。 – markE

+0

私はやった、私の答えを参照してください。あなたの助けをもう一度ありがとう:)最適化のためのいくつかのアイデアがある場合は、私に知らせてください。 – Fidel90

1

最後に、マークされた別のオプションを使用して成功しました(少し修正されていますが)。私はこれを達成するためにMarching Squares Algorithm (MSA)Floodfill Algorithm (FFA)を使用しています。結果のポイントを簡略化するには、Douglas-Peucker Algorithm (DPA)を使用します。

私はこのjsFiddleで一緒にすべてをかけます。


ステップ:

  1. GETパスオブジェクト、ユーザは、自由描画
  2. 終了後にbase64でdataURL
  3. 介しパスから画像を作成する二値画像(のみ0と255ピクセル、なし透明度)に変換
  4. を0,0の位置にランダムカラーで保存し、色を保存する
  5. 次のピクセルに移動画素がFLOODFILL色やパスの色(黒色)を知っている場合
  6. 、5-7を繰り返して、すべてのピクセル上のカラー保存、そうでなければ新しいランダム色でFLOODFILL次
  7. 移動に移動します。
  8. インデックス1(これはパス輪郭(パディング)を囲む色なので、それはパスも穴もないです)
  9. に削除保存された色は、他のすべての色についてMSAを適用し、(DPA有する)点を得簡素化
  10. いずれかの削除、キャンバスに追加するパスの入力経路
012 :) DONE
  • を...
  • ...滑らかな点を簡略化された点からポリゴンORを作成し、作成

    もっと簡単なコードでは、私のランダムな色は現時点では灰色の陰影しか作成していません。 R = G = BおよびA = 255は、より簡単なチェックを可能にする。他方、この解決策は輪郭を最大値に制限する。 254個の穴(灰色 - パス色(0) - パディング色(穴なし)の256色)。 1つ以上のコードが必要な場合は、コードを拡張してR、G、B、さらにはAのランダム値を作成しても問題ありません。

    アルゴリズム全体がパフォーマンスのために最適化されていない可能性があります正直なところ私は現時点でそうする必要はないと考えています。私の使用事例には十分に速いです。とにかく、もし誰かが最適化に関するヒントを持っていたら、私は聞いて喜んで/読んでください:)

  • +1

    珍しい、面白い仕事をしている素敵な仕事! :-)最適化? R、G、B、Aのデータを、4つの8ビットの数値ではなく、32ビットの単一の数値としてキャストします。 4x8bitを1x32ビットとしてキャストするには、[DataView](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView)を使用できます。ほとんどのブラウザーはlittleEndianですが、確認する必要があります。また、MSAとFFAに単一の数字で作業するよう教えなければなりません。縮小カラーパレット(256)を使用している場合は、各色のトークンを含むUint8Arrayを使用することもできます。乾杯! – markE

    +1

    @markE:そうですね、TypedArraysは素晴らしいアプローチです。将来的に行う画像処理が増えれば、必ずそれらの使用を検討します。私に迷惑をかけることの1つ:最初に単純化してからパスを滑らかにする(それは私がatmする)か、それを逆にする(滑らかにしてから単純化する)方が良いでしょうか? – Fidel90

    +1

    平滑化アルゴリズムは、しばしば頂点(パスポイント)をスプラインで置き換えます。 MSAはスプラインの問題をもたらす頂点を過剰生成します。ですから、あなたは単純化して平滑化するかもしれません。簡素化と平滑化の両方を行うと、元のMSAポイントに対する許容範囲が失われる可能性があることに注意してください。シンプルな滑らかなスプラインは、MSAが指しているようにBLOBを表すわけではありません。そのため、設計上の考慮事項によってしばしば決定されるバランスの取れた決定があります。あなたのプロジェクトに幸運を祈る! :-) – markE

    関連する問題