首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >一种点的“簇”检测算法

一种点的“簇”检测算法
EN

Stack Overflow用户
提问于 2008-12-10 13:28:26
回答 16查看 20.1K关注 0票数 43

我有一个2D区域,在这个区域上分布着“点”。我现在正在尝试检测点的“簇”,即具有特定高密度点的区域。

有没有关于如何优雅地检测这些区域的想法(或者链接到文章的链接)?

EN

回答 16

Stack Overflow用户

回答已采纳

发布于 2008-12-10 13:40:44

如何为你的空间定义一个任意的分辨率,并为矩阵中的每个点计算从该点到所有点的距离,然后你可以制作一个“热图”,并使用一个阈值来定义集群。

这是一个很好的处理练习,也许稍后我会发布一个解决方案。

编辑:

这就是它:

代码语言:javascript
复制
//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(低效代码稍少,但输出相同):

代码语言:javascript
复制
//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);
*/

以及使用(简化的) Kent样本的输出:

票数 24
EN

Stack Overflow用户

发布于 2009-01-05 18:28:05

我建议使用mean-shift内核来找到点的密度中心。

Mean-shift illustration http://cvr.yorku.ca/members/gradstudents/kosta/compvis/file_mean_shift_path.gif

该图显示了mean-shift内核(最初以集群边缘为中心)向集群的最高密度点收敛。

理论上(简而言之):

这个问题的几个答案已经暗示了mean-shift的方法:

您在动画图形中看到的是这两个建议的组合:它使用移动的“块”(即内核)来寻求局部最高密度。

均值偏移是一种迭代方法,它使用称为内核的像素邻域(类似于this one),并使用它来计算底层图像数据的平均值。在此上下文中的平均值是内核坐标的像素加权平均值。

在每次迭代中,内核的平均值定义了下一次迭代的中心坐标-这称为移位。因此得名mean-shift。迭代的停止条件是当移位距离降为0时(即,我们处于邻域中最密集的点)。

有关均值漂移的全面介绍(包括理论和应用),请参阅this ppt presentation.

在实践中:

OpenCV中提供了mean-shift的实现

代码语言:javascript
复制
int cvMeanShift( const CvArr* prob_image, CvRect window,
                 CvTermCriteria criteria, CvConnectedComp* comp );

O'Reilly's Learning OpenCv (google book excerpts)对它的工作原理也有一个很好的解释。基本上就是给它提供你的点图像(prob_image)。

在实践中,诀窍是选择适当的内核大小。内核越小,就越需要将其初始化到集群中。内核越大,初始位置的随机性就越大。但是,如果您的图像中有几个点的群集,内核可能会在它们之间收敛。

票数 24
EN

Stack Overflow用户

发布于 2008-12-10 13:56:31

为了给Trebs语句增加一点帮助,我认为重要的是首先实际地定义集群的定义是什么,当然,“更紧密的点在一起”,这是相当有意义的。

以我生成的样本集为例,我知道那里有一个簇形状,我创建了它。

然而,以编程方式识别这个“集群”可能很困难。

人类可能会认为这是一个大的环形星团,但你的自动程序更有可能决定它是一系列半近距离的较小星团。

此外,请注意,有一些超高密度的区域,这些区域处于更大的背景下,只是分散了注意力。

您将需要考虑此行为,并可能将类似密度的集群链接在一起,仅由较低密度的无关紧要的空洞分隔,这取决于特定的应用程序。

无论您开发什么,我至少会对它如何识别这个集合中的数据感兴趣。

(我认为研究HDRI ToneMapping背后的技术可能是合适的,因为这些技术或多或少地作用于光密度,并且有“局部”色调映射和“全局”色调映射,每个色调映射产生不同的结果)

票数 12
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/356035

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档