擦除算子#
在此示例中,我们演示了 Erase
算子的功能以及指定其参数的不同方式。
Erase
算子可用于通过指定一个或多个区域以及用于填充擦除区域的值来移除张量(例如,图像)的某些部分。
定义一个 DALI pipeline,我们将使用它来演示不同的用例。
[1]:
from nvidia.dali.pipeline import Pipeline
import nvidia.dali.fn as fn
import nvidia.dali.types as types
import matplotlib.pyplot as plt
batch_size = 1
image_filename = "../data/images"
def erase_pipeline(
anchor,
shape,
axis_names,
fill_value=0,
normalized_anchor=False,
normalized_shape=False,
centered_anchor=False,
):
pipe = Pipeline(batch_size=batch_size, num_threads=1, device_id=0)
with pipe:
jpegs, _ = fn.readers.file(device="cpu", file_root=image_filename)
images = fn.decoders.image(jpegs, device="cpu", output_type=types.RGB)
erased = fn.erase(
images,
device="cpu",
anchor=anchor,
shape=shape,
axis_names=axis_names,
fill_value=fill_value,
normalized_anchor=normalized_anchor,
normalized_shape=normalized_shape,
centered_anchor=centered_anchor,
)
pipe.set_outputs(erased)
return pipe
编写一个简单的实用函数来运行和显示 pipeline 实例的输出
[2]:
def show(pipe):
pipe.build()
out = pipe.run()
plt.imshow(out[0].at(0))
我们现在可以使用 pipeline 来演示擦除算子的不同用例。
指定一个矩形区域,该区域具有锚点和以绝对坐标指定的矩形形状。
anchor
和 shape
参数中轴的顺序由 axis_names
参数描述。指定的轴名称还需要存在于输入的布局中。例如,layout="HWC"
和 axis_names="HW"
等效于表示第一个坐标对应于索引为 0 的轴,第二个坐标对应于索引为 1 的轴。或者,您可以指定带有轴索引列表的 axes
参数,例如 axes=(0, 1)
。
注意:使用 axis_names
优于 axes
。
[3]:
show(erase_pipeline(anchor=(40, 20), shape=(140, 50), axis_names="HW"))
如果我们更改
axis_names
值,则相同的区域参数可能会被不同地解释。例如,
layout="HWC"
和axis_names="WH"
表示第一个坐标指的是索引为 1 的轴,第二个坐标对应于索引为 0 的轴。
[4]:
show(erase_pipeline(anchor=(40, 20), shape=(140, 50), axis_names="WH"))
通过仅指定一个维度来指定垂直或水平条纹
[5]:
show(erase_pipeline(anchor=(350), shape=(50), axis_names="W"))
[6]:
show(erase_pipeline(anchor=(350), shape=(50), axis_names="H"))
通过向
anchor
和shape
参数添加更多点来指定多个区域。
例如,具有 4 个点且参数 axis_names="HW"
表示 2 个轴的 anchor
和 shape
被解释为以下区域
anchor=(y0, x0, y1, x1)
shape=(h0, w0, h1, w1)
[7]:
show(
erase_pipeline(
anchor=(30, 20, 350, 450), shape=(150, 40, 50, 150), axis_names="HW"
)
)
类似地,具有 3 个元素且仅表示一个轴 (axis_names="W"
) 的 anchor
和 shape
对应于以下区域
anchor=(x0, x1, x2)
shape=(w0, w1, w2)
[8]:
show(erase_pipeline(anchor=(50, 400, 550), shape=(60, 60, 60), axis_names="W"))
我们还可以更改擦除区域的默认值。如果提供一个
fill_value
,则它将在所有通道中使用。
[9]:
show(erase_pipeline(anchor=(400), shape=(120), axis_names="W", fill_value=120))
或者,我们可以指定一个多通道填充值,例如
fill_value=(118, 185, 0)
。在这种情况下,输入布局需要包含
C
通道,例如"HWC"
。
[10]:
show(
erase_pipeline(
anchor=(400), shape=(120), axis_names="W", fill_value=(118, 185, 0)
)
)
完全或部分超出图像边界的区域将被忽略或分别修剪。
[11]:
show(
erase_pipeline(
anchor=(800), shape=(120), axis_names="W", fill_value=(118, 185, 0)
)
)
[12]:
show(
erase_pipeline(
anchor=(500), shape=(500), axis_names="W", fill_value=(118, 185, 0)
)
)
区域坐标也可以通过相对坐标指定。在这种情况下,为了获得绝对坐标,相对坐标乘以输入维度。
[13]:
show(
erase_pipeline(
anchor=(0.8),
shape=(0.15),
axis_names="W",
normalized_anchor=True,
normalized_shape=True,
)
)
您可以使用相对和绝对坐标来独立指定 anchor
和 shape
。
[14]:
show(
erase_pipeline(
anchor=(0.8),
shape=(100),
axis_names="W",
normalized_anchor=True,
normalized_shape=False,
)
)
[15]:
show(
erase_pipeline(
anchor=(450),
shape=(0.22),
axis_names="W",
normalized_anchor=False,
normalized_shape=True,
)
)
指定区域应以指定的
anchor
为中心,而不是从其开始。为此,我们可以使用
centered_anchor
布尔参数。
[16]:
show(
erase_pipeline(
anchor=(0.5, 0.5),
shape=(0.5, 0.5),
axis_names="HW",
centered_anchor=True,
normalized_anchor=True,
normalized_shape=True,
)
)
[17]:
anchor = [k / 10 for k in range(11)]
shape = [0.03] * 11
show(
erase_pipeline(
anchor=anchor,
shape=shape,
axis_names="W",
centered_anchor=True,
normalized_anchor=True,
normalized_shape=True,
)
)
使用张量输入来指定区域。
例如,我们可以使用随机数生成器的输出来馈送
Erase
算子的anchor
和shape
参数。
[18]:
def random_erase_pipeline(axis_names="W", nregions=5):
pipe = Pipeline(batch_size=batch_size, num_threads=1, device_id=0)
with pipe:
jpegs, _ = fn.readers.file(device="cpu", file_root=image_filename)
images = fn.decoders.image(jpegs, device="cpu", output_type=types.RGB)
ndims = len(axis_names)
args_shape = (ndims * nregions,)
random_anchor = fn.random.uniform(range=(0.0, 1.0), shape=args_shape)
random_shape = fn.random.uniform(range=(20.0, 50), shape=args_shape)
erased = fn.erase(
images,
device="cpu",
anchor=random_anchor,
shape=random_shape,
axis_names=axis_names,
fill_value=(118, 185, 0),
normalized_anchor=True,
normalized_shape=False,
)
pipe.set_outputs(erased)
return pipe
[19]:
show(random_erase_pipeline(axis_names="W", nregions=1))
[20]:
show(random_erase_pipeline(axis_names="WH", nregions=4))
[21]:
show(random_erase_pipeline(axis_names="W", nregions=3))