2

我有一个i频道图像,image. 我也有f过滤器,filters可以应用于频道。我想通过有选择地将过滤器应用于图像的通道来生成o通道图像。output我目前用两个列表定义了这个,image_idx并且filter_idx,因此处理完成为

for j in xrange(o) :
    output[j] = filter[filter_idx[j]](image[image_idx[j]])

因为图像可能非常大,我可能想就地进行此处理。这可能需要按特定顺序处理通道,以避免覆盖您稍后需要的数据。我目前正在检查是否存在这样的订单,并使用以下函数对其进行计算:

def in_place_sequence(indices) :
    """
    Figure out a processing sequence for in-place computation.
    """
    indices = [j for j in indices]
    positions = set(range(len(indices)))
    processing_order = []
    change = True
    while change and len(positions) :
        change = False
        for j in list(positions) :
            val = indices[j]
            if (j not in indices) or (indices.count(val) == 1 and val == j) :
                indices[j] = None
                positions.remove(j)
                processing_order.append(j)
                change = True
    if len(positions) :
        return None
    return processing_order

例如:

In [21]: in_place_sequence([4, 0, 3, 0, 4])
Out[21]: [1, 2, 3, 0, 4]

避免覆盖的可能处理顺序是:

img[0] -> img[1]
img[3] -> img[2]
img[0] -> img[3]
img[4] -> img[0]
img[4] -> img[4]

这是实现的:

for j in in_place_sequence(image_idx) :
    image[j] = filter[filter_idx[j]](image[image_idx[j]])

我开始暗示,当它找不到序列时,是因为image_idx定义了一个闭环排列。例如:

In [29]: in_place_sequence([2, 0, 3, 1])

返回None,但它仍然可以在 1 个通道的最小存储量的情况下就地完成:

img[0] -> temp
img[2] -> img[0]
img[3] -> img[2]
img[1] -> img[3]
temp   -> img[1]

我在想办法自动实现这一点时遇到了麻烦。我认为你要走的路是保留我当前的算法,如果它无法耗尽positions,找出闭环并为每个闭环做类似上面的事情。不过,我的印象是,我可能在这里重新发明轮子。所以在开始编码之前,我想我会问:确定处理顺序以最小化中间存储的最佳方法是什么?


编辑在 Sam Mussmann 的鼓励下,我已经开始计算剩余的周期。我的代码现在看起来像这样:

def in_place_sequence(indices) :
    """
    Figures out a processing sequence for in-place computation.

    Parameters
    ----------
     indices : array-like
         The positions that the inputs will take in the output after
         processing.

    Returns
    -------
     processing_order : list
         The order in which output should be computed to avoid overwriting
         data needed for a later computation.

     cycles : list of lists
         A list of cycles present in `indices`, that will require a one
         element intermediate storage to compute in place.

    Notes
    -----
    If not doing the opearation in-place, if `in_` is a sequence of elements
    to process with a function `f`, then `indices` would be used as follows to
    create the output `out`:

        >>> out = []
        >>> for idx in indices :
        ...     out.append(f(in_[idx]))

    so that `out[j] = f(in_[indices[j]])`.

    If the operation is to be done in-place, `in_place_sequence` could be used
    as follows:

        >>> sequence, cycles = in_place_sequence(indices)
        >>> for j, idx in enumerate(sequence) :
        ...     in_[j] = f(in_[idx])
        >>> for cycle in cycles :
        ...     temp = in_[cycle[0]]            
        ...     for to, from_ in zip(cycle, cycle[1:]) :
        ...         in_[to] = f(in_[from_])
        ...     in_[cycle[-1]] = f(temp)
    """
    indices = [j for j in indices]
    print indices
    positions = set(range(len(indices)))
    processing_order = []
    change = True
    while change and positions :
        change = False
        for j in list(positions) :
            val = indices[j]
            if (j not in indices) or (indices.count(val) == 1 and val == j) :
                indices[j] = None
                positions.remove(j)
                processing_order.append(j)
                change = True
    cycles = []
    while positions :
        idx = positions.pop()
        start = indices.index(idx)
        cycle = [start]
        while idx != start :
            cycle.append(idx)
            idx = indices[idx]
            positions.remove(idx)
        cycles.append(cycle)
    return processing_order, cycles
4

1 回答 1

1

我认为你的方法和你得到的一样好。

将您的indices列表表示为有向图,其中每个通道是一个节点,边 ( u, v) 表示输出通道v取决于输入通道u

如所写,您的解决方案找到一个没有出站边的节点,删除该节点及其传入边,并重复直到无法删除更多节点。如果没有更多的节点,你就完成了——如果还有节点,你就卡住了。

在我们的图形表示中,被卡住意味着存在一个循环。添加一个临时通道让我们“拆分”一个节点并打破循环。

不过,在这一点上,我们可能想要变得聪明。是否有任何我们可以拆分的节点会破坏一个以上的循环?不幸的是,答案是否定的。每个节点只有一个入站边,因为每个输出通道v只能依赖一个输入通道。为了让一个节点成为多个循环的一部分,它(或某个其他节点)必须有两个入站边。

所以,我们可以通过添加一个临时通道来打破每个循环,而添加一个临时通道只能打破一个循环。

此外,当您只剩下循环时,拆分任何节点都会破坏其中一个循环。所以你不需要任何花哨的启发式方法。只需运行你现在拥有的代码,直到它完成——如果还有positions剩余,添加一个临时通道并再次运行你的代码。

于 2013-02-16T02:56:07.660 回答