在图像处理任务中,常用拉普拉斯算子对物体边缘进行提取,拉普拉斯算子为一个大小为3×3的卷积核,中心元素值是8,其余元素值是−1-1−1
先根据二维卷积算子,构造一个简单的拉普拉斯算子,并对一张输入的灰度图片进行边缘检测,提取出目标的外形轮廓。
一、定义一个带步长和填充的二维卷积算子
# 带步长和填充的二维卷积算子
import paddle
class Conv2D(paddle.nn.Layer):
def __init__(self,kernel_size,stride=1,padding=0,
weight_attr=paddle.ParamAttr(
initializer=paddle.nn.initializer.Constant(value=1.0))):
super(Conv2D,self).__init__()
self.weight=paddle.create_parameter(shape=[kernel_size,kernel_size],
dtype='float32',attr=weight_attr)
#步长
self.stride=stride
#零填充
self.padding=padding
def forward(self,x):
new_x=paddle.zeros(shape=[x.shape[0],x.shape[1] 2*self.padding,x.shape[2] 2*self.padding])
new_x[:,self.padding:x.shape[1] self.padding,self.padding:x.shape[2] self.padding]=x
u,v=self.weight.shape
output_w=int((x.shape[1]-u 2*self.padding)/self.stride 1)
output_h=int((x.shape[2]-v 2*self.padding)/self.stride 1)
output=paddle.zeros(shape=[x.shape[0],output_w,output_h])
for i in range(output_w):
for j in range(output_h):
output[:,i,j]=paddle.sum(
new_x[:,i*self.stride:i*self.stride u,j*self.stride:j*self.stride v]*self.weight,
axis=[1,2])
return output
#测试算子
inputs=paddle.randn([2,8,8])
conv2d_padding=Conv2D(kernel_size=3,padding=1)
outputs=conv2d_padding(inputs)
print(outputs.shape)
conv2d_stride=Conv2D(kernel_size=3,stride=2,padding=1)
outputs=conv2d_stride(inputs)
print(outputs.shape)
#输出,
#从输出结果看出,使用3×3大小卷积,padding为1,当stride=1时,模型的输出特征图可以与输入特征图保持一致;
#当stride=2时,输出特征图的宽和高都缩小一倍。
[2, 8, 8]
[2, 4, 4]
输出后的长度和宽度计算方式
二、构造一个简单的拉普拉斯算子,进行图像边缘检测
import matplotlib.pyplot as plt
from PIL import Image
import numpy as np
#读取图片灰度图
img=Image.open("img/catgray.jpg")
inputs=np.array(img).astype(np.float32)
print(inputs.shape)
#设置卷积核
w=np.array([[-1,-1,-1],[-1,8,-1],[-1,-1,-1]],dtype=np.float32)
print(w.shape)
#创建卷积算子,卷积核为w,步长为1,零填充为1
conv=Conv2D(kernel_size=3,stride=1,padding=1,
weight_attr=paddle.ParamAttr(initializer=paddle.nn.initializer.Assign(value=w)))
#将图片转换为tensor
inputs=paddle.to_tensor(inputs)
print(inputs.shape)
inputs=paddle.unsqueeze(inputs,axis=0)
print(inputs.shape)
outputs=conv(inputs)
outputs=outputs.numpy()
print(outputs.shape)
#可视化结果
plt.figure(figsize=(8,4))
plt.subplot(121)
plt.imshow(img)
plt.subplot(122)
plt.imshow(outputs.squeeze(),cmap='gray')
plt.show()
#输出的形状,最后输出图像的形状保持不变
(100, 100)
(3, 3)
[100, 100]
[1, 100, 100]
(1, 100, 100)
检测结果
从输出结果看,使用拉普拉斯算子,目标的边缘可以成功被检测出来。
catgray.jpg
,