一、灰度實驗
將彩色圖像轉換為灰度圖像的過程稱為灰度化,這種做法在圖像處理中和計算機視覺領域非常常見
1、灰度圖
灰度圖是一種 單通道圖像,每個像素僅存儲 亮度信息(0=純黑,255=純白),沒有顏色信息(RGB)。在計算機視覺(OpenCV)和圖像處理中廣泛使用。
灰度圖 vs RGB 圖的區別
特性 | 灰度圖 | RGB 彩色圖 |
---|---|---|
通道數 | 1(單通道) | 3(紅、綠、藍三通道) |
像素值范圍 | 0(黑)~255(白) | 每個通道 0~255 |
存儲大小 | 較小(節省內存) | 較大(3倍于灰度圖) |
適用場景 | 邊緣檢測、人臉識別等 | 彩色圖像分析、顯示 |
2、圖像灰度化方法
灰度圖與彩色圖最大的不同就是:彩色圖是由R、G、B三個通道組成,而灰度圖只有一個通道,也稱為單通道圖像,所以彩色圖轉成灰度圖的過程本質上就是將R、G、B三通道合并成一個通道的過程。本實驗中一共介紹了三種合并方法,分別是最大值法、平均值法以及加權均值法。
(1)最大值法
對于彩色圖像的每個像素,它會從R、G、B三個通道的值中選出最大的一個,并將其作為灰度圖像中對應位置的像素值。
OpenCV代碼實現
import cv2 as cv
import numpy as np#讀圖
cat = cv.imread("../../images/cat1.png")
cv.imshow("cat", cat)
#提取高度和寬度
h,w = cat.shape[:2]
#創建單通道全0矩陣(黑色),用于存放灰度圖 (h,w)
black = np.zeros((h,w), np.uint8)for i in range(h):#遍歷每一行for j in range(w):#遍歷每一列black[i,j] = max(cat[i,j,0],cat[i,j,1],cat[i,j,2]) # 提取RGB的最大值cv.imshow("black", black)
cv.waitKey(0)
cv.destroyAllWindows()
(2)平均值法
對于彩色圖像的每個像素,它會將R、G、B三個通道的像素值全部加起來,然后再除以三,得到的平均值就是灰度圖像中對應位置的像素值。
OpenCV代碼實現:
import cv2 as cv
import numpy as np
#讀圖
cat = cv.imread("../../images/cat1.png")
cv.imshow("cat", cat)
#提取高度和寬度
h,w = cat.shape[:2]
#創建單通道全0矩陣(黑色),用于存放灰度圖 (h,w)
black = np.zeros((h,w), np.uint8)
#遍歷每一行
for i in range(h):#遍歷每一列for j in range(w):#數據類型為unint8,為了防止數值溢出,需要轉為更大的數值類型(int),處理完后將數據類型轉回來(np.uint8)black[i,j] = np.uint8((int(cat[i,j,0])+int(cat[i,j,1])+int(cat[i,j,2]))//3)cv.imshow("black", black)
cv.waitKey(0)
cv.destroyAllWindows()
(3)加權平均值法
對于彩色圖像的每個像素,它會按照一定的權重去乘以每個通道的像素值,并將其相加,得到最后的值就是灰度圖像中對應位置的像素值。本實驗中,權重的比例為: R乘以0.299,G乘以0.587,B乘以0.114,這是經過大量實驗得到的一個權重比例,也是一個比較常用的權重比例。
所使用的權重之和應該等于1。這是為了確保生成的灰度圖像素值保持在合理的亮度范圍內,并且不會因為權重的比例不當導致整體過亮或過暗
OpenCV代碼實現:
import cv2 as cv
import numpy as np
#讀圖
cat = cv.imread("../../images/cat1.png")
cv.imshow("cat", cat)
h,w = cat.shape[:2]
#創建單通道全0矩陣(黑色),用于存放灰度圖 (h,w)
black = np.zeros((h,w), np.uint8)
#定義每個通道上的權重
wb,wg,wr = 0.114,0.587,0.299
#遍歷每一行
for i in range(h):#遍歷每一列for j in range(w): # round取整black[i,j] = round(wb * cat[i,j,0] + wg * cat[i,j,1] + wr * cat[i,j,2])cv.imshow("black", black)
cv.waitKey(0)
cv.destroyAllWindows()
3、 兩個極端的灰度值
在灰度圖像中,“極端”的灰度值指的是亮度的兩個極端:最暗和最亮的值。
- 最暗的灰度值:0。這代表完全黑色,在灰度圖像中沒有任何亮度。
- 最亮的灰度值:255。這代表完全白色,在灰度圖像中具有最大亮度。
二、圖像二值化處理
圖像二值化是將灰度圖像轉換為僅包含黑白兩種像素值(通常0和255)的圖像處理技術,是計算機視覺預處理的關鍵步驟。
通俗的說就是將某張圖像的所有像素改成只有兩種值
1、二值圖像
一幅二值圖像的二維矩陣僅由0、1兩個值構成,“0”代表黑色,“1”代白色。由于每一像素(矩陣中每一元素)取值僅有0、1兩種可能,所以計算機中二值圖像的數據類型通常為1個二進制位。二值圖像通常用于文字、線條圖的掃描識別(OCR)和掩膜圖像的存儲。
灰度圖:
二值圖像(舉例):
其操作的圖像也必須是灰度圖。也就是說,二值化的過程,就是將一張灰度圖上的像素根據某種規則修改為0和maxval(maxval表示最大值,一般為255,顯示白色)兩種像素值,使圖像呈現黑白的效果,能夠幫助我們更好地分析圖像中的形狀、邊緣和輪廓等特征。
特點:
- 簡便:降低計算量和計算需求,加快處理速度。
- 節約資源:二值圖像占用空間遠小于彩色圖。
- 邊緣檢測:二值化常作為邊緣檢測的預處理步驟,因為簡化后的圖易于識別出輪廓和邊界。
全局閾值法代碼以及參數
_,binary = cv2.threshold(img,thresh,maxval,type)
- img:輸入圖像,要進行二值化處理的灰度圖像。
- thresh:設定的閾值。
- type:閾值處理的類型
返回值:
- 第一個值(通常用下劃線表示):計算出的閾值,若使用自適應閾值法,會根據算法自動計算出這個值。
- 第二個值(binary):二值化后的圖像矩陣。與輸入圖像(需進行處理的灰度圖)尺寸相同。
2、基本閾值方法
(1)閾值法
閾值法就是通過設置一個閾值,將灰度圖中的每一個像素值與該閾值進行比較,小于等于閾值的像素就被設置為0(通常代表背景),大于閾值的像素就被設置為maxval(通常代表前景)。對于我們的8位圖像(0~255)來說,通常是設置為255。
使用場景:
- 文檔掃描
- 高對比度圖像分割
- 工業零件檢測
特點:
-
計算速度快
-
對光照變化敏感
舉例處理前文灰度圖(后面記錄的方法同樣,可以作為比較):
OpenCV代碼實現:
import cv2 as cv
#讀圖
flower = cv.imread("./images/flower.png")
#重新設定圖像尺寸
flower1=cv.resize(flower,(480,480))
cv.imshow("flower1",flower1)#灰度化處理,二值化處理的對象是灰度圖
gray = cv.cvtColor(flower1, cv.COLOR_BGR2GRAY)#閾值法:小于閾值的像素設置為0,大于閾值的像素設置為maxval
_,binary=cv.threshold(gray,127,255,cv.THRESH_BINARY)
cv.imshow("binary",binary)cv.waitKey(0)
cv.destroyAllWindows()
處理結果
(2)反閾值法
顧名思義,就是與閾值法相反。反閾值法是當灰度圖的像素值大于閾值時,該像素值將會變成0(黑),當灰度圖的像素值小于等于閾值時,該像素值將會變成maxval。
應用場景:
-
深色背景上的淺色物體檢測
-
醫學圖像處理(如X光片)
OpenCV代碼實現:
import cv2 as cv
#讀圖
flower = cv.imread("../../images/flower.png")
#重新設定圖像尺寸
flower1=cv.resize(flower,(480,480))
cv.imshow("flower1",flower1)#灰度化處理,二值化處理的對象是灰度圖
gray = cv.cvtColor(flower1, cv.COLOR_BGR2GRAY)#反閾值法:大于閾值的像素值設置為0,小于閾值的像素值設置為maxval
_,binary_inv=cv.threshold(gray,127,255,cv.THRESH_BINARY_INV)
cv.imshow("binary_inv",binary_inv)cv.waitKey(0)
cv.destroyAllWindows()
處理結果
(3)截斷閾值法
截斷閾值法,指將灰度圖中的所有像素與閾值進行比較,像素值大于閾值的部分將會被修改為閾值,小于等于閾值的部分不變。
換句話說,經過截斷閾值法處理過的二值化圖中的最大像素值就是閾值
特點:
-
保留部分灰度信息
-
用于圖像壓縮
OpenCV代碼實現:
import cv2 as cv
#讀圖
flower = cv.imread("../../images/flower.png")
#重新設定圖像尺寸
flower1=cv.resize(flower,(480,480))
cv.imshow("flower1",flower1)#灰度化處理,二值化處理的對象是灰度圖
gray = cv.cvtColor(flower1, cv.COLOR_BGR2GRAY)#截斷閾值法,大于閾值的像素值修改為閾值,小于等于閾值的部分不變,像素的最大值就是閾值
_,trunc = cv.threshold(gray,170,255,cv.THRESH_TRUNC)
cv.imshow("trunc",trunc)cv.waitKey(0)
cv.destroyAllWindows()
處理結果
(4)低閾值零處理
低閾值零處理,字面意思,就是像素值小于等于閾值的部分設置為0(也就是黑色),大于閾值的部分不變。
應用場景:
-
弱邊緣增強
-
噪聲抑制
OpenCV代碼實現:
import cv2 as cv
#讀圖
flower = cv.imread("../../images/flower.png")
#重新設定圖像尺寸
flower1=cv.resize(flower,(480,480))
cv.imshow("flower1",flower1)#灰度化處理,二值化處理的對象是灰度圖
gray = cv.cvtColor(flower1, cv.COLOR_BGR2GRAY)#低閾值零處理,小于閾值的像素值修設置為0,大于閾值的部分不變,像素值的最小值就是閾值
_,zeros = cv.threshold(gray,127,255,cv.THRESH_TOZERO)
cv.imshow("zeros",zeros)cv.waitKey(0)
cv.destroyAllWindows()
處理結果
(5)超閾值零處理
超閾值零處理就是將灰度圖中的每個像素與閾值進行比較,像素值大于閾值的部分置為0(也就是黑色),像素值小于等于閾值的部分不變。
特殊應用:
- 高光區域抑制
- 陰影分析
OpenCV代碼實現:
import cv2 as cv
#讀圖
flower = cv.imread("../../images/flower.png")
#重新設定圖像尺寸
flower1=cv.resize(flower,(480,480))
cv.imshow("flower1",flower1)#灰度化處理,二值化處理的對象是灰度圖
gray = cv.cvtColor(flower1, cv.COLOR_BGR2GRAY)#超閾值零處理,大于閾值的像素值設置為0,小于閾值的像素值不變
_,tozero_inv = cv.threshold(gray,170,255,cv.THRESH_TOZERO_INV)
cv.imshow("tozero_inv",tozero_inv)cv.waitKey(0)
cv.destroyAllWindows()
處理結果
2、高級閾值方法
(1)OTSU閾值法
cv2.THRESH_OTSU 并不是一個有效的閾值類型或標。THRESH_OTSU 本身并不是一個獨立的閾值化方法,而是與 OpenCV 中的二值化方法結合使用的一個標志。具體來說,THRESH_OTSU 通常與 THRESH_BINARY 或 THRESH_BINARY_INV 結合使用。在實際應用中,如果你使用 THRESH_OTSU 標志但沒有指定其他二值化類型,默認情況下它會與 THRESH_BINARY 結合使用。也就是說,當你僅指定了 cv2.THRESH_OTSU,實際上等同于同時指定了 cv2.THRESH_BINARY + cv2.THRESH_OTSU。
原理簡答
OTSU算法像是一個"自動找最佳分界線"的方法——它遍歷所有可能的黑白分界值(閾值),計算按該值分成兩類像素時,兩類之間的差異最大(比如前景和背景顏色差別最明顯)的那個閾值,最終選擇這個"讓黑白對比最強烈"的值作為最佳分界點。(算法自動生成閾值)
也就是說OTSU方法只是計算出了處理灰度圖時最佳閾值,處理時需再加上基本閾值方法(默認閾值法)才能對灰度圖進行處理
適用條件:
-
直方圖呈雙峰分布
-
前景背景對比度明顯
優點:
-
自動確定最佳閾值
-
無需人工干預
OpenCV代碼實現:
import cv2 as cv
#讀圖
flower = cv.imread("../../images/flower.png")
#重新設定圖像尺寸
flower1=cv.resize(flower,(480,480))
cv.imshow("flower1",flower1)#灰度化處理,二值化處理的對象是灰度圖
gray = cv.cvtColor(flower1, cv.COLOR_BGR2GRAY)#OTSU閾值法,默認結合閾值法,最大類間方差 cv.THRESH_OTSU = cv.THRESH_OTSU+CV.THRESH_BINARY
thresh,otsu = cv.threshold(gray,0,255,cv.THRESH_OTSU)
print(f"OTSU自動計算的閾值:{thresh}")cv.imshow("otsu",otsu)
cv.waitKey(0)
cv.destroyAllWindows()
處理結果
(2)自適應二值化
與二值化算法相比,自適應二值化更加適合用在明暗分布不均的圖片,因為圖片的明暗不均,導致圖片上的每一小部分都要使用不同的閾值進行二值化處理,這時候傳統的二值化算法就無法滿足我們的需求了,于是就出現了自適應二值化。
自適應二值化方法會對圖像中的所有像素點計算其各自的閾值,這樣能夠更好的保留圖片里的一些信息。
兩種自適應求和的方法:
1、取均值(ADAPTIVE_THRESH_MEAN_C)::計算鄰域均值作為局部閾值
2、加權求和(高斯法) (ADAPTIVE_THRESH_GAUSSIAN_C):使用高斯加權計算局部閾值
應用場景:
-
光照不均勻的圖像
-
文檔圖像陰影處理
-
自然場景文本識別
cv2.adaptiveThreshold(img, maxval, cv2.ADAPTIVE_THRESH_MEAN_C, thresholdType, blockSize, C)
其中各個參數的含義如下:
-
maxval:最大閾值,一般為255
-
ADAPTIVE_THRESH_MEAN_C:小區域內取均值
-
ADAPTIVE_THRESH_GAUSSIAN_C:小區域內加權求和,權重是個高斯核
-
thresholdType:二值化方法,只能使用THRESH_BINARY、THRESH_BINARY_INV,也就是閾值法和反閾值法
-
blockSize:選取的小區域的面積,如7就是7*7的小塊。
-
c:最終閾值等于小區域計算出的閾值再減去此值
OpenCV代碼實現:
import cv2 as cv
#讀圖
flower = cv.imread("../../images/flower.png")
#重新設定圖像尺寸
flower1=cv.resize(flower,(480,480))
cv.imshow("flower1",flower1)#灰度化處理,二值化處理的對象是灰度圖
gray = cv.cvtColor(flower1, cv.COLOR_BGR2GRAY)# 自適應二值化 必須結合閾值法或者反閾值法 返回值只有一個
#取均值 (ADAPTIVE_THRESH_MEAN_C)
binary=cv.adaptiveThreshold(gray,255,cv.ADAPTIVE_THRESH_MEAN_C,cv.THRESH_BINARY,7,10)
cv.imshow("binary",binary)
#加權求和(高斯法) (ADAPTIVE_THRESH_GAUSSIAN_C)
binary_gauss=cv.adaptiveThreshold(gray,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C,cv.THRESH_BINARY,7,10)
cv.imshow("gauss",binary_gauss)cv.waitKey(0)
cv.destroyAllWindows()
處理結果
取均值:
加權求和(高斯法):
3、方法對比
方法 | 計算復雜度 | 適用場景 | 參數敏感性 | 抗噪性 | 保留細節 |
---|---|---|---|---|---|
標準閾值 | O(1) | 均勻光照 | 高 | 差 | 一般 |
反閾值 | O(1) | 反色場景 | 高 | 差 | 一般 |
截斷閾值 | O(1) | 壓縮處理 | 中 | 一般 | 好 |
OTSU | O(L) L=256 | 雙峰圖像 | 無 | 一般 | 好 |
自適應 | O(N×M) | 非均勻光 | 中 | 較好 | 優秀 |
(L為灰度級數,N×M為圖像尺寸)
三、圖像掩膜
1、制作掩膜
掩膜(Mask)是一種在圖像處理中常見的操作,它用于選擇性地遮擋圖像的某些部分,以實現特定任務的目標。掩膜通常是一個二值化圖像,并且與原圖像的大小相同,其中目標區域被設置為1(或白色),而其他區域被設置為0(或黑色),并且目標區域可以根據HSV的顏色范圍進行修改。
創建掩膜代碼
mask = cv2.inRange(src, lowerb, upperb)
**作用:**檢查圖像 src 的每個像素,如果像素值在 [lowerb, upperb] 范圍內,則 mask 中對應位置置為 255(白色),否則置為 0(黑色)。
2、與運算
通過掩膜與原圖的與運算,我們就可以提取出圖像中被掩膜覆蓋的區域(扣圖)。
cv2.bitwise_and(src1,src2[,mask])
參數
- src1:第一個輸入數組。通常是輸入的原始圖像。
- src2:第二個輸入數組。它可以是另一個圖像、一個常數值或者與 src1 相同的圖像。
- 當應用掩膜時,這個參數經常就是src1本身;即對同一個圖像進行操作。
- 如果對兩個不同的圖像執行按位與操作(例如,將兩張圖片的某些部分組合在一起),可以分別將它們作為 src1 和 src2 輸入到 cv2.bitwise_and() 函數中,創建復雜的圖像效果或進行圖像合成。
- mask:掩膜(可選)。輸入數組元素只有在該掩膜非零時才被處理。是一個8位單通道的數組,尺寸必須與src1和src2相同。
- 返回值:輸出數組,應用掩膜后的圖像,與輸入數組大小和類型相同。
3、顏色替換
前一個實驗中,我們已經能夠識別到圖像中的某一種顏色,那么我們就可以對識別到的顏色進行一個操作,比如將其替換成別的顏色,其原理就是在得到原圖的掩膜之后,對掩膜中的白色區域所對應的原圖中的區域進行一個像素值的修改即可。
由于掩膜與原圖的大小相同,并且像素位置一一對應,那么我們就可以得到掩膜中白色(也就是像素值為255)區域的坐標,并將其帶入到原圖像中,即可得到原圖中的紅色區域的坐標,然后就可以修改像素值了,這樣就完成了顏色的替換
在替換過程中,實際上對數組做布爾索引
掩膜部分OpenCV代碼實現:
import cv2 as cv
import numpy as np#讀圖
demo = cv.imread("../../images/demo.png")
demo = cv.resize(demo, (480, 380))
#轉hsv
hsv = cv.cvtColor(demo, cv.COLOR_BGR2HSV)
#創建掩膜(紅色為例)
mask = cv.inRange(hsv, (0,43,46),(10,255,255))
cv.imshow("demo", demo)
cv.imshow("hsv", hsv)
cv.imshow("mask", mask)#顏色提取 與運算
dst = cv.bitwise_and(demo, demo, mask=mask)
cv.imshow("dst", dst)#顏色替換 布爾索引
demo[mask==255]=(177,177,0)
cv.imshow("demo", demo)cv.waitKey(0)
cv.destroyAllWindows()
掩膜
顏色提取,掩膜與原圖進行與運算
顏色替換,在原圖的基礎上,按照掩膜的位置進行顏色的替換
四、ROI切割
ROI(感興趣區域)切割是圖像處理中常用的技術,用于提取圖像中的特定區域進行分析或處理
1. 基礎ROI切割(矩形區域)
(1)方法一:NumPy數組切片
import cv2
import numpy as np# 讀取圖像
img = cv2.imread("image.jpg")# 定義ROI坐標 (x1,y1)為左上角,(x2,y2)為右下角
x1, y1, x2, y2 = 100, 50, 300, 200 # 矩形區域:寬=x2-x1,高=y2-y1# 切割ROI (注意OpenCV是height-first: img[y1:y2, x1:x2])
roi = img[y1:y2, x1:x2]# 顯示結果
cv2.imshow("ROI", roi)
cv2.waitKey(0)
參數說明:
-
y1:y2:垂直方向范圍(行)
-
x1:x2:水平方向范圍(列)
注意事項:
-
OpenCV的圖像數組是(height, width, channels)順序
-
確保坐標不越界(可用img.shape檢查圖像尺寸)
(2)方法二:cv2.rectangle + 掩膜(Mask)
# 創建與原圖同尺寸的黑色掩膜
mask = np.zeros_like(img)# 在掩膜上繪制白色矩形(定義ROI區域)
cv2.rectangle(mask, (x1, y1), (x2, y2), (255,255,255), -1) # -1表示填充# 通過按位與運算提取ROI
roi = cv2.bitwise_and(img, mask)# 顯示結果
cv2.imshow("Masked ROI", roi)
cv2.waitKey(0)
適用場景:
-
需要非矩形ROI時(結合下文多邊形方法)
-
保留ROI外區域為黑色背景
2、 非矩形ROI切割
(1)方法一:多邊形ROI(cv2.fillPoly)
# 定義多邊形頂點(順時針或逆時針順序)
points = np.array([[100,50], [300,50], [350,200], [150,200]]) # 四邊形# 創建掩膜
mask = np.zeros_like(img)
cv2.fillPoly(mask, [points], (255,255,255)) # 填充多邊形# 提取ROI
roi = cv2.bitwise_and(img, mask)# 裁剪多邊形外區域(可選)
rect = cv2.boundingRect(points) # 獲取外接矩形
roi_cropped = roi[rect[1]:rect[1]+rect[3], rect[0]:rect[0]+rect[2]] # y, x
關鍵函數:
-
cv2.fillPoly():填充多邊形區域
-
cv2.boundingRect():獲取多邊形的最小外接矩形
(2)方法二:圓形ROI
# 定義圓心和半徑
center = (200, 150)
radius = 100# 創建圓形掩膜
mask = np.zeros_like(img)
cv2.circle(mask, center, radius, (255,255,255), -1)# 提取ROI
roi = cv2.bitwise_and(img, mask)
五、圖像添加水印
整個圖像添加水印的操作實質是灰度化處理、二值化處理、圖像掩膜、ROI切割結合的實驗操作
OpenCV代碼實現:,每一步都寫了注釋
import cv2 as cv#讀圖
bg = cv.imread("../images/bg.png")
logo = cv.imread("../images/logohq.png")
#對logo圖進行灰度化
gray = cv.cvtColor(logo, cv.COLOR_BGR2GRAY)#生成兩種掩膜
#提取白色Logo,生成黑底白字掩膜。進行反閾值二值化處理,提取出白色的logo
_,mask1 = cv.threshold(gray,170,255,cv.THRESH_BINARY_INV)
cv.imshow("mask1", mask1)
#提取黑色Logo,生成白底黑字掩膜。進行閾值二值化處理,提取出黑色的logo
_,mask2 = cv.threshold(gray,170,255,cv.THRESH_BINARY)
cv.imshow("mask2", mask2)#提取logo圖的尺寸
shape = logo.shape
#從背景里面截取出與logo圖尺寸相同的子區域
roi = bg[:shape[0],:shape[1]]#與運算
#拿logo,只有logo,使用白色logo與logo圖進行與運算,mask1 屏蔽了白色背景,保留原logo顏色,提取出logo圖中的logo標
dst1 = cv.bitwise_and(logo, logo, mask=mask1)
cv.imshow("dst1", dst1)#拿背景,只有背景,使用黑logo與背景圖進行與運算,摳出背景圖中與logo標相同的位置
dst2 = cv.bitwise_and(roi, roi, mask=mask2)
cv.imshow("dst2", dst2)#圖像融合
dst = cv.add(dst1, dst2)
cv.imshow("dst", dst)#將融合后的圖像dst寫回背景圖bg的ROI區域
roi[:] = dst
cv.imshow("bg", bg)cv.waitKey(0)
cv.destroyAllWindows()
六、圖像早點消除
首先介紹一些概念:
噪聲:指圖像中的一些干擾因素,通常是由圖像采集設備、傳輸信道等因素造成的,表現為圖像中隨機的亮度,也可以理解為有那么一些點的像素值與周圍的像素值格格不入。常見的噪聲類型包括高斯噪聲和椒鹽噪聲。高斯噪聲是一種分布符合正態分布的噪聲,會使圖像變得模糊或有噪點。椒鹽噪聲則是一些黑白色的像素值分布在原圖像中。
濾波器:也可以叫做卷積核,與自適應二值化中的核一樣,本身是一個小的區域,有著特定的核值,并且工作原理也是在原圖上進行滑動并計算中心像素點的像素值。濾波器可分為線性濾波和非線性濾波,線性濾波對鄰域中的像素進行線性運算,如在核的范圍內進行加權求和,常見的線性濾波器有均值濾波、高斯濾波等。非線性濾波則是利用原始圖像與模板之間的一種邏輯關系得到結果,常見的非線性濾波器中有中值濾波器、雙邊濾波器等。
濾波與模糊聯系與區別:
- 它們都屬于卷積,不同濾波方法之間只是卷積核不同(對線性濾波而言)
- 低通濾波器是模糊,高通濾波器是銳化
- 低通濾波器就是允許低頻信號通過,在圖像中邊緣和噪點都相當于高頻部分,所以低通濾波器用于去除噪點、平滑和模糊圖像。高通濾波器則反之,用來增強圖像邊緣,進行銳化處理。
**注意:**椒鹽噪聲可以理解為斑點,隨機出現在圖像中的黑點或白點;高斯噪聲可以理解為拍攝圖片時由于光照等原因造成的噪聲。
本實驗中共提供了五種濾波的方式,下面進行一一介紹。
1、均值濾波
原理:用鄰域像素的平均值替換中心像素值
特點:
-
優點:實現簡單,計算速度快
-
缺點:導致圖像模糊,邊緣信息丟失
-
適用場景:高斯噪聲或均勻噪聲
2、方框濾波
原理:
-
均值濾波的推廣形式,可控制是否歸一化:
-
歸一化時等同于均值濾波
-
未歸一化時直接求和
特點:
-
優點:比均值濾波更靈活
-
缺點:非歸一化時可能導致像素值溢出
-
適用場景:需要快速平滑時
3、高斯濾波
原理:根據高斯函數權重計算鄰域像素的加權平均值,中心像素權重最大
特點
-
優點:保留邊緣效果優于均值濾波
-
缺點:計算量較大
適用場景:高斯噪聲,需要保邊平滑
4、中值濾波
原理:取鄰域像素的中值作為中心像素值:
特點
-
優點:有效去除椒鹽噪聲,保留邊緣
-
缺點:計算排序耗時
適用場景:椒鹽噪聲
5. 雙邊濾波
原理:同時考慮空間距離和像素值相似性的加權平均:
特點
-
優點:極好的邊緣保留特性
-
缺點:計算復雜度高
適用場景:需要保邊的去噪,如人像美化
6、各個濾波方法對比
濾波方法 | 原理 | 保留邊緣 | 計算速度 | 適用噪聲類型 | 典型應用場景 |
---|---|---|---|---|---|
均值濾波 | 鄰域平均 | 差 | 快 | 高斯噪聲 | 實時系統預處理 |
方框濾波 | 可調歸一化求和 | 差 | 快 | 均勻噪聲 | 快速平滑 |
高斯濾波 | 高斯加權平均 | 中 | 中 | 高斯噪聲 | 一般圖像去噪 |
中值濾波 | 取鄰域中值 | 好 | 慢 | 椒鹽噪聲 | 醫學圖像處理 |
雙邊濾波 | 空間+值域加權 | 極好 | 極慢 | 所有噪聲 | 人像美化、HDR |
關鍵知識點
-
噪聲類型決定濾波選擇
高斯噪聲:高斯濾波或均值濾波
椒鹽噪聲:中值濾波
混合噪聲:可嘗試雙邊濾波 -
邊緣保留的重要性
需要銳利邊緣的場景(如OCR):優先中值或雙邊濾波
允許適度模糊的場景:可使用高斯濾波 -
計算效率權衡
實時系統:均值/方框濾波
離線處理:可考慮雙邊濾波 -
參數選擇經驗
核大小:通常3×3到9×9,過大導致過度模糊
高斯濾波σ:越大越模糊
雙邊濾波:σ_color和σ_space需平衡
7、OpenCV代碼實現
import cv2 as cv# 讀圖
lvbo2 = cv.imread("../images/lvbo2.png")
lvbo3 = cv.imread("../images/lvbo3.png")
cv.imshow("lvbo2", lvbo2)
cv.imshow("lvbo3", lvbo3)#均值濾波
mean = cv.blur(lvbo2,(7,7))
cv.imshow("mean", mean)#方框濾波 normalize:ture-均值濾波 False鄰域內求和
box = cv.boxFilter(lvbo2,-1,(3,3),normalize=False)
cv.imshow("box", box)#高斯濾波
gauss = cv.GaussianBlur(lvbo2,(3,3),10000)
cv.imshow("gauss", gauss)#中值濾波,適合去除椒鹽噪聲
middle = cv.medianBlur(lvbo3,3)
cv.imshow("middle", middle)#雙邊濾波 使用了兩個高斯核 同時考慮空域和值域
double = cv.bilateralFilter(lvbo2,9,20,20)
cv.imshow("double", double)cv.waitKey(0)
cv.destroyAllWindows()