題目:對任意圖檔進行簡單磁碟區積操作,并提取圖檔的邊緣資訊
文章目錄
- 小練習~卷積執行個體
- 小練習~邊緣特征提取執行個體
- 關于邊緣檢測的原理
- 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()
可以看到結果:
…額 有點吓人。
小練習~邊緣特征提取執行個體
在剛才的程式中,我們使用了卷積核次元5*5。
現在用于邊緣檢測,我們初始化用于邊緣檢測的卷積核。
隻需要加一行代碼
ker[2, 2] = 24
關于邊緣檢測的原理
其實就是設定了特殊的卷積核(濾波器)達到了檢測邊緣的目的。
可以看一下上面這張圖, 設定的卷積核(濾波器)設計的非常巧妙 一列1 一列0 一列-1(稱為垂直邊緣檢測)。
這就導緻顔色相同的區域與這個卷積核做卷積得到的資料近0。而越接近0顔色就越淺。
區域内顔色相差越大,得到的數字也就越大,顔色就會越深。
最後就會描繪出圖像邊緣。
一行1 一行 0 一行-1 就是水準邊緣檢測。
Sobel濾波器
,其增加了中間一行的權重,加強處理圖像中央的元素點。
Scharr濾波器
。也是一種垂直邊緣檢測,反轉90度就變成了水準邊緣檢測。
本題中用到的 全是-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()