非常大的图像中的记忆效率线缝合

时间:2011-01-29 14:45:34

标签: c image-processing scalability feature-detection satellite-image

背景

我使用Synthetic Aperture Radar卫星的非常大的数据集。这些可以被认为是一侧10k像素量级的高动态范围灰度图像。

最近,我一直在开发Lindeberg's scale-space ridge detection algorithm method的单尺度变体的应用程序,用于检测SAR图像中的线性特征。这是对使用方向滤波器或使用Hough变换的改进,这两种方法以前都使用过,因为它的计算成本低于其中任何一种。 (我将在4月的JURSE 2011上介绍一些最近的结果,如果有帮助,我可以上传预印本。)

我目前使用的代码生成一个记录数组,每个像素一个,每个记录描述矩形到像素右下角的一个脊段,并由相邻的像素限定。

struct ridge_t { unsigned char top, left, bottom, right };
int rows, cols;
struct ridge_t *ridges;  /* An array of rows*cols ridge entries */

ridges中的条目包含一个脊段,如果topleftrightbottom中只有两个值的范围为0 - 128假设我有:

ridge_t entry;
entry.top = 25; entry.left = 255; entry.bottom = 255; entry.right = 76;

然后我可以找到脊段的开始(x1,y1)和结束(x2,y2):

float x1, y1, x2, y2;
x1 = (float) col + (float) entry.top / 128.0;
y1 = (float) row;
x2 = (float) col + 1;
y2 = (float) row + (float) entry.right / 128.0;

当渲染这些单独的脊段时,我得到的图像就像这样(图像的一个非常小的角落):

Rendered ridge segments

每条长曲线都是从一系列细小的脊段中渲染出来的。

确定是否连接了包含脊段的两个相邻位置是微不足道的。如果我在(x,y)和ridge1处有ridge2(x + 1,y),那么如果0 <= ridge1.right&lt; =,它们就是同一行的一部分128 ridge2.left = ridge1.right

问题

理想情况下,我想将所有脊线段拼接成线,这样我就可以遍历图像中找到的每个线来应用进一步的计算。不幸的是,我发现很难找到一个算法来做到这一点,它既低复杂度内存效率适合多处理(真正处理时所有重要的考虑因素)巨大的图像!)

我考虑过的一种方法是扫描图像,直到找到一个只有一个连接的脊段的脊,然后走过生成的线,标记线上的任何脊。但是,这不适用于多处理,因为没有办法判断是否没有另一个线程从另一个方向(例如)走同一条线而没有昂贵的锁定。

读者建议采用什么方法?看起来有人会在过去想出一个有效的方法......

4 个答案:

答案 0 :(得分:4)

答案 1 :(得分:2)

您可以使用Hough Transform的非通用形式。它似乎在N x N网格数组上达到令人印象深刻的O(N)时间复杂度(如果您可以访问~10000x10000 SIMD数组且网格为N x N - 请注意:在您的情况下,{ {1}}将是一个脊结构,或N脊的集群,而不是像素)。 Click for Source。更保守的(非内核)解决方案将复杂度列为O(kN ^ 2),其中A x BSource

然而,Hough变换确实有一些陡峭的内存要求,并且空间复杂度将是O(kN)但是如果你预先计算k = [-π/2, π]sin()并提供适当的查找表,它会去下降到O(k + N),这可能仍然太多,取决于你cos()的大小......但是我没有看到你得到它更低。

编辑:跨线程/内核/ SIMD /流程线元素的问题并非易事。我的第一个冲动告诉我将网格细分为递归四叉树(取决于一定的公差),检查直接边缘并忽略所有边缘脊结构(您实际上可以将它们标记为“潜在的长线”并在整个分布式系统中共享它们);只是对那个特定四边形中的所有内容进行工作并逐步向外移动。这是一个图形表示(绿色是第一遍,红色是第二遍,等等)。但是,我的直觉告诉我,这在计算上很昂贵。

Passes

答案 2 :(得分:0)

如果脊得到足够的分辨,断裂只有几个像素,那么标准扩张 - 找到邻居 - 侵蚀你要做的寻找线/ OCR的步骤应该有效。

从许多细分中加入更长的轮廓并知道何时创建颈部或何时制作单独的岛屿要复杂得多

答案 3 :(得分:0)

好的,所以考虑到这个问题的时间有点长,我有一个建议,看起来效率太简单了......我很欣赏一些关于它是否合理的反馈!

1)由于我可以轻松确定每个ridge_t脊段是否连接到零,一个或两个相邻的段,我可以适当地为每个段着色(LINE_NONELINE_ENDLINE_MID)。这可以很容易地并行完成,因为没有竞争条件的可能性。

2)着色完成后:

for each `LINE_END` ridge segment X found:
    traverse line until another `LINE_END` ridge segment Y found
    if X is earlier in memory than Y:
        change X to `LINE_START`
    else:
        change Y to `LINE_START`

这也没有竞争条件,因为即使两个线程同时遍历同一条线,它们也会做同样的改变。

3)现在,图像中的每一行都有一个标记为LINE_START的结尾。这些线可以在一个线程中找到并打包成更方便的结构,而无需进行任何查找以查看该线是否已被访问过。

我可能会考虑是否应该在步骤2中收集行长等统计数据,以帮助最终重新包装...

我错过了任何陷阱吗?

编辑:显而易见的问题是,我最后两次走线,一次找到RIDGE_START,一次做最后的重新打包,导致计算效率低下。尽管如此,它在存储和计算时间方面似乎仍然是O(N),这是一个好兆头......