在圖像處理任務中,常用拉普拉斯算子對物體邊緣進行提取,拉普拉斯算子為一個大小為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
,