2 回答

TA貢獻(xiàn)1797條經(jīng)驗(yàn) 獲得超4個(gè)贊
我曾經(jīng)不得不解決一個(gè)類似的任務(wù),所以我為它創(chuàng)建了以下函數(shù)。它允許為每個(gè)維度指定大小差異的分?jǐn)?shù),應(yīng)該在之前和之后填充(類似于np.pad)。例如,如果您有兩個(gè)形狀數(shù)組(3,)和(5,),那么before=1將在左側(cè)填充整個(gè)差異(在本例2中為 ),而在左側(cè)填充before=0.5一個(gè)元素,在右側(cè)填充一個(gè)元素。與np.pad這些因素類似,也可以為每個(gè)維度指定。這是實(shí)現(xiàn):
import numpy as np
def pad_max_shape(arrays, before=None, after=1, value=0, tie_break=np.floor):
"""Pad the given arrays with a constant values such that their new shapes fit the biggest array.
Parameters
----------
arrays : sequence of arrays of the same rank
before, after : {float, sequence, array_like}
Similar to `np.pad -> pad_width` but specifies the fraction of values to be padded before
and after respectively for each of the arrays. Must be between 0 and 1.
If `before` is given then `after` is ignored.
value : scalar
The pad value.
tie_break : ufunc
The actual number of items to be padded _before_ is computed as the total number of elements
to be padded times the `before` fraction and the actual number of items to be padded _after_
is the remainder. This function determines how the fractional part of the `before` pad width
is treated. The actual `before` pad with is computed as ``tie_break(N * before).astype(int)``
where ``N`` is the total pad width. By default `tie_break` just takes the `np.floor` (i.e.
attributing the fraction part to the `after` pad width). The after pad width is computed as
``total_pad_width - before_pad_width``.
Returns
-------
padded_arrays : list of arrays
Notes
-----
By default the `before` pad width is computed as the floor of the `before` fraction times the number
of missing items for each axis. This is done regardless of whether `before` or `after` is provided
as a function input. For that reason the fractional part of the `before` pad width is attributed
to the `after` pad width (e.g. if the total pad width is 3 and the left fraction is 0.5 then the
`before` pad width is 1 and the `after` pad width is 2; in order to f). This behavior can be controlled
with the `tie_break` parameter.
"""
shapes = np.array([x.shape for x in arrays])
if before is not None:
before = np.zeros_like(shapes) + before
else:
before = np.ones_like(shapes) - after
max_size = shapes.max(axis=0, keepdims=True)
margin = (max_size - shapes)
pad_before = tie_break(margin * before.astype(float)).astype(int)
pad_after = margin - pad_before
pad = np.stack([pad_before, pad_after], axis=2)
return [np.pad(x, w, mode='constant', constant_values=value) for x, w in zip(arrays, pad)]
對(duì)于您的示例,您可以按如下方式使用它:
test = [np.ones(shape=(i, i, 3)) for i in range(5, 10)]
result = pad_max_shape(test, before=0.5, value=255)
print([x.shape for x in result])
print(result[0][:, :, 0])
這會(huì)產(chǎn)生以下輸出:
[(9, 9, 3), (9, 9, 3), (9, 9, 3), (9, 9, 3), (9, 9, 3)]
[[255. 255. 255. 255. 255. 255. 255. 255. 255.]
[255. 255. 255. 255. 255. 255. 255. 255. 255.]
[255. 255. 1. 1. 1. 1. 1. 255. 255.]
[255. 255. 1. 1. 1. 1. 1. 255. 255.]
[255. 255. 1. 1. 1. 1. 1. 255. 255.]
[255. 255. 1. 1. 1. 1. 1. 255. 255.]
[255. 255. 1. 1. 1. 1. 1. 255. 255.]
[255. 255. 255. 255. 255. 255. 255. 255. 255.]
[255. 255. 255. 255. 255. 255. 255. 255. 255.]]
所以我們可以看到每個(gè)數(shù)組都被對(duì)稱地填充到最大數(shù)組的形狀(9, 9, 3)。

TA貢獻(xiàn)1836條經(jīng)驗(yàn) 獲得超3個(gè)贊
的使用np.pad()實(shí)際上是有據(jù)可查的。
一個(gè)適用于您提供的數(shù)字的 3D 數(shù)據(jù)的示例是:
import numpy as np
arr = np.random.randint(0, 255, (72, 72, 3))
new_arr = np.pad(
arr, ((0, 92 - 72), (0, 92 - 72), (0, 0)),
'constant', constant_values=255)
print(new_arr.shape)
# (92, 92, 3)
編輯
要解決完整的問(wèn)題,您需要首先確定最大尺寸,然后相應(yīng)地填充所有其他圖像。FlyingCircus包為您提供了許多功能,可以更輕松地完成工作(免責(zé)聲明:我是它的主要作者)。
如果您可以將所有圖像放入內(nèi)存中,最簡(jiǎn)單的方法就是使用fc.extra.multi_reframe(),即:
import flyingcircus as fc
new_arrs = fc.extra.multi_reframe(arrs, background=255)
如果您無(wú)法將所有數(shù)據(jù)放入內(nèi)存中,則應(yīng)分兩次執(zhí)行此操作,一次計(jì)算適合所有輸入的最小形狀,然后執(zhí)行實(shí)際填充fc.extra.reframe():
# assume your data is loaded with `load(filepath)`
# ... and saved with `save(array, filepath)`
# : first pass
shapes = [load(filepath).shape for filepath in filepaths]
target_shape = tuple(np.max(np.array(shapes), axis=0))
# : second pass
for filepath in filepaths:
arr = load(filepath)
new_arr = fc.extra.reframe(arr, target_shape, 0.5, 255)
save(new_arr, filepath)
在內(nèi)部,fc.extra.reframe()正在使用np.pad()(或類似但更快的東西),它大致相當(dāng)于:
def reframe(arr, target_shape, position=0.5, *args, **kws):
source_shape = arr.shape
padding = tuple(
(int(position * (dim_target - dim_source)),
(dim_target - dim_source) - int(position * (dim_target - dim_source)))
for dim_target, dim_source in zip(target_shape, source_shape))
return np.pad(arr, padding, *args, **kws)
reframe(arr, target_shape, 0.5, 'constant', constant_values=255)
請(qǐng)注意,position參數(shù)決定了數(shù)組相對(duì)于新形狀的位置。的默認(rèn)值0.5會(huì)將所有圖像放在中心,而0.0或1.0會(huì)將其推到所有軸上新形狀的一側(cè)或另一側(cè)。它的 FlyingCircus 版本更加靈活,您可以position分別為所有軸指定一個(gè)值。
添加回答
舉報(bào)