图像中物体边缘检测

边缘检测是什么?

边缘检测是计算机视觉领域中的一项基本任务,其目的是在图像中找到物体的边缘。边缘是物体的边界或者是物体内部的强度变化区域。边缘检测在很多应用中都有着重要的作用,例如图像分割、目标识别、三维重建等。

边缘检测的步骤

边缘检测的基本步骤如下:

  1. 将图像转换为灰度图像,使得每个像素只有一个强度值。
  2. 对图像进行滤波,以去除噪声和平滑图像。
  3. 计算图像中每个像素的梯度,以找到强度变化的位置。
  4. 应用非极大值抑制,以保留梯度方向上的局部极大值。
  5. 应用双阈值算法,以将边缘像素分为强边缘和弱边缘。
  6. 应用连接分析,以将弱边缘转换为强边缘或者去除它们。

边缘检测的实现

在本文中,我们将使用PyTorch实现边缘检测。我们将使用Canny算法,这是一种经典的边缘检测算法。

灰度化

首先,我们将图像转换为灰度图像。这可以通过下面的代码实现:

import torch
import torchvision.transforms.functional as TF

def to_gray(image):
    return TF.to_grayscale(image, num_output_channels=1)

滤波

然后,我们需要对图像进行滤波,以去除噪声和平滑图像。我们将使用高斯滤波器,这可以通过下面的代码实现:

import torch.nn.functional as F

def gaussian_kernel(size, sigma=1.5):
    x = torch.arange(size).float()
    k = torch.exp(-(x - size // 2)**2 / (2 * sigma**2))
    return k / k.sum()

def gaussian_filter(image, size=5, sigma=1.5):
    kernel = gaussian_kernel(size, sigma).unsqueeze(0).unsqueeze(0)
    return F.conv2d(image, kernel, padding=size // 2)

计算梯度

然后,我们需要计算图像中每个像素的梯度。我们将使用Sobel算子,这可以通过下面的代码实现:

def sobel_filter(image):
    kernel_x = torch.tensor([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]]).float().unsqueeze(0).unsqueeze(0)
    kernel_y = torch.tensor([[-1, -2, -1], [0, 0, 0], [1, 2, 1]]).float().unsqueeze(0).unsqueeze(0)
    gradient_x = F.conv2d(image, kernel_x, padding=1)
    gradient_y = F.conv2d(image, kernel_y, padding=1)
    gradient = torch.sqrt(gradient_x**2 + gradient_y**2)
    angle = torch.atan2(gradient_y, gradient_x)
    return gradient, angle

非极大值抑制

然后,我们需要应用非极大值抑制,以保留梯度方向上的局部极大值。这可以通过下面的代码实现:

def non_maximum_suppression(gradient, angle):
    h, w = gradient.shape[-2:]
    suppressed = torch.zeros_like(gradient)
    for i in range(1, h - 1):
        for j in range(1, w - 1):
            a = angle[0, 0, i, j].item() / np.pi * 180
            if (a < -22.5 or a >= 157.5) and gradient[0, 0, i, j] >= gradient[0, 0, i, j - 1] and gradient[0, 0, i, j] >= gradient[0, 0, i, j + 1]:
                suppressed[0, 0, i, j] = gradient[0, 0, i, j]
            elif (a >= -22.5 and a < 22.5) and gradient[0, 0, i, j] >= gradient[0, 0, i - 1, j] and gradient[0, 0, i, j] >= gradient[0, 0, i + 1, j]:
                suppressed[0, 0, i, j] = gradient[0, 0, i, j]
            elif (a >= 22.5 and a < 67.5) and gradient[0, 0, i, j] >= gradient[0, 0, i - 1, j - 1] and gradient[0, 0, i, j] >= gradient[0, 0, i + 1, j + 1]:
                suppressed[0, 0, i, j] = gradient[0, 0, i, j]
            elif (a >= 67.5 and a < 112.5) and gradient[0, 0, i, j] >= gradient[0, 0, i - 1, j] and gradient[0, 0, i, j] >= gradient[0, 0, i + 1, j]:
                suppressed[0, 0, i, j] = gradient[0, 0, i, j]
            elif (a >= 112.5 and a < 157.5) and gradient[0, 0, i, j] >= gradient[0, 0, i - 1, j + 1] and gradient[0, 0, i, j] >= gradient[0, 0, i + 1, j - 1]:
                suppressed[0, 0, i, j] = gradient[0, 0, i, j]
    return suppressed

双阈值算法

然后,我们需要应用双阈值算法,以将边缘像素分为强边缘和弱边缘。这可以通过下面的代码实现:

def double_threshold(suppressed, low_threshold=20, high_threshold=50):
    strong = (suppressed >= high_threshold).float()
    weak = (suppressed >= low_threshold).float() - strong
    return strong, weak

连接分析

最后,我们需要应用连接分析,以将弱边缘转换为强边缘或者去除它们。这可以通过下面的代码实现:

def edge_tracking(strong, weak):
    h, w = strong.shape[-2:]
    for i in range(1, h - 1):
        for j in range(1, w - 1):
            if weak[0, 0, i, j] and strong[0, 0, i - 1:i + 2, j - 1:j + 2].max() > 0:
                strong[0, 0, i, j] = 1
                weak[0, 0, i, j] = 0
    return strong

完整代码

下面是完整的边缘检测代码:

import numpy as np
import torch
import torchvision.transforms.functional as TF
import torch.nn.functional as F

def to_gray(image):
    return TF.to_grayscale(image, num_output_channels=1)

def gaussian_kernel(size, sigma=1.5):
    x = torch.arange(size).float()
    k = torch.exp(-(x - size // 2)**2 / (2 * sigma**2))
    return k / k.sum()

def gaussian_filter(image, size=5, sigma=1.5):
    kernel = gaussian_kernel(size, sigma).unsqueeze(0).unsqueeze(0)
    return F.conv2d(image, kernel, padding=size // 2)

def sobel_filter(image):
    kernel_x = torch.tensor([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]]).float().unsqueeze(0).unsqueeze(0)
    kernel_y = torch.tensor([[-1, -2, -1], [0, 0, 0], [1, 2, 1]]).float().unsqueeze(0).unsqueeze(0)
    gradient_x = F.conv2d(image, kernel_x, padding=1)
    gradient_y = F.conv2d(image, kernel_y, padding=1)
    gradient = torch.sqrt(gradient_x**2 + gradient_y**2)
    angle = torch.atan2(gradient_y, gradient_x)
    return gradient, angle

def non_maximum_suppression(gradient, angle):
    h, w = gradient.shape[-2:]
    suppressed = torch.zeros_like(gradient)
    for i in range(1, h - 1):
        for j in range(1, w - 1):
            a = angle[0, 0, i, j].item() / np.pi * 180
            if (a < -22.5 or a >= 157.5) and gradient[0, 0, i, j] >= gradient[0, 0, i, j - 1] and gradient[0, 0, i, j] >= gradient[0, 0, i, j + 1]:
                suppressed[0, 0, i, j] = gradient[0, 0, i, j]
            elif (a >= -22.5 and a < 22.5) and gradient[0, 0, i, j] >= gradient[0, 0, i - 1, j] and gradient[0, 0, i, j] >= gradient[0, 0, i + 1, j]:
                suppressed[0, 0, i, j] = gradient[0, 0, i, j]
            elif (a >= 22.5 and a < 67.5) and gradient[0, 0, i, j] >= gradient[0, 0, i - 1, j - 1] and gradient[0, 0, i, j] >= gradient[0, 0, i + 1, j + 1]:
                suppressed[0, 0, i, j] = gradient[0, 0, i, j]
            elif (a >= 67.5 and a < 112.5) and gradient[0, 0, i, j] >= gradient[0, 0, i - 1, j] and gradient[0, 0, i, j] >= gradient[0, 0, i + 1, j]:
                suppressed[0, 0, i, j] = gradient[0, 0, i, j]
            elif (a >= 112.5 and a < 157.5) and gradient[0, 0, i, j] >= gradient[0, 0, i - 1, j + 1] and gradient[0, 0, i, j] >= gradient[0, 0, i + 1, j - 1]:
                suppressed[0, 0, i, j] = gradient[0, 0, i, j]
    return suppressed

def double_threshold(suppressed, low_threshold=20, high_threshold=50):
    strong = (suppressed >= high_threshold).float()
    weak = (suppressed >= low_threshold).float() - strong
    return strong, weak

def edge_tracking(strong, weak):
    h, w = strong.shape[-2:]
    for i in range(1, h - 1):
        for j in range(1, w - 1):
            if weak[0, 0, i, j] and strong[0, 0, i - 1:i + 2, j - 1:j + 2].max() > 0:
                strong[0, 0, i, j] = 1
                weak[0, 0, i, j] = 0
    return strong

def canny(image):
    gray = to_gray(image)
    filtered = gaussian_filter(gray)
    gradient, angle = sobel_filter(filtered)
    suppressed = non_maximum_suppression(gradient, angle)
    strong, weak = double_threshold(suppressed)
    strong = edge_tracking(strong, weak)
    return strong

# 例子
import matplotlib.pyplot as plt
from PIL import Image

image = Image.open('example.jpg')
edges = canny(image)
plt.imshow(edges.squeeze(), cmap='gray')
plt.show()

结构图

下面是边缘检测的结构图:

输入图像
灰度化
滤波
梯度计算
非极大值抑制
双阈值算法
连接分析
输出边缘

下面介绍几种常见的边缘检测方法。

1. Canny边缘检测

Canny边缘检测是一种经典的边缘检测方法,它基于一系列的图像处理步骤,包括高斯滤波、计算梯度、非极大值抑制和双阈值处理。其中,高斯滤波用于平滑图像,计算梯度用于检测图像中的边缘,非极大值抑制用于压缩边缘,双阈值处理用于确定边缘的强度。

Canny边缘检测的步骤如下:

  1. 对图像进行高斯滤波,以平滑图像,去除噪声。
  2. 计算图像的梯度,找到图像中的边缘。
  3. 对梯度幅值进行非极大值抑制,以压缩边缘。
  4. 通过双阈值处理,确定边缘的强度,进一步压缩边缘。

2. Sobel边缘检测

Sobel边缘检测是一种基于梯度的边缘检测方法,它使用两个卷积核(Sobel X和Sobel Y)来计算图像的水平和垂直梯度。然后,使用这些梯度计算边缘的强度和方向。

Sobel边缘检测的步骤如下:

  1. 对图像进行灰度化处理,以便进行梯度计算。
  2. 使用Sobel X和Sobel Y卷积核计算图像的水平和垂直梯度。
  3. 计算梯度幅值和方向。
  4. 通过设置阈值,确定边缘的强度。

3. Laplacian边缘检测

Laplacian边缘检测是一种基于二阶导数的边缘检测方法,它使用拉普拉斯算子来计算图像的二阶导数。然后,使用这些导数计算边缘的强度。

Laplacian边缘检测的步骤如下:

  1. 对图像进行灰度化处理,以便进行导数计算。
  2. 使用拉普拉斯算子计算图像的二阶导数。
  3. 计算导数的幅值。
  4. 通过设置阈值,确定边缘的强度。

4. 边缘检测在PyTorch中的实现

在PyTorch中,可以使用torchvision包中的transforms模块来实现边缘检测。其中,transforms模块提供了多种边缘检测方法,如Canny边缘检测、Sobel边缘检测和Laplacian边缘检测。

下面是使用transforms模块实现Canny边缘检测的代码示例:

import torch
import torchvision.transforms as transforms
from PIL import Image

# 加载图像
img = Image.open('image.jpg')

# 定义Canny边缘检测变换
canny = transforms.Compose([
    transforms.Grayscale(),
    transforms.Canny(100, 200)
])

# 应用Canny边缘检测变换
edge = canny(img)

# 显示边缘检测结果
edge.show()

在上面的代码中,首先加载了一张图像,然后定义了一个Canny边缘检测变换,该变换包括灰度化和Canny边缘检测两个步骤。最后,应用该变换并显示边缘检测结果。

总之,边缘检测是图像处理中的一个重要步骤,可以为其他图像处理任务提供有用的信息。常见的边缘检测方法包括Canny边缘检测、Sobel边缘检测和Laplacian边缘检测。在PyTorch中,可以使用transforms模块来实现这些边缘检测方法。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值