天天看點

Pytorch----卷積神經網絡(CNN,圖像邊緣檢測 , Sobel濾波器 , Scharr濾波器)--入門級小執行個體(逐行注釋)---學習筆記

題目:對任意圖檔進行簡單磁碟區積操作,并提取圖檔的邊緣資訊

文章目錄

  • ​​小練習~卷積執行個體​​
  • ​​小練習~邊緣特征提取執行個體​​
  • ​​關于邊緣檢測的原理​​
  • ​​Sobel濾波器​​
  • ​​Scharr濾波器​​

本次使用圖檔:

Pytorch----卷積神經網絡(CNN,圖像邊緣檢測 , Sobel濾波器 , Scharr濾波器)--入門級小執行個體(逐行注釋)---學習筆記

小練習~卷積執行個體

首先将圖檔讀取進來->轉為灰階圖->轉為numpy數組:

# 讀圖
image = Image.open('../data/cat.png')
# 轉為灰階圖
image = image.convert("L")
# 轉為numpy數組
image_np = np.array(image)      

此時得到的numpy數組次元為二維,可以使用shape輸出圖檔大小(719,719) 。

将 (719,719) 變成(11719*719)的張量,友善後面卷積操作。

h , w = image_np.shape
image_tensor = torch.from_numpy(image_np.reshape(1,1,h,w)).float() 
# torch.from_numpy ()方法把數組轉換成張量,      

此時進行shape輸出得到四維張量 torch.Size([1, 1, 719, 719])。

設定卷積核的大小,定義卷積層。

kersize = 5 # 5*5的卷積核大小


ker = torch.ones(kersize, kersize, dtype=torch.float32) * -1   # 元素全部設定為 -1
conv2d = torch.nn.Conv2d(1, 1, (kersize, kersize),  bias=False) # 設定卷積網絡
ker = ker.reshape((1, 1, kersize, kersize))# 将ker變成四維張量
conv2d.weight.data = ker # 初始化權重      

将資料放進去卷積,然後壓縮一下次元:

這裡的squeeze()函數就是壓縮次元,可以去掉其中為1的次元。

image_out = conv2d(image_tensor)
image_out = image_out.data.squeeze()

去次元之前和之後:

torch.Size([1, 1, 715, 715])
torch.Size([715, 715])      

這樣的二維資料就可以拿去畫圖了:

plt.axis('off') # 不顯示坐标軸
plt.imshow(image_out, cmap=plt.cm.gray) # cmap表示給圖上黑白色
plt.show()      

完整代碼:

## 普通卷積


## 普通卷積

from PIL import Image
import torch
import matplotlib.pyplot as plt
import numpy as np
from torch import nn

image = Image.open('../data/cat.png')
image = image.convert("L")
image_np = np.array(image)

h, w = image_np.shape
image_tensor = torch.from_numpy(image_np.reshape(1, 1, h, w)).float()

kersize = 5

ker = torch.ones(kersize, kersize, dtype=torch.float32) * -1
print(ker)
conv2d = torch.nn.Conv2d(1, 1, (kersize, kersize), bias=False)
ker = ker.reshape((1, 1, kersize, kersize))
conv2d.weight.data = ker

image_out = conv2d(image_tensor)
image_out = image_out.data.squeeze()
plt.axis('off')
plt.imshow(image_out, cmap=plt.cm.gray)
plt.show()      

可以看到結果:

Pytorch----卷積神經網絡(CNN,圖像邊緣檢測 , Sobel濾波器 , Scharr濾波器)--入門級小執行個體(逐行注釋)---學習筆記

…額 有點吓人。

小練習~邊緣特征提取執行個體

在剛才的程式中,我們使用了卷積核次元5*5。

現在用于邊緣檢測,我們初始化用于邊緣檢測的卷積核。

隻需要加一行代碼

ker[2, 2] = 24      

關于邊緣檢測的原理

其實就是設定了特殊的卷積核(濾波器)達到了檢測邊緣的目的。

Pytorch----卷積神經網絡(CNN,圖像邊緣檢測 , Sobel濾波器 , Scharr濾波器)--入門級小執行個體(逐行注釋)---學習筆記

可以看一下上面這張圖, 設定的卷積核(濾波器)設計的非常巧妙 一列1 一列0 一列-1(稱為垂直邊緣檢測)。

這就導緻顔色相同的區域與這個卷積核做卷積得到的資料近0。而越接近0顔色就越淺。

區域内顔色相差越大,得到的數字也就越大,顔色就會越深。

最後就會描繪出圖像邊緣。

一行1 一行 0 一行-1 就是水準邊緣檢測。

Sobel濾波器

,其增加了中間一行的權重,加強處理圖像中央的元素點。

Pytorch----卷積神經網絡(CNN,圖像邊緣檢測 , Sobel濾波器 , Scharr濾波器)--入門級小執行個體(逐行注釋)---學習筆記

Scharr濾波器

。也是一種垂直邊緣檢測,反轉90度就變成了水準邊緣檢測。

Pytorch----卷積神經網絡(CNN,圖像邊緣檢測 , Sobel濾波器 , Scharr濾波器)--入門級小執行個體(逐行注釋)---學習筆記

本題中用到的 全是-1 僅僅中間是24這個情況。。沒懂。不過查閱資料發現有點類似于 拉普拉斯算子卷積核的情況。

先不管這個為什麼設定中間為24了 ,後面懂了再回來補吧。

from PIL import Image
import torch
import matplotlib.pyplot as plt
import numpy as np
# 在Image轉Tensor過程中,圖檔的格式會由: H * W * C的格式轉為: C * H * W格式。
from torch import nn

# 讀圖
image = Image.open('../data/cat.png')
# 轉為灰階圖
image = image.convert("L")
# 轉為numpy數組
image_np = np.array(image)

# plt.figure(figsize=(6,6)) # 繪圖并指定長和高
# # 參數cmap将标量資料映射到圖檔  cmap = plt.cm.gray    傳回線性灰階色圖
# # cmap參數接受一個值(每個值代表一種配色方案),并将該值對應的顔色圖配置設定給目前圖窗。
# # 如果将目前圖窗比作一幅簡筆畫,則cmap就代表顔料盤的配色,用所提供的顔料盤自動給目前簡筆畫上色,就是cmap所做的事。
# plt.imshow(image_np,cmap=plt.cm.gray)
# plt.axis("off")  # 不顯示坐标軸
# plt.show()

# print(image_np.shape) # 得到 結果 (719, 719)
# 将上述數組轉換成 1*1*719*719的張量
h , w = image_np.shape
image_tensor = torch.from_numpy(image_np.reshape(1,1,h,w)).float() # torch.from_numpy ()方法把數組轉換成張量,

# print(image_tensor.shape) # 得到torch.Size([1, 1, 719, 719])
kersize = 5
ker = torch.ones(kersize,kersize,dtype=torch.float32)*-1

ker[2,2] = 24

ker = ker.reshape((1,1,kersize,kersize)) # 邊緣卷積核

conv2d = torch.nn.Conv2d(1,2,(kersize,kersize),bias=False) # 設定卷積核
# print(ker)
# print(conv2d.weight.data.shape)  # 權重次元  2*1*5*5  輸出通道數,輸入通道數,卷積核長寬
conv2d.weight.data[0] = ker
print(conv2d.weight.data) # 第一個次元的權重用于進行邊緣提取,第二個卷積核是随機數


image_out = conv2d(image_tensor)
print(image_out.shape)
image_out = image_out.data.squeeze() # 數組的次元壓縮,去掉其中為1的次元
print(image_out.shape) # 要注意此時的 image_out裡面有兩個  715*715的圖  torch.Size([2, 715, 715]) 三維張量
print(image_out)

plt.figure(figsize=(18,6)) # 表示輸出的長和寬
plt.subplot(1,3,1) # 1行 2列  然後按照從左到右,從上到下的順序對每個子區域進行編号,左上的子區域的編号為1,最後那個參數指定顯示的區域編号
plt.imshow(image_out[0],cmap=plt.cm.gray) # 拿出來第0個 就是秒輪廓的那個
plt.axis('off')

plt.subplot(1,3,2) # 寫第二個圖
plt.imshow(image_out[1],cmap=plt.cm.gray)
plt.axis('off')

plt.subplot(1,3,3)
plt.imshow(image_np,cmap=plt.cm.gray)
plt.axis('off')
plt.show()