文章目錄
本文主要從卷積, 圖像, 圖像的卷積處理, 卷積神經網絡CNN的構建三部分,從理論到代碼應用
使用python3.6編譯器, jupyter編輯器
未完待續…
一、卷積介紹
1、origination:
一個面積不變的長方形,底邊被擠的窄窄的,高度被擠的高高的,在數學中它可以被擠到無限高,但即使它無限瘦、無限高、但它仍然保持面積不變;爲了證實它的存在,可以對它進行積分。
2、significance:
- 意義1
假設system1, 時刻t輸入爲x(t), 輸出爲y(t), 系統響應時間爲h(t), 按道理輸入輸出關係是y(y)=h(t)*x(t); however, 系統輸出不僅與系統t時刻相關, 還與t時刻之前響應相關, 所以t時刻的輸出應該爲t時刻之前系統響應函數在各個時刻響應的疊加,這就是卷積,用數學公式表示就是y(s)=∫x(t)h(s-t)dt - 物理意義
卷積圖像處理方面的應用
用一個模板和一幅圖像進行卷積,對於圖像上的一個點,讓模板的原點和該點重合,然後模板上的點和圖像上對應的點相乘,然後各點的積相加,就得到了該點的卷積值。對圖像上的每個點都這樣處理。由於大多數模板都是對稱的,所以模板不旋轉。卷積是一種積分運算,用來求兩個曲線重疊區域面積。可以看作加權求和,可以用來消除噪聲、特徵增強。
把一個點的像素值用它周圍的點的像素值的加權平均代替。
卷積是一種線性運算,圖像處理中常見的mask運算都是卷積,廣泛應用於圖像濾波。
卷積在數據處理中用來平滑,卷積有平滑效應和展寬效應.
參考:卷積的本質及物理意義(全面理解卷積)
3、卷積計算
爲了更好的理解, 直接上例子
a-、濾波器(卷積核)
a、卷積例子
b、卷積之padding填充
填充方法有:
補零填充
邊界複製填充, 鏡像填充, 塊填充
c、步幅
### d、計算增加參數後, 卷積輸出shape
e、注意
f、整體理解
二、圖像處理基礎
1、讀取圖像
import numpy as np
import matplotlib.pyplot as plt
import sys,os
sys.path.append(os.pardir)
%matplotlib inline
img = np.array(plt.imread("../data/劉亦菲.jpg")) # 將圖像格式轉化np.array格式,方便後續處理
plt.figure("劉大姐")
plt.imshow(img) # 函數負責對圖像進行處理,並顯示其格式,但是不能顯示
plt.axis("off")
plt.show()
print( img.shape )
print( img.dtype )
print( img.size )
print( type(img) )
print(img[0,0]) # 因爲是RGB三通道
(1200, 1920, 3)
uint8
6912000
<class 'numpy.ndarray'>
[ 95 96 124]
2、撒點椒鹽
#隨機生成5000個椒鹽
rows,cols,dims=img.shape
for i in range(5000):
x=np.random.randint(0,rows) # 在0-rows之間隨便取值
y=np.random.randint(0,cols) #
img[x,y,:]=255 # 將這個隨機點設置爲白點, 即椒鹽
plt.figure("beauty")
plt.imshow(img)
plt.axis('off')
plt.show()
3、圖像二值化
# 圖像二值化
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
img = np.array(Image.open("../data/劉亦菲.jpg").convert('L'))
rows, cols = img.shape
for i in range(rows):
for j in range(cols):
if (img[i, j] <= 128):
img[i, j] = 0
else:
img[i, j] = 1
plt.figure("Mona Lisa")
plt.imshow(img, cmap='gray')
plt.axis('off')
plt.show()
4、分量提取
import matplotlib.pyplot as plt
import numpy as np
import tensorflow as tf
img = np.array(plt.imread("../data/劉亦菲.jpg"))
plt.imshow(img[:, :, 0], cmap="gray") #L 分量轉化爲灰度圖
plt.show()
plt.imshow(img[:, :, 1], cmap="gray") #G 分量轉化爲灰度圖
plt.show()
plt.imshow(img[:, :, 1], ) # 只顯示G 分量
plt.show()
5、灰度圖片
from PIL import Image
img = np.array([1]) # 讀取圖片,並轉換爲灰度圖片
img_1 = Image.open("../data/劉亦菲.jpg").convert('1') # 非黑即白
img = np.array(Image.open("../data/劉亦菲.jpg").convert('L')) # 0黑255白,其他數字灰度不同
plt.imshow(img_1, cmap="gray") # 圖片只顯示像素點爲0或者255的值
plt.show()
plt.imshow(img, cmap="gray")
plt.show()
6、圖像卷積處理之numpy
- 本部分的圖像卷積處理使用的是科學計算包numpy , 利用numpy的廣播功能, 能夠很簡單的進行矩陣運。
- 本部分的圖像卷積, 是直接將圖像的每一個像素點的三個通道的像素都進行了卷積處理,然後顯示
# 圖像卷積運算
import numpy as np
import matplotlib.pyplot as plt
import sys
sys.path.append("../")
%matplotlib inline
img = np.array(plt.imread("../data/劉亦菲.jpg"))
# 構建輸出矩陣形狀, 使用0填充,
def generate_dst(img, kernel, stride=1, padding=0): #默認步幅=1, 填充爲0
m = (img.shape[0] + 2*padding - kernel.shape[0] + stride)/stride # 高
n = (img.shape[1] + 2*padding - kernel.shape[1] + stride)/stride # 長
rgb_channel = img.shape[2] # RGB三通道
print("新構建的圖片形狀%0.3f,%0.3f,%0.3f"%(m,n,rgb_channel))
return np.zeros((int(m),int(n),int(rgb_channel)),)
# 單個卷積核的運算
def div_convolution(img_block,kernel):
_img = np.array(img_block).flatten() #轉化爲一維
_kernel = np.array(kernel).flatten()
# return np.mean(_img*_kernel) #
return np.sum(_img*_kernel) # 正常的卷積運算是直接加和,並不進行均值計算
# 將圖片按照convolution變換, 注意這裏還沒有對最終結果進行歸一化
def convolution2dst(img,dst,kernel):
for i in range(dst.shape[0]):
for j in range(dst.shape[1]):
for k in range(dst.shape[2]): #通道
dst[i,j,k] = div_convolution(img[i:i+kernel.shape[0],
j:j+kernel.shape[1],k], # 與kernel一致的矩陣
kernel)
# 將圖片歸一化到256之間
def img2normalization_256(img_convolution):
_img = img_convolution.flatten()
_max = np.max(_img)
_min = np.min(_img)
_img = (_img-_min)*255/(_max-_min)
_img = np.array(_img, dtype="int64") # 將所有數據轉化爲int型
img_convolution_normalization = _img.reshape((img_convolution.shape[0],
img_convolution.shape[1],
img_convolution.shape[2]))
return img_convolution_normalization
def convolution(img,kernel,is_normalization=False):
dst = generate_dst(img,kernel)
convolution2dst(img,dst,kernel)
if not is_normalization:
return dst
else:
new_img = img2normalization_256(dst)
return new_img
img = np.array(plt.imread("../data/劉亦菲.jpg"))
test_kernel = np.array([[-1, -1, -1],
[-1, 9, -1],
[-1, -1, -1]])
img_convolution = convolution(img,test_kernel, True)
# 顯示直接卷積後的結果
plt.figure("劉大姐")
plt.imshow(img_convolution)
plt.axis("off")
plt.show()
print(img_convolution[0,0])
# 顯示處理完的圖像
img_convolution = img2normalization_256(img_convolution)
plt.figure("劉大姐")
plt.imshow(img_convolution)
plt.axis("off")
plt.show()
7、圖像卷積處理之tensorflow
from PIL import Image
import matplotlib.pyplot as plt
import numpy as np
import tensorflow as tf
%matplotlib inline
'''
tf.nn.conv2d(input=, # 輸入圖像 [batch, height, width, channels]
filter=, # 卷積核,
strides=, # 步幅 一維向量,長度爲4
padding, # 擴展 SAME表示在掃描的時候,如果遇到卷積核比剩下的元素要大時,這個時候需要補0進行最後一次的行掃描或者列掃描
use_cudnn # 啓用cudnn加速
name) # 執行該操作name
'''
img = np.array([1]) # 讀取圖片,並轉換爲灰度圖片
Image.open("../data/劉亦菲.jpg").convert('1') # 非黑即白
img = np.array(Image.open("../data/劉亦菲.jpg").convert('L')) # 0黑255白,其他數字灰度不同
img_full = np.reshape(img, [1, img.shape[0], img.shape[1], 1])
print(img_full.shape) # (1, 1200, 1920, 1)
#創建佔位
input_full = tf.Variable(tf.constant(1.0, shape=img_full.shape))
# input_full = tf.Variable(img_R_full, dtype=tf.float32) # 可以直接輸入
# 創建卷積核
filter_kernel = tf.Variable(tf.constant([#[1.0, 2, 1], [0, 0, 0], [-1, -2, -1] # 水平邊緣濾波器
#[0, -4, 0], [-4, 16, -4], [0, -4, 0] # 整體邊緣濾波器
# [1, 0, -1], [2, 0, -2], [1, 0, -1] # 垂直邊緣濾波器
[-1,-1,-1],[-1,9,-1],[-1,-1,-1]
],
shape = [3,3,1, 1], dtype="float32")) # 3卷積核格式爲3*3 輸入通道1, 輸出通道1
op = tf.nn.conv2d(input_full, filter=filter_kernel, strides=[1,1,1,1], padding="VALID") # SAME是自動填充, 這裏選擇不自動填充的VALID
o=tf.cast(((op-tf.reduce_min(op))/(tf.reduce_max(op)-tf.reduce_min(op)) ) *255 ,tf.uint8) # 歸一化, 因爲經過卷積後像素會有不在0-255範圍內的
with tf.Session() as sess:
sess.run(tf.global_variables_initializer() )
conv_img = sess.run(o, feed_dict={ input_full:img_full})
print(conv_img.shape)
conv_img = conv_img.reshape([conv_img.shape[1], conv_img.shape[2]])
plt.imshow(conv_img, cmap="gray") # 顯示圖片
plt.axis('off') # 不顯示座標軸
plt.show()
(1, 1200, 1920, 1)
(1, 1198, 1918, 1)