ビットマップマスクを長方形のリストに減らすアルゴリズム?


7

自分でこれを書いて午後を過ごす前に、たとえ参考としても、すでに利用可能な実装があるかどうか尋ねたいと思いました。最初の画像は、長方形のリストにしたいビットマップマスクの例です。悪いアルゴリズムは、設定されたすべてのピクセルを1x1の長方形として返します。優れたアルゴリズムは2番目の画像のようになり、オレンジと赤の長方形の座標を返します。長方形が重なっているという事実は重要ではなく、返されるのは2つだけです。

要約すると、理想的な結果は次の2つの長方形(x、y、w、h)です。 [ { 3, 1, 2, 6 }, { 1, 3, 6, 2 } ]

回答:


6

その特定の問題のアルゴリズムはわかりませんが、これにどのように取り組むことができるかを以下に示します。

  1. ましょうXYなります0
  2. (X, Y)ビットマップを検索してインクリメントし、未訪問の前景ピクセルに到達するまで、各ピクセルを左から右、上から下に移動します。
  3. (X, Y)背景ピクセルまたは既にアクセスしたピクセルに到達するまで、右側から検索します。検出されたピクセルの量をとして保持しWIDTHます。セットするHEIGHT1ます。
  4. X, Y + HEIGHT)およびWIDTHピクセルを検索します。これらのピクセルがすべて前景に属している場合はHEIGHT1
  5. 検索で背景ピクセルに到達するまで、手順3を繰り返します。次に、長方形を追加します(X, YおよびWIDTHで形成され、HEIGHT、検索された四角形のリストに)をそれを囲むすべてのピクセルを訪問済みとしてマークします。
  6. 増分XWIDTHて検索を続けます(ステップ2に進みます)。ビットマップの右下のピクセルに到達すると、検索が終了します。

アルゴリズムは、特定の例の3つの長方形を生成します。長方形が2つしかない結果を得るには、ステップ3を変更して、背景ピクセルでのみ停止し、すでにアクセスしたピクセルを無視するようにする必要があります。ただし、これにより四角形が重複する可能性があります。したがって、ステップ3は、未訪問および訪問済みの前景ピクセルを追跡することでさらに最適化できます。最後のピクセル(背景ピクセルの前)がアクセスされたピクセルである場合、最後にアクセスされていない前景ピクセルを使用してを取得しWIDTHます。

更新:私は先に進み、提案したアルゴリズムを実装しました。自分で試すことができるインタラクティブなデモを次に示します(ディスプレイが小さすぎる場合は、[Flashフルスクリーンで再生]をクリックしてください)。

コントロール:黒い領域をクリックしてドラッグし、ピクセルを描画します。ホールドShiftたまま消して消去します。ダブルクリックしてキャンバスをクリアします。

こちらがフラッシュデモの完全なソースです


この質問は最近、私のSOの歴史にぶつかりましたが、正直に言って、この質問をしたことさえも思い出せません。:)とはいえ、あなたのアルゴリズムとソースは、私が望んでいたものは何でも請求書に合うように見えます。ありがとう。
moswald

3

この問題は十分に規定されていません。単純な例を1つ提供したので、ここでは重要な論理的可能性とコーナーケースの一部を逃しました(または、それらを明示的に除外していません)。たとえば、この提案されたアプリケーションについて言及していないので、何がより重要であるかを指定していません。マップ全体を、同じ面積の専用の長方形に分割しますを可能な限りします(任意のソリューションの数)、または単にxとyのそれぞれでエッジが一致する長方形を取得します。後者だと思います。

上で描画した「プラス記号」の形をしたビットマスクのコーナーにすぐに位置する4つのタイルのそれぞれを埋める場合を考えます([2、2]が一番上)。次に、最適な長方形は何ですか?列だけを考えると、横に細いものを備えた、幅が狭く長い長方形、または画像の中央にあり、上下にずんぐりとした正方形の大きくて広い正方形を好みますか?

とにかく、可能な限り最長のエッジマッチングrectsを想定して、これを最初の試みのソリューションとして使用します。

  • ビットマスクを列に分割します。各列は、ある値y0で始まり、他の値y1で終わります。各列を(y0、y1)タプルとしてリストに格納します。
  • 列:リストを評価します。隣接するタプルが同じy0 AND y1を持つ場所を見つけます(たとえば、列Aはy0 = 1で始まり、y1 = 4で終わります。列Bも同様です)。連続する各列が同じである限り、これらを表すために作成した長方形の幅を1つ増やします。ない場合は、この長方形を終了して保存し、後続の列グループ用に新しい長方形を作成します。

列についてと同じように、行に対して上記の両方の手順を繰り返します(もちろん、代わりにx0とx1を使用し、別のリストを使用します)。

これで、きれいに縁取られた長方形のリストがいくつかあるはずです。ただし、アプリケーションに最適ではない場合があります。この場合、より効率的なパッキングを可能にするヒューリスティックスのシステムが必要になります。詳細については、パッキング問題を参照してください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.