图像的边缘是指图像中灰度值发生急剧变化的位置,边缘检测的目的是为了绘制出边缘线条。边缘通常是不连续的,不能表示整体。图像轮廓是指将边缘连接起来形成的整体。
Laplacian边缘检测使用图像矩阵与拉普拉斯核进行卷积运算, 其本质是计算图像中任意一点与其在水平方向和垂直方向上4个相邻点平均值的差值。
cv2.Laplacian()函数用于实现Laplacian边缘检测,基本格式如下。
dst=cv2.Laplacian(src,depth[,kszie[,scale[,delta[,borderType]]]])
参数说明如下。
dst表示边缘检测后结果图像
src为原图像
ddepth为目标图像的深度
ksize为用于计算二阶导数滤波器的系数,必须为正数且是奇数
scale为可选比例因子
delta可添加到边缘检测结果中的可选增量值
borderType为边界值类型
import cv2
img=cv2.imread('D:\zhangjing\photo\hua.png',cv2.IMREAD_REDUCED_COLOR_2)
cv2.imshow('original',img)
'''
Laplacian边缘检测
dst=cv2.Laplacian(src,depth[,kszie[,scale[,delta[,borderType]]]])
dst表示边缘检测后结果图像
src为原图像
ddepth为目标图像的深度
ksize为用于计算二阶导数滤波器的系数,必须为正数且是奇数
scale为可选比例因子
delta可添加到边缘检测结果中的可选增量值
borderType为边界值类型
'''
img2=cv2.Laplacian(img,cv2.CV_8U)#拉普拉斯边缘检测
cv2.imshow('Laplacian',img2)
cv2.waitKey(0)
|
|
Sobel边缘检测将高斯滤波和微分结合起来进行图像卷积运算,结果具有一定的抗噪性。
dst=cv2.sobel(src,depth,dx,dy[,kszie[,scale[,delta[,borderType]]]])
dx为导数x的阶数
dy为导数y的阶数
ksize为扩展的Sobel内核的大小,必须是1、3、5、7
import cv2
img=cv2.imread('D:\zhangjing\photo\hua.png',cv2.IMREAD_REDUCED_COLOR_2)
cv2.imshow('original',img)
'''
Laplacian边缘检测
dst=cv2.Laplacian(src,depth[,kszie[,scale[,delta[,borderType]]]])
dst表示边缘检测后结果图像
src为原图像
ddepth为目标图像的深度
ksize为用于计算二阶导数滤波器的系数,必须为正数且是奇数
scale为可选比例因子
delta可添加到边缘检测结果中的可选增量值
borderType为边界值类型
'''
img3=cv2.Sobel(img,cv2.CV_8U,0,1)#Sobel边缘检测
cv2.imshow('Sobel',img3)
cv2.waitKey(0)
|
|
Canny边缘检测的算法包括下列5个步骤。
cv2.Canny()函数用于实现Canny边缘检测,其基本格式如下。
dst=cv2.Canny(src,threshold1,threshold2[,apertureSize[,L2gradient]])
参数说明如下。
threshold1为第一阈值
threshold2为第二阈值
apertureSize为计算梯度时使用的Sobel核大小
L2gradient为标志
import cv2
img=cv2.imread('D:\zhangjing\photo\hua.png',cv2.IMREAD_REDUCED_COLOR_2)
cv2.imshow('original',img)
'''
Laplacian边缘检测
dst=cv2.Laplacian(src,depth[,kszie[,scale[,delta[,borderType]]]])
dst表示边缘检测后结果图像
src为原图像
ddepth为目标图像的深度
ksize为用于计算二阶导数滤波器的系数,必须为正数且是奇数
scale为可选比例因子
delta可添加到边缘检测结果中的可选增量值
borderType为边界值类型
'''
img4=cv2.Canny(img,200,300)#Canny边缘检测
cv2.imshow('Canny',img4)
cv2.waitKey(0)
|
|
Laplacian算子法对噪声比较敏感,所以很少用该算子检测边缘,而是用来判断边缘像素视为与图像的明区还是暗区。拉普拉斯高斯算子是一种二阶导数算子,将在边缘处产生一个陡峭的零交叉,Laplacian算子是各向同性的,能对任何走向的界线和线条进行锐化,无方向性。这是拉普拉斯算子区别于其他算法的最大优点。
Sobel算子检测方法对灰度渐变和噪声较多的图像处理效果较好,sobel算子对边缘定位不是很准确,图像的边缘不止一个像素;当对精度要求不是很高时,是一种较为常用的边缘检测方法。
Canny方法不容易受噪声干扰,能够检测到真正的弱边缘。优点在于,使用两种不同的阈值分别检测强边缘和弱边缘,并且当弱边缘和强边缘相连时,才将弱边缘包含在输出图像中。
图像轮廓是指由位于边缘、连续的、具有相同颜色和强度的点构成的曲线,它可用于形状分析以及对象检测和识别。
cv2.findContours()函数用于从二值图像中查找图像轮廓,其基本格式如下。
contours,hierarchy=cv2.findContours(image,mode,method[,offset])
参数说明如下。
contours为返回的轮廓
hierarchy为返回的轮廓的层次结构
image为原图像
mode为轮廓的检索模式
method为轮廓的近似方法
offset为每个轮廓点的可选偏移量
#查找轮廓
import cv2
import numpy as np
img=cv2.imread('D:\zhangjing\photo\shape.png')#读取图像
cv2.imshow('original',img)#显示原图像
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#将其转换为灰度图像
ret,img2=cv2.threshold(gray,125,255,cv2.THRESH_BINARY)#二值化阈值处理
c,h=cv2.findContours(img2,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)#查找轮廓
'''
contours,hierarchy=cv2.findContours(image,mode,method[,offset])
contours为返回的轮廓
hierarchy为返回的轮廓的层次结构
image为原图像
mode为轮廓的检索模式
method为轮廓的近似方法
offset为每个轮廓点的可选偏移量
'''
print('轮廓',c)
print('轮廓类型',type(c))
print('伦廓个数',len(c))
print('层次',h)
print('层次类型',type(h))
for n in range((3)):
img3=np.zeros(img.shape,np.uint8)+255#按原图大小创建一幅白色图像
cv2.polylines(img3,[c[n]],True,(255,0,0),2)#绘制轮廓
cv2.imshow('%s'%n,img3)#显示轮廓图像
cv2.waitKey(0)
cv2.destroyAllWindows()
1.轮廓的矩
轮廓的矩包含了轮廓的各种几何特征,如面积、位置、角度、形状等。
cv2.moments()函数用于返回轮廓的矩,其基本格式如下。
ret=cv2.moments(array[,binaryImage])
参数说明如下。
ret为返回的轮廓矩,是一个字典对象
array为表示轮廓的数组
binaryimage值为true时,会将array对象中所有非0值设为1
#轮廓的矩
import cv2
import numpy as np
img=cv2.imread('D:\photo\shapes.png')
cv2.imshow('original',img)
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#将其转换为灰度图像
ret,img2=cv2.threshold(gray,125,255,cv2.THRESH_BINARY)#二值化阈值处理
c,h=cv2.findContours(img2,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)#查找轮廓
img3=np.zeros(img.shape,np.uint8)+255#按原图大小创建一副白色图像
img3=cv2.drawContours(img3,c,-1,(0,0,255),2)
cv2.imshow('Contours',img3)
for n in range(len(c)):
m=cv2.moments(c[n])
'''
ret=cv2.moments(array[,binaryImage])
ret为返回的轮廓矩,是一个字典对象
array为表示轮廓的数组
binaryimage值为true时,会将array对象中所有非0值设为1
'''
print('轮廓%s的矩:'%n,m)
print('轮廓%s的面积:'%n,m['m00'])
cv2.waitKey(0)
cv2.destroyAllWindows()
运行结果
2.轮廓的面积
cv2.contourArea()函数用于返回轮廓面积,其基本格式如下。
ret=cv2.contourArea(contour[,oriented]
参数说明如下。
ret为返回的面积
contour为轮廓
oriented为可选参数,其参数值为True时,返回值的正与负表示轮廓是顺指针还是逆时针;参数值为False时,函数返回值为绝对值
#轮廓的面积
import cv2
import numpy as np
img=cv2.imread('D:\photo\shapes.png')
cv2.imshow('original',img)
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#将其转换为灰度图像
ret,img2=cv2.threshold(gray,125,255,cv2.THRESH_BINARY)#二值化阈值处理
c,h=cv2.findContours(img2,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)#查找轮廓
img3=np.zeros(img.shape,np.uint8)+255#按原图大小创建一副白色图像
img3=cv2.drawContours(img3,c,-1,(0,0,255),2)
cv2.imshow('Contours',img3)
for n in range(len(c)):
m=cv2.contourArea(c[n])
'''
ret=cv2.contourArea(contour[,oriented]
ret为返回的面积
contour为轮廓
oriented为可选参数,其参数值为True时,返回值的正与负表示轮廓是顺指针还是逆时针;参数值为False时,函数返回值为绝对值
'''
print('轮廓%s的面积'%n,m)
cv2.waitKey(0)
cv2.destroyAllWindows()
3.轮廓的长度
cv2.arcLength()函数用于返回轮廓的长度,其基本格式如下。
ret=cv2.arcLength(contour,closed)
ret为返回的长度
contour为轮廓
closed为布尔值,为True时表示轮廓是封闭的
#轮廓的长度
import cv2
import numpy as np
img=cv2.imread('D:\photo\shapes.png')
cv2.imshow('original',img)
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#将其转换为灰度图像
ret,img2=cv2.threshold(gray,125,255,cv2.THRESH_BINARY)#二值化阈值处理
c,h=cv2.findContours(img2,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)#查找轮廓
img3=np.zeros(img.shape,np.uint8)+255#按原图大小创建一副白色图像
img3=cv2.drawContours(img3,c,-1,(0,0,255),2)
cv2.imshow('Contours',img3)
for n in range(len(c)):
m=cv2.arcLength(c[n],True)
'''
ret=cv2.arcLength(contour,closed)
ret为返回的长度
contour为轮廓
closed为布尔值,为True时表示轮廓是封闭的
'''
print('轮廓%s的长度:'%n,m)
cv2.waitKey(0)
cv2.destroyAllWindows()
4.轮廓的近似多边形
cv2.approxPolyDP()函数用于返回轮廓的近似多边形,其基本格式如下。
ret=cv2.approxPolyDP(contour,epsilon,closed)
ret为返回的近似多边形
contour为轮廓
epsilon为精度,表示近似多边形接近轮廓的最大距离
closed为布尔值,为True时表示轮廓是封闭的
轮廓的近似多边形
import cv2
import numpy as np
img=cv2.imread('D:\photo\shape3.png')
cv2.imshow('original',img)
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#将其转换为灰度图像
ret,img2=cv2.threshold(gray,125,255,cv2.THRESH_BINARY)#二值化阈值处理
c,h=cv2.findContours(img2,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)#查找轮廓
ep=[0.1,0.05,0.01]
arc1=cv2.arcLength(c[0],True)
print(arc1)
img3=np.zeros(img.shape,np.uint8)+255
img3=cv2.drawContours(img3,c,-1,(0,0,255),2)
for n in range(3):
eps=ep[n]*arc1
img4=img3.copy()
app=cv2.approxPolyDP(c[0],eps,True)
'''
ret=cv2.approxPolyDP(contour,epsilon,closed)
ret为返回的近似多边形
contour为轮廓
epsilon为精度,表示近似多边形接近轮廓的最大距离
closed为布尔值,为True时表示轮廓是封闭的
'''
img4=cv2.drawContours(img4,[app],-1,(255,0,0),2)
cv2.imshow('appro%.2f'%ep[n],img4)
cv2.waitKey(0)
cv2.destroyAllWindows()
5.轮廓的凸包
cv2.convexHull()函数用于返回轮廓的凸包,其基本格式如下。
cv2.convexHull(contour[,clockwise[,returnPoints]]])
参数说明如下。
hull为返回的凸包,是一个numpy.ndaarray对象,包含了凸包的关键点。
contour为轮廓。
clockwise为方向标记,为True时,凸包为顺时针方向;为False时,凸包为逆时针方向。
returnPoints为True时,返回的hull中包含的是凸包关键点的坐标;为False时,返回的是凸包关键点在轮廓中的索引。
6.轮廓的直边界矩形
cv2.boundingRect()函数用于返回轮廓的直边界矩形,其基本格式如下。
ret=cv2.boundingRect(contour)
ret返回的直边界矩形,是一个四元组,其格式为(矩形左上角x坐标,矩形左上角y坐标,矩形的宽度,矩形的高度)
contour为用于计算直边界矩形的轮廓
7.轮廓的旋转矩形
轮廓的旋转矩形是指可容纳轮廓的最小的矩形。cv2.minAreaRect()函数用于返回轮廓的旋转矩形,其基本格式如下。
box=cv2.minAreaRect(contour)
8.轮廓的最小外包圆
cv2.minEnclosingCircle()函数用于可返回轮廓的最小外包圆,其基本格式如下。
center,radius=cv2.minEnclosingCircle(contour)
参数说明如下。
center为圆心。
radius为半径。
contour为用于计算最小外包圆的轮廓。
9.轮廓的拟合椭圆
cv2.fitEllipse()函数用于返回轮廓的拟合椭圆,其基本格式如下。
ellipse=cv2.fitEllipse(contour)
参数说明如下。
ellipse为返回的椭圆。
contour为计算拟合椭圆的轮廓
10.轮廓的拟合直线
cv2.fitLine()函数用于返回轮廓的拟合直线,其基本格式如下。
line=cv2.fitLine(contour,distType,param,reps,aeps)
参数说明如下。
line为返回的拟合直线。
contour为用于计算拟合直线的轮廓。
distType为距离类型参数。
param为距离参数,与距离类型参数有关,其设置为0时,函数将自动选择最优值。
reps为计算拟合直线需要的径向精度,通常为0.01。
aeps为计算拟合直线需要的角度精度,通常为0.01。
11.轮廓的最小外包三角形
cv2.minEnclosingTriangle()函数用于可返回可容纳轮廓的最小外包三角形,其基本格式如下。
参数说明如下。
retval,triangle=cv2.minEnclosingTriangle(contour)
retval为最小外包三角形的面积。
triangle为最小外包三角形。
contour为用于计算最小外包三角形的轮廓。
霍夫变换用于在图像中查找直线和圆等形状。
cv2.HoughLines()函数利用霍夫变换算法检测图像中的直线,其基本格式如下。
lines=cv2.HoughLines(image,rho,theta,threshold)
image为原图像
rho为距离的精度
theta为角度的精度
threshold为阈值,值越小,检测出的直线就越多
#霍夫直线
import cv2
import numpy as np
img=cv2.imread('D:\zhangjing\photo\shape3.jfif')
cv2.imshow('original',img)
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
edges=cv2.Canny(gray,50,150,apertureSize=3)#执行边缘检测
lines=cv2.HoughLines(edges,1,np.pi/180,150)#霍夫直线变换
'''
lines=cv2.HoughLines(image,rho,theta,threshold)
image为原图像
rho为距离的精度
theta为角度的精度
threshold为阈值,值越小,检测出的直线就越多
'''
img3=img.copy()
for line in lines:#逐条绘制直线
rho,theta=line[0]
print()
a=np.cos(theta)
b=np.sin(theta)
x0,y0=a*rho,b*rho
pt1=(int(x0+1000*(-b)),int(y0+1000*(a)))#计算直线端点
pt2=(int(x0-1000*(-b)),int(y0-1000*(a)))#计算直线端点
cv2.line(img3,pt1,pt2,(0,0,255),2)#绘制直线
cv2.imshow('HoughLines',img3)#显示结果图像
cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.HoughLinesP()函数利用霍夫变换算法检测图像中的直线,其基本格式如下。
lines=cv2.HoughLinesP(image,rho,theta,threshold[,minLineLength[,maxLineGap]])
minLineLength为可接受的直线最小长度,默认为0
maxLineGap为共线线段之间的最大间隔,默认为0
概率霍夫直线
import cv2
import numpy as np
img=cv2.imread('D:\zhangjing\photo\shape3.jfif')
cv2.imshow('original',img)
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
edges=cv2.Canny(gray,50,150,apertureSize=3)
lines=cv2.HoughLinesP(edges,1,np.pi/180,1,minLineLength=100,maxLineGap=10)
'''
lines=cv2.HoughLinesP(image,rho,theta,threshold[,minLineLength[,maxLineGap]])
minLineLength为可接受的直线最小长度,默认为0
maxLineGap为共线线段之间的最大间隔,默认为0
'''
img3=img.copy()
for line in lines:
x1,y1,x2,y2=line[0]
cv2.line(img3,(x1,y1),(x2,y2),(0,0,255),2)
cv2.imshow('HoughLines',img3)
cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.HoughCircles()函数利用霍夫变换查找图像中的圆,其基本格式如下。
circles=cv2.HoughCircles(image,method,dp,mindist[param1[,param2[,minRadius[,maxRadius]]]])
method为查找方法,可设置为cv2.HOUGH_GRADIENT和cv2.HOUGH_GRADIENT_ALT。
dp为累加器分辨率,它与图像分辨率成反比。
minDist为圆心间的最小距离。
param1为对应Canny边缘检测的高阈值,默认值为100。
param2为圆心位置必须到达达到的投票数,值越大,检测出的圆越少,默认值为100。
minRadius为最小圆半径,半径小于该值的圆不会被检测出来。
maxRadius为最大圆半径,半径大于该值的圆不会被检测出来。
# 霍夫圆
import cv2
import numpy as np
img=cv2.imread('D:\zhangjing\photo\shape3.jfif')
cv2.imshow('original',img)
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
edges=cv2.Canny(gray,50,150,apertureSize=3)
circles=cv2.HoughCircles(edges,cv2.HOUGH_GRADIENT,1,50,param2=30,minRadius=10,maxRadius=40)
circles=np.uint16(np.around(circles))
img2=img.copy()
for i in circles[0,:]:
cv2.circle(img2,(i[0],i[1]),i[2],(255,0,0),2)
cv2.circle(img2,(i[0],i[1]),2,(0,0,255),3)
cv2.imshow('circle',img2)
cv2.waitKey(0)
cv2.destroyAllWindows()