【问题标题】:How is a convolution calculated on an image with three (RGB) channels?如何在具有三个 (RGB) 通道的图像上计算卷积?
【发布时间】:2016-09-02 21:48:21
【问题描述】:

假设我们有一个单通道图像 (5x5)

A = [ 1 2 3 4 5
      6 7 8 9 2
      1 4 5 6 3
      4 5 6 7 4
      3 4 5 6 2 ]

还有一个过滤器 K (2x2)

K = [ 1 1
      1 1 ]

应用卷积的示例(让我们从 A 中取出前 2x2)是

1*1 + 2*1 + 6*1 + 7*1 = 16

这很简单。但是让我们为矩阵 A 引入一个深度因子,即具有 3 个通道的 RGB 图像,甚至是深度网络中的卷积层(深度可能 = 512)。使用相同的过滤器如何进行卷积操作? 类似的方法对 RGB 案例非常有帮助。

【问题讨论】:

    标签: rgb matrix-multiplication convolution dot-product


    【解决方案1】:

    假设我们有一个由某个矩阵 A 给出的 3 通道 (RGB) 图像

    A = [[[198 218 227] [196 216 225] [196 214 224] ... ... [185 201 217] [176 192 208] [162 178 194]]

    和一个模糊内核

    K = [[0.1111, 0.1111, 0.1111], [0.1111, 0.1111, 0.1111], [0.1111, 0.1111, 0.1111]] #实际上是 0.111 ~= 1/9

    卷积可以如下图所示表示

    正如您在图像中看到的,每个通道都单独进行卷积,然后组合成一个像素。

    【讨论】:

    • 这就是模糊操作的工作原理。在卷积中,每个通道的内核权重是不同的,我们将 3 个通道加在一起以产生单个通道输出。为了产生 m 个通道,我们需要在每个内核中具有不同权重的 m 个 3*3 过滤器。
    【解决方案2】:

    它们将与您对单通道图像的处理方式相同,只是您将获得三个矩阵而不是一个。 This 是一个关于 CNN 基础的讲义,我认为可能对你有所帮助。

    【讨论】:

    • 您好,当您说 3 个矩阵时,您的意思是您将第一个矩阵的过滤器和点积与第二个矩阵的过滤器点积相加,然后将其与用第三个矩阵过滤点积?然后,这将为您提供该位置的单个值。我说的对吗?
    • cmets中的问题确定了吗?
    • 注意 CNN 卷积和图像预处理(如高斯模糊)的差异!前者应用一个“深度”内核(每个通道使用不同过滤器),然后有效地总结输出矩阵(连同偏置项)以产生单通道特征图。而 RGB 图像的“模糊”通过对每个通道应用 same 过滤器来生成过滤后的 RGB 图像,仅此而已。
    • @Desmond 是的,您是对的,您将获得位置的单个值,但最有可能的是,您将训练三个不同的“过滤器”,而不是使用相同的过滤器对每个通道进行点积每个通道(也可以看作是训练一个三维滤波器 M x N x D,其中 D 为 3 对于 RGB 图像)。
    • 我发现这个答案很难理解,但链接的讲义非常好。
    【解决方案3】:

    在卷积神经网络中,卷积操作实现如下,(注意:模糊/过滤操作中的卷积是分开的)

    对于类 RGB 的输入,滤波器实际上是 223,每个滤波器对应一个颜色通道,产生三个滤波器响应。这三个加起来就是一个通过偏置和激活流动。最后,这是输出图中的一个像素。

    【讨论】:

      【解决方案4】:

      如果您尝试在 RGB 图像上实现 Conv2d,那么在 pytorch 中的实现应该会有所帮助。

      抓取一张图片并将其设为 uint8 (note that imshow needs uint8 to be values between 0-255 whilst floats should be between 0-1) 的 numpy ndarray:

      link = 'https://oldmooresalmanac.com/wp-content/uploads/2017/11/cow-2896329_960_720-Copy-476x459.jpg'
      
      r = requests.get(link, timeout=7)
      im = Image.open(BytesIO(r.content))
      pic = np.array(im)
      

      您可以查看它

      f, axarr = plt.subplots()
      axarr.imshow(pic)
      plt.show()
      

      创建您的卷积层(以随机权重开始)

      conv_layer = nn.Conv2d(in_channels=3, 
                 out_channels=3,kernel_size=3, 
                 stride=1, bias=None)
      

      将输入图像转换为浮动并添加一个空维度,因为这是 pytorch 期望的输入

      pic_float = np.float32(pic)
      pic_float = np.expand_dims(pic_float,axis=0)
      

      通过卷积层运行图像(置换维度位置周围的变化,使其与 pytorch 的预期相匹配)

      out = conv_layer(torch.tensor(pic_float).permute(0,3,1,2))
      

      移除我们添加的额外的第一个暗淡(可视化不需要),从 GPU 分离并转换为 numpy ndarray

      out = out.permute(0,2,3,1).detach().numpy()[0, :, :, :]
      

      可视化输出(我们开始使用转换为 uint8)

      f, axarr = plt.subplots()
      axarr.imshow(np.uint8(out))
      plt.show()
      

      然后,您可以通过访问过滤器来更改它们的权重。例如:

      kernel = torch.Tensor([[[[0.01, 0.02, 0.01],
                           [0.02, 0.04, 0.02],
                           [0.01, 0.02, 0.01]]]])
      
      kernel = kernel.repeat(3, 3, 1, 1)
      conv_layer.weight.data = kernel
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-04-07
        • 2019-09-29
        • 2023-03-17
        • 2018-08-25
        • 2019-06-12
        相关资源
        最近更新 更多