# 測試max pooling和average pooling套在影像上的結果(size=2, stride=2)
**Max pooling**就像是星探一樣眼裡只有最亮、最顯眼的原石才能入的了眼,為什麼要這樣做?因為處理細節的時候,想要把每一個像素都顧到,但這樣做不就會累死嗎? 所以 Max pooling直接把一些瑣碎的細節給篩掉,留一些重要的特徵點。
**Average pooling**相對就很佛系,它在指定的範圍內,取所有像素的平均值,也就是說不管亮的暗的,高的矮的,全部都平均,就像是在夜市賣的西瓜汁,打得時候混半杯水和碎冰,喝的時候該有的味道還在,但是不會那麼濃。
讓我們先看圖片

**左邊Max pooling**這波操作過後,圖片少了好多細節,雖然還是看的出來眼睛是眼睛,鼻子是鼻子,但是可愛度就完全不見了。雖然圖片少了很多細節,但它的好處就是能夠防止過擬合,什麼意思?就是不讓你的模型,只變得記得所有的細節,結果一看到新的東西就卡住了,所以Max pooling可以幫模型學習抓大不抓小變得更聰明。
**右邊Average pooling**可以在想模糊掉細節但不太想丟太多細節,它會讓整個區域的像素都參與近來。它讓圖片的各個部分都均衡發展,這樣當拿去給神經網路看的時候,它就都看得懂,不會因為一個細節的變化看起來很奇怪。
因為要使用numpy,cv模組,先在最一開始引用
```
import numpy as np;
import cv2 as cv;
```
用-1讀取原本圖片的顏色
使用.shape取得圖片的高 寬 顏色通道
題目要求pool的整數範圍是2和移步距離2
```
img1 = cv.imread('image1.jpg', -1)
height1, width1, channel1 = img1.shape
pSize = 2
stride = 2
```
做兩張跟原本圖片長寬高通道都一樣的內容為零的空白圖片,之後要在這張空白圖片裡放入經過Max pooling跟mean pooling處理過的照片
```
newHeight = height1
newWidth = width1
newChannel = channel1
maxPoolImage = np.zeros((newHeight, newWidth, newChannel), dtype=np.uint8)
meanPoolImage = np.zeros((newHeight, newWidth, newChannel), dtype=np.uint8)
```
使用三個迴圈遍歷圖片每個像素點和通道,stride//pSize是為了讓窗口移動配合步輻來移動
```
#max pooling and mean pooling
for i in range(newHeight):
for j in range(newWidth):
for k in range(channel1):
heightStart = i*stride // pSize
widthStart = j*stride // pSize
```
這行是從圖片框一個2*2的框框,然後存像素最大值在maxPoolImage和存區域像素平均值到meanPoolImage裡
```region = img1[heightStart:heightStart+pSize, widthStart:widthStart + pSize, k]
maxPoolImage[i, j, k] = np.max(region)
meanPoolImage[i, j, k] = np.mean(region)
```
這裡讀入簽名照片,然後讀取它的長寬通道,如果簽名圖片通道的數量大於三,就只保留三個通道
```
#shrink sign
img2 = cv.imread('sign.jpg', -1)
height2, width2, channel2 = img2.shape
if channel2 > 3:
channel2 = 3
```
把簽名圖片的長寬縮小60%,然後做一張用長寬通道跟簽名照一樣的內容為0的圖片,然後用int(i/0.6)把結果存入newImg2中。
```
newHeight2 = int(0.6*height2)
newWidth2 = int(0.6*width2)
newImg2 = np.zeros((newHeight2, newWidth2, channel2), dtype=np.uint8)
for i in range(newHeight2):
for j in range(newWidth2):
for k in range(channel2):
newImg2[i,j,k] = img2[int(i/0.6), int(j/0.6), k]
```
outputMax跟outputMean是pooling的副本,使用迴圈遍歷每個圖片的像素把縮小的簽名照加到副本上。
```
#put sign and image together
outputMax = maxPoolImage.copy()
outputMean = meanPoolImage.copy()
for i in range(newHeight2):
for j in range(newWidth2):
for k in range(channel2):
if newImg2[i, j, k] != 0:
outputMean[height1-newHeight2+i, width1-newWidth2+j, k]=newImg2[i, j, k]
outputMax[height1-newHeight2+i, width1-newWidth2+j, k]=newImg2[i, j, k]
```
10像素的白色邊框,然後做一個比原本圖片大10邊框像素的全白照片,把pooling過後的圖片放在這個全白圖片的中間,四周保留10像素的白色邊框,這樣就大功告成。
```
paddingSize = 10
paddingHeight = height1 + 2*paddingSize
paddingWidth = width1 + 2*paddingSize
paddingImgMean = np.full((paddingHeight, paddingWidth,3), 255, dtype=np.uint8)
paddingImgMax = np.full((paddingHeight, paddingWidth,3), 255, dtype=np.uint8)
paddingImgMean[paddingSize:height1+paddingSize, paddingSize:width1+paddingSize] = outputMean
paddingImgMax[paddingSize:height1+paddingSize, paddingSize:width1+paddingSize] = outputMax
```
在OpenCV用cv.imshow來顯示圖片,cv.waitkey會讓圖片暫停,等待使用者按下叉叉,沒有這個函式圖片會瞬間出來瞬間關閉,根本來不及看。
cv.destroyAllWindows(),關閉cv.imshow的視窗,當按下鍵盤上的按鍵後,所有圖片視窗會被關閉。
```
# cv.imshow('max', poolImage)
cv.imshow('max', paddingImgMax)
cv.imshow('mean', paddingImgMean)
cv.waitKey()
cv.destroyAllWindows()
```
# 完整程式碼
```
import numpy as np;
import cv2 as cv;
img1 = cv.imread('image1.jpg', -1)
height1, width1, channel1 = img1.shape
pSize = 2
stride = 2
newHeight = height1
newWidth = width1
newChannel = channel1
maxPoolImage = np.zeros((newHeight, newWidth, newChannel), dtype=np.uint8)
meanPoolImage = np.zeros((newHeight, newWidth, newChannel), dtype=np.uint8)
#max pooling and mean pooling
for i in range(newHeight):
for j in range(newWidth):
for k in range(channel1):
heightStart = i*stride // pSize
widthStart = j*stride // pSize
region = img1[heightStart:heightStart+pSize, widthStart:widthStart + pSize, k]
maxPoolImage[i, j, k] = np.max(region)
meanPoolImage[i, j, k] = np.mean(region)
#shrink sign
img2 = cv.imread('sign.jpg', -1)
height2, width2, channel2 = img2.shape
if channel2 > 3:
channel2 = 3
newHeight2 = int(0.6*height2)
newWidth2 = int(0.6*width2)
newImg2 = np.zeros((newHeight2, newWidth2, channel2), dtype=np.uint8)
for i in range(newHeight2):
for j in range(newWidth2):
for k in range(channel2):
newImg2[i,j,k] = img2[int(i/0.6), int(j/0.6), k]
#put sign and image together
outputMax = maxPoolImage.copy()
outputMean = meanPoolImage.copy()
for i in range(newHeight2):
for j in range(newWidth2):
for k in range(channel2):
if newImg2[i, j, k] != 0:
outputMean[height1-newHeight2+i, width1-newWidth2+j, k]=newImg2[i, j, k]
outputMax[height1-newHeight2+i, width1-newWidth2+j, k]=newImg2[i, j, k]
paddingSize = 10
paddingHeight = height1 + 2*paddingSize
paddingWidth = width1 + 2*paddingSize
paddingImgMean = np.full((paddingHeight, paddingWidth,3), 255, dtype=np.uint8)
paddingImgMax = np.full((paddingHeight, paddingWidth,3), 255, dtype=np.uint8)
paddingImgMean[paddingSize:height1+paddingSize, paddingSize:width1+paddingSize] = outputMean
paddingImgMax[paddingSize:height1+paddingSize, paddingSize:width1+paddingSize] = outputMax
# cv.imshow('max', poolImage)
cv.imshow('max', paddingImgMax)
cv.imshow('mean', paddingImgMean)
cv.waitKey()
cv.destroyAllWindows()
```