# 測試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() ```