人工智能图像识别四大算子

news2024/11/23 9:16:56

文章目录

  • 背景引入
  • 图像识别发展简介
    • 边缘检测算法
      • *Prewitt算子*
      • *Sobel算子*
      • *Laplace算子*
      • *Conny算子*
  • * 文末寄语*


背景引入

图像识别是当今计算机科学最热门的研究方向之一。随着科学技术的发展和人类社会的不断进步,图像识别技术在很多行业得到了广泛的应用。本章除了对图像识别基本概念进行介绍外,还将从图像识别基本算法与实际应用等几个方面引导读者利用Python以及所需第三方工具进行相关的编程实践。

图像识别发展简介

图像识别(Image Recognition)是人工智能的一个重要研究领域。它以图像的主要特征区域(检测目标)为基础,通过数据获取一系列的相关处理,并采用各种算法来对目标图像进行检测,识别与理解。其中,图象是承载检测目标的载体,而检测目标则需事先进行特征提取,归纳。最终通过相应的算法分离出来。通常情况下,一个图像识别系统主要由图像分割图像特征提取,分类与识别3个部分组成。其中,图像分割主要用于将图像划分成多个区域,而图像特征提取则是从图像中寻找最具区分能力的特征,分类与识别则是按照图像特征所提取的结果进行适当的分类。
图像识别的发展经历了三个阶段:文字识别(Character Recognition),数字图像处理(Digital Image Processing)与识别,物体识别(Object Recognition)

①.文字识别的研究从20世纪50年代开始,主要是识别字母,数字和符号,包括印刷文字以及手写文字等,应用非常广泛。
②.数字图像处理与识别的研究始于20世纪70年代,数字图像与模拟图像相比具有易于存储,便于传输,可压缩,传输过程中不易失真,处理方便等巨大优势,这些都为图像识别技术的发展提供了有力支持。
③. 物体识别技术起源于20世纪50年代,他是计算机视觉领域中的一个重要分支,其主要任务是识别出图像中有什么物体,并指出该物体在图像场景中的位置和方向等相关信息。随着人工智能,大数据和深度学习技术的不断发展,以及3D传感器,深度摄像头等硬件的不断升级,利用深度信息进行三维物体识别技术的广泛应用,让物体识别领域有了较大发展。目前,物体识别方法主要有基于模型的识别和基于上下文(Context)的识别。

图像识别的数学本质是模式空间到类别空间的映射。目前在图像识别技术的发展过程中,主要有三种识别方法:统计模式识别,结构模式识别以及模糊模式识别

边缘检测算法

边缘检测是图像处理和计算机视觉,尤其是图像特征提取中的一个重要研究领域。图像的边缘是图像的重要特征,是计算机视觉,模式识别的基础,是图像处理中一个重要的环节。通常情况下,人们可以仅凭一个剪影或草图来识别出物体的类型或姿态,而剪影就由边缘特征构成。边缘检测的目的是标识数字图像中亮度变化明显的点。图像属性中的显著变化通常包括:深度上的不连续,表面方向不连续,物质属性变化和场景照明变化等图像边缘检测会大幅度减少数据量,并剔除不相关的信息,只保留图像重要的结构属性。
人类视觉系统认识目标的过程分为两步:首先,将图像边缘与背景分离出来;然后,感知图像的细节,辨认出图像的轮廓。计算机视觉正是模仿人类视觉的这个过程,在检测物体边缘时,先对其轮廓点进行粗略检测,然后通过连接规则把原来检测到的轮廓点连接起来,同时也检测和连接遗漏的边界点以及除去虚假的边界点。
如果我们需要检测一幅图像的边缘,我们首先需要明确知晓边缘的特征。对于一幅灰度图像而言,边缘两边的灰度值肯定不同,因此,当我们检测灰度图像的边缘时,就需要找出图像何处的灰度值变化最大。显然,灰度值变化越大,对比度越大,边缘也就越明显。
在数学中,与变化率息息相关的是导数。如果灰度图像的像素是连续的,那么我们可以对图像G的x方向和y方向分别求导数:
Gx=f'(G,x)Gy=f'(G,y)
获得x方向的图像导数Gx和y方向的图像导数Gy。Gx和Gy分别隐含了x方向和y方向的灰度变化信息,也就是隐含了图像的边缘信息。
如果要在同一图像上包含两个方向的边缘信息,我们可以用梯度。原图像G的梯度向量Gxy为(Gx,Gy),梯度向量的大小|Gxy|和方向∠Gxy可用以下两个公式进行计算:
|Gxy|=^(Gx²+Gy²) ∠Gxy=arctan(Gy/Gx)
梯度向量的大小就包含了x方向和y方向的边缘信息。
实际上,图像矩阵是离散的。连续函数求变化率用的是导数,而离散函数求变化率用的是差分。差分的概念也很容易理解,就是用相邻两个数的差来表示变化率。下面公式是向后差分
x方向的差分:Gx(n,y)=G(n,y)-G(n-1,y) y方向的差分:Gy(x,n)=Gy(x,n)-Gy(x,n-1)
实际计算图像导数时,我们是通过原图像和一个 **算子(Operator)进行卷积计算来完成的(该方法是求图像的近似导数)。所谓“算子”就是数学中的映射。如果映射的作用是把函数映射到函数或者把函数映射到数,那么这种映射就被称为算子。广而言之,对任何函数进行某一项操作皆可以认为是一个算子,甚至包括求幂,开方等皆可认为是一个算子,只是有的算子我们用符号来代替他们的主要运算。对于图像边缘检测的常见算子有 Prewitt算子,Sobel算子,Laplace算子,Canny算子等

Prewitt算子

Prewitt算子是最简单的图像求导算子,也是一种常用的边缘检测一阶微分算子。它利用像素点左右上下,左右相邻点的灰度差在边缘处达到极值来进行边缘检测。Prewitt算子在图像空间利用两个方向模板与图像进行领域卷积(Adjacent Convolution)运算来完成边缘检测。在图像处理中,卷积是常用的一种运算,通常是使用一个卷积核(算子)对图像中的每个像素进行一系列操作从而得到新的像素值。Prewitt算子有两个方向模板,一个用于水平方向(x)方向的边缘检测,一般设置为在这里插入图片描述
;另一个则用于垂直方向上(y)的边缘检测,一般设置为:在这里插入图片描述
前面我们已经介绍过卷积算法,这里就直接使用,不再过度介绍。
示例代码:

import numpy as np #用于处理图像矩阵,算子矩阵即相关运算
from PIL import Image #图像处理模块
import matplotlib.pyplot as plt
import matplotlib.cm as cm
#定义图像卷积函数
'''
Scipy库中的signal模块含有一个二维卷积函数convolved2d() 后面就会直接使用
'''
def img_conv(image_array,operator):
    image=image_array.copy()#原图像矩阵的深拷贝
    dim1,dim2=image.shape
    #将矩阵中的每个元素与算子矩阵中的对应元素相乘再求和(忽略最外圈的边框像素)
    for i in range(1,dim1-1):
        for j in range(1,dim2-1):
            image[i,j]=(image_array[(i-1):(i+2),(j-1):(j+2)]*operator).sum()
        #由于卷积后各元素的值不一定为0~255,需归一化0~255
    image=image*(255.0/image.max())
    #返回结果矩阵
    return image
#定义x方向的Prewitt算子
operator_x=np.array([[-1,0,-1],[-1,0,-1],[-1,0,-1]])
#定义y方向上的prewitt算子
operator_y=np.array([[-1,-1,-1],[0,0,0],[1,1,1]])
#打开原图并将其转化为灰度图像
image=Image.open('D:\Python\.vscode\__pycache__\.vscode\__pycache__\opencv视图\Python爬虫\图形化界面\\123.png').convert('L')
image_array=np.array(image)
#得到x方向导数矩阵
image_x=img_conv(image_array,operator_x)
#得到y方向上的导数矩阵
image_y=img_conv(image_array,operator_y)
#得到梯度矩阵
image_xy=np.sqrt(image_x**2+image_y**2)
#将梯度矩阵个元素的值归一为0~255
image_xy=(255.0/image_xy.max())*image_xy
plt.subplot(2,2,1)
plt.imshow(image_array,cmap=plt.cm.gray)
plt.axis('off')
plt.subplot(2,2,2)
plt.imshow(image_x,cmap=plt.cm.gray)
plt.axis('off')
plt.subplot(2,2,3)
plt.imshow(image_y,cmap=plt.cm.gray)
plt.axis('off')
plt.subplot(2,2,4)
plt.imshow(image_xy,cmap=plt.cm.gray)
plt.axis('off')
plt.show()


结果展示:
在这里插入图片描述
Prewitt算子虽然可以检测出图像边缘,但是结果较为粗糙,图像带有大量高频噪声。下面我们可以介绍更为精细的算法。

Sobel算子

Sobel算子是典型的边缘检测一阶微分算子。它利用像素临近区域的梯度值来计算1个像素的梯度值,然后根据一定的绝对值来取舍。在技术上他是离散性的差分算子,用于计算图像亮度函数的梯度近似值。由于Sobel算子中引入了类似局部平均的运算,因此对噪声具有平滑作用,能很好地消除噪声影响。Sobel算子对于像素的位置的影响进行了加权,与Prewitt算子相比效果更佳。Sobel算子由两个3x3矩阵表示的卷积核组成,通常其中一个对垂直边缘响应最大,另一个则对水平边缘响应最大。两个卷积核分别代表水平和垂直方向的算子,将其与原图像进行卷积运算,即可分别得到水平与垂直方向的亮度差分近似值。实际使用中,常用如下两个算子对图像边缘进行检测:
检测水平方向的Sobel算子:在这里插入图片描述
检测垂直水平方向的Sobel算子:在这里插入图片描述
图像的每一个像素的横向及纵向梯度近似值可以用以下公式来计算其大小:
G=sqrt(Gx²+Gy²)(sqrt表示开方)
然后用以下的公式计算梯度值:
β=arctan(Gx/Gy)
如果β的值为0,则表示图像在该处拥有垂直边缘,左方较右方暗。利用Sobel算子进行边缘检测示例代码:

#利用Sobel算子进行边缘检测
import numpy as np #算子矩阵处理
from PIL import Image  #图片导入
import matplotlib.cm as cm  #用于色彩映射
import scipy.signal as signal  #使用signal中的convolve2d卷积算法
import matplotlib.pyplot as plt #绘图

#定义x方向的Sobel算子
operator_x=np.array([[-1,0,1],[-2,0,2],[-1,0,1]])
#定义y方向的sobel算子
operator_y=np.array([[-1,-2,-1],[0,0,0],[1,2,1]])
#打开图像并将其转化为灰度图像
Image=Image.open('D:\Python\.vscode\__pycache__\.vscode\__pycache__\opencv视图\Python爬虫\图形化界面\\123.png').convert('L')
#转换成图像矩阵
image_array=np.array(Image)
#x方向的导数矩阵
image_x=signal.convolve2d(image_array,operator_x,mode='same') #标签:full,valid,same
image_y=signal.convolve2d(image_array,operator_y,mode='same')
#得到梯度矩阵
image_xy=np.sqrt(image_x**2+image_y**2)
#将梯度矩阵归一化为0~255
image_xy=image_xy*(255/image_xy.max())
#输出边缘检测图像
plt.subplot(2,2,1)
plt.imshow(image_array,cmap=cm.gray)
plt.axis('off')
plt.subplot(2,2,2)
plt.imshow(image_x,cmap=cm.gray)
plt.axis('off')
plt.subplot(2,2,3)
plt.imshow(image_y,cmap=cm.gray)
plt.axis('off')
plt.subplot(2,2,4)
plt.imshow(image_xy,cmap=cm.gray)
plt.axis('off')
plt.show()

结果展示:
在这里插入图片描述
除了上述的通过Sobel算子卷积运算进行图像边缘检测。我们也可以通过Opencv中自带的Sobel函数来进行图像检测,示例代码如下:

#基于opencv中的sobel算子函数
import cv2
import numpy as np
from PIL import Image
#读取原图
#Image=Image.open('D:\Python\.vscode\__pycache__\.vscode\__pycache__\opencv视图\Python爬虫\图形化界面\\123.png').convert('L')
image=cv2.imread('D:\Image\one.jpg')
#将图像转换为灰度图像
image=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
cv2.imshow('Original',image)
cv2.waitKey() #等待按键
'''
Sobel边缘检测,其中SobelX为x方向导数图像,SobelY为y方向导数图像,SobelCombined为梯度图像
'''
SobelX=cv2.Sobel(image,cv2.CV_64F,1,0)
SobelY=cv2.Sobel(image,cv2.CV_64F,0,1)
#x方向梯度的绝对值
SobelX=np.uint8(np.absolute(SobelX))
#y方向梯度的绝对值
SobelY=np.uint8(np.absolute(SobelY))
sobelCombined=cv2.bitwise_or(SobelX,SobelY)
cv2.imshow('Sobel X',SobelX)
cv2.waitKey()
cv2.imshow('Sobel Y',SobelY)
cv2.waitKey()
cv2.imshow('Sobel Combined',sobelCombined)
cv2.waitKey()

结果展示:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
从这两种方法的检测结果可以看出,Sobel算子的图像边缘检测结果也十分模糊,Sobel算子并没有将图像的主体与背景严格分开,换而言之,Sobel算子并没有基于图像灰度进行处理。由于Sobel算子并没有严格的模拟人类的视觉生理特征,所以提取的图像轮廓并不能让人满意。

Laplace算子

Label算子是一个二阶微分算子,它实际上是一个x方向的二阶导数和y方向的二阶导数之和的近似微分。该算子比较适合应用于只关心边缘位置而不考虑其周围像素灰度差值的图像边缘检测场景。Laplace算子对孤立像素的响应比对边缘像素的响应要更强烈些,因此适用于无噪声的图像处理。存在噪声的情况下,使用Laplace算子检测边缘前需要先对图像进行低通滤波。所以,通常的分割算法都是把Laplace算子和平滑算子结合起来生成一个新的模板。
为了更适合数字图像处理,可将Laplace算子表示为如下离散形式:
▽²f=(f(x+1,y)+f(x-1,y)+f(x,y+1)+f(x,y-1))
常用的离散Laplace算子在这里插入图片描述
其拓展算子为在这里插入图片描述
Laplace算子一般不以其原始形式用于边缘检测,因其作为一个二阶导数,Laplace算子对噪声有无法接受的敏感性,一般使用的是高斯型Laplace算子(Laplace of Gaussian,LoG)。再LoG公式中使用高斯函数的目的是对图像进行平滑处理,使用Laplace算子的目的就是提供一幅用零交叉确定边缘位置的图像。图像的平滑处理减少了噪声的影响,且他的主要作用是抵消由Laplace算子的二阶导数引起的逐渐增加的噪声影响。
利用Laplace算子进行图像边缘检测的代码如下:


#Laplace算子
import numpy as np
from PIL import Image
import matplotlib.cm as cm
import matplotlib.pyplot as plt
import scipy.signal as signal
#定义Laplace算子
Operator1=np.array([[0,1,0],[1,-4,1],[0,1,0]])
#定义Laplace拓展算子
Operator2=np.array([[1,1,1],[1,-8,1],[1,1,1]])
image=Image.open('D:\Image\one.jpg').convert('L')
image_array=np.array(image)
#卷积计算
image_oper1=signal.convolve2d(image,Operator1,mode='same')
image_oper2=signal.convolve2d(image,Operator2,mode='same')
#由于卷积后的元素的值不一定为0~255,所以需要归一化为0~255
image_oper1=image_oper1*(255/float(image_oper1.max()))
image_oper2=image_oper2*(255/float(image_oper2.max()))
#将大于灰度平均值的灰度值变成255(白色),方便观察
image_oper1[image_oper1>image_oper1.mean()]=255
image_oper2[image_oper2>image_oper2.mean()]=255
#显示边缘检测结果
plt.subplot(2,1,1)
plt.imshow(image_array,cmap=cm.gray)
plt.axis('off')
plt.subplot(2,2,3)
plt.imshow(image_oper1,cmap=cm.gray)
plt.axis('off')
plt.subplot(2,2,4)
plt.imshow(image_oper2,cmap=cm.gray)
plt.axis('off')
plt.show()

结果展示:
在这里插入图片描述
为了更好的边缘检测效果,可先对图像进行模糊平滑处理,除去图像中的高频噪声,高频噪声一般可采用高斯算法来进行处理,该算法示例代码如下:

def func(x,y,sigma=1):
    return 100*(1/(2*np.pi*sigma))*np.exp(-((x-2)**2)/(2.0*sigma**2))

使用高斯算法降噪后的代码:

#Laplace算子
import numpy as np
from PIL import Image
import matplotlib.cm as cm
import matplotlib.pyplot as plt
import scipy.signal as signal
#高斯算法示例代码
def func(x,y,sigma=1):
    return 100*(1/(2*np.pi*sigma))*np.exp(-((x-2)**2)/(2.0*sigma**2))
Operator1=np.fromfunction(func,(5,5),sigma=5)
#定义Laplace算子
Operator2=np.array([[0,1,0],[1,-4,1],[0,1,0]])
image=Image.open('D:\Image\one.jpg').convert('L')
image_array=np.array(image)
#卷积计算
#通过生成的高斯算子与原图像进行卷积计算来对图像进行平滑处理
image_blur=signal.convolve2d(image_array,Operator1,mode='same')
image_oper1=signal.convolve(image_blur,Operator2,mode='same')
#由于卷积后的元素的值不一定为0~255,所以需要归一化为0~255
image_oper1=image_oper1*(255/float(image_oper1.max()))
#将大于灰度平均值的灰度值变成255(白色),方便观察
image_oper1[image_oper1>image_oper1.mean()]=255
#显示边缘检测结果
plt.subplot(1,2,1)
plt.imshow(image_array,cmap=cm.gray)
plt.axis('off')
plt.subplot(1,2,2)
plt.imshow(image_oper1,cmap=cm.gray)
plt.axis('off')
plt.show()

结果展示:
在这里插入图片描述

Conny算子

Conny算子是一种基于图像梯度计算的图像边缘检测算法,与上文提及的基于Laplace算法的图像边缘检测方法类似,亦属于先平滑后求导的方法。利用Conny算子实现图像边缘检测的过程分为以下几个步骤:
`①.图像灰度化```
②.对图像进行高斯平滑滤波
首先生成二维高斯分布矩阵:
p (x,y) = p (x)p (y) = frac {1} {2pi} exp (-frac {x^2+y^2} {2}) tag {5} 为了向量化公式,用向量 textbf {v}= [x y]^T
然后,将其与灰度图像进行卷积实现图像滤波:
fs(x,y)=f(x,y)*p(x,y)
③.计算梯度幅值和方向。
求变化率时,对于一元函数,即为求导,对于二元函数即为求偏导。在数字图像处理中,用一阶有限差分近似方法求得灰度值的梯度幅值(变化率)。
④.对梯度幅值进行非极大值抑制(Non-Maximum Suppression,NMS)。
寻找像素点局部最大值,沿着梯度方向,比较它前面和后面的梯度幅值。在沿其梯度方向上领域的梯度幅值最大则保留,反之则抑制。这一步主要是排除非边缘像素,仅保留部分细线条(候选边缘)。
⑤.用双阈值法检测和连接边缘。
——>选取梯度幅值为高阈值TH和低阈值TL,TH:TL为2:1或3:1.
——>如果某一像素位置的梯度幅值超过TH,则该像素被保留为边缘像素。
——>如果某一像素位置的梯度幅值小于TL,则该像素排除。
——>如果某一像素位置的梯度幅值在TH和TL之间,则该像素仅仅在连接到一个高于原像素时被保留。
利用Canny算子进行图像边缘检测示例代码:


#Canny算子
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import numpy as np
import math
#载入原图
img=plt.imread('D:\Image\one.jpg')
sigma1=sigma2=1 #设定高斯滤波器标准差,缺省值为1
sum=0
gaussian=np.zeros([5,5])#初始化5*5高斯算子矩阵
for i in range(5):
    for j in range(5):
        #生成二维高斯分布矩阵
        gaussian[i,j]=math.exp(-1/2*(np.square(i-3)/np.square(sigma1)+(np.square(j-3)/np.square(sigma2))))/(2*math.pi*sigma1*sigma2)
        sum=sum+gaussian[i,j]
gaussian=gaussian/sum

def rgb2gray(rgb):  #rgb图像转换为灰度图像
    return np.dot(rgb[...,:3],[0.299,0.587,0.114])
#高斯滤波
gray=rgb2gray(img)
W,H=gray.shape
new_gray=np.zeros([W-5,H-5])
for i in range(W-5):
    for j in range(H-5):
        #与高斯矩阵卷积实现滤波
        new_gray[i,j]=np.sum(gray[i:i+5,j:j+5]*gaussian)
#通过求梯幅值使图像增强
W1,H1=new_gray.shape
dx=np.zeros([W1-1,H1-1])
dy=np.zeros([W1-1,H1-1])
d=np.zeros([W1-1,H1-1])
for i in range(W1-1):
    for j in range(H1-1):
        dx[i,j]=new_gray[i,j+1]-new_gray[i,j]
        dy[i,j]=new_gray[i+1,j]-new_gray[i,j]
        #图像梯度幅值作为图像强度值
        d[i,j]=np.sqrt(np.square(dx[i,j])+np.square(dy[i,j]))
#非极大值抑制NMS
W2,H2=d.shape
NMS=np.copy(d)
NMS[0,:]=NMS[W2-1,:]=NMS[:,0]=NMS[:,H2-1]=0
for i in range(1,W2-1):
    for j in range(1,H2-1):
        if d[i,j]==0:
            NMS[i,j]=0
        else:
            gradX=dx[i,j]
            gradY=dx[i,j]
            gradTemp=d[i,j]
            #如果Y方向梯度幅值较大
            if np.abs(gradY)>np.abs(gradX):
                weight=np.abs(gradX)/np.abs(gradY)
                grad2=d[i-1,j]
                grad4=d[i+1,j]
                #如果x,y方向梯度幅值的符号相同
                if gradX*gradY>0:
                    grad1=d[i-1,j-1]
                    grad3=d[i+1,j+1]
                #如果x,y方向梯度幅值的符号相反
                else:
                    grad1=d[i-1,j+1]
                    grad3=d[i+1,j-1]
            else:
                weight=np.abs(gradY)/np.abs(gradX)
                grad2=d[i,j-1]
                grad4=d[i,j+1]
                if gradX*gradY>0:
                    grad1=d[i+1,j-1]
                    grad3=d[i+1,j+1]
                else:
                    grad1=d[i-1,j-1]
                    grad3=d[i+1,j+1]
            gradTemp1=weight*grad1+(1-weight)*grad2
            gradTemp2=weight*grad3+(1-weight)*grad4
            if gradTemp>=gradTemp1 and gradTemp>=gradTemp2:
                NMS[i,j]=gradTemp
            else:
                NMS[i,j]=0
W3,H3=NMS.shape
DT=np.zeros([W3,H3])
#定义高低阈值TH,TL
TL=0.2*np.max(NMS)
TH=0.3*np.max(NMS)
for i in range(1,W3-1):
    for j in range(1,H3-1):
        if (NMS[i,j]<TL):
            DT[i,j]=0
        elif (NMS[i,j]>TH):
            DT[i,j]=1
        elif ((NMS[i-1,j-1:j+1]<TH).any() or (NMS[i+1,j-1:j+1]).any() or (NMS[i,[j-1,j+1]]<TH).any()):
            DT[i,j]=1
plt.subplot(2,2,1)
plt.imshow(new_gray,cmap=cm.gray) #原始图像
plt.axis('off')
plt.subplot(2,2,2)
plt.imshow(d,cmap=cm.gray)  #高斯滤波图像
plt.axis('off')
plt.subplot(2,2,3)
plt.imshow(NMS,cmap=cm.gray) #非极大值抑制图像
plt.axis('off')
plt.subplot(2,2,4)
plt.imshow(DT,cmap=cm.gray)  #双阈值检测边缘图像
plt.axis('off')
plt.show()

结果展示:
在这里插入图片描述
OpenCV中也封装了Canny图形边缘检测函数,其函数原型:
cv2.Canny(image,threshold1,threshold2[,edges[,apertureSize[,L2gradient]]])
参数说明如下:
(1).image:需要处理的原图,该图像必须为单通道的灰度图像。
(2).threshold1:阈值1。
(3).threshold2:阈值2。(较大的阈值,用于检测明显的边缘,但是会出现断断续续的,所以需要使用threshold2进行连接)。
(4).edges:函数返回一幅二值图像(黑白),其中包含检测出来的边缘。
(5).apertureSize:Sobel算子。
(6).L2gradient:一个布尔值,如果为True,则使用更精确的L2范数进行计算(即两个方向导数的平方和再开方);如果为False,则使用L1范数进行计算(直接将两个方向导数的绝对值)。
基于opencv的Canny函数的图像边缘检测示例代码:

#OPenCV的canny算子
import cv2
import numpy as np
#Canny只能处理灰度图像
img=cv2.imread('D:\Image\\two.jpg',0)
#通过高斯平滑处理对原图像进行降噪
img=cv2.GaussianBlur(img,(3,3),0)
canny=cv2.Canny(img,50,150) #apertureSize默认为3
cv2.imshow('Canny边缘检测',canny)
cv2.waitKey(0)
cv2.destroyAllWindows()

结果展示
在这里插入图片描述
Canny处理:
在这里插入图片描述

* 文末寄语*

本文介绍了图像边缘检测的四大算子,每一种方法都有优缺点,根据实际情况选择与之对应的算子。
新年即将到来,祝愿所有小伙伴新年快乐!万事如意,学业有成!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/169939.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【单链表】数据结构,详解单链表,java实现代码

前言&#xff1a; 大家好&#xff0c;我是良辰丫&#x1f353;&#x1f353;&#x1f353;&#xff0c;今天我和大家一起了解一下数据结构中的链表&#xff0c;链表&#xff0c;顾名思义是用链子把一个个数据串连起了的&#xff0c;那么链表和顺序表又有什么不同呢&#xff1f;…

mysql存储过程基本语法

本文来说下mysql存储过程基本语法 文章目录基本语法使用实例变量的使用变量定义declare语句变量赋值用户变量存储过程的参数in 输入参数out 输出参数inout输入输出参数本文小结基本语法 存储过程就是具有名字的一段代码&#xff0c;用来完成一个特定的功能。创建的存储过程保存…

2022年全球白帽常用工具排行榜TOP 10

虽然此时还未到2022年年底&#xff0c;但并不妨碍我们整理一份2022年全球白帽常用的工具榜单&#xff0c;希望能给白帽们和企业安全人员们带来一定的借鉴和参考。 一方面&#xff0c;工具的重要性不言而喻&#xff0c;各大SRC的白帽们也有深刻的切身体会。一个好用且靠谱的工具…

带模糊加工时间的柔性作业车间调度理论和GA复现(python)

文章目录1.模糊作业车间1.1 模糊数1.2 三角模糊数操作1.3 模糊甘特图2.FJSP模糊加工时间GA2.1 GA算法设置2.2 python代码2.3 测试结果1.模糊作业车间 1.1 模糊数 论域X上的模糊集合A由隶属度函数u(x)表示&#xff0c;u(x)取值[0,1]。如果A为三角模糊数&#xff0c;A可以表示为…

软件测试复习07:软件测试过程

作者&#xff1a;非妃是公主 专栏&#xff1a;《软件测试》 个性签&#xff1a;顺境不惰&#xff0c;逆境不馁&#xff0c;以心制境&#xff0c;万事可成。——曾国藩 文章目录测试计划测试设计测试执行测试监控测试结束软件测试过程主要有5个阶段&#xff1a;测试计划、测试设…

《深入浅出计算机组成原理》学习笔记 Day3

ELF和静态链接1. 程序执行&#xff1a;编译、链接和装载2. ELF 格式和链接3. 总结延伸参考1. 程序执行&#xff1a;编译、链接和装载 有这么两个C文件&#xff1a; \\ add.c int add(int a, int b) {return a b; }\\ test.c #include <stdio.h> int main() {int a 1;…

JVM学习(三):聊聊内存泄漏(memory leak)

一、什么是内存泄漏&#xff08;memory leak&#xff09;可达性分析算法来判断对象是否是不再使用的对象&#xff0c;本质都是判断一个对象是否还被引用。那么对于这种情况下&#xff0c;由于代码的实现不同就会出现很多种内存泄漏问题&#xff08;让JVM误以为此对象还在引用中…

最新光速配置VScode运行C/C++教程(W11适用)

文章目录1.下载MingW编译器&#xff1a;2.解压7z压缩文件方法3.VScode配置4.下面看看成果&#xff1a;1.下载MingW编译器&#xff1a; 下载地址 往下面拖找到上面这个东西-下载最新版本 2.解压7z压缩文件方法 7z解压程序官网 下它&#xff01;相信这个时候在装的一般都是6…

【ubuntu | cuda】ubuntu22.04 安装cuda11.3方法

every blog every motto: You can do more than you think. 0. 前言 ubuntu22.04 安装cuda11.3方法记录 1. 正文 1.1 方法一&#xff1a; https://developer.nvidia.com/cuda-11.3.0-download-archive?target_osLinux&target_archx86_64&DistributionUbuntu&…

服务网格领域的百花齐放,是否存在一个更优解?

作者lingsamuel&#xff0c;API7.ai 云原生技术专家&#xff0c;Apache APISIX Committer。 作者林志煌&#xff0c;API7.ai 技术工程师&#xff0c;Apache APISIX contributor。 服务网格是一种技术架构&#xff0c;它用于管理微服务系统中各个服务之间的通信&#xff0c;旨在…

关于volatile和gcc 优化的的思考

volatile是一个特征修饰符&#xff08;type specifier&#xff09; volatile的作用是作为指令关键字&#xff0c;确保本条指令不会因编译器的优化而省略&#xff0c;且要求每次直接读值。这是百度百科的介绍&#xff0c;那编译器是具体是怎么优化的呢。我们知道gcc 是有O0 O1 O…

torch.nn.MSELoss扒开看看它

目录官网介绍Toy默认参数定制参数预测问题-线性回归官网介绍 Toy 设X,Y∈Rnd\mathbf{X} , \mathbf{Y} \in \mathbf{R}^{n\times d}X,Y∈Rnd&#xff0c;假设其中X\mathbf{X}X是模型的输入&#xff0c;Y\mathbf{Y}Y是真实标签 默认参数 torch.nn.MSELoss(size_averageNone, r…

【Java IO流】字节流详解

文章目录1. IO 流概述2. IO 流分类3. 字节输出流4. 字节输入流5. 文件拷贝6. IO 流中的异常处理7. 总结Java编程基础教程系列1. IO 流概述 什么是 IO 流&#xff1f; IO 流是存取数据的解决方案&#xff0c;在计算机中数据存放在硬盘的文件中&#xff0c;如果程序需要使用这些…

Gitlab 项目上传到Maven仓库

Gitlab 项目上传到Maven仓库Gitlab 项目上传到Maven仓库1. 生成Deploy tokens2.项目工程AS的build.gradle配置Maven3. 拉取Maven库Gitlab 项目上传到Maven仓库 1. 生成Deploy tokens 项目地址-》Settings-》Repository-》Deploy tokens-》Expand-》输入Name-》Create deploy …

回收租赁商城系统功能拆解10讲-会员等级

回收租赁系统适用于物品回收、物品租赁、二手买卖交易等三大场景。 可以快速帮助企业搭建类似闲鱼回收/爱回收/爱租机/人人租等回收租赁商城。 回收租赁系统支持智能评估回收价格&#xff0c;后台调整最终回收价&#xff0c;用户同意回收后系统即刻放款&#xff0c;用户微信零…

数据分析面试题--SQL面试题

目录标题1&#xff0c;UNION和JOIN的区别2&#xff0c;连续登录问题3&#xff0c;窗口函数和普通聚合函数的区别4&#xff0c;窗口函数的基本用法5&#xff0c;序号函数:row_number(),rank(),dense_rank()的区别6&#xff0c;窗口函数涉及的一些其他函数7&#xff0c;次日留存率…

CAD软件中如何标注曲线长度?

在CAD设计过程中&#xff0c;如果想要用CAD标注图纸中某一曲线的长度该如何操作呢&#xff1f;今天小编就来给大家分享一个CAD标注曲线长度的小工具&#xff0c;有需要的小伙伴可以一起来看看哦&#xff01; 此插件可以用多种方式标注多段线、样条曲线的长度&#xff0c;并可以…

Go语言笔记:UDP基础使用与广播

文章目录目的基础说明作为服务器使用作为客户端使用广播总结目的 UDP是比较基础常用的网络通讯方式&#xff0c;这篇文章将介绍Go语言中UDP基础使用的一些内容。 本文中使用 Packet Sender 工具进行测试&#xff0c;其官网地址如下&#xff1a; https://packetsender.com/ 基…

知识站点上关于Notes Domino话题几个问答

大家好&#xff0c;才是真的好。 今天周一我们继续不讲技术&#xff0c;介绍一下知识网站上关于Notes/Domino几个有趣问题的讨论。 国内的知识网站头把交椅是知乎&#xff0c;在中文界中是扛把子.不过在国外&#xff0c;最流行的知识网站叫做Quora&#xff0c;上面关于Notes/…

【Java】【系列篇】【Spring源码解析】【三】【体系】【PostProcessors体系】

PostProcessor英文翻译为后置处理器&#xff0c;在Spring体系里面主要针对的对象为Bean和BeanFactory.有着收尾或完善的作用。一、BeanPostProcessor分支 1.1、作用 在Bean对象在实例化和依赖注入完毕后&#xff0c;在显示调用初始化方法的前后添加我们自己的逻辑。注意是Bean…