当前位置: 首页 > article >正文

OpenCV边沿检测(Python版)

        边缘检测是图像处理中的一项重要任务,用于找到图像中的边界或边缘。它在计算机视觉、图像处理和模式识别等领域中具有广泛的应用。

        边缘可以被定义为图像亮度、颜色或纹理的突变区域。边缘检测算法旨在识别这些变化并将其标记为边缘。边缘检测可以用于分割图像、检测物体边界、提取图像特征等任务。

        常用的边缘检测算法包括:

        1. Roberts算子:通过对每个像素点进行水平和垂直方向上的差分计算来检测边缘。

        2. Sobel算子:使用3x3的卷积核对图像进行卷积运算,分别计算水平和垂直方向上的梯度,然后通过这两个梯度来估计边缘。

        3. Prewitt算子:类似于Sobel算子,但使用不同的卷积核来计算水平和垂直方向上的梯度。

        4. Canny边缘检测:一种基于多步骤的算法,包括高斯滤波、计算梯度、非极大值抑制和双阈值处理等步骤。Canny边缘检测通常能够提供较好的边缘检测结果,并且对噪声具有较好的鲁棒性。

        5. Laplacian算子:通过对图像进行二阶微分操作来检测边缘。它可以提供边缘的强度和方向信息。

        这些算法各有优缺点,适用于不同的应用场景。选取合适的边缘检测算法需要考虑图像的特点、噪声水平、计算效率等因素。

一、Sobel算子

        Sobel算子是一种离散型的差分算子,用来运算图像灰度函数的梯度的近似值。Sobel算子是典型的基于一阶导数的边缘检测算子,由于该算子中引人了类似局部平均的运算,因此对噪声具有平滑作用,能很好地消除噪声的影响。

        Sobel算子是一种常用的图像边缘检测算法。它利用图像灰度变化的一阶导数来检测边缘。Sobel算子由两个3×3的模板组成,分别计算图像在水平和竖直方向的灰度变化。

        水平方向的模板如下:
                                        -1 0 1
                                        -2 0 2
                                        -1 0 1

        竖直方向的模板如下:
                                        -1 -2 -1
                                         0  0  0
                                         1  2  1

        在图像上运用Sobel算子时,首先将模板与图像的某个像素及其周围的8个像素进行卷积运算,得到该像素的梯度值(水平方向和竖直方向分别计算)。然后利用梯度值计算该像素的边缘强度,一般采用以下公式:
                EdgeMagnitude = sqrt((horizontalGradient)^2 + (verticalGradient)^2)

        最后,可以对边缘强度进行二值化处理,将高于某个阈值的像素标记为边缘像素,低于阈值的像素标记为非边缘像素。

        Sobel算子是一种简单而有效的边缘检测方法,可以帮助我们找到图像中的边缘信息,常用于计算机视觉、图像处理等领域。

1、API 

def Sobel(src,ddepth,dx,dy,dst,ksize,scale,delta,borderType)

dst:表示计算得到目标函数图像。
src: 表示原始图像。
ddepth :表示输出图像的深度
dx:表示x方向上求导的阶数。
dy: 表示y方向上求导的阶数。
ksize:表示 Sobel核的大小。
scale :表示计算导数时的缩放因子,默认值是1。
delta: 表示在目标函数上所附加的值,默认为0。
borderType: 表示边界样式。

2、代码示例

import cv2

#读取该图片的灰度图
image = cv2.imread('../photo_Input/lyy.jpg', cv2.IMREAD_GRAYSCALE)
#设置参数dx=1,dy=0.得到图像水平方向上的边缘信息
SobelX = cv2.Sobel(image, cv2.CV_64F, 1, 0)
#对结果取绝对值
SobelX = cv2.convertScaleAbs(SobelX)
#设置参数dx=0,dy=1.得到图像竖直方向上的边缘信息
SobelY = cv2.Sobel(image, cv2.CV_64F, 0, 1)
#对结果取绝对值
SobelY = cv2.convertScaleAbs(SobelY)
#加权实现完整的边沿信息
SobelXY = cv2.addWeighted(SobelX, 0.5, SobelY, 0.5, 0)

cv2.imshow("image", image)
cv2.imshow("SobelXY", SobelXY)
cv2.waitKey(0)
cv2.destroyAllWindows()

二、schaar算子

        

        Schaar算子是一种用于边缘检测的图像处理算子,常用于图像边缘的定位和提取。它通过计算图像中每个像素点的梯度值来识别出图像中的边缘。

        Schaar算子使用了两个不同的模板进行计算,分别针对水平和垂直方向的梯度。对于一个像素点(x, y),水平方向的梯度计算公式为:

        Gx = (P(x+1, y-1) + 2P(x+1, y) + P(x+1, y+1)) - (P(x-1, y-1) + 2P(x-1, y) + P(x-1, y+1))

        其中,P(x, y)表示图像在位置(x, y)处的像素值。

        垂直方向的梯度计算公式为:

        Gy = (P(x-1, y+1) + 2P(x, y+1) + P(x+1, y+1)) - (P(x-1, y-1) + 2P(x, y-1) + P(x+1, y-1))

        最后,将水平和垂直方向的梯度合并,得到像素点的边缘强度:

                                        G = sqrt(Gx^2 + Gy^2)

        根据边缘强度可以判断该像素点是否为边缘点,通常会设定一个阈值来进行判断。

        Schaar算子的优点是能够在水平和垂直方向上同时检测边缘,相比其他算子,它的计算复杂度较低,能够快速得到边缘位置。然而,它也存在一些缺点,如对噪声比较敏感,容易产生虚假的边缘,以及在某些情况下可能会漏检边缘。因此,一般会将Schaar算子与其他算子相结合使用,以提高边缘检测的准确性。

1、API

def Scharr(src, ddepth, dx, dy, dst, scale, delta, borderType)

dst:表示计算得到目标函数图像
src: 表示原始图像。
ddepth :表示输出图像的深度
dx:表示x方向上求导的阶数
dy:表示y方向上求导的阶数
scale: 表示计算导数时的缩放因子,默认值是1。
delta:表示在目标函数上所附加的值,默认为0。
borderType: 表示边界样式

2、代码示例

import cv2

#读取该图片的灰度图
image = cv2.imread('../photo_Input/lyy.jpg', cv2.IMREAD_GRAYSCALE)
#设置参数dx=1,dy=0.得到图像水平方向上的边缘信息
SchaarX = cv2.Scharr(image, cv2.CV_64F, 1, 0)
#对结果取绝对值
SchaarX = cv2.convertScaleAbs(SchaarX)
#设置参数dx=0,dy=1.得到图像竖直方向上的边缘信
SchaarY = cv2.Scharr(image, cv2.CV_64F, 0, 1)
#对结果取绝对值
SchaarY = cv2.convertScaleAbs(SchaarY)
#加权实现完整的边沿信息
SchaarXY = cv2.addWeighted(SchaarX, 0.5, SchaarY, 0.5, 0)

cv2.imshow("image", image)
cv2.imshow('SchaarXY', SchaarXY)
cv2.waitKey(0)

三、Canny边缘检测

        Canny边缘检测是一种经典的边缘检测算法,被广泛应用于计算机视觉和图像处理领域。该算法能够有效地检测图像中的边缘,并具有较低的误检率和高的检测率。

        Canny边缘检测算法的步骤如下:

                1. 噪声抑制:使用高斯滤波器对图像进行平滑,以减少噪声的影响。高斯滤波器可以模糊图像,使得图像中的噪声细节被平滑掉。

                2. 计算梯度:利用Sobel算子计算图像的梯度,找到图像中的边缘。对平滑后的图像进行水平和竖直方向的梯度计算,得到梯度幅值和梯度方向。

                3. 非极大值抑制:在梯度图像上进行非极大值抑制,保留局部梯度最大的像素点,抑制其他像素点。这一步骤可以细化边缘线,使其更加细长和清晰。

                4. 双阈值检测:设置高阈值和低阈值。若梯度幅值大于高阈值,则被标记为强边缘像素;若梯度幅值介于高阈值和低阈值之间,则被标记为弱边缘像素;若梯度幅值低于低阈值,则被标记为非边缘像素。一般情况下,高阈值是低阈值的两倍。

                5. 边缘连接:通过强边缘像素和与之相邻的弱边缘像素进行连接,形成完整的边缘线。如果一个像素点与至少一个强边缘像素点相邻,则该像素点被标记为边缘像素。

        Canny边缘检测算法通过多个步骤的处理,能够准确地检测图像中的边缘,并能够提供较好的边缘连续性和边缘定位信息。这使得它在许多计算机视觉任务中得到了广泛应用,如目标检测、图像分割、图像识别等。

1、API

Canny(image, threshold1, threshold2, edges, apertureSize, L2gradient) 

edgs: 表示计算得到的边缘信息
src :表示输人的8位图像。
threshould1:表示第一个阈值
threshould2: 表示第二个阈值。
apertureSize :表示 Sobel算子的大小。
L2gradient:表示计算图像梯度幅度的标识,默认为False

2、代码示例

import cv2

image = cv2.imread('../photo_Input/lyy.jpg', cv2.IMREAD_GRAYSCALE)
#设置不同的阈值信息对图像进行边沿检测
edg1 = cv2.Canny(image, 30, 100)
edg2 = cv2.Canny(image, 100, 200)
edg3 = cv2.Canny(image, 200, 255)

cv2.imshow('image', image)
cv2.imshow('edg1', edg1)
cv2.imshow('edg2', edg2)
cv2.imshow('edg3', edg3)
cv2.waitKey(0)
cv2.destroyAllWindows()

四、Laplacian算子

        Laplacian算子是一种常见的数学算子,通常表示为∇^2 (读作“del squared”)或Δ。它在数学、物理学和工程学的许多领域中发挥重要作用。

        Laplacian算子可以用于描述场(如温度、电场、重力场等)的二阶空间变化。对于一个二维场,Laplacian算子可以用以下形式表示:

                                ∇^2f = (∂^2f/∂x^2) + (∂^2f/∂y^2)

        其中,∇^2f表示场f的Laplacian,∂^2f/∂x^2表示f对x的二阶偏导数,∂^2f/∂y^2表示f对y的二阶偏导数。

        对于一个三维场,Laplacian算子可以用以下形式表示:

                        ∇^2f = (∂^2f/∂x^2) + (∂^2f/∂y^2) + (∂^2f/∂z^2)

        Laplacian算子可以用来描述场的平均曲率和变化率,以及场中的不稳定点、最小值和最大值。它在物理学中特别常见,例如在描述流体流动、电场分布和热传导等方面。

        Laplacian算子也可以用于求解微分方程和优化问题。在微分方程中,Laplacian算子常常与其他项一起出现,用来描述场的演化和平衡条件。在优化问题中,Laplacian算子可以用来衡量目标函数的曲率和变化率,从而帮助寻找最优解。

        总之,Laplacian算子是一种重要的数学算子,具有广泛的应用。

1、API

Laplacian(src, ddepth, dst, ksize, scale, delta, borderType)

dst:表示计算得到的目标函数图像
src :表示原始图像。
ddepth:表示输出图像的深度
ksize :表示二阶导数核的大小,必须是正奇数                                                                        scale: 表示计算导数时的缩放因子,默认值是1。                                                                      delta:表示在目标函数上所附加的值,默认为0。
borderType:表示边界样式。

2、代码示例

import cv2

image = cv2.imread('../photo_Input/wawa.jpg', cv2.IMREAD_GRAYSCALE)

cv2.imshow("image", image)

Laplacian = cv2.Laplacian(image, cv2.CV_64F)
Laplacian = cv2.convertScaleAbs(Laplacian)

cv2.imshow("Laplacian", Laplacian)
cv2.waitKey(0)

五、高斯拉普拉斯边缘检测

        高斯拉普拉斯边缘检测是一种常用的图像边缘检测方法,它结合了高斯平滑和拉普拉斯算子。

        首先,将原始图像进行高斯平滑处理,目的是减少噪声的影响,并模糊图像。这可以通过应用高斯滤波器来实现。

        然后,对平滑后的图像应用拉普拉斯算子,以突出图像中的边缘。拉普拉斯算子是一个二阶微分算子,它可以对图像进行边缘检测。

        拉普拉斯算子的离散形式可以通过对图像的像素进行加权求和来计算。常用的离散拉普拉斯算子有以下几种形式:
        1. 4邻域拉普拉斯算子:对于像素点(x, y),其边缘值可以通过以下计算得到:4 * f(x, y) - f(x-1, y) - f(x+1, y) - f(x, y-1) - f(x, y+1)
        2. 8邻域拉普拉斯算子:对于像素点(x, y),其边缘值可以通过以下计算得到:8 * f(x, y) - f(x-1, y) - f(x+1, y) - f(x, y-1) - f(x, y+1) - f(x-1, y-1) - f(x-1, y+1) - f(x+1, y-1) - f(x+1, y+1)

        最后,根据计算得到的边缘值,可以通过设置一个阈值来判断是否为边缘。通常,较大的边缘值被认为是图像中的边缘。

        高斯拉普拉斯边缘检测可以有效地检测出图像中的边缘,并且对于不同大小的边缘都具有较好的响应。然而,由于高斯平滑的模糊效果,可能会导致一些边缘细节的丢失。因此,在应用高斯拉普拉斯边缘检测时,需要根据具体应用场景进行参数调整和结果分析。

import numpy as np
import cv2
import math
from scipy import signal

# 创建拉普拉斯高斯(LoG)卷积核
def CreateLoGKernel(sigma, KSize):
    winH, winW = KSize
    # 初始化卷积核为全零数组
    logkernel = np.zeros(KSize, dtype=np.float32)
    sigmaSquare = pow(sigma, 2.0)

    centerH = (winH - 1) / 2
    centerW = (winW - 1) / 2
    for r in range(winH):
        for c in range(winW):
            # 计算到中心的距离的平方
            norm2 = pow(r - centerH, 2.0) + pow(c - centerW, 2.0)
            # 根据LoG公式计算卷积核的值
            logkernel[r][c] = 1.0 / sigmaSquare * (norm2 / sigmaSquare - 2) * math.exp(-norm2 / (2.0 * sigmaSquare))
    return logkernel

# 使用LoG卷积核对图像进行卷积操作
def LoG(image, sigma, kSize, _boundary='fill', _fillValue=0):
    LOGKernel = CreateLoGKernel(sigma, kSize)
    # 使用scipy的signal库进行二维卷积
    img_conv_log = signal.convolve2d(image, LOGKernel,'same', boundary=_boundary)
    return img_conv_log

# 将图像进行二值化处理,用于边缘检测
def edge_binary(image):
    edge = np.copy(image)
    # 将大于等于0的值设置为0
    edge[edge >= 0] = 0
    # 将小于0的值设置为255
    edge[edge < 0] = 255
    edge = edge.astype(np.uint8)
    return edge

if __name__ == '__main__':
    # 读取灰度图像
    image = cv2.imread('../photo_Input/lyy.jpg', cv2.IMREAD_GRAYSCALE)
    cv2.imshow('image', image)
    # 使用不同大小的卷积核进行LoG操作
    image1 = LoG(image, 2, (7, 7),'symm')
    image2 = LoG(image, 2, (11, 11),'symm')
    image3 = LoG(image, 2, (13, 13),'symm')

    # 对LoG操作后的结果进行二值化处理
    L1 = edge_binary(image1)
    L2 = edge_binary(image2)
    L3 = edge_binary(image3)
    # 显示二值化后的结果
    cv2.imshow('L1', L1)
    cv2.imshow('L2', L2)
    cv2.imshow('L3', L3)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

 


http://www.kler.cn/a/514840.html

相关文章:

  • 无人机在城市执法监管中的应用:技术革新与监管挑战
  • ubuntu20.04有亮度调节条但是调节时亮度不变
  • STM32更新程序OTA
  • 深入解析人工智能中的协同过滤算法及其在推荐系统中的应用与优化
  • Flutter:carousel_slider 横向轮播图、垂直轮播公告栏实现
  • numpy库ndarray维度问题
  • 本地部署DeepSeek-R1 1.5B
  • java ,springboot 对接支付宝支付,实现生成付款二维码,退款,查询订单状态等接口
  • 十三、数据的的输入与输出(3)
  • Android节点读写实现
  • 【影刀RPA_初级课程_影刀初相识】
  • 解决安装 Composer 依赖报错:“./composer.json“ does not match the expected JSON schema
  • 【QNX】QNX侧查看CPU的信息
  • 如何在Matplotlib中绘制多个Y轴刻度
  • Unity Line Renderer Component入门
  • IP所属地与上网地点:如何匹配?
  • 2024大模型双向突破:MoE架构创新与小模型崛起
  • [Dialog屏幕开发] 屏幕绘制(文本/输入框/按钮控件)
  • 【组件分享】商品列表组件-最佳实践
  • 【子矩阵——优先队列】
  • Leecode刷题C语言之从栈中取出K个硬币的最大面积和
  • node.js 07.npm下包慢的问题与nrm的使用
  • Java 设计模式一
  • 聚类OTU vs 降噪识别生物序列——谁将主宰扩增子领域未来
  • CSDN 博客之星 2024:默语的技术进阶与社区耕耘之旅
  • Markdown Viewer 浏览器, vscode