python版本:python3.5.4 ; opencv-python版本:opencv-python3.4.2.17
使用的開發環境是jupyter notebook,是一個python的交互式開發環境,測試十分方便,併集成了vim操作,安裝教程可參考:https://blog.csdn.net/feilong_csdn/article/details/80186276
先導文章:
opencv-python快速入門篇【數字圖像處理系列一】
基本概念:亮度、對比度、飽和度、銳化、解析度【數字圖像處理系列二】
圖像增強:線性、 分段線性、 對數、 反對數、 冪律(伽馬)變換、直方圖均衡【數字圖像處理系列三】
圖像數據集增強方式總結和實現【數字圖像處理系列四】
在圖像增強:線性、 分段線性、 對數、 反對數、 冪律(伽馬)變換、直方圖均衡【數字圖像處理系列三】一文中我們從圖像灰度變換的角度闡述了圖像增強的各種方式,本文我們將一起學習圖像處理中重點的方式:圖像濾波,圖像濾波分為空間域濾波和頻率域濾波,頻率域濾波我們將在下一節重點說明。圖像空間濾波對於圖像處理主要體現在兩個方面:
(1) 平滑圖像,達到降低圖像噪音的效果(平滑空間濾波)
(2) 銳化圖像,主要目的是突出灰度的過渡部分,即突出圖像的邊緣(銳化空間濾波)
先上圖,感受一下空間濾波對圖像處理的效果(原圖、經過拉普拉斯處理後的圖像):
一、空間濾波原理
圖像的空間濾波器有兩大部分:
(1) 一個基於圖像像素的矩形鄰域
(2) 對矩形鄰域包圍的圖像像素的操作方式
理解圖像的矩形鄰域如下圖所示
將圖像的左上角看做是空間域中的原點O,向下取為x軸,向右取為y軸,圖中便顯示了中心點(x,y)的一個3*3鄰域。每經過一個濾波產生一個新像素,新像素的坐標等於領域中心坐標(x,y),新像素的值是濾波操作的結果。而濾波器的類型也取決於鄰域上操作的類型,如果鄰域操作是線性操作,則濾波器稱為線性空間濾波器;反之如果鄰域操作是非線性操作,則濾波器稱為非線性空間濾波器。
這裡我們假設 f(x,y) 為原像素值,g(x,y) 為濾波後的像素值,則對於一個大小為M * N的圖像使用大小為m * n的濾波器進行線性空間濾波,若令m=2a+1,n=2b+1,則鄰域上線性操作可統一表達成下式:
其中x,y是可變的,以便w中的每個像素可訪問f中的每個像素,我們一般稱鄰域內像素和濾波器模板的操作叫做卷積。下面將分別講解平滑空間濾波器和銳化空間濾波器
二、平滑空間濾波
1、均值濾波、加權均值濾波
均值濾波又稱為線性空間濾波,利用鄰域平均法,即用幾個像素灰度的平均值來代替每個像素的灰度。有效抑制加性噪聲,但容易引起圖像模糊,尤其是會模糊圖像邊緣。通過下圖便可看到均值濾波和加權均值濾波的區別:
其中左圖是均值濾波,即鄰域中每個像素權重相同,取鄰域平均值作為中心像素點的濾波輸出值,則濾波器模板計算公式為:
而右圖濾波器模板則賦予中心點最高權重,然後隨著距中心點距離的增加而減小係數值,其目的是在平滑處理中試圖降低模糊,加權均值濾波器的操作如下是:
下面分別通過opencv-python提供的均值濾波和自定義均值濾波器兩種方式實現圖像的均值濾波:
import cv2import copyimport randomimport imutilsimport numpy as np
img = cv2.imread('E:/peking_rw/ocr_project/base_prehandle/img/lena.png')gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#利用opencv提供函數實現均值濾波blur_img = cv2.blur(gray_img, (3, 3))
#在灰度圖上手動實現均值濾波器gray_avg_img = copy.deepcopy(gray_img)for i in range(1, gray_img.shape[0]-1): for j in range(1, gray_img.shape[1]-1): sum_pix = sum([gray_img[l, k] for l in range(i-1, i+2) for k in range(j-1, j+2)]) gray_avg_img [i, j] = int(sum_pix/9)
#在RGB彩色圖上手動實現均值濾波器rgb_avg_img = copy.deepcopy(img)for i in range(1, img.shape[0]-1): for j in range(1, img.shape[1]-1): sum_b_pix = sum([img[l, k, 0] for l in range(i-1, i+2) for k in range(j-1, j+2)]) sum_g_pix = sum([img[l, k, 1] for l in range(i-1, i+2) for k in range(j-1, j+2)]) sum_r_pix = sum([img[l, k, 2] for l in range(i-1, i+2) for k in range(j-1, j+2)]) rgb_avg_img [i, j] = [int(sum_b_pix/9), int(sum_g_pix/9), int(sum_r_pix/9)]
cv2.imshow('origin image', imutils.resize(img, 500))cv2.imshow('gray image', imutils.resize(gray_img, 500))cv2.imshow('blur image', imutils.resize(blur_img, 500))cv2.imshow('gray average image', imutils.resize(gray_avg_img , 500))cv2.imshow('rgb average image', imutils.resize(rgb_avg_img , 500))if cv2.waitKey(0) == 27: cv2.destroyAllWindows()
效果圖如下:依次是原圖、灰度圖、基於灰度圖opencv提供函數blur均值濾波效果、基於灰度圖自定義均值濾波效果、基於彩色圖自定義均值濾波效果
2、中值濾波
中值濾波是基於排序統計理論的一種能有效抑制噪聲的非線性平滑濾波信號處理技術。中值濾波的特點即是首先確定一個以某個像素為中心點的鄰域,然後將鄰域中各像素的灰度值排序,取其中間值作為中心像素灰度的新值。中值濾波在對於椒鹽噪音處理上效果很好
下面分別通過opencv-python提供的中值濾波和自定義中值濾波器兩種方式實現圖像的中值濾波,下面實驗中我們嘗試著對圖像添加椒鹽噪音然後進行使用中值濾波進行消除:
import cv2import copyimport randomimport imutilsimport numpy as np
img = cv2.imread('E:/peking_rw/ocr_project/base_prehandle/img/old.jpg')gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
pepper_img = copy.deepcopy(gray_img)for i in range(gray_img.shape[0]): for j in range(gray_img.shape[1]): if random.randint(0, 20) == 0: pix = random.randint(250, 255) pepper_img[i, j] = pix
blur_img = cv2.medianBlur(pepper_img, 5)
temp_arr = np.zeros((9))median_img = copy.deepcopy(pepper_img)for i in range(1, pepper_img.shape[0]-1): for j in range(1, pepper_img.shape[1]-1): temp_arr[0] = pepper_img[i-1, j-1] temp_arr[1] = pepper_img[i-1, j] temp_arr[2] = pepper_img[i-1, j+1] temp_arr[3] = pepper_img[i, j-1] temp_arr[4] = pepper_img[i, j] temp_arr[5] = pepper_img[i, j+1] temp_arr[6] = pepper_img[i+1, j-1] temp_arr[7] = pepper_img[i+1, j] temp_arr[8] = pepper_img[i+1, j+1] arr = np.sort(temp_arr) median_img[i, j] = arr[4]
cv2.imshow('pepper image', imutils.resize(pepper_img, 600))cv2.imshow('blur image', imutils.resize(blur_img, 600))cv2.imshow('median image', imutils.resize(median_img, 600))if cv2.waitKey(0) == 27: cv2.destroyAllWindows()效果圖如下:依次是含椒鹽噪音圖、經過cv2.medianBlur()函數處理後的圖像、經過自定義中值濾波器濾波後圖像
除了中值濾波外,還有一種非線性濾波是最值濾波,最值濾波是去鄰域中的最大值最為新像素值,在搜尋一幅圖像最亮點時非常有用。
三、銳化空間濾波器
寫在前面:上節提到的圖像平滑是通過模糊圖像達到圖像降噪的目的,但同時存在一個問題就是會使得圖像的邊緣被淡化。因此本節圖像銳化濾波恰相反,圖像平滑是一個積分的過程,圖像銳化便是通過圖像微分增強邊緣和其他突變,削弱灰度變換緩慢的區域。
在圖像微分銳化操作中,對於一階微分的任何定義需要保證以下三點:
(1) 在恆定灰度區域的微分值為零
(2) 在灰度臺階或斜坡處微分值非零
(3) 沿著斜坡的微分值非零
同樣類比得對於二階微分的任何保證以下三點:
(1) 在恆定區域微分值為零
(2) 在灰度臺階或斜坡的起點處微分值非零
(3) 沿著斜坡的微分值非零
1、二階微分圖像銳化—laplacian算子
首先一個二維圖像函數 f(x,y) 的拉普拉斯算子定義為:
拉普拉斯變換是一個線性算子,在x方向上離散化有:
在y方向離散化有:
從上面三個式子可以得出離散拉普拉斯算子是:
上面公式便是拉普拉斯算子中一種計算方式,等價於下圖中的laplacian模板1,自然laplacian模板2也可以類比寫出離散算子公式:
註:由於拉普拉斯是一種微分算子,因此其強調的是圖像中灰度的變換,忽視圖像灰度變換緩慢的區域。因此我們通過laplacian算子得出的是圖像更多的是邊緣線,因此,我們可以將原圖和拉普拉斯圖像疊加在一起,可以復原背景特性並且保持拉普拉斯銳化處理的效果,由此得出下面公式:
對於上面展示的拉普拉斯模板1和拉普拉斯模板2,常數c取-1,也有其他模板,這裡不再詳述
下面給出利用opencv函數和自實現上述拉普拉斯模板的應用實例:
import cv2import copyimport randomimport imutilsimport numpy as np
img = cv2.imread('E:/peking_rw/ocr_project/base_prehandle/img/blurry_moon.jpg')
lap_img1 = copy.deepcopy(img)for i in range(1, img.shape[0]-1): for j in range(1, img.shape[1]-1): temp = img[i+1, j] + img[i-1, j] + img[i, j+1] + img[i, j-1] -4*img[i, j] lap_img1[i, j] = img[i, j] - temp
lap_img2 = copy.deepcopy(img)for i in range(1, img.shape[0]-1): for j in range(1, img.shape[1]-1): temp = img[i-1, j-1] + img[i-1, j] + img[i-1, j+1] + img[i, j-1] + \ img[i, j+1] + img[i+1, j-1] + img[i+1, j] + img[i+1, j+1] - 8*img[i, j] lap_img2[i, j] = img[i, j] - temp
kernel = np.array([[0, 1, 0], [1, -4, 1], [0, 1, 0]]) lapkernel_img = cv2.filter2D(img, -1, kernel)lap_img3 = img - lapkernel_img
cv2.imshow('origin image', imutils.resize(img, 400))cv2.imshow('laplacian image1', imutils.resize(lap_img1, 400))cv2.imshow('laplacian image2', imutils.resize(lap_img2, 400))cv2.imshow('laplacian image3', imutils.resize(lap_img3, 400))if cv2.waitKey(0) == 27: cv2.destroyAllWindows()效果圖如下,順序既是上述程序的輸出順序:
2、非銳化掩蔽
非銳化掩蔽的思路便是應原圖像減去平滑的圖像,這樣便得到強調邊緣的圖像,然後再和原圖像相加,便達到強調圖像邊緣的效果,具體步驟如下:
(1) 模糊原圖像
(2) 從原圖像減去模糊圖像(產生的差值圖像稱為模板)
(3) 將模板和原圖像相加
則將上述思路換算成數學公式便是:
然後在原圖像加上模板的一個權重部分:
當k>1時我們稱該處理為高提升濾波,當k<1時則是不強調非銳化模板的作,下面提供代碼實現如下:
import cv2import copyimport randomimport imutilsimport numpy as np
img = cv2.imread('E:/peking_rw/ocr_project/base_prehandle/img/blurry_moon.jpg')blur_img = cv2.blur(img, (5, 5))
mask_img = img - blur_imgsharp_mask_img = img + mask_img
cv2.imshow('origin image', imutils.resize(img, 400))cv2.imshow('blur image', imutils.resize(blur_img, 400))cv2.imshow('mask image', imutils.resize(mask_img, 400))cv2.imshow('sharpen mask image', imutils.resize(sharp_mask_img, 400))if cv2.waitKey(0) == 27: cv2.destroyAllWindows()
3、cv2.filter2D()自定義卷積核濾波opencv-python中提供cv2.filter2D()函數可實現自定義內核和圖像進行卷積操作,cv2.filter2D()一般定義為:
cv2.filter2D(img, -1, kernel)下面我們提供實例展示對圖像濾波的效果:
import cv2import copyimport randomimport imutilsimport numpy as np
img = cv2.imread('E:/peking_rw/ocr_project/base_prehandle/img/old.jpg')kernel = np.array([[0, -1, 0], [0, 5, 0], [0, -1, 0]]) new_img = cv2.filter2D(img, -1, kernel)
cv2.imshow('origin image', imutils.resize(img, 400))cv2.imshow('new image', imutils.resize(new_img, 400))if cv2.waitKey(0) == 27: cv2.destroyAllWindows()根據自定義的卷積核 kernel = np.array([[0, -1, 0], [0, 5, 0], [0, -1, 0]]) 得到的濾波效果如下:
往期精彩:
深度學習多種模型評估指標介紹 - 附sklearn實現
乾貨 | Attention注意力機制超全綜述
Tensorflow常用函數使用說明及實例簡記
機器學習中優化相關理論知識簡述
自己動手實現一個神經網絡多分類器
Transformer 模型的 PyTorch 實現
乾貨 | NLP中的十個預訓練模型
乾貨|一文弄懂機器學習中偏差和方差
FastText原理和文本分類實戰,看這一篇就夠了
Transformer模型細節理解及Tensorflow實現
GPT,GPT2,Bert,Transformer-XL,XLNet論文閱讀速遞
機器學習算法篇:最大似然估計證明最小二乘法合理性
Word2vec, Fasttext, Glove, Elmo, Bert, Flair訓練詞向量教程+數據+源碼
原創不易,別偷偷摸摸的在看,有用就點個好看呀