---
# System prepended metadata

title: 數位影像處理 HW1 Pooling

---

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

讓我們先看圖片






![圖片1](https://hackmd.io/_uploads/SJmwqJOxkg.png)





**左邊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()
```