我有一个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
答案 0 :(得分:1)
我认为你的方法和你一样好。
将indices
列表的表示视为有向图,其中每个通道都是一个节点,边(u
,v
)表示输出通道{{1 }取决于输入渠道v
。
如上所述,您的解决方案会找到一个没有出站边缘的节点,删除此节点及其传入边缘,并重复直到无法删除任何更多节点。如果没有剩下的节点,那么你就完成了 - 如果还有节点,你就会被卡住。
在我们的图表表示中,卡住表示存在循环。添加临时通道让我们“拆分”一个节点并打破循环。
但是,在这一点上,我们可能希望变得聪明。是否有任何我们可以拆分的节点会破坏多个循环?不幸的是,答案是否定的。每个节点只有一个入站边,因为每个输出通道u
只能依赖于一个输入通道。为了使节点成为多个周期的一部分,它(或其他一些节点)必须有两个入站边。
因此,我们可以通过添加临时通道来中断每个周期,添加临时通道只能打破一个周期。
此外,当您剩下的只是循环时,拆分任何节点都会破坏其中一个循环。所以你不需要任何花哨的启发式方法。只需运行您现在拥有的代码,直到完成为止 - 如果仍有v
,请添加临时频道并再次运行代码。