图像增强-基于滤波的方法
小记一下多种滤波方法的代码实现!
-
局部二值模式(LBP)
1996年由Ojala提出的特征提取方法,具有灰度不变性和旋转不变性,主要用于纹理特征提取。其基本思想是:用中心像素的灰度值作为阈值,与它的邻域相比较得到的二进制码来表述局部纹理特征。
以中心点为基准,在3*3的窗口内,与8个相邻点进行比较,若小于中心点,则该位置被置0,否则被置1,这样可以得到一个8位二进制数,即共256种的LBP码。然后利用这个LBP值来反映该区域的纹理信息,值得注意的是,LBP值是顺时针组成的二进制数。
import cv2 import numpy as np import matplotlib.pyplot as plt import matplotlib.image as mpimg %matplotlib inline #释放窗口 def releaseWin(): cv2.waitKey(0) cv2.destroyAllWindows() key = cv2.waitKey(0) if key==27: print(key) c2v.destroyAllWindows() def origin_LBP(img): dst = np.zeros(img.shape,dtype=img.dtype) h,w=img.shape for i in range(1,h-1): for j in range(1,w-1): center = img[i][j] code = 0 code |= (img[i-1][j-1] >= center) << (np.uint8)(7) code |= (img[i-1][j ] >= center) << (np.uint8)(6) code |= (img[i-1][j+1] >= center) << (np.uint8)(5) code |= (img[i ][j+1] >= center) << (np.uint8)(4) code |= (img[i+1][j+1] >= center) << (np.uint8)(3) code |= (img[i+1][j ] >= center) << (np.uint8)(2) code |= (img[i+1][j-1] >= center) << (np.uint8)(1) code |= (img[i ][j-1] >= center) << (np.uint8)(0) dst[i-1][j-1]= code return dst gray = cv2.imread(r'C:\Users\admin\Desktop\Data\ComputerVision\exp1\testPic\peppers.png', cv2.IMREAD_GRAYSCALE) # cv2.imshow('img', gray) org_lbp = origin_LBP(gray) # cv2.imshow('org_lbp', org_lbp) plt.imshow(gray, cmap='gray') plt.show() plt.imshow(org_lbp, cmap='gray') plt.show() # releaseWin()
-
均值滤波
均值滤波器是包含在滤波器邻域内像素的平均值,其作用是减小图像灰度的“尖锐”变化,减小噪声,但也会存在边缘模糊的问题。
def mean_filter(x, y, step): sum_s = 0 for k in range(-int(step/2),int(step/2)+1): for m in range(-int(step/2),int(step/2)+1): sum_s += img[x+k][y+m] / (step*step) return sum_s img = cv2.imread(r'C:\Users\admin\Desktop\Data\ComputerVision\exp1\testPic\save2.bmp',0) mean_img = img.copy() medStep = 3 for i in range(int(medStep/2),img.shape[0]-int(medStep/2)): for j in range(int(medStep/2),img.shape[1]-int(medStep/2)): mean_img[i][j] = mean_filter(i, j, medStep) plt.imshow(img, cmap='gray') plt.show() plt.imshow(mean_img, cmap='gray') plt.show()
-
非线性滤波
非线性滤波器包括了中值滤波器、最大值滤波器和最小值滤波器,分别是用像素领域内的中间值、最大值、最小值代替像素,作用分别是去除噪声、寻找最亮点、寻找最暗点。
Ø 中值滤波
用像素领域内的中间值代替像素
def m_filter(x, y, step): sum_s=[] for k in range(-int(step/2),int(step/2)+1): for m in range(-int(step/2),int(step/2)+1): sum_s.append(img[x+k][y+m]) sum_s.sort() return sum_s[(int(step*step/2)+1)] img = cv2.imread(r'C:\Users\admin\Desktop\Data\ComputerVision\exp1\testPic\save2.bmp',0) mid_img = img.copy() medStep = 3 for i in range(int(medStep/2),img.shape[0]-int(medStep/2)): for j in range(int(medStep/2),img.shape[1]-int(medStep/2)): mid_img[i][j] = m_filter(i, j, medStep) plt.imshow(img, cmap='gray') plt.show() plt.imshow(mid_img, cmap='gray') plt.show()
Ø 最大值滤波
用像素领域内的最大值代替像素
def max_filter(x, y, step): sum_s=[] for k in range(-int(step/2),int(step/2)+1): for m in range(-int(step/2),int(step/2)+1): sum_s.append(img[x+k][y+m]) return max(sum_s) def min_filter(x, y, step): sum_s=[] for k in range(-int(step/2),int(step/2)+1): for m in range(-int(step/2),int(step/2)+1): sum_s.append(img[x+k][y+m]) return min(sum_s) img = cv2.imread(r'C:\Users\admin\Desktop\Data\ComputerVision\exp1\testPic\save2.bmp',0) mid_img = img.copy() medStep = 3 for i in range(int(medStep/2),img.shape[0]-int(medStep/2)): for j in range(int(medStep/2),img.shape[1]-int(medStep/2)): mid_img[i][j] = max_filter(i, j, medStep) plt.imshow(img, cmap='gray') plt.show() plt.imshow(mid_img, cmap='gray') plt.show()
Ø 最小值滤波
用像素领域内的最小值代替像素
def min_filter(x, y, step): sum_s=[] for k in range(-int(step/2),int(step/2)+1): for m in range(-int(step/2),int(step/2)+1): sum_s.append(img[x+k][y+m]) return min(sum_s) img = cv2.imread(r'C:\Users\admin\Desktop\Data\ComputerVision\exp1\testPic\save2.bmp',0) mid_img = img.copy() medStep = 3 for i in range(int(medStep/2),img.shape[0]-int(medStep/2)): for j in range(int(medStep/2),img.shape[1]-int(medStep/2)): mid_img[i][j] = min_filter(i, j, medStep) plt.imshow(img, cmap='gray') plt.show() plt.imshow(mid_img, cmap='gray') plt.show()
-
高斯滤波
高斯滤波是一种线性平滑滤波器,对于服从正态分布的噪声有很好的抑制效果,通常我们都会假定白噪声为高斯噪声,实际应用中常用高斯滤波来抑制噪声。
例如标准差为1.3的3*3大小的整数形式的高斯滤波器,不难发现,最重要的参数是高斯分布的标准差σ,当σ越小,生成的算子中心系数较大,平滑的效果不会很明显;当σ越大,生成的算子各个系数相差较小,平滑效果会更加明显。
def gaussian_filter(img, K_size=3, sigma=1.3): if len(img.shape) == 3: H, W, C = img.shape else: img = np.expand_dims(img, axis=-1) H, W, C = img.shape ## Zero padding pad = K_size // 2 out = np.zeros((H + pad * 2, W + pad * 2, C), dtype=np.float) out[pad: pad + H, pad: pad + W] = img.copy().astype(np.float) ## prepare Kernel K = np.zeros((K_size, K_size), dtype=np.float) for x in range(-pad, -pad + K_size): for y in range(-pad, -pad + K_size): K[y + pad, x + pad] = np.exp( -(x ** 2 + y ** 2) / (2 * (sigma ** 2))) K /= (2 * np.pi * sigma * sigma) K /= K.sum() tmp = out.copy() # filtering for y in range(H): for x in range(W): for c in range(C): out[pad + y, pad + x, c] = np.sum(K * tmp[y: y + K_size, x: x + K_size, c]) out = np.clip(out, 0, 255) out = out[pad: pad + H, pad: pad + W].astype(np.uint8) return out img = cv2.imread(r'C:\Users\admin\Desktop\Data\ComputerVision\exp1\testPic\rice_gaussian_0_0.01.bmp',0) res_img = gaussian_filter(img, K_size=3, sigma=0.6) res_img2 = gaussian_filter(img, K_size=3, sigma=1.3) plt.imshow(img, cmap='gray') plt.show() plt.imshow(res_img, cmap='gray') plt.show() plt.imshow(res_img2, cmap='gray') plt.show()
-
图像锐化
与前几个滤波作用(平滑)相反的是,我们可以对图像进行锐化操作,突出图像的边缘。具体实现方法包括了一阶导数和二阶导数,分别利用Sobel算子和Laplacian算子进行滤波。
Ø Sobel算子
Sobel算子包括横向和纵向两种算子如下所示,分别提取竖直边缘和水平边缘。
def SobelOperator(roi, operator_type): if operator_type == "horizontal": sobel_operator = np.array([[-1, -2, -1], [0, 0, 0], [1, 2, 1]]) #横向模板 elif operator_type == "vertical": sobel_operator = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]]) #纵向模板 else: raise ("type Error") result = np.abs(np.sum(roi * sobel_operator)) return result def SobelAlogrithm(image): new_image1 = np.zeros(image.shape) new_image2 = np.zeros(image.shape) for i in range(1, image.shape[0] - 1): for j in range(1, image.shape[1] - 1): new_image1[i - 1, j - 1] = SobelOperator(image[i - 1:i + 2, j - 1:j + 2], 'horizontal') new_image2[i - 1, j - 1] = SobelOperator(image[i - 1:i + 2, j - 1:j + 2], 'vertical') new_image1 = np.sqrt(new_image1*new_image1+new_image2*new_image2) new_image1 = 255 - new_image1*(255 / np.max(new_image1)) return new_image1.astype(np.uint8) img = cv2.imread(r'C:\Users\admin\Desktop\Data\ComputerVision\exp1\testPic\mytable.jpg',0) img = cv2.resize(img,(img.shape[1]//5,img.shape[0]//5)) plt.imshow(img, cmap='gray') plt.show() plt.imshow(SobelAlogrithm(img), cmap='gray') plt.show() plt.imshow(SobelAlogrithm(img), cmap='binary')
Ø Laplacian算子
Laplacian算子的操作过程域Sobel算子基本一致,它具有4邻域算子和8邻域算子。
def LaplaceOperator(roi, operator_type): if operator_type == "fourfields": laplace_operator = np.array([[0, 1, 0], [1, -4, 1], [0, 1, 0]]) elif operator_type == "eightfields": laplace_operator = np.array([[1, 1, 1], [1, -8, 1], [1, 1, 1]]) else: raise ("type Error") result = np.abs(np.sum(roi * laplace_operator)) return result def LaplaceAlogrithm(image, operator_type): new_image = np.zeros(image.shape) image = cv2.copyMakeBorder(image, 1, 1, 1, 1, cv2.BORDER_DEFAULT) for i in range(1, image.shape[0] - 1): for j in range(1, image.shape[1] - 1): new_image[i - 1, j - 1] = LaplaceOperator(image[i - 1:i + 2, j - 1:j + 2], operator_type) new_image = 255-new_image * (255 / np.max(image)) return new_image.astype(np.uint8) img = cv2.imread(r'C:\Users\admin\Desktop\Data\ComputerVision\exp1\testPic\mytable.jpg',0) img = cv2.resize(img,(img.shape[1]//5,img.shape[0]//5)) plt.imshow(img, cmap='gray') plt.show() plt.imshow(LaplaceAlogrithm(img,'fourfields'), cmap='gray') plt.show() plt.imshow(LaplaceAlogrithm(img,'fourfields'), cmap='binary')
-
Gabor滤波
Gabor滤波也是用来提取图像边缘的方法.
import cv2 import numpy as np import matplotlib.pyplot as plt # Grayscale def BGR2GRAY(img): # Grayscale gray = 0.2126 * img[..., 2] + 0.7152 * img[..., 1] + 0.0722 * img[..., 0] return gray # Gabor Filter def Gabor_filter(K_size=111, Sigma=10, Gamma=1.2, Lambda=10, Psi=0, angle=0): # get half size d = K_size // 2 # prepare kernel gabor = np.zeros((K_size, K_size), dtype=np.float32) # each value for y in range(K_size): for x in range(K_size): # distance from center px = x - d py = y - d # degree -> radian theta = angle / 180. * np.pi # get kernel x _x = np.cos(theta) * px + np.sin(theta) * py # get kernel y _y = -np.sin(theta) * px + np.cos(theta) * py # fill kernel gabor[y, x] = np.exp(-(_x**2 + Gamma**2 * _y**2) / (2 * Sigma**2)) * np.cos(2*np.pi*_x/Lambda + Psi) # kernel normalization gabor /= np.sum(np.abs(gabor)) return gabor # 使用Gabor滤波器作用于图像上 def Gabor_filtering(gray, K_size=111, Sigma=10, Gamma=1.2, Lambda=10, Psi=0, angle=0): # get shape H, W = gray.shape # padding gray = np.pad(gray, (K_size//2, K_size//2), 'edge') # prepare out image out = np.zeros((H, W), dtype=np.float32) # get gabor filter gabor = Gabor_filter(K_size=K_size, Sigma=Sigma, Gamma=Gamma, Lambda=Lambda, Psi=0, angle=angle) # filtering for y in range(H): for x in range(W): out[y, x] = np.sum(gray[y : y + K_size, x : x + K_size] * gabor) out = np.clip(out, 0, 255) out = out.astype(np.uint8) return out # 使用6个不同角度的Gabor滤波器对图像进行特征提取 def Gabor_process(img): # get shape H, W = img.shape # gray scale # gray = BGR2GRAY(img).astype(np.float32) # define angle #As = [0, 45, 90, 135] As = [0,30,60,90,120,150] # prepare pyplot plt.subplots_adjust(left=0, right=1, top=1, bottom=0, hspace=0, wspace=0.2) out = np.zeros([H, W], dtype=np.float32) # each angle for i, A in enumerate(As): # gabor filtering _out = Gabor_filtering(img, K_size=11, Sigma=1.5, Gamma=1.2, Lambda=3, angle=A) # add gabor filtered image out += _out # scale normalization out = out / out.max() * 255 out = out.astype(np.uint8) return out # Read image img = cv2.imread(r'C:\Users\admin\Desktop\Data\ComputerVision\exp1\testPic\mytable.jpg',0) img = cv2.resize(img,(img.shape[1]//5,img.shape[0]//5)).astype(np.float32) # img = cv2.imread(r'C:\Users\admin\Desktop\Data\ComputerVision\exp1\testPic\mytable.jpg').astype(np.float32) # gabor process out = Gabor_process(img) plt.imshow(img, cmap='gray') plt.show() plt.imshow(out, cmap='gray') plt.show() plt.imshow(out, cmap='binary')