均值滤波
均值滤波是指先选按某种规律选中图像的像素点(从左到右,从上到下),对选中的像素点进行一个范围区域的选取,按选中的像素个数进行平均。
按上图方式,第一个点的新像素值就应该是原始像素与周围八个像素和的平均,计算完后,移入下一个像素进行计算,直到遍历完整的图像,就可以得到框为3的均值滤波图像。如果是三通道的RGB图,记得要对每一层进行滤波操作。
该操作可以呗总结为一个3x3大小,每个元素值为1/9的卷积核与图像进行卷积操作,根据该思想可以对算法进行加速处理。
从上面的操作可以看出,当框处于图像边界时,外部是没有像素的,这里我们一般处理是填0,或者是镜像填充或者是边缘复制,这两种处理会对滤波图像的边缘产生影响。
处理结果如下所示:
import cv2
import numpy as np
# 对图像边界进行0填充
def set_border_zero(image_data, ksize):
h_, w_, c_ = image_data.shape
border = int((ksize - 1) / 2)
result_data = np.zeros((h_ + ksize - 1, w_ + ksize - 1, c_))
result_data[border:border+h_, border:border+w_, :] = image_data
return result_data.astype("uint8")
# 对图像进行边缘镜像处理
def set_border_sym(image_data, ksize):
h_, w_, c_ = image_data.shape
border = int((ksize - 1) / 2)
result_data = np.zeros((h_ + ksize - 1, w_ + ksize - 1, c_))
for c in range(c_):
for i in range(h_ + 2 * border):
if i < border:
y_ori = border - i
elif i > h_ + border - 1:
y_ori = (h_ + border - 1) - (i - (border + h_ - 1)) - border
else:
y_ori = i - border
for j in range(w_ + 2 * border):
if j < border:
x_ori = border - j
elif j > w_ + border - 1:
x_ori = (w_ + border - 1) - (j - (border + w_ - 1)) - border
else:
x_ori = j - border
result_data[i, j, c] = image_data[y_ori, x_ori, c]
return result_data.astype("uint8")
def mean_filtering(image_pad_data, ksize):
h_, w_, c_ = image_pad_data.shape
result_data = np.zeros_like(image_pad_data)
# 定义卷积核大小
k_ = np.ones((ksize, ksize)) / (ksize * ksize)
border = int((ksize - 1) / 2)
# 对图像分图层进行处理
for c in range(c_):
# 输入的是填充后的图像,但索引要从原图像素处开始
for y in range(border, h_ - border):
for x in range(border, w_ - border):
# 获得(x, y)处的像素参考框,然后与k逐像素相乘并求和
reference_matrix = image_pad_data[y-border:y+border + 1, x-border:x+border+1, c]
sum_ref = 0
for i in range(ksize):
for j in range(ksize):
sum_ref += reference_matrix[i, j] * k_[i, j]
result_data[y, x, c] = sum_ref
return result_data[border:h_ - border, border:w_ - border, :].astype("uint8")
if __name__ == "__main__":
ori_image = cv2.imread("../../data/image/lena.png")
# cv2自带的均值滤波 cv2.blur(原始图像,核大小)
cv2_result = cv2.blur(ori_image, (5, 5))
# 手写均值滤波, 这里ksize一般为奇数,便于边缘填充,当ksize = 1 时,算发不起作用
# zero_border_image = set_border_zero(ori_image, 5)
sym_border_image = set_border_sym(ori_image, 5)
result_data_mean = mean_filtering(sym_border_image, 5)
cv2.imshow("ori_image", ori_image)
# cv2.imshow("zero_border_image", zero_border_image)
cv2.imshow("sym_border_image", sym_border_image)
cv2.imshow("cv2_result", cv2_result)
cv2.imshow("result_data_mean", result_data_mean)
cv2.waitKey(0)
中值滤波
按下图方式,第一个点的新像素值就应该是原始像素与周围八个像素排序,去中位数作为新像素点,移入下一个像素进行计算,直到遍历完整的图像,
import cv2
import numpy as np
# 对图像边界进行0填充
def set_border_zero(image_data, ksize):
h_, w_, c_ = image_data.shape
border = int((ksize - 1) / 2)
result_data = np.zeros((h_ + ksize - 1, w_ + ksize - 1, c_))
result_data[border:border+h_, border:border+w_, :] = image_data
return result_data.astype("uint8")
# 对图像进行边缘镜像处理
def set_border_sym(image_data, ksize):
h_, w_, c_ = image_data.shape
border = int((ksize - 1) / 2)
result_data = np.zeros((h_ + ksize - 1, w_ + ksize - 1, c_))
for c in range(c_):
for i in range(h_ + 2 * border):
if i < border:
y_ori = border - i
elif i > h_ + border - 1:
y_ori = (h_ + border - 1) - (i - (border + h_ - 1)) - border
else:
y_ori = i - border
for j in range(w_ + 2 * border):
if j < border:
x_ori = border - j
elif j > w_ + border - 1:
x_ori = (w_ + border - 1) - (j - (border + w_ - 1)) - border
else:
x_ori = j - border
result_data[i, j, c] = image_data[y_ori, x_ori, c]
return result_data.astype("uint8")
def median_filtering(image_pad_data, ksize):
h_, w_, c_ = image_pad_data.shape
result_data = np.zeros_like(image_pad_data)
# 定义卷积核大小
border = int((ksize - 1) / 2)
# 对图像分图层进行处理
for c in range(c_):
# 输入的是填充后的图像,但索引要从原图像素处开始
for y in range(border, h_ - border):
for x in range(border, w_ - border):
# 获得(x, y)处的像素参考框,然后排序取中值
reference_matrix = image_pad_data[y-border:y+border + 1, x-border:x+border+1, c]
# 转为1维矩阵
reference_matrix = reference_matrix.reshape(-1)
# 排序
reference_matrix = np.sort(reference_matrix)
result_data[y, x, c] = reference_matrix[border]
return result_data[border:h_ - border, border:w_ - border, :].astype("uint8")
if __name__ == "__main__":
ori_image = cv2.imread("../../data/image/lena.png")
# cv2自带的均值滤波 cv2.blur(原始图像,核大小)
cv2_result = cv2.medianBlur(ori_image, 5)
# 手写均值滤波, 这里ksize一般为奇数,便于边缘填充,当ksize = 1 时,算发不起作用
# zero_border_image = set_border_zero(ori_image, 5)
sym_border_image = set_border_sym(ori_image, 5)
result_data_median = median_filtering(sym_border_image, 5)
cv2.imshow("ori_image", ori_image)
# cv2.imshow("zero_border_image", zero_border_image)
cv2.imshow("sym_border_image", sym_border_image)
cv2.imshow("cv2_result", cv2_result)
cv2.imshow("result_data_median", result_data_median)
cv2.waitKey(0)
此处按中值滤波原理写的结果,与cv2的结果有明显区别,后续有时间需要查看源码作详细对比。