Opencv入门系列八

Opencv入门系列八


主要内容:边缘检测,在图像处理中将相邻像素点的像素值的差值作为图像的梯度。同时有较大差值的部分也就是图像的边界。此处的算子就是滤波器,用于边缘检测。

  • Sobel算子
  • Scharr算子
  • Laplacian算子

1.Sobel 算子

Sobel算子:一种离散的微分算子,结合了高斯平滑和微分运算。该算子利用局部差分寻找边缘,计算所得的是一个梯度的近似值。如下图是算子的提现:

image-20210204142834359

左图是水平方向的算子,右图是垂直方向的算子。

①将水平方向的Sobel算子与原始图像src进行卷积计算,可以计算水平方向上的像素值变化情况。

image-20210204143728218

如下是求一个像素点水平方向梯度的例子:

image-20210204143032915

步骤如下:

首先:找出P5周围的所有点作为一个3×3的矩阵,我们称它为G。(注意:在图像边界的像素点,我们还需要选择一种边界填充的方式)

其次:将水平方向的Sobel算子与矩阵G进行卷积,卷积就是对应位置的点的乘积再求和。

最后:可以得到如下表达式。

image-20210204143040979

②将垂直方向的Sobel算子与原始图像src进行卷积计算,可以计算水平方向上的像素值变化情况。

image-20210204143847615

如下是求一个像素点垂直方向梯度的例子:

image-20210204143918741

同理可得:

image-20210204143954317

在Opencv中我们使用cv2.Sobel()函数实现如上运算,其语法如下:

image-20210204144133927

● dst:处理后的图像。

● src:原图像。

● ddepth:输出图像的深度。 ddepth参数的值设置为-1时,处理结果与原始图像保持一致,但处理结果可能错误。通常要将函数cv2.Sobel()内参数ddepth的值设置为==“cv2.CV_64F”==,避免信息丢失。在不同的参数选择处理下可能会有不同的处理效果,一定要选择合适的参数

图像深度可选参数如下:

image-20210204144538273

● dx:x方向上的求导阶数。

● dy:y方向上的求导阶数。

● ksize:Sobel核的大小。该值为-1时,则会使用Scharr算子进行运算。

● scale:计算导数的缩放因子,默认情况下该值是1,即:没有缩放。

● delta:变换后要加上的值delta,默认为0。

● borderType:边界填充方式。

在OpenCV中,使用函数cv2.convertScaleAbs()对参数取绝对值,其语法格式为:

image-20210204145255357

● dst:处理结果。= src*alpha + beta

● src:原始图像。

● alpha:调节系数,该值是可选值,默认为1。

● beta:调节亮度值,该值是默认值,默认为0。

下面实验程序在dx=1 dy=0 对比在ddepth默认CV_8U和CV_64F下的图像情况:

import cv2
import numpy as np

img = cv2.imread("Resources/12.jpg",cv2.IMREAD_GRAYSCALE)
imgSobel = cv2.Sobel(img,-1,1,0)
imgSobel2 = cv2.Sobel(img,cv2.CV_64F,1,0)

cv2.imshow("img",img)
cv2.imshow("imgSobel",imgSobel)
cv2.imshow("imgSobel2",imgSobel2)

cv2.waitKey(0)

image-20210204150245586

通过图像我们可以看出,在默认条件下的图像右边的梯度无法表现出来,而ddepth=CV_64F时可以更好的表现出图像的边界。

下面实验程序在dx=0 dy=1 对比在ddepth默认CV_8U和CV_64F下的图像情况:

import cv2
import numpy as np

img = cv2.imread("Resources/12.jpg",cv2.IMREAD_GRAYSCALE)
imgSobel = cv2.Sobel(img,-1,0,1)
imgSobel2 = cv2.Sobel(img,cv2.CV_64F,0,1)

cv2.imshow("img",img)
cv2.imshow("imgSobel",imgSobel)
cv2.imshow("imgSobel2",imgSobel2)

cv2.waitKey(0)

image-20210204150813740

通过图像我们可以看出,在默认条件下的图像下边的梯度无法表现出来,而ddepth=CV_64F时可以更好的表现出图像的边界。

下面实验程序在dx=1 dy=1 对比在ddepth默认CV_8U和CV_64F下的图像情况:

import cv2
import numpy as np

img = cv2.imread("Resources/12.jpg",cv2.IMREAD_GRAYSCALE)
imgSobel = cv2.Sobel(img,-1,1,1)
imgSobel2 = cv2.Sobel(img,cv2.CV_64F,1,1)

cv2.imshow("img",img)
cv2.imshow("imgSobel",imgSobel)
cv2.imshow("imgSobel2",imgSobel2)

cv2.waitKey(0)

image-20210204150658803

2.Scharr算子

Scharr算子:在使用3×3的Sobel算子时,可能计算结果并不太精准。OpenCV提供了Scharr算子,该算子具有和Sobel算子同样的速度,且精度更高。如下图:

image-20210204151147310

在Opencv中我们使用cv2.Scharr()函数实现如上运算,其语法如下:

image-20210204151217857

● dst:输出图像。

● src:原图像。

● ddepth:输出图像深度。该值与函数cv2.Sobel()中的参数ddepth的含义相同。

● dx:x方向上的导数阶数。

● dy:y方向上的导数阶数。

● scale:同Sobel()算子。

● borderType:边界填充方式。

以下是Sobel()函数和Scharr()函数等价的情况:

注意:此函数中dx和dy不能同时为1。

image-20210204151406145

如下程序展示Scharr()函数的边缘检测效果:

import cv2
import numpy as np

img = cv2.imread("Resources/12.jpg",cv2.IMREAD_GRAYSCALE)
imgScharrx = cv2.Scharr(img,cv2.CV_64F,0,1)				#y方向上的Scharr
imgScharry = cv2.Scharr(img,cv2.CV_64F,1,0)				#x方向上的Scharr
imgSobelToScharrxy = cv2.Sobel(img,cv2.CV_64F,1,1,-1)       #使用Sobel函数实现x,y方向上的Scharr

# 合成前必须保证像素点为正数
imgScharrx = cv2.convertScaleAbs(imgScharrx)			
imgScharry = cv2.convertScaleAbs(imgScharry)
imgScharrxy = cv2.addWeighted(imgScharrx,0.5,imgScharry,0.5,0)#第二种方式实现x,y方向的scharr

cv2.imshow("img",img)
cv2.imshow("imgScharrx",imgScharrx)
cv2.imshow("imgScharry",imgScharry)
cv2.imshow("imgSobelToScharrxy",imgSobelToScharrxy)
cv2.imshow("imgScharrxy",imgScharrxy)

cv2.waitKey(0)

image-20210204152348090

3.Laplacian 算子

Laplacian(拉普拉斯)算子是一种二阶导数算子,其具有旋转不变性,可以满足不同方向的图像边缘锐化(边缘检测)的要求。如下图:算子系数之和为0。

image-20210204152841284

如下是求一个像素点方向梯度的例子:

image-20210204153001155

其结果可以表示为(具体要根据ksize的选取来看):

image-20210204153021135

在OpenCV内使用函数cv2.Laplacian()实现Laplacian算子的计算,其语法格式为:

image-20210204153046889

● dst:目标图像。

● src:原图像。

● ddepth:目标图像的深度。

● ksize:用于计算二阶导数的核尺寸大小。该值必须是正的奇数

● scale:计算时的缩放因子。默认情况下,该值为1,即不进行缩放。

● delta:同前两种算子。

● borderType:边界填充方式。

该函数分别对x、y方向进行二次求导,具体为:

image-20210204153653383

import cv2
import numpy as np

img = cv2.imread("Resources/12.jpg",cv2.IMREAD_GRAYSCALE)
imgLaplasian = cv2.Laplacian(img,cv2.CV_64F)

cv2.imshow("img",img)
cv2.imshow("imgLaplasian",imgLaplasian)

cv2.waitKey(0)

image-20210204153930888

4.Canny边缘检测

Canny边缘检测:一种使用多级边缘检测算法检测边缘的方法。

Canny边缘检测分为如下几个步骤。

  • 步骤1:去噪。噪声会影响边缘检测的准确性,因此首先要将噪声过滤掉。
  • 步骤2:计算梯度的幅度与方向。
  • 步骤3:非极大值抑制,即适当地让边缘“变瘦”。
  • 步骤4:确定边缘。使用双阈值算法确定最终的边缘信息。

Opencv提供了函数cv2.Canny()来实现Canny边缘检测,其语法格式如下

image-20210204154507853

● edges:边缘图像。

● image:8位的原图像。

● threshold1:处理过程中的第一个阈值。

● threshold2:处理过程中的第二个阈值。

● apertureSize:Sobel算子的孔径大小。

● L2gradient:计算梯度的方式。

​ 默认值为False,直接将两个方向导数的绝对值相加计算导数。

​ 如果为True,以两个方向的导数的平方和再开方计算导数。

一下是一个简单的使用程序:

import cv2

img = cv2.imread("Resources/12.jpg",cv2.IMREAD_GRAYSCALE)
imgCanny = cv2.Canny(img,32,168)

cv2.imshow("img",img)
cv2.imshow("imgCanny",imgCanny)

cv2.waitKey(0)

image-20210204154948764

不难看出使用Canny边缘检测的效果比前三种要好得多。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值