简单的黑白边界检测

*
有如下一张50
50的黑白图片:
📃 卷积算子的应用 - 图1
问题:如何找出图片中明暗分界线所处位置?

解题思路:使用如下卷积核对图片进行卷积运算
📃 卷积算子的应用 - 图2
卷积核大小为1*3,让其在图像中滑动:
📃 卷积算子的应用 - 图3
这样,通过卷积运算后,只有黑白边界处的像素值不等于0,程序实现如下:

  1. import matplotlib.pyplot as plt
  2. import numpy as np
  3. import paddle
  4. import paddle.fluid as fluid
  5. from paddle.fluid.dygraph.nn import Conv2D
  6. from paddle.fluid.initializer import NumpyArrayInitializer
  7. %matplotlib inline
  8. with fluid.dygraph.guard():
  9. # 创建初始化权重参数w
  10. w = np.array([1, 0, -1], dtype='float32')
  11. # 将权重参数调整成维度为[cout, cin, kh, kw]的四维张量
  12. w = w.reshape([1, 1, 1, 3])
  13. # 创建卷积算子,设置输出通道数,卷积核大小,和初始化权重参数
  14. # filter_size = [1, 3]表示kh = 1, kw=3
  15. # 创建卷积算子的时候,通过参数属性param_attr,指定参数初始化方式
  16. # 这里的初始化方式时,从numpy.ndarray初始化卷积参数
  17. conv = Conv2D(num_channels=1, num_filters=1, filter_size=[1, 3],
  18. param_attr=fluid.ParamAttr(
  19. initializer=NumpyArrayInitializer(value=w)))
  20. # 创建输入图片,图片左边的像素点取值为1,右边的像素点取值为0
  21. img = np.ones([50,50], dtype='float32')
  22. img[:, 30:] = 0.
  23. # 将图片形状调整为[N, C, H, W]的形式
  24. x = img.reshape([1,1,50,50])
  25. # 将numpy.ndarray转化成paddle中的tensor
  26. x = fluid.dygraph.to_variable(x)
  27. # 使用卷积算子作用在输入图片上
  28. y = conv(x)
  29. # 将输出tensor转化为numpy.ndarray
  30. out = y.numpy()
  31. f = plt.subplot(121)
  32. f.set_title('input image', fontsize=15)
  33. plt.imshow(img, cmap='gray')
  34. f = plt.subplot(122)
  35. f.set_title('output featuremap', fontsize=15)
  36. # 卷积算子Conv2D输出数据形状为[N, C, H, W]形式
  37. # 此处N, C=1,输出数据形状为[1, 1, H, W],是4维数组
  38. # 但是画图函数plt.imshow画灰度图时,只接受2维数组
  39. # 通过numpy.squeeze函数将大小为1的维度消除
  40. plt.imshow(out.squeeze(), cmap='gray')
  41. plt.show()

输出:
📃 卷积算子的应用 - 图4

  1. # 查看卷积层的参数
  2. with fluid.dygraph.guard():
  3. # 通过 conv.parameters()查看卷积层的参数,返回值是list,包含两个元素
  4. print(conv.parameters())
  5. # 查看卷积层的权重参数名字和数值
  6. print(conv.parameters()[0].name, conv.parameters()[0].numpy())
  7. # 参看卷积层的偏置参数名字和数值
  8. print(conv.parameters()[1].name, conv.parameters()[1].numpy())

输出:

  1. [name conv2d_0.w_0, dtype: VarType.FP32 shape: [1, 1, 1, 3] lod: {}
  2. dim: 1, 1, 1, 3
  3. layout: NCHW
  4. dtype: float
  5. data: [1 0 -1]
  6. , name conv2d_0.b_0, dtype: VarType.FP32 shape: [1] lod: {}
  7. dim: 1
  8. layout: NCHW
  9. dtype: float
  10. data: [0]
  11. ]
  12. conv2d_0.w_0 [[[[ 1. 0. -1.]]]]
  13. conv2d_0.b_0 [0.]

图像中物体边缘检测

**
上面展示的是一个人为构造出来的简单图片,使用卷积网络检测图片明暗分界处的示例。对于真实的图片,也可以使用合适的卷积核对其进行操作,用来检测物体的外形轮廓,观察输出特征图跟原图之间的对应关系。

  1. import matplotlib.pyplot as plt
  2. from PIL import Image
  3. import numpy as np
  4. import paddle
  5. import paddle.fluid as fluid
  6. from paddle.fluid.dygraph.nn import Conv2D
  7. from paddle.fluid.initializer import NumpyArrayInitializer
  8. img = Image.open('./work/001.png')
  9. with fluid.dygraph.guard():
  10. # 设置卷积核参数
  11. w = np.array([[-1,-1,-1], [-1,8,-1], [-1,-1,-1]], dtype='float32')/8
  12. w = w.reshape([1, 1, 3, 3])
  13. # 由于输入通道数是3,将卷积核的形状从[1,1,3,3]调整为[1,3,3,3]
  14. w = np.repeat(w, 3, axis=1)
  15. # 创建卷积算子,输出通道数为1,卷积核大小为3x3,
  16. # 并使用上面的设置好的数值作为卷积核权重的初始化参数
  17. conv = Conv2D(num_channels=3, num_filters=1, filter_size=[3, 3],
  18. param_attr=fluid.ParamAttr(
  19. initializer=NumpyArrayInitializer(value=w)))
  20. # 将读入的图片转化为float32类型的numpy.ndarray
  21. x = np.array(img).astype('float32')
  22. # 图片读入成ndarry时,形状是[H, W, 3],
  23. # 将通道这一维度调整到最前面
  24. x = np.transpose(x, (2,0,1))
  25. # 将数据形状调整为[N, C, H, W]格式
  26. x = x.reshape(1, 3, img.height, img.width)
  27. x = fluid.dygraph.to_variable(x)
  28. y = conv(x)
  29. out = y.numpy()
  30. plt.figure(figsize=(20, 10))
  31. f = plt.subplot(121)
  32. f.set_title('input image', fontsize=15)
  33. plt.imshow(img)
  34. f = plt.subplot(122)
  35. f.set_title('output feature map', fontsize=15)
  36. plt.imshow(out.squeeze(), cmap='gray')
  37. plt.show()

输出:
📃 卷积算子的应用 - 图5

图像均值模糊

另外一种比较常见的卷积核是用当前像素跟它邻域内的像素取平均,这样可以使图像上噪声比较大的点变得更平滑。

  1. import matplotlib.pyplot as plt
  2. from PIL import Image
  3. import numpy as np
  4. import paddle
  5. import paddle.fluid as fluid
  6. from paddle.fluid.dygraph.nn import Conv2D
  7. from paddle.fluid.initializer import NumpyArrayInitializer
  8. # 读入图片并转成numpy.ndarray
  9. img = Image.open('./work/002.png').convert('L')
  10. img = np.array(img)
  11. # 换成灰度图
  12. with fluid.dygraph.guard():
  13. # 创建初始化参数
  14. w = np.ones([1, 1, 5, 5], dtype = 'float32')/25
  15. conv = Conv2D(num_channels=1, num_filters=1, filter_size=[5, 5],
  16. param_attr=fluid.ParamAttr(
  17. initializer=NumpyArrayInitializer(value=w)))
  18. x = img.astype('float32')
  19. x = x.reshape(1,1,img.shape[0], img.shape[1])
  20. x = fluid.dygraph.to_variable(x)
  21. y = conv(x)
  22. out = y.numpy()
  23. plt.figure(figsize=(20, 12))
  24. f = plt.subplot(121)
  25. f.set_title('input image')
  26. plt.imshow(img, cmap='gray')
  27. f = plt.subplot(122)
  28. f.set_title('output feature map')
  29. out = out.squeeze()
  30. plt.imshow(out, cmap='gray')
  31. plt.show()

输出:
📃 卷积算子的应用 - 图6