この領域に「ドット」が分散された2D領域があります。現在、ドットの「クラスター」、つまり特定の高密度のドットがある領域を検出しようとしています。
これらの領域をエレガントに検出する方法についての考え(または考えのある記事へのリンク)はありますか?
スペースの任意の解像度を定義し、そのマトリックス内の各ポイントについて、そのポイントからすべてのドットまでの距離の測定値を計算して、「ヒートグラフ」を作成し、しきい値を使用してクラスターを定義するのはどうでしょうか。
これは処理のための素晴らしい演習です。後で解決策を投稿するかもしれません。
編集:
ここにあります:
//load the image
PImage sample;
sample = loadImage("test.png");
size(sample.width, sample.height);
image(sample, 0, 0);
int[][] heat = new int[width][height];
//parameters
int resolution = 5; //distance between points in the gridq
int distance = 8; //distance at wich two points are considered near
float threshold = 0.5;
int level = 240; //leven to detect the dots
int sensitivity = 1; //how much does each dot matters
//calculate the "heat" on each point of the grid
color black = color(0,0,0);
loadPixels();
for(int a=0; a<width; a+=resolution){
for(int b=0; b<height; b+=resolution){
for(int x=0; x<width; x++){
for(int y=0; y<height; y++){
color c = sample.pixels[y*sample.width+x];
/**
* the heat should be a function of the brightness and the distance,
* but this works (tm)
*/
if(brightness(c)<level && dist(x,y,a,b)<distance){
heat[a][b] += sensitivity;
}
}
}
}
}
//render the output
for(int a=0; a<width; ++a){
for(int b=0; b<height; ++b){
pixels[b*sample.width+a] = color(heat[a][b],0,0);
}
}
updatePixels();
filter(THRESHOLD,threshold);
編集2(わずかに非効率的なコードですが同じ出力):
//load the image
PImage sample;
sample = loadImage("test.png");
size(sample.width, sample.height);
image(sample, 0, 0);
int[][] heat = new int[width][height];
int dotQ = 0;
int[][] dots = new int[width*height][2];
int X = 0;
int Y = 1;
//parameters
int resolution = 1; //distance between points in the grid
int distance = 20; //distance at wich two points are considered near
float threshold = 0.6;
int level = 240; //minimum brightness to detect the dots
int sensitivity = 1; //how much does each dot matters
//detect all dots in the sample
loadPixels();
for(int x=0; x<width; x++){
for(int y=0; y<height; y++){
color c = pixels[y*sample.width+x];
if(brightness(c)<level) {
dots[dotQ][X] += x;
dots[dotQ++][Y] += y;
}
}
}
//calculate heat
for(int x=0; x<width; x+=resolution){
for(int y=0; y<height; y+=resolution){
for(int d=0; d<dotQ; d++){
if(dist(x,y,dots[d][X],dots[d][Y]) < distance)
heat[x][y]+=sensitivity;
}
}
}
//render the output
for(int a=0; a<width; ++a){
for(int b=0; b<height; ++b){
pixels[b*sample.width+a] = color(heat[a][b],0,0);
}
}
updatePixels();
filter(THRESHOLD,threshold);
/** This smooths the ouput with low resolutions
* for(int i=0; i<10; ++i) filter(DILATE);
* for(int i=0; i<3; ++i) filter(BLUR);
* filter(THRESHOLD);
*/
そして、(縮小された)ケントサンプルを使用した出力:
mean-shiftカーネルを使用して、ドットの密度中心を見つけることをお勧めします。
平均シフトの図http://cvr.yorku.ca/members/gradstudents/kosta/compvis/file_mean_shift_path.gif
この図は、平均シフトカーネル(最初はクラスターのエッジを中心とする)がクラスターの最高密度のポイントに向かって収束することを示しています。
この質問に対するいくつかの回答は、それを行うための平均シフトの方法をすでに示唆しています。
Pパパが画像をぼかして最も暗いスポットを見つける は実際には カーネル密度推定 (KDE)法であり、これは平均シフトの理論的基礎です。
j0rd4n と Bill the Lizard の両方で、スペースをブロックに離散化し、それらの密度を調べることをお勧めします。
アニメーションの図に表示されているのは、これら2つの提案の組み合わせです。移動する「ブロック」(つまり、カーネル)を使用して、局所的に最も高い密度を探します。
平均シフトは、カーネル( これ と同様)と呼ばれるピクセル近傍を使用し、それを使用して基になる画像データの平均。このコンテキストでのmeanは、カーネル座標のピクセル加重平均です。
各反復で、カーネルの平均は、次の反復の中心座標を定義します-これはshiftと呼ばれます。したがって、名前mean-shift。反復の停止条件は、シフト距離が0に低下したときです(つまり、近隣で最も密度の高い場所にいます)。
平均シフト(理論と応用の両方)の包括的な紹介は、 このpptプレゼンテーション にあります。
平均シフトの実装は OpenCV :で利用可能です。
int cvMeanShift( const CvArr* prob_image, CvRect window,
CvTermCriteria criteria, CvConnectedComp* comp );
O'Reilly's Learning OpenCv(google book抜粋) それがどのように機能するかについての素晴らしい説明もあります。基本的には、ドット画像(prob_image)をフィードするだけです。
実際には、適切なカーネルサイズを選択するのがコツです。カーネルが小さいほど、カーネルをクラスターに近づける必要があります。カーネルが大きいほど、初期位置はよりランダムになります。ただし、画像にドットのクラスターが複数ある場合、カーネルはそれらの間に収束する可能性があります。
Trebs ステートメントに少し助力を加えるために、クラスターの定義が何であるかを現実的に最初に定義することが重要だと思います。
私が生成したこのサンプルセットを見てください。そこにクラスター形状があることを知っているので、それを作成しました。
ただし、この「クラスター」をプログラムで識別するのは難しい場合があります。
人間は大きなトロイダルクラスターと見なすかもしれませんが、自動化されたプログラムは、半近接した一連の小さなクラスターを決定する可能性が高くなります。
また、超高密度の領域があり、それは全体像の文脈にあり、単に気を散らすものであることに注意してください
特定のアプリケーションに応じて、この動作を考慮し、場合によっては、密度の低い重要でないボイドによってのみ分離された、同様の密度のクラスターを連鎖させる必要があります。
あなたが開発するものが何であれ、私は少なくともそれがこのセットのデータをどのように識別するかに興味があります。
(HDRI ToneMappingの背後にあるテクノロジーを調べるのは適切だと思います。これらは光密度で多かれ少なかれ機能し、「ローカル」トーンマップと「グローバル」トーンマップがあり、それぞれが異なる結果をもたらすからです)
2D領域のコピーにぼかしフィルターを適用します。何かのようなもの
1 2 3 2 1
2 4 6 4 2
3 6 9 6 3
2 4 6 4 2
1 2 3 2 1
「暗い」領域は、ドットのクラスターを識別するようになりました。
データの Quadtree 表現を作成してみてください。グラフの短いパスは、高密度の領域に対応します。
または、より明確に言うと、クアッドツリーとレベル次のトラバーサルが与えられた場合、「ドット」で構成される各下位レベルのノードは高密度領域を表します。ノードのレベルが上がると、そのようなノードは「ドット」の密度の低い領域を表します
形態論的アプローチはどうですか?
しきい値処理された画像を(ドットのターゲット密度に応じて)いくつかの数だけ拡張すると、クラスター内のドットが単一のオブジェクトとして表示されます。
OpenCVは、形態学的操作をサポートします(さまざまな画像処理ライブラリと同様)。
http://www.seas.upenn.edu/~bensapp/opencvdocs/ref/opencvref_cv.htm#cv_imgproc_morphology
これは本当に学術的な質問のように聞こえます。
頭に浮かぶ解決策には、r *ツリーが含まれます。これにより、総面積が個別のサイズの、場合によっては重複するボックスに分割されます。これを行った後、平均距離を計算することにより、各ボックスが「クラスター」を表すかどうかを判断できます。
そのアプローチの実装が困難になった場合は、データグリッドを同じサイズのサブディビジョンに分割し、それぞれにクラスターが発生するかどうかを判断する方がよい場合があります。ただし、このアプローチでは、エッジの状態に非常に注意する必要があります。最初の分割後、定義されたエッジの特定のしきい値内のデータポイントでエリアを通過して再結合することをお勧めします。
これは、機械学習ツールボックスを使用して、Matlabなどのツールで非常にすばやくコーディングできます。 MoG/EM学習/ K-Meansクラスタリングは、Web /標準テキストで広く議論されています。私の好きなテキストは、Duda/Hartによる「パターン分類」です。
これを研究論文として整理させてください
a。問題の説明
引用 Epaga : "この領域に「ドット」が分布している2D領域があります。現在、ドットの「クラスター」、つまり特定の高密度のドットがある領域を検出しようとしています。 「」
ドットが画像からのものであるとはどこにも言及されていないことに注意してください。 (1つとして注文することもできますが)。
b.Methodケース1:ポイントが単なるドットの場合(ドット= 2D空間内のポイント)。このシナリオでは、すべてのポイントにxとyの両方の場所がすでにあります。問題は、ポイントのクラスタリングの1つになります。 Ivan は解決策を提案するという素晴らしい仕事をしました。彼はまた、同様のフレーバーの他の回答を要約しました。彼の投稿に加えて私の2ctは、クラスターの数を事前に知っているかどうかを検討することです。アルゴリズム(教師ありクラスタリングと教師なしクラスタリングを適宜選択できます)。
ケース2:ポイントが実際に画像に由来する場合。ここで問題を明確にする必要があります。この画像を使って説明させてください ドットのグレー値が区別されない場合、グループ1、2、3、4、および5はすべて「別個のクラスター」です。ただし、グレー値に基づいて区別する場合、ドットのグレー値が異なるため、クラスター5には注意が必要です。
とにかく、この問題は、画像をラスタースキャンし、ゼロ以外(白以外)のピクセルの座標を保存することで、ケース1に減らすことができます。次に、前述のように、クラスタリングアルゴリズムを使用して、クラスターとクラスターセンターの数を計算できます。
「特定の高密度の領域」とは、単位面積あたりのドットの数がおおよそわかっていることを意味します。これにより、グリッドアプローチに進みます。このアプローチでは、合計領域を適切なサイズのサブ領域に分割し、各領域のドット数をカウントします。しきい値の近くにグリッドの領域が見つかったら、グリッドの隣接する領域も検索できます。
ドットとクラスターの間にどれだけの分離があるかによると思います。距離が大きくて不規則な場合は、最初に triangulate ポイントを作成し、次に統計的に長いエッジ長を持つすべての三角形を削除/非表示にします。残りのサブ三角形分割は、任意の形状のクラスターを形成します。これらのサブ三角形分割のエッジをトラバースすると、各クラスター内にある特定のポイントを判別するために使用できるポリゴンが生成されます。必要に応じて、ポリゴンをケントフレドリックのトーラスなどの既知の形状と比較することもできます。
IMO、グリッドメソッドは、迅速でダーティなソリューションには適していますが、スパースデータでは非常にすぐに空腹になります。四分木は優れていますが、TINは、より複雑な分析のための私の個人的なお気に入りです。
Accusoft PegasusのImagXpressのようなシンプルな既製のソリューションを試しましたか?
BlobRemovalメソッドは、ピクセル数と密度を調整して、連続していない場合でも穴あけを見つけることができます。 (ギャップを埋めるために拡張機能を試すこともできます)
少し遊んでみると、ほとんどの場合、コードや科学がほとんどなくても、必要な結果を得ることができます。
C#:
public void DocumentBlobRemoval(Rectangle Area、int MinPixelCount、int MaxPixelCount、short MinDensity)
平面上に論理グリッドをオーバーレイできます。グリッドに一定数のドットが含まれている場合、それは「密」と見なされ、薄くなる可能性があります。これは、クラスター許容値を操作するときにGISアプリケーションで多く実行されます。グリッドを使用すると、間引きアルゴリズムを区分化するのに役立ちます。
Cluster 3.0には、統計的クラスタリングを行うためのCメソッドのライブラリが含まれています。ドットクラスターがどのような形式をとるかによって問題が解決する場合と解決しない場合がある、いくつかの異なる方法があります。ライブラリはここから入手できます ここ そしてPythonライセンスの下で配布されます。
これには遺伝的アルゴリズムを使用できます。たとえば、「クラスター」をドット密度の高い長方形のサブエリアとして定義すると、「ソリューション」の初期セットを作成できます。各ソリューションは、ランダムに生成された、重複しない長方形のクラスターで構成されます。 。次に、各ソリューションを評価する「適応度関数」を記述します。この場合、適応度関数でクラスターの総数を最小化し、各クラスター内のドット密度を最大化する必要があります。
最初の「解決策」のセットはすべてひどいものになる可能性が高いですが、他のものよりも少しひどいものが少ない可能性があります。適応度関数を使用して最悪のソリューションを排除し、最後の世代の「勝者」を交配して次世代のソリューションを作成します。このプロセスを世代ごとに繰り返すことで、この問題に対する1つ以上の優れた解決策が得られるはずです。
遺伝的アルゴリズムが機能するためには、問題空間に対するさまざまな可能な解決策が、問題をどれだけうまく解決するかという点で、互いに段階的に異なる必要があります。ドットクラスターはこれに最適です。
各ポイントから他のすべてのポイントまでの距離を計算します。次に、距離を並べ替えます。互いに距離がしきい値を下回っているポイントは、Nearと見なされます。互いにnearであるポイントのグループはクラスターです。
問題は、clusterは、グラフを見ると人間には明らかかもしれませんが、明確な数学的定義がないことです。 nearしきい値を定義する必要があります。おそらく、アルゴリズムの結果が(多かれ少なかれ)クラスター化されていると感じるものと等しくなるまで、経験的に調整します。