手写中值滤波与OpenCV的中值滤波对比效果

本文通过对比手写中值滤波和OpenCV库实现的中值滤波,展示了两者在图像去噪方面的相似效果。尽管手写实现与OpenCV在视觉效果上接近,但在效率上存在显著差距。文章提供了代码示例,解释了中值滤波的工作原理,并强调其在消除椒盐噪声上的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

《OpenCV系列教程》
《深度学习-如何提高数据集质量》

项目位置:OpenCV-Sample
代码位置:37-MedianBlur.py

先看一下效果吧,如图显示:
第一列:原图 第二列:自己手写的中值滤波 第三列 OpenCV的中值滤波.

原图手写openCV

在这里插入图片描述
在这里插入图片描述
肉眼参看非常的接近.但效率上仍然无法与OpenCV匹敌.一个天上一个地下.以学习的目的进行手写.
原理比较简单,对消除椒盐噪点效果是非常的好.上面的图就是一个充满了椒盐噪点的图片.

传入原始图像

如果图片是一个4x4的矩阵,kernel是一个3x3的矩阵,kernel会在图片上进行滑动.

假设这个就是原始图形
[[6 4 8 1]
 [2 5 4 5]
 [2 3 7 6]
 [8 6 6 6]]

进行Padding处理

因为kernel是3x3的,所以要进行padding处理 padding = kernel//2
处理完的图像是:

[[0 0 0 0 0 0]
 [0 6 4 8 1 0]
 [0 2 5 4 5 0]
 [0 2 3 7 6 0]
 [0 8 6 6 6 0]
 [0 0 0 0 0 0]]

Kernel在图像时滑动取值

然后就是kernel在图片上滑动了,第一次平移取到的数值.

            [[0 0 0]               [[0 0 0]               [[0 0 0]             [[0 0 0]
 第一个取到的->[0 6 4] 第二个取到的->   [6 4 8]   第三个取到的->  [4 8 1] 第四个取到的-> [8 1 0]
             [0 2 5]]               [2 5 4]]                [5 4 5]]             [4 5 0]]
             中值为4

将取到数值进行展开

第一个为[0 0 0 0 6 4 0 2 5 ], 第二为[ 0 0 0 6 4 8 2 5 4 ], 第三个为[0 0 0 4 8 1 5 4 5], 第四个为0 0 0 8 1 0 4 5 0]

对数值进行排序呢

第一个为[0 0 0 0 0 2 4 5 6 ], 第二为[0 0 0 2 4 4 5 6 8 ], 第三个为[0 0 0 1 4 4 5 5 8], 第四个为[0 0 0 0 0 1 4 5 8]

取中值

我都是去矩阵中的最中间的那个,也有取数值最接近平均数的那个.

取出的中值分别为第一个是0, 第二个是4 ,第三个是4, 第四个是0.

通过这些中值合成新的图片,详细代码如下:

import cv2
import numpy as np


def medianBlur(img, kernel, padding_way='ZERO', Multithreading=False):
    # 检测传入的kernel是否为一个合法数组.
    if kernel % 2 == 0 or kernel is 1:
        print('kernel size need 3, 5, 7, 9....')
        return None

    # 通过kernel的大小来计算paddingSize的大小
    paddingSize = kernel // 2

    # 获取图片的通道数
    layerSize = len(img.shape)

    # 获取传入的图片的大小
    height, width = img.shape[:2]

    # 假设输入,如下矩阵,5x5
    # [[2 6 3 4 7]
    #  [6 1 7 1 5]
    #  [4 6 7 3 3]
    #  [3 1 8 8 6]
    #  [2 4 8 0 7]]

    # 这里是对多通道的处理
    if layerSize == 3:  # 多通道的处理方式,就是反复的调用单通道.
        matMutbase = np.zeros_like(img)
        for l in range(matMutbase.shape[2]):
            matMutbase[:, :, l] = medianBlur(img[:, :, l], kernel, padding_way)
        return matMutbase
    elif layerSize == 2:  # 单通道是中值滤波的实际工作的位置.
        # 实现方式和np.lib.pad相同
        # matBase = np.lib.pad(img,paddingSize, mode='constant', constant_values=0)
        matBase = np.zeros((height + paddingSize * 2, width + paddingSize * 2), dtype=img.dtype)

        # 创建一个添加了padding的矩阵,初始值为0
        # 如果kernel的大小为3,所以从5x5变成了7x7
        # [[0 0 0 0 0 0 0]
        #  [0 0 0 0 0 0 0]
        #  [0 0 0 0 0 0 0]
        #  [0 0 0 0 0 0 0]
        #  [0 0 0 0 0 0 0]
        #  [0 0 0 0 0 0 0]
        #  [0 0 0 0 0 0 0]]

        matBase[paddingSize:-paddingSize, paddingSize:-paddingSize] = img
        # 将原值写入新创建的矩阵当中
        # [[0 0 0 0 0 0 0]
        # [0 2 6 3 4 7 0]
        # [0 6 1 7 1 5 0]
        # [0 4 6 7 3 3 0]
        # [0 3 1 8 8 6 0]
        # [0 2 4 8 0 7 0]
        # [0 0 0 0 0 0 0]]
        # print(matBase)
        if padding_way is 'ZERO':
            pass
        elif padding_way is 'REPLICA':
            for r in range(paddingSize):
                matBase[r, paddingSize:-paddingSize] = img[0, :]
                matBase[-(1 + r), paddingSize:-paddingSize] = img[-1, :]
                matBase[paddingSize:-paddingSize, r] = img[:, 0]
                matBase[paddingSize:-paddingSize, -(1 + r)] = img[:, -1]
                # 通过REPLICA后的矩阵,讲四个边补齐
                # [[0 2 6 3 4 7 0]
                # [2 2 6 3 4 7 7]
                # [6 6 1 7 1 5 5]
                # [4 4 6 7 3 3 3]
                # [3 3 1 8 8 6 6]
                # [2 2 4 8 0 7 7]
                # [0 2 4 8 0 7 0]]
                # 实现方式和np.lib.pad相同
                # matBase = (img, padding, mode='edge')
            # print(matBase)
        else:
            print('padding_way error need ZERO or REPLICA')
            return None

        # 创建用于输出的矩阵
        matOut = np.zeros((height, width), dtype=img.dtype)
        # 这里是遍历矩阵的每个点
        for x in range(height):
            for y in range(width):
                # 获取kernel X kernel 的内容,并转化成队并列
                line = matBase[x:x + kernel, y:y + kernel].flatten()
                # 队列排序处理.
                line = np.sort(line)
                # 取中间值赋值
                matOut[x, y] = line[(kernel * kernel) // 2]
        return matOut
    else:
        print('image layers error')
        return None


def main():
    # 读取原始图片
    img = cv2.imread("res/jyan.jpeg")
    # print(img)

    # 使用自己手写的medianBlur进行中值滤波啊
    myself = medianBlur(img, 5, padding_way='REPLICA')
    if myself is None:
        return

    # 调用OpenCV的接口进行中值滤波
    opencv = cv2.medianBlur(img, 3)

    # 这里进行图片合并
    img = np.hstack((img, myself))
    img = np.hstack((img, opencv))

    # 显示对比效果
    cv2.imshow('ORG + myself + OpenCV', img)

    cv2.waitKey()
    cv2.destroyAllWindows()


if __name__ == '__main__':
    main()

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值