Python 如何在3D域中检测特定序列的结束位置(x,y,z)

Python 如何在3D域中检测特定序列的结束位置(x,y,z),python,algorithm,graph,analytics,d3dimage,Python,Algorithm,Graph,Analytics,D3dimage,我对蛋白质进行了3D creo-EM扫描,这样它就包含了一条围绕自身弯曲和扭曲的链——在三维空间中有两条链的末端(像连续的绳子)。我需要检测(x,y,z)在给定立方体空间中两个或可能是两个端点的乘法器的位置。扫描的立方体空间由扫描EM显微镜提供的每个体素(范围0到1)中的密度表示,因此“现有物质”给出的值接近1,“无物质”给出的密度值接近0。我需要一种方法来检测蛋白质的“绳子”边缘(可能的“绳子末端”定义是在某些纠结的方向上缺乏连续性。直觉上,我认为至少有两种方法:1)图论中的某些方法(我不能精

我对蛋白质进行了3D creo-EM扫描,这样它就包含了一条围绕自身弯曲和扭曲的链——在三维空间中有两条链的末端(像连续的绳子)。我需要检测(x,y,z)在给定立方体空间中两个或可能是两个端点的乘法器的位置。扫描的立方体空间由扫描EM显微镜提供的每个体素(范围0到1)中的密度表示,因此“现有物质”给出的值接近1,“无物质”给出的密度值接近0。我需要一种方法来检测蛋白质的“绳子”边缘(可能的“绳子末端”定义是在某些纠结的方向上缺乏连续性。直觉上,我认为至少有两种方法:1)图论中的某些方法(我不能精确指定-如果你知道-请命名或描述它。2)解析代数的导数——但我也不能说明具体的态度——所以请说出或解释一个。请指定建议方法的计算复杂度。我的项目是用Python实现的。请帮忙。提前感谢。

一种方法是选择阈值密度,将低于该阈值的所有体素转换为0,将高于该阈值的所有体素转换为1,然后在所有1-体素对中查找最短路径最长的1-体素对。这两个体素应该靠近最长“绳索”的末端,而不管绳索的确切形状如何

您可以定义一个图形,其中每个1体素有一个顶点,每个1体素与其6个(或可能14个)邻居之间有一条边。然后,您可以使用宽度优先搜索(这里不需要Dijkstra或Floyd Warshall,因为每条边都有权重1),计算某个给定顶点u和O(|V |)时间和空间中其他每个顶点之间的最短路径长度。对每个可能的起始顶点u重复此操作将给出一个O(| V | ^2)-时间算法。执行此操作时,请跟踪到目前为止最远的一对

如果你的体素空间有w*h*d个单元,那么图中可能有w*h*d个顶点(如果每个体素都是一个1-体素),所以在最坏的情况下,这可能需要O(w^2*h^2*d^2)时间,这可能相当多。幸运的是,如果你能给出一个稍微不精确的答案,有很多方法可以加快速度:

  • 仅计算位于边界处的起始顶点的最短路径,即具有少于6个(或14个)邻居的顶点。(我相信这不会牺牲最佳解决方案。)
  • 或者,首先通过反复删除所有这些边界顶点来“骨架化”图形,这些边界顶点的删除不会断开图形
  • 选择起始顶点的一个好顺序是首先选择任何顶点,然后始终选择与最后一个顶点的最大可能距离处的顶点(当然,还没有尝试过)。经过3次迭代后,这将使您非常接近最长最短路径:距离起始顶点最远的顶点将靠近两个绳索末端之一,距离该顶点最远的顶点将靠近另一端

注意:如果由于弯曲,绳索上彼此靠近的远点之间没有完整的体素间隙,则最短路径将通过这些错误连接“短路”,并可能降低精度。您可以通过增加阈值来改善这一点。OTOH,如果阈值太高,那么绳子可能会断开。我希望您希望选择仅导致1个连接组件的最高阈值。

如果您希望在3D扫描中枚举每个连续路径(从而获得每个路径的端点),您可以对每个位置应用基本的深度优先搜索,例如:

//applied at some voxel
dfs(...)
    for each surrounding voxel 
        dfs(...)
或详细说明:

class coordinate{
    x
    y
    z
    visited
}

initialize pathList
initialize coords

add all coordinates which contain "matter" to coords

dfs(coordinate,path)
    coordinate.visited = TRUE
    isEnd = TRUE
    FOR each coordinate
        //check each of the 26 possible locations (total 26 conditionals)
        IF coordinate.get(x-1,y-1,z+1) IN coords AND 
           NOT coordinate.get(x-1,y-1,z+1).visited THEN
            isEnd = FALSE
            path += coordinate.get(x-1,y-1,z+1)
            dfs(coordinate.get(x-1,y-1,z+1),path)
        ...
        IF coordinate.get(x+1,y+1,z-1) IN coords AND 
           NOT coordinate.get(x+1,y+1,z-1).visited THEN 
            isEnd = FALSE
            path += coordinate.get(x+1,y+1,z-1) 
            dfs(coordinate.get(x+1,y+1,z-1),path)
    IF isEnd THEN
        add path to pathList
    remove coordinate from coords

WHILE coords isn't empty
    dfs(coords.get(0),"")
通用过程(dfs)在几十个其他站点上都有很好的文档记录,但是如果您想测试它,这里有一些粗糙的java(我对python不太熟悉),它反映了上面的内容:

公共C类{
ArrayList coords=新的ArrayList();
ArrayList路径=新的ArrayList();
静态类坐标{
int x,y,z;
参观;
坐标(整数x,整数y,整数z){
这个.x=x;
这个。y=y;
这个。z=z;
访问=假;
}
公共字符串toString(){
返回“(“+x+”、“+y+”、“+z+”)”;
}
}
无效dfs(坐标c,字符串路径){
c、 访问=真实;
path+=c.toString();
布尔值isEnd=true;
//将dfs应用于26个可能的邻居
对于(int x=c.x-1;x