边缘检测系列1:传统边缘检测算子

P粉084495128
发布: 2025-07-18 10:32:14
原创
1009人浏览过
本文介绍了图像边缘检测的原理,指出边缘是灰度剧变处,检测基于方向导数掩码卷积。实现了通用边缘检测算子EdgeOP,集成Roberts、Prewitt等多种算子,提供四种边缘强度计算方式,并通过测试函数对比效果,展示了不同算子和计算方法的检测结果。

☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜

边缘检测系列1:传统边缘检测算子 - php中文网

引入

  • 图像的边缘指的是灰度值发生急剧变化的位置。

  • 在图像形成过程中,由于亮度、纹理、颜色、阴影等物理因素的不同而导致图像灰度值发生突变,从而形成边缘。

  • 边缘是通过检查每个像素的邻域并对其灰度变化进行量化的,这种灰度变化的量化相当于微积分里连续函数中方向导数或者离散数列的差分。

算法原理

  • 传统的边缘检测大多数是通过基于方向导数掩码(梯度方向导数)求卷积的方法。

  • 计算灰度变化的卷积算子包含Roberts算子、Prewitt算子、Sobel算子、Scharr算子、Kirsch算子、Robinson算子、Laplacian算子。

  • 大多数边缘检测算子是基于方向差分卷积核求卷积的方法,在使用由两个或者多个卷积核组成的边缘检测算子时假设有 n 个卷积核,记 Conv1,Conv2,...,ConvnConv1,Conv2,...,Convn,为图像分别与个卷积核做卷积的结果,通常有四种方式来衡量最后输出的边缘强度。

    1. 取对应位置绝对值的和:i=1nconvi∑i=1n∣convi∣

    2. 取对应位置平方和的开方:i=1nconvi2∑i=1nconvi2

    3. 取对应位置绝对值的最大值:max{conv1,conv2,...,convi}max{∣conv1∣,∣conv2∣,...,∣convi∣}

    4. 插值法:i=1naiconvi∑i=1nai∣convi∣,其中 ai>=0ai>=0,且 i=1nai=1∑i=1nai=1

      AGI-Eval评测社区
      AGI-Eval评测社区

      AI大模型评测社区

      AGI-Eval评测社区 63
      查看详情 AGI-Eval评测社区

代码实现

构建通用的边缘检测算子

  • 因为上述的这些算子在本质上都是通过卷积计算实现的,只是所使用到的卷积核参数有所不同
  • 所以可以构建一个通用的计算算子,只需要传入对应的卷积核参数即可实现不同的边缘检测
  • 并且在后处理时集成了上述的四种计算最终边缘强度的方式
In [1]
import numpy as npimport paddleimport paddle.nn as nnclass EdgeOP(nn.Layer):
    def __init__(self, kernel):
        '''
        kernel: shape(out_channels, in_channels, h, w)
        '''
        super(EdgeOP, self).__init__()
        out_channels, in_channels, h, w = kernel.shape
        self.filter = nn.Conv2D(in_channels=in_channels, out_channels=out_channels, kernel_size=(h, w), padding='SAME', bias_attr=False)
        self.filter.weight.set_value(kernel.astype('float32'))    
    @staticmethod
    def postprocess(outputs, mode=0, weight=None):
        '''
        Input: NCHW
        Output: NHW(mode==1-3) or NCHW(mode==4)

        Params:
            mode: switch output mode(0-4)
            weight: weight when mode==3
        '''
        if mode==0:
            results = paddle.sum(paddle.abs(outputs), axis=1)        elif mode==1:
            results = paddle.sqrt(paddle.sum(paddle.pow(outputs, 2), axis=1))        elif mode==2:
            results = paddle.max(paddle.abs(outputs), axis=1)        elif mode==3:            if weight is None:
                C = outputs.shape[1]
                weight = paddle.to_tensor([1/C] * C, dtype='float32')            else:
                weight = paddle.to_tensor(weight, dtype='float32')
            results = paddle.einsum('nchw, c -> nhw', paddle.abs(outputs), weight)        elif mode==4:
            results = paddle.abs(outputs)        return paddle.clip(results, 0, 255).cast('uint8')    
    @paddle.no_grad()
    def forward(self, images, mode=0, weight=None):
        outputs = self.filter(images)        return self.postprocess(outputs, mode, weight)
登录后复制

图像边缘检测测试函数

  • 为了方便测试就构建了如下的测试函数,测试同一张图片不同算子/不同边缘强度计算方法的边缘检测效果
In [2]
import osimport cv2from PIL import Imagedef test_edge_det(kernel, img_path='test.jpg'):
    img = cv2.imread(img_path, 0)
    img_tensor = paddle.to_tensor(img, dtype='float32')[None, None, ...]
    op = EdgeOP(kernel)
    all_results = []    for mode in range(4):
        results = op(img_tensor, mode=mode)
        all_results.append(results.numpy()[0])
    
    results = op(img_tensor, mode=4)    for result in results.numpy()[0]:
        all_results.append(result)    return all_results, np.concatenate(all_results, 1)
登录后复制

Roberts 算子

边缘检测系列1:传统边缘检测算子 - php中文网

In [3]
roberts_kernel = np.array([
    [[
        [1,  0],
        [0, -1]
    ]],
    [[
        [0, -1],
        [1,  0]
    ]]
])

_, concat_res = test_edge_det(roberts_kernel)
Image.fromarray(concat_res)
登录后复制
<PIL.Image.Image image mode=L size=3600x600 at 0x7F2548799F10>
登录后复制

Prewitt 算子

边缘检测系列1:传统边缘检测算子 - php中文网

In [4]
prewitt_kernel = np.array([
    [[
        [-1, -1, -1],
        [ 0,  0,  0],
        [ 1,  1,  1]
    ]],
    [[
        [-1,  0,  1],
        [-1,  0,  1],
        [-1,  0,  1]
    ]],
    [[
        [ 0,  1,  1],
        [-1,  0,  1],
        [-1, -1,  0]
    ]],
    [[
        [ -1, -1,  0],
        [ -1,  0,  1],
        [  0,  1,  1]
    ]]
])

_, concat_res = test_edge_det(prewitt_kernel)
Image.fromarray(concat_res)
登录后复制
<PIL.Image.Image image mode=L size=4800x600 at 0x7F251781EF10>
登录后复制

Sobel 算子

边缘检测系列1:传统边缘检测算子 - php中文网

In [5]
sobel_kernel = np.array([
    [[
        [-1, -2, -1],
        [ 0,  0,  0],
        [ 1,  2,  1]
    ]],
    [[
        [-1,  0,  1],
        [-2,  0,  2],
        [-1,  0,  1]
    ]],
    [[
        [ 0,  1,  2],
        [-1,  0,  1],
        [-2, -1,  0]
    ]],
    [[
        [ -2, -1,  0],
        [ -1,  0,  1],
        [  0,  1,  2]
    ]]
])

_, concat_res = test_edge_det(sobel_kernel)
Image.fromarray(concat_res)
登录后复制
<PIL.Image.Image image mode=L size=4800x600 at 0x7F251782E8D0>
登录后复制

Scharr 算子

边缘检测系列1:传统边缘检测算子 - php中文网

In [6]
scharr_kernel = np.array([
    [[
        [-3, -10, -3],
        [ 0,   0,  0],
        [ 3,  10,  3]
    ]],
    [[
        [-3,  0,   3],
        [-10, 0,  10],
        [-3,  0,   3]
    ]],
    [[
        [ 0,  3,  10],
        [-3,  0,  3],
        [-10, -3,  0]
    ]],
    [[
        [ -10, -3, 0],
        [ -3,  0, 3],
        [ 0,  3,  10]
    ]]
])

_, concat_res = test_edge_det(scharr_kernel)
Image.fromarray(concat_res)
登录后复制
<PIL.Image.Image image mode=L size=4800x600 at 0x7F251782EE10>
登录后复制

Krisch 算子

边缘检测系列1:传统边缘检测算子 - php中文网

In [7]
Krisch_kernel = np.array([
    [[
        [5, 5, 5],
        [-3,0,-3],
        [-3,-3,-3]
    ]],
    [[
        [-3, 5,5],
        [-3,0,5],
        [-3,-3,-3]
    ]],
    [[
        [-3,-3,5],
        [-3,0,5],
        [-3,-3,5]
    ]],
    [[
        [-3,-3,-3],
        [-3,0,5],
        [-3,5,5]
    ]],
    [[
        [-3, -3, -3],
        [-3,0,-3],
        [5,5,5]
    ]],
    [[
        [-3, -3, -3],
        [5,0,-3],
        [5,5,-3]
    ]],
    [[
        [5, -3, -3],
        [5,0,-3],
        [5,-3,-3]
    ]],
    [[
        [5, 5, -3],
        [5,0,-3],
        [-3,-3,-3]
    ]],
])

_, concat_res = test_edge_det(Krisch_kernel)
Image.fromarray(concat_res)
登录后复制
<PIL.Image.Image image mode=L size=7200x600 at 0x7F24FF09E4D0>
登录后复制

Robinson算子

边缘检测系列1:传统边缘检测算子 - php中文网

In [8]
robinson_kernel = np.array([
    [[
        [1, 2, 1],
        [0, 0, 0],
        [-1, -2, -1]
    ]],
    [[
        [0, 1, 2],
        [-1, 0, 1],
        [-2, -1, 0]
    ]],
    [[
        [-1, 0, 1],
        [-2, 0, 2],
        [-1, 0, 1]
    ]],
    [[
        [-2, -1, 0],
        [-1, 0, 1],
        [0, 1, 2]
    ]],
    [[
        [-1, -2, -1],
        [0, 0, 0],
        [1, 2, 1]
    ]],
    [[
        [0, -1, -2],
        [1, 0, -1],
        [2, 1, 0]
    ]],
    [[
        [1, 0, -1],
        [2, 0, -2],
        [1, 0, -1]
    ]],
    [[
        [2, 1, 0],
        [1, 0, -1],
        [0, -1, -2]
    ]],
])

_, concat_res = test_edge_det(robinson_kernel)
Image.fromarray(concat_res)
登录后复制
<PIL.Image.Image image mode=L size=7200x600 at 0x7F251782EED0>
登录后复制

Laplacian 算子

边缘检测系列1:传统边缘检测算子 - php中文网

In [9]
laplacian_kernel = np.array([
    [[
        [1, 1, 1],
        [1, -8, 1],
        [1, 1, 1]
    ]],
    [[
        [0, 1, 0],
        [1, -4, 1],
        [0, 1, 0]
    ]]
])

_, concat_res = test_edge_det(laplacian_kernel)
Image.fromarray(concat_res)
登录后复制
<PIL.Image.Image image mode=L size=3600x600 at 0x7F24FF0A6A90>
登录后复制

总结

  • 简单介绍并实现了几种常用的传统边缘检测算子

以上就是边缘检测系列1:传统边缘检测算子的详细内容,更多请关注php中文网其它相关文章!

相关标签:
最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
热门推荐
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号