Sobel求图像梯度(从0实现以及cv2实现)

图像就是函数,梯度对应的数值就是像素值的突变情况。

图像梯度可以把图像看成二维离散函数,图像梯度其实就是这个二维离散函数的求导。

图像梯度: G(x,y) = dx(i,j) + dy(i,j);

dx(i,j) = I(i+1,j) - I(i,j);

dy(i,j) = I(i,j+1) - I(i,j);

其中,I是图像像素的值(如:RGB值),(i,j)为像素的坐标。

图像梯度一般也可以用中值差分:

dx(i,j) = [I(i+1,j) - I(i-1,j)]/2;

dy(i,j) = [I(i,j+1) - I(i,j-1)]/2;

图像边缘一般都是通过对图像进行梯度运算来实现的。

以Sobel算子为例

class Sobel(nn.Module):
    def __init__(self):
        super(Sobel, self).__init__()
        self.edge_conv = nn.Conv2d(1, 2, kernel_size=3, stride=1, padding=1, bias=False)
        edge_kx = np.array([[1, 0, -1], [2, 0, -2], [1, 0, -1]])
        edge_ky = np.array([[1, 2, 1], [0, 0, 0], [-1, -2, -1]])
        edge_k = np.stack((edge_kx, edge_ky))

        edge_k = torch.from_numpy(edge_k).float().view(2, 1, 3, 3)
        self.edge_conv.weight = nn.Parameter(edge_k)
        
        for param in self.parameters():
            param.requires_grad = False

    def forward(self, x):
        out = self.edge_conv(x) 
        out = out.contiguous().view(-1, 2, x.size(2), x.size(3))
  
        return out
    image = Image.open(r"F:\Datasets\nyu_depth_v2\test\bedroom\rgb_01038.jpg")
    image = torchvision.transforms.Grayscale()(image)
    image = torchvision.transforms.ToTensor()(image)
    sobel = Sobel()
    out = sobel(image.unsqueeze(dim=0))
    dx = out[:, 0, :, :]
    dy = out[:, 1, :, :]
    plt.imshow(dx.squeeze().numpy())
    plt.show()
    plt.imshow(dy.squeeze().numpy())
    plt.show()
    grad = dx * 0.5 + dy * 0.5
    plt.imshow(grad.squeeze().numpy())
    plt.show()

 之后我们再尝试用cv2封装好的函数去提取梯度

    image = cv2.imread(r"F:\Datasets\nyu_depth_v2\test\bedroom\rgb_01038.jpg", 0)
    grad_x = cv2.Sobel(image,cv2.CV_64F, 1, 0, ksize = 3)
    sobelx = cv2.convertScaleAbs(grad_x)
    grad_y = cv2.Sobel(image,cv2.CV_64F, 0, 1, ksize = 3)
    sobely = cv2.convertScaleAbs(grad_y)
    plt.imshow(sobelx)
    plt.show()
    plt.imshow(sobely)
    plt.show()
    grad = sobely * 0.5 + sobelx * 0.5
    plt.imshow(grad)
    plt.show()

 

 二者图像显示不同的原因是因为cv2提取的是灰度图像 numpy像素值在0-255之间,而tensor不同。
tensor的像素值特别接近,我们可以简单的设定一个阈值,将无用像素设置为0,并将其他像素归一化到0-255区间,就可以得到近似的结果

    dx = out[:, 0, :, :]
    dy = out[:, 1, :, :]
    dx = torch.where(dx > 0, dx, 0)
    dy = torch.where(dy > 0, dy, 0)
    dx = torch.sigmoid(dx) * 255
    dy = torch.sigmoid(dy) * 255

 

结果已经接近,不过还是有差别(舍弃的梯度值较多),原因是此时的dx,dy有负值。在筛选时将负数去除,导致梯度值损失较多,只需要在更改 dx = torch,where(dx!=0,dx.abs(),0) 就可得到如下结果

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Sobel算子是一种常用的边缘检测算子,可以利用它来分割图像。 以下是利用Sobel算子图像进行分割的步骤: 1. 首先,将图像转换为灰度图像。 2. 然后,利用Sobel算子计算图像梯度值。Sobel算子可以计算水平和垂直方向上的梯度值,一般使用两个3x3的卷积核来进行计算。 3. 接着,将梯度值进行加权合并,得到图像的边缘强度图。一般使用下面的公式来进行计算: edge_strength = sqrt((Gx)^2 + (Gy)^2) 其中,Gx和Gy分别为水平和垂直方向上的梯度值。 4. 最后,根据设定的阈值对边缘强度图进行二值化理,得到分割后的图像。 下面是Python代码实现: ```python import cv2 import numpy as np # 读取图像 img = cv2.imread("image.jpg") # 转换为灰度图像 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 计算Sobel算子 sobelx = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=3) sobely = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=3) # 计算边缘强度图 edge_strength = np.sqrt(sobelx ** 2 + sobely ** 2) # 二值化理 threshold_value = 100 edge_img = np.zeros_like(edge_strength) edge_img[edge_strength > threshold_value] = 255 # 显示结果 cv2.imshow("Original Image", img) cv2.imshow("Edge Image", edge_img) cv2.waitKey(0) cv2.destroyAllWindows() ``` 在上面的代码中,我们使用了cv2.Sobel函数来计算Sobel算子,使用了np.sqrt函数计算边缘强度图的值,使用了numpy数组的操作来进行二值化理。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lins H

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值