Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/346.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 为一组点生成最近邻距离贴图_Python_Nearest Neighbor - Fatal编程技术网

Python 为一组点生成最近邻距离贴图

Python 为一组点生成最近邻距离贴图,python,nearest-neighbor,Python,Nearest Neighbor,我有一个(x,y)点的列表。我试图以图像的形式绘制到每个点的距离图,因此我的朴素函数如下所示: from scipy.spatial.distance import cdist from numpy import * def findDistances(imageSize, points): image = zeros(imageSize) for x in range(0,imageSize[1]): for y in range(0,imageSize[0]

我有一个(x,y)点的列表。我试图以图像的形式绘制到每个点的距离图,因此我的朴素函数如下所示:

from scipy.spatial.distance import cdist
from numpy import *

def findDistances(imageSize, points):
    image = zeros(imageSize)
    for x in range(0,imageSize[1]):
        for y in range(0,imageSize[0]):
            image[y,x] = np.min(cdist(array([[x,y]]), points))
    return image
这个函数很好,它给出了我想要的(见下图)。对于一张1MP的图像,这大约需要100秒,对于只需要做一次的事情来说,这是很好的,但我认为还有改进的空间。我还尝试:

image[y,x] = min(linalg.norm(array([[x,y]])- points, axis=1))
这在一个可比的时间内运行-有道理,他们可能正在做一些类似的引擎盖下,虽然我还没有检查的来源,以确保

我看了一下Scipy的cKDTree,其中有:

from scipy.spatial import cKDTree

def findDistancesTree(imageSize, points):
    tree = cKDTree(points)
    image = zeros(imageSize)
    for x in range(0,imageSize[1]):
        for y in range(0,imageSize[0]):
            image[y,x] = tree.query([x,y])[0]
    return image
调用
tree.query
大约需要50µs(从
%timeit
开始),而实际上,生成1MP距离图需要70-80µs。20秒的进步比踢腹股沟要好,但我不知道我是否能进一步提高

%timeit np.min(linalg.norm(array([[random.random()*1000,random.random()*1000]]) - points, axis=1))
%timeit np.min(cdist(array([[random.random()*1000,random.random()*1000]]), points))
%timeit tree.query(array([[random.random()*1000,random.random()*1000]]))

10000 loops, best of 3: 82.8 µs per loop
10000 loops, best of 3: 67.9 µs per loop
10000 loops, best of 3: 52.3 µs per loop
就复杂性而言,蛮力应该类似于
O(NM)
,其中
N
是图像中的像素数,
M
是要检查的点数。我期待着更多的加速,因为搜索时间应该更像
O(N log(M))
对于
N
像素,每个像素都有
log(M)
查找时间-我遗漏了什么吗

也许可以找到您想要的解决方案

其想法是:

  • 计算Voronoi图或O(M ln(M))中的M点
  • 对于N个像素中的每一个像素
    • 找到对应的区域
    • 计算到区域点的距离
现在的问题是如何找到与O(ln(M))中的像素对应的区域


希望这有帮助

这听起来像是一个问题,即使是使用GPU的基本蛮力实现也能带来很好的改进。所以我试了一下。而且进步也很好

我使用pyopencl进行了测试

import pyopencl as cl 
import numpy as np 

def findDistances_cl(imageSize, points):
    #Boilerplate opencl code
    ctx = cl.create_some_context()
    queue = cl.CommandQueue(ctx)

    f = open('nn.cl', 'r')
    fstr = "".join(f.readlines())
    program = cl.Program(ctx, fstr).build()

    #Creating buffers for the opencl kernel
    mf = cl.mem_flags
    img = np.empty(imageSize, dtype=np.float32)
    x_buf = cl.Buffer(ctx, mf.READ_ONLY | mf.USE_HOST_PTR, hostbuf=points[:,0].astype(np.float32))
    y_buf = cl.Buffer(ctx, mf.READ_ONLY | mf.USE_HOST_PTR, hostbuf=points[:,1].astype(np.float32))
    n_points = cl.Buffer(ctx, mf.READ_ONLY | mf.USE_HOST_PTR, hostbuf=np.array([len(points)],dtype=np.int))
    img_buf = cl.Buffer(ctx, mf.WRITE_ONLY, img.nbytes)

    #Run the kernel
    exec_evt = program.nn(queue, img.shape, None, img_buf, x_buf, y_buf, n_points)
    exec_evt.wait()
    #read back the result
    cl.enqueue_read_buffer(queue, img_buf, img).wait()

    return img
opencl内核(nn.cl)


速度提高约490倍。如果您需要更高的速度,有更先进的算法可用于使用GPU进行近邻运算。

您可以使用分层聚类对点进行聚类,即dendogram。对于每棵树,您可以计算voronoi图和polygone函数中的一个点。

我认为基本kd树的最近邻搜索通常不是O(log(M))操作,因为您的点不是随机分布的。我确实有过这种情况。我尝试使用Scipy的voronoi函数和matplotlib的路径。检查每个多边形是否命中大约需要10µs。问题是有1200个左右的多边形,检查每一个都相当于一个蛮力,我想还有一个更聪明的方法来决定检查哪些多边形。实际的图表生成非常快,只有几毫秒。我想还有一种更聪明的方法。“点位置”查询在中有很好的文档记录。这可能是一个很好的灵感来源。点定位很难理解。最好不要。困难但有效率。很高兴知道。这太棒了,在我的GeForce 9400米上大约需要2.5秒。我会在我的iMac上试一试,觉得它有更强劲的东西。以前从未使用过pyopencl,使用起来似乎非常简单!我还编辑了函数定义中的_globals,否则会挂起我的系统-我检查了输出,更改后看起来很好。@Josh我在你建议的编辑中编辑过,似乎你的编辑被审稿人拒绝了。尽管我似乎还记得,对于参数,还有一些其他的标志,使它们被放置在每个内核的本地内存中。那可能更快。你知道为什么它以前挂着吗?编译的模块正常运行,但对
wait()
的调用从未返回。此外,还更新了编辑-它可能取决于OpenCL的版本。在我的iMac上,您的原始代码编译没有任何问题(在Radeon 6770M上运行只需0.31秒)。所以可能只是我那笨重的旧Macbook造成了问题。
__kernel void nn(__global float *output, __global constant float *x , __global constant float *y, __global constant int *numPoints)
    {
        int row = get_global_id(0);
        int col = get_global_id(1);

        int numRows = get_global_size(0);
        int numCols = get_global_size(1);

        int gid = col+ row*numCols;

        float minDist = numRows * numCols;

        for(int i = 0; i < *numPoints; i++){
          minDist = min(minDist, sqrt((row - y[i])*(row - y[i]) + (col - x[i])*(col - x[i])));
        }
        output[gid] = minDist;
    }
imageSize = [1000, 1000]
points = np.random.random((1000,2))*imageSize[0]

In [4]: %timeit findDistancesTree(imageSize, points)
1 loops, best of 3: 27.1 s per loop

In [7]: %timeit findDistances_cl(imageSize, points)
10 loops, best of 3: 55.3 ms per loop