之前在看卷積神經網絡,很好奇卷積到底是什么,最后看到了這篇文章http://blog.csdn.net/zouxy09/article/details/49080029,講得很清楚,這篇文章中提到了對圖像的濾波處理就是對圖像應用一個小小的卷積核,並給出了以下例子:
對圖像的卷積,opencv已經有實現的函數filter2D,注意,卷積核需要是奇數行,奇數列,這樣才能有一個中心點。opencv卷積的簡單實踐如下:
import matplotlib.pyplot as plt import pylab import cv2 import numpy as np img = plt.imread("apic.jpg") #在這里讀取圖片 plt.imshow(img) #顯示讀取的圖片 pylab.show() fil = np.array([[ -1,-1, 0], #這個是設置的濾波,也就是卷積核 [ -1, 0, 1], [ 0, 1, 1]]) res = cv2.filter2D(img,-1,fil) #使用opencv的卷積函數 plt.imshow(res) #顯示卷積后的圖片 plt.imsave("res.jpg",res) pylab.show()
知道了原理以后,就想自己實現一個簡單的卷積,卷積的過程如下,對於mxn的圖像,用kxk的濾波依次掃描,掃描的過程就是把原圖的矩陣和卷積核依次進行逐點相乘(wise-element)並求和(需要注意求和結果可能大於255或小於0),在卷積特征提取ufldl講了卷積的具體過程。
可以發現一個規律,就是卷積后的圖像的大小為(m - k + 1)x(n - k + 1),寫代碼的時候需要根據這個規律來確定卷積后的圖像的大小。
根據原理,實現代碼如下:
1 import matplotlib.pyplot as plt 2 import pylab 3 import numpy as np 4 5 def convolve(img,fil,mode = 'same'): #分別提取三個通道 6 7 if mode == 'fill': 8 h = fil.shape[0] // 2 9 w = fil.shape[1] // 2 10 img = np.pad(img, ((h, h), (w, w),(0, 0)), 'constant') 11 conv_b = _convolve(img[:,:,0],fil) #然后去進行卷積操作 12 conv_g = _convolve(img[:,:,1],fil) 13 conv_r = _convolve(img[:,:,2],fil) 14 15 dstack = np.dstack([conv_b,conv_g,conv_r]) #將卷積后的三個通道合並 16 return dstack #返回卷積后的結果 17 def _convolve(img,fil): 18 19 fil_heigh = fil.shape[0] #獲取卷積核(濾波)的高度 20 fil_width = fil.shape[1] #獲取卷積核(濾波)的寬度 21 22 conv_heigh = img.shape[0] - fil.shape[0] + 1 #確定卷積結果的大小 23 conv_width = img.shape[1] - fil.shape[1] + 1 24 25 conv = np.zeros((conv_heigh,conv_width),dtype = 'uint8') 26 27 for i in range(conv_heigh): 28 for j in range(conv_width): #逐點相乘並求和得到每一個點 29 conv[i][j] = wise_element_sum(img[i:i + fil_heigh,j:j + fil_width ],fil) 30 return conv 31 32 def wise_element_sum(img,fil): 33 res = (img * fil).sum() 34 if(res < 0): 35 res = 0 36 elif res > 255: 37 res = 255 38 return res 39 40 img = plt.imread("photo.jpg") #在這里讀取圖片 41 42 plt.imshow(img) #顯示讀取的圖片 43 pylab.show() 44 45 46 #卷積核應該是奇數行,奇數列的 47 fil = np.array([[-1,-1,-1, 0, 1], 48 [-1,-1, 0, 1, 1], 49 [-1, 0, 1, 1, 1]]) 50 51 res = convolve(img,fil,'fill') 52 print("img shape :" + str(img.shape)) 53 plt.imshow(res) #顯示卷積后的圖片 54 print("res shape :" + str(res.shape)) 55 plt.imsave("res.jpg",res) 56 pylab.show()
使用圖像水平邊緣濾波和浮雕濾波的結果如下,效果和opencv結果一致:
另外這里也有關於卷積c/c++實現:http://lodev.org/cgtutor/filtering.html