使用算术运算的自定义增强#

本节向您展示如何通过在 DALI Pipeline 中使用带有算术运算的表达式来实现自定义增强。

混合图像#

我们将创建一个 Pipeline,以几种不同的方式混合图像。为了轻松可视化结果,我们创建了以下文件列表,其中包含猫和狗的图片

  • cats.txt

  • dogs.txt

导入#

从必要的导入开始。

[1]:
from nvidia.dali.pipeline import Pipeline
import nvidia.dali.fn as fn
import nvidia.dali.types as types
from nvidia.dali.types import Constant

显式使用的运算符#

  1. Pipeline 将使用两个 readers.file 来创建两个张量批次,一个包含猫,另一个包含狗。

  2. 我们还需要一个 decoders.image 来解码加载的图像。

  3. 您需要 resize 运算符用于两个输入。

  4. 算术运算符在张量之间应用逐点运算,并要求它们具有匹配的形状和大小。

    在此示例中,使用了 400 x 400 图像。

  5. 我们可能想要在 Pipeline 中声明的最终运算符是 Cast 运算符,用于将数据转换回所需的类型。

具有自定义增强的图#

以下是初始步骤

  1. 加载两个输入批次。

  2. 解码两个输入。

  3. 将输入调整为相等的大小。

现在,我们有两个变量 dogscats,它们代表两个相等大小的图像批次。我们可以使用一些权重混合这些图像,并通过使用以下公式将像素强度减半

(0.4 * cats + 0.6 * dogs) / 2

在这里,我们使用了 Python 直接值作为算术表达式中的常量输入。

使用 dali.types.Constant 指示类型#

  1. 我们也可以更加注意我们使用的类型,并以 uint16 执行所有计算。

输入为 uint8,并且使用标记为 uint16 的常量进行计算会将结果提升为 uint16。有关更多信息,请参阅“DALI 二进制算术运算符 - 类型提升”教程。

  1. 我们还可以使用 // 除法,这使我们能够保持结果的整数类型。

(Constant(4).uint16() * cats + Constant(6).uint16() * dogs) // Constant(20).uint16()
  1. 我们返回两个输入,并且结果已强制转换回 uint8

[2]:
pipe = Pipeline(batch_size=1, num_threads=4, device_id=0, seed=42)
with pipe:
    cats_jpegs, _ = fn.readers.file(
        device="cpu", file_root="../../data/images", file_list="cats.txt"
    )
    dogs_jpegs, _ = fn.readers.file(
        device="cpu", file_root="../../data/images", file_list="dogs.txt"
    )
    images = fn.decoders.image(
        [cats_jpegs, dogs_jpegs], device="cpu", output_type=types.RGB
    )
    cats, dogs = fn.resize(images, resize_x=400, resize_y=400)
    blend_float = (0.4 * cats + 0.6 * dogs) / 2
    blend_uint16 = (
        Constant(4).uint16() * cats + Constant(6).uint16() * dogs
    ) // Constant(20).uint16()

    pipe.set_outputs(
        cats,
        dogs,
        fn.cast_like(blend_float, cats),
        fn.cast_like(blend_uint16, cats),
    )

运行 Pipeline#

  1. 创建 Pipeline 的实例并构建它。为了简化结果显示,我们使用 batch_size = 1

[3]:
pipe.build()
  1. 我们将使用一个简单的辅助函数来显示图像。

对于较大的批次,可以调整 data_idx 以显示不同的样本。output_titles 将用于设置 Pipeline 输出的标题。

[4]:
import matplotlib.pyplot as plt


def display(output, titles, cpu=True):
    data_idx = 0
    fig, axes = plt.subplots(len(output) // 2, 2, figsize=(15, 15))
    if len(output) == 1:
        axes = [axes]
    for i, out in enumerate(output):
        img = out.at(data_idx) if cpu else out.as_cpu().at(data_idx)
        axes[i // 2, i % 2].imshow(img)
        axes[i // 2, i % 2].axis("off")
        axes[i // 2, i % 2].set_title(titles[i])


output_titles = [
    "Cat",
    "Dog",
    "(0.4 * Cat + 0.6 * Dog) / 2",
    "(Constant(4).uint16() * Cat + Constant(6).uint16() * Dog) // "
    "Constant(20).uint16()",
]
  1. 我们将运行并显示结果。

您可以多次播放此单元格以查看不同图像的结果。

[5]:
output = pipe.run()
display(output, output_titles)
../../../_images/examples_general_expressions_expr_blend_image_12_0.png