web-dev-qa-db-ja.com

OpenCVでの高速カラー量子化

どうすればOpenCV(+ C++)を使用して画像内の異なる色の数を最速で減らすことができますか?完全なコードは必要ありません。私はすでにkmeansを使用してそれを行っていますが、あまり速くありません。これは私のコードの遅い部分です:

_kmeans(samples, clusterCount, labels,
    TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 10, 10.0),
    1, KMEANS_RANDOM_CENTERS, centers);
_

このコードの処理には数秒かかりますが、これは非常に低速です。私はこの(_rgb2ind_)にMatlabを使用していましたが、高速でした。ほぼ0.01秒。

ユーザーがプログラムの高速化を期待している本番環境でコードを使用したい。

色の量子化のためのkmeansの代替はありますか? kmeansをより速く実行する方法はありますか(多くの異なるパラメーターを試したため、そうは思いません)?

編集:
色の量子化は非常に複雑なトピックであり、適切に最適化されたものを書くには時間がかかります。これにはMagick++ (ImageMagick API)を使用することにしました。
そのため、Cris Luengoの新しい(編集された)回答を試していません。しかし、私はそれを回答としてマークします(コメントもチェックしてください)ので、他の人はこの質問に回答がないとは思わないでしょう。

12
J. Mando

色を量子化するには多くの方法があります。ここでは4つ説明します。

均一な量子化

ここでは、画像に存在するかどうかに関係なく、均一に分散された色のカラーマップを使用しています。 MATLAB-speakでは、次のように書きます。

qimg = round(img*(N/255))*(255/N);

各チャネルをNレベルに量子化するには(入力が[0,255]の範囲内であると想定します。floorを使用することもできます。これは、場合によってはより適切です。これにより、N^3の色が異なります。たとえば、N=8を使用すると、512の一意のRGBカラーを取得できます。

K平均クラスタリング

これは、アダプティブパレットを生成する「クラシック」な方法です。明らかにそれは最も高価になるでしょう。 OPは、すべてのピクセルのコレクションにk平均を適用しています。代わりに、k-meansをカラーヒストグラムに適用できます。プロセスは同じですが、1000万のデータポイント(現在の一般的な画像)ではなく、32 ^ 3 = 33千のデータしかありません。ビンの数を減らしたヒストグラムによる量子化は、自然な写真を扱う場合、ほとんど効果がありません。色のセットが限られているグラフを量子化する場合、k平均クラスタリングを行う必要はありません。

すべてのピクセルを1回パスして、ヒストグラムを作成します。次に、通常のk-meansクラスタリングを実行しますが、ヒストグラムビンを使用します。各データポイントには、考慮に入れる必要がある重み(そのビン内のピクセル数)もあります。クラスターの中心を決定するアルゴリズムのステップが影響を受けます。通常の平均ではなく、データポイントの加重平均を計算する必要があります。

結果は初期化の影響を受けます。

オクトリー量子化

八分木は、空間インデックスのデータ構造であり、ボリュームは、各軸を半分にカットすることにより、8つのサブボリュームに再帰的に分割されます。したがって、ツリーはそれぞれ8つの子を持つノードで形成されます。色の量子化では、RGBキューブはオクツリーで表され、ノードあたりのピクセル数がカウントされます(これは、カラーヒストグラムを構築し、その上にオクツリーを構築することと同じです)。次に、必要な数のリーフノードが残るまで、リーフノードが削除されます。リーフノードの削除は一度に8回行われ、1レベル上のノードがリーフになります。どのノードをプルーニングするかを選択する方法はいくつかありますが、それらは通常、ピクセル数の少ないプルーニングノードを中心に展開します。

これはGimpが使用する方法です。

Octreeは常にノードを中央で分割するため、k平均クラスタリングや次の方法ほど柔軟性がありません。

最小分散量子化

MATLABのrgb2ind は、OPが言及しているように、均一な量子化と「最小分散量子化」と呼ばれるものを実行します。

最小分散量子化は、RGBカラーキューブを、画像での色の分布方法に応じて、異なるサイズの小さなボックス(必ずしもキューブではない)にカットします。

どういう意味かわかりません。 このページ はこれ以上何もしませんが、RGBキューブのk-dツリーパーティショニングのように見える図があります。 K-dツリーは、空間データを半分に再帰的に分割する空間インデックス構造です。各レベルで、最も離れているディメンションを選択し、そのディメンションに沿って分割して、追加のリーフノードを1つ作成します。八分木とは対照的に、分割は最適な場所で発生する可能性があり、ノードの中央ではありません。

空間インデックス構造(k-dツリーまたはoctrees)を使用する利点は、カラールックアップが本当に速いことです。ルートから開始し、リーフノードに到達するまで、R、G、またはBの値に基づいてバイナリの決定を行います。 k-meansの場合のように、各プロトタイプクラスターまでの距離を計算する必要はありません。

[2週間後に編集]私は可能な実装について考えていました、そして 1つになった 。これはアルゴリズムです:

  • フルカラーヒストグラムはパーティションと見なされます。これはk-dツリーのルートになります。他のノードがまだないため、これは現在、リーフノードでもあります。
  • 優先キューが作成されます。これには、k-dツリーのすべてのリーフノードが含まれます。優先順位は、1つの軸に沿ったパーティションの分散から、その軸に沿ってパーティションを分割する場合の2つの半分の分散を引いたものによって与えられます。分割位置は、2つの半分の分散が最小になるように選択されます(大津のアルゴリズムを使用)。つまり、優先度が大きいほど、分割によって分散の合計が減少します。各リーフノードについて、各軸のこの値を計算し、最大の結果を使用します。
  • 目的のパーティション数になるまで、キューのパーティションを処理します。
    • 優先順位を決定するときに計算された位置と軸に沿って、優先順位が最も高いパーティションを分割します。
    • 2つの半分のそれぞれの優先度を計算し、それらをキューに入れます。

これは、このように記述すると比較的単純なアルゴリズムです。 コード は、効率的でありながら汎用的なものにしようとしたため、やや複雑です。

比較

256x256x256 RGBヒストグラムで、k平均クラスタリングとこの新しいアルゴリズムを比較して、次のタイミングを得ました。

# clusters    kmeans (s)    minvar (s)
     5          3.98         0.34
    20         17.9          0.48
    50        220.8          0.59

クラスタの数が増えると、k-meansはより多くの反復を必要とするため、指数時間が増加することに注意してください。通常、このような大きなヒストグラムは使用しません。タイミングをより堅牢にするために、大きなデータが必要でした。

以下は、テスト画像に適用されるこれら3つの方法の例です。

入力:

Input

N=4で統一し、最大64の異なる色を作成します[N=2を使用して8つの異なる色を取得し、他のメソッドと比較すると、結果は非常に醜いです]:

Uniform

8色のK平均値:

K-means

8色の新しい「最小分散」:

New "minimum variance"

これらはかなり似ていますが、K-meansの結果よりもこの最後の結果が好きです。

17
Cris Luengo

高速ペアワイズニアレストネイバーベースのアルゴリズム 8色で
高品質で高速
enter image description here

効率的、エッジ対応、カラー量子化とディザリングの組み合わせ 8色で
32色以下の場合は高品質ですが、低速です
enter image description here

空間色量子化 8色で
32色以下の場合は高品質ですが、最も遅い
enter image description here

サンプルC++コード
速度については、 GPU並列プログラミングC/C++ に依存する場合があります。

5
Miller Cy Chan