快速中值滤波——Python实现

原理

中值滤波是空域中常用的一种滤波方式,是一种非线性的滤波。它的原理就是将窗口像素排序,取中值,然后移动窗口,不断重复取中值的过程

但是,可以发现,每次移动窗口,都需要对像素点进行排序,从而选取中间的那个像素点。每次重新排序的效率特别低,为了优化这个排序,便有了快速中值滤波。

快速中值滤波是中值滤波的优化版,它利用了窗口每次平移时,没有移出窗口的像素点还是排好序的,因此,只需要把新加入的像素点插入到其中即可完成排序。此外,由于我们并不需要一个完整的排序数列, 只需要找到中值就可以了。

基于上面两点,快速中值滤波采用的是直方图的方式来统计像素点,横坐标是像素点的值,纵坐标是窗口中像素点的个数。设置一个“光标”,在横轴上左右移动,当两边像素点相等时,对应的像素点就是要找的中值。然后移动窗口,更新直方图,再次移动“光标”,找到中值,不断反复。

需要注意的是,“光标”的每次移动,都只能移动在数目不为 0 的像素点上,否则,取到的中值很可能不在这个窗口中。

步骤

  • 第一步:
    设置门限th = N*M/2。门限是用来判断像素点是否是中值的,它是窗口大小的一半,如果不知道有啥用,看第五步的用法。

  • 第二步:
    将窗口移动到一个新行的开始,建立窗口像素的直方图,通过直方图确定中值 med,记下亮度小于或等于 med 的像素数目到变量 n 中。

  • 第三步:
    对于最左列的每个像素,去掉每一个元素,并将直方图中的相应的数值更新,然后更新n的值。

  • 第四步:
    同理,与第三步一样,对于最右列的每个像素,增加每一个元素的值,并将直方图中的相应的数值进行更新。

  • 第五步:
    然后判断n的值与门限 th 的大小。如果 n > th,则将 med 进行递减操作;如果n < th 则将 med 进行递增操作。直到 n 超过 th 为止。得到的 med 就是需要的中值。

代码

R、G、B 三个通道分别计算(可以一起计算,但单通道计算更清晰)

窗口大小为 3*3 的代码:

# -*- coding: UTF-8 -*-
import numpy as np
import cv2

def quickMedianFiltering(img) :
    B, G, R = cv2.split(img)
    # 对 蓝色通道 进行中值滤波
    H = np.zeros(256, dtype=int)    # 直方图
    for row in range(1, len(B) - 1) :
        # 到达一个新的行 初始化
        H = np.zeros(256, dtype=int)    # 直方图
        # 求中值
        med = np.uint8(np.median(B[row - 1 : row + 2, 0:3]))
        n = 0
        for i in range(-1, 2) :
            for j in range(0, 3) :
                H[B[row+i][j]] = H[B[row+i][j]] + 1
                if B[row+i][j] <= med :
                    n = n + 1
        for col in range(1, len(B[row]) - 1) :
            if col == 1 :
                None
            # 移到下一列
            else :
                # 更新直方图 并计算 n 的值
                for i in range(-1, 2) :
                    # 对左列元素 值减一 
                    H[B[row+i][col-2]] = H[B[row+i][col-2]] - 1
                    if B[row+i][col-2] <= med :
                        n = n - 1
                    # 对右列元素 值加一
                    H[B[row+i][col+1]] = H[B[row+i][col+1]] + 1
                    if B[row+i][col+1] <= med :
                        n = n + 1
                # 重新计算中值
                if n > 5 :
                    while n > 5 :
                        if med == 0 :
                            break
                        n = n - H[med]
                        med = med - 1
                elif n < 5 :
                    while n < 5 :
                        med = med + 1
                        n = n + H[med]
            sum = 0
            for k in range(med + 1) :
                sum = sum + H[k]
            # 更新中值后的直方图
            H[B[row][col]] = H[B[row][col]] - 1
            if med < B[row][col] :
                n = n + 1
            B[row][col] = med
            H[med] = H[med] + 1
    # 对 绿色通道 进行中值滤波
    H = np.zeros(256, dtype=int)    # 直方图
    for row in range(1, len(G) - 1) :
        # 到达一个新的行 初始化
        H = np.zeros(256, dtype=int)    # 直方图
        # 求中值
        med = np.uint8(np.median(G[row - 1 : row + 2, 0:3]))
        if med == -128 :
            print(G[row - 1 : row + 2, 0:3])
        n = 0
        for i in range(-1, 2) :
            for j in range(0, 3) :
                H[G[row+i][j]] = H[G[row+i][j]] + 1
                if G[row+i][j] <= med :
                    n = n + 1
        for col in range(1, len(G[row]) - 1) :
            if col == 1 :
                None
            # 移到下一列
            else :
                # 更新直方图 并计算 n 的值
                for i in range(-1, 2) :
                    # 对左列元素 值减一 
                    H[G[row+i][col-2]] = H[G[row+i][col-2]] - 1
                    if G[row+i][col-2] <= med :
                        n = n - 1
                    # 对右列元素 值加一
                    H[G[row+i][col+1]] = H[G[row+i][col+1]] + 1
                    if G[row+i][col+1] <= med :
                        n = n + 1
                # 重新计算中值
                if n > 5 :
                    while n > 5 :
                        if med == 0 :
                            break
                        n = n - H[med]
                        med = med - 1
                elif n < 5 :
                    while n < 5 :
                        med = med + 1
                        n = n + H[med]
            # 更新中值后的直方图
            H[G[row][col]] = H[G[row][col]] - 1
            if med < G[row][col] :
                n = n + 1
            G[row][col] = med
            H[med] = H[med] + 1
    # 对 红色通道 进行中值滤波
    H = np.zeros(256, dtype=int)    # 直方图
    for row in range(1, len(R) - 1) :
        # 到达一个新的行 初始化
        H = np.zeros(256, dtype=int)    # 直方图
        # 求中值
        med = np.uint8(np.median(R[row - 1 : row + 2, 0:3]))
        if med == -128 :
            print(R[row - 1 : row + 2, 0:3])
        n = 0
        for i in range(-1, 2) :
            for j in range(0, 3) :
                H[R[row+i][j]] = H[R[row+i][j]] + 1
                if R[row+i][j] <= med :
                    n = n + 1
        for col in range(1, len(R[row]) - 1) :
            if col == 1 :
                None
            # 移到下一列
            else :
                # 更新直方图 并计算 n 的值
                for i in range(-1, 2) :
                    # 对左列元素 值减一 
                    H[R[row+i][col-2]] = H[R[row+i][col-2]] - 1
                    if R[row+i][col-2] <= med :
                        n = n - 1
                    # 对右列元素 值加一
                    H[R[row+i][col+1]] = H[R[row+i][col+1]] + 1
                    if R[row+i][col+1] <= med :
                        n = n + 1
                # 重新计算中值
                if n > 5 :
                    while n > 5 :
                        if med == 0 :
                            break
                        n = n - H[med]
                        med = med - 1
                elif n < 5 :
                    while n < 5 :
                        med = med + 1
                        n = n + H[med]
            sum = 0
            # 更新中值后的直方图
            H[R[row][col]] = H[R[row][col]] - 1
            if med < R[row][col] :
                n = n + 1
            R[row][col] = med
            H[med] = H[med] + 1
    
    return cv2.merge([B,G,R])

最后

快速中值滤波主要是利用了直方图的思想,虽然思路很简单,但写代码的时候,也遇到不少bug,所幸最后写完了。

如果有任何错误的地方,请联系我改正,非常感谢。

  • 9
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值