我在这个区域有一个带有“点”的2D区域。我现在正在尝试检测点的“簇”,即具有一定高密度点的区域。
对如何优雅地检测这些区域的任何想法(或链接到有关思考的文章)?
答案 0 :(得分:24)
如何为您的空间定义任意分辨率,并计算该矩阵中的每个点,衡量从该点到所有点的距离,然后您可以制作“热图”并使用阈值来定义簇。
这是一个很好的处理练习,也许以后我会发布一个解决方案。
编辑:
这是:
//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);
*/
输出(减少的)肯特样本:
答案 1 :(得分:23)
我建议使用均值漂移内核来查找点的密度中心。
此图显示了一个平均移位内核(最初以群集边缘为中心)收敛到群集的最高密度点。
这个问题的几个答案已经暗示了这种做法的平均转变方式:
P Daddy's blurring the image and finding the darkest spot实际上是一种kernel density estimation(KDE)方法,它是均值漂移的理论基础。
j0rd4n和Bill the Lizard建议将您的空间分隔成块并检查其密度。
您在动画人物中看到的是这两个建议的组合:它使用移动的“块”(即内核)来寻找当地最高的密度。
均值漂移是一种迭代方法,它使用一个名为内核的像素邻域(类似于this one)并使用它来计算均值底层图像数据。此上下文中的 mean 是内核坐标的像素加权平均值。
在每次迭代中,内核的平均值定义下一次迭代的中心坐标 - 这称为 shift 。因此名称 mean-shift 。迭代的停止条件是当移位距离下降到0时(即,我们处于邻域中最密集的点)。
中找到关于均值漂移(理论和应用)的全面介绍OpenCV中提供了均值漂移的实现:
int cvMeanShift( const CvArr* prob_image, CvRect window,
CvTermCriteria criteria, CvConnectedComp* comp );
O'Reilly's Learning OpenCv (google book excerpts)对其工作方式也有很好的解释。基本上只是喂你的点图像(prob_image)。
在实践中,诀窍是选择足够的内核大小。内核越小,就越需要将其发送到集群。内核越大,初始位置就越随机。但是,如果图像中有多个点簇,则内核可能会在它们之间汇聚。
答案 2 :(得分:13)
为了向Trebs语句添加一点助手,我认为现实地首先定义群集的定义是肯定的,“点在一起”,这很重要。
拿这个我生成的样本集,我知道那里有一个簇形状,我创建了它。
但是,以编程方式识别此“群集”可能很难。
人类可能会认为是一个大的环形星团,但是你的自动程序更有可能决定它是一系列半近距离的小型星团。
另外,请注意,存在超高密度区域,这些区域在更大的背景下,仅仅是分心
您需要考虑这种行为,并可能将相似密度的簇链接在一起,这些簇仅由较低密度的微小空隙分开,具体取决于具体应用。
无论你开发什么,我至少会对它如何识别这一组中的数据感兴趣。
(我认为研究HDRI ToneMapping背后的技术可能是有序的,因为它们或多或少地对光密度起作用,并且有“本地”色调图和“全局”色调图,每个都会产生不同的结果)< / p>
答案 3 :(得分:12)
将模糊滤镜应用于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
“较暗”的区域现在可以识别出多个点。
答案 4 :(得分:10)
您可以尝试创建数据的Quadtree表示。图中较短的路径对应于高密度区域。
或者,更清楚地说明:给定四叉树和水平顺序遍历,由“点”组成的每个低级节点将代表高密度区域。随着节点级别的增加,这些节点代表“点”的低密度区域
答案 5 :(得分:5)
形态学方法怎么样?
将阈值图像扩展一些数字(取决于点的目标密度),然后群集中的点将显示为单个对象。
OpenCV支持形态学操作(与一系列图像处理库一样):
http://www.seas.upenn.edu/~bensapp/opencvdocs/ref/opencvref_cv.htm#cv_imgproc_morphology
答案 6 :(得分:4)
这听起来像是一个学术问题。
想到的解决方案涉及r *树。这会将您的总面积划分为单独尺寸和可能重叠的框。完成此操作后,您可以通过计算平均距离来确定每个框是否代表“群集”。
如果这种方法变得难以实现,最好将数据网格划分为相等大小的细分,并确定每个细分是否发生;尽管如此,你必须非常注意边缘条件。我建议在初始划分之后,您将通过并在定义边缘的特定阈值内重新组合具有数据点的区域。
答案 7 :(得分:4)
这可以使用机器学习工具箱在Matlab等工具中快速编码。在网络/标准文本中广泛讨论了MoG / EM学习/ K-Means聚类。我最喜欢的文字是Duda / Hart的“模式分类”。
答案 8 :(得分:3)
“具有一定高密度的区域”意味着您大致了解每单位面积中您认为高的点数。这使我走向网格方法,您将总面积分成适当大小的子区域,然后计算每个区域中的点数。一旦找到靠近阈值的网格区域,您也可以搜索网格的相邻区域。
答案 9 :(得分:3)
让我把它作为研究论文组织起来
<强>一个。问题陈述
引用Epaga: “我在这个区域有一个带有”点“的2D区域。我现在正在尝试检测点的”簇“,即具有一定高密度点的区域。”
请注意,没有提到点是来自图像。 (虽然它们可以作为一个订购)。
<强>弘强> 情况1:如果点只是点(点= 2D空间中的点)。 在这种情况下,您已经拥有x&amp; y所有点的位置。问题减少到集中点之一。 Ivan在提出解决方案方面做得很好。他还总结了其他类似风味的答案。 我的帖子除了他的帖子之外,你考虑的是你是否知道先验集群的数量。算法(可以相应地选择监督与非监督聚类)。
案例2:如果这些点确实来自图像。这里需要澄清问题。让我解释一下使用这张图片 如果没有对点的灰度值进行区分,则组1,2,3,4和4表示。 5都是“不同的集群”。但是,如果基于灰度值进行区分,则簇5很棘手,因为点具有不同的灰度值。
无论如何,通过光栅扫描图像并存储非零(非白色)像素的坐标,可以将该问题简化为情况1。然后,可以使用之前提出的聚类算法来计算聚类和聚类中心的数量。
答案 10 :(得分:2)
我认为这取决于点和簇之间的分离程度。如果距离很大且不规则,我最初会triangulate这些点,然后删除/隐藏具有统计上较大边长的所有三角形。剩余的子三角测量形成任意形状的簇。遍历这些子三角测量的边缘产生多边形,这些多边形可用于确定每个簇中的哪些特定点。根据需要,也可以将多边形与已知的形状进行比较,例如Kent Fredric的圆环。
IMO,网格方法适用于快速和脏的解决方案,但在稀疏数据上非常快速地变得非常饥饿。四棵树更好,但TIN是我个人最喜欢的任何更复杂的分析。
答案 11 :(得分:0)
我会计算从每个点到所有其他点的距离。然后对距离进行排序。彼此之间的距离低于阈值的点被视为 Near 。 在附近的一组点是一个集群。
问题在于,人们在看到图表时可能会清楚 cluster ,但没有明确的数学定义。您需要定义 near 阈值,可能需要根据经验进行调整,直到您的算法结果(或多或少)等于您认为的群集结果。
答案 12 :(得分:0)
您可以在您的飞机上叠加逻辑网格。如果网格具有一定数量的包含点,则认为它是“密集的”,然后可以变薄。在处理群集容差时,这在GIS应用程序中完成了很多工作。使用网格有助于划分稀疏算法。
答案 13 :(得分:0)
你可以使用遗传算法。如果将“簇”定义为具有高点密度的矩形子区域,则可以创建一组初始的“解决方案”,每个“解决方案”由一些随机生成的非重叠矩形簇组成。然后,您将编写一个“适应度函数”来评估每个解决方案 - 在这种情况下,您希望适应度函数最小化聚类总数,同时最大化每个聚类中的点密度。
你最初的“解决方案”一切都很糟糕,很可能,但有些可能会比其他解决方案稍微糟糕一些。您使用适应度函数来消除最糟糕的解决方案,然后通过交叉培育上一代的“赢家”来创建下一代解决方案。通过逐代重复这个过程,你应该得到一个或多个解决这个问题的好方法。
为了使遗传算法起作用,问题空间的不同可能解决方案在解决问题的程度方面必须逐渐增加。点簇是完美的。
答案 14 :(得分:0)
Cluster 3.0包含一个用于进行统计聚类的C方法库。它有一些不同的方法,可能会或可能不会解决您的问题,加快您的点群集采取什么形式。该库在here可用,并在Python许可下发布。
答案 15 :(得分:0)
您是否尝试过简单的现成解决方案,例如Accusoft Pegasus的ImagXpress?
可以调整BlobRemoval方法的像素数和密度,以找到打孔,即使它们不连续。 (您也可以尝试使用Dilate函数来缩小间隙)
通过一点点游戏,您可以在绝大多数情况下获得所需的结果,只需很少的代码或科学。
C#:
public void DocumentBlobRemoval(
矩形区域,
int MinPixelCount,
int MaxPixelCount,
简短MinDensity
)