图像梯度:
图像梯度是指图像某像素在x和y两个方向上的变化率(与相邻像素比较),是一个二维向量,由2个分量组成X轴的变化、Y轴的变化 。图像梯度可以把图像看成二维离散函数,图像梯度其实就是这个二维离散函数的求导。图像边缘一般都是通过对图像进行梯度运算来实现的。
Sobel算子:
函数:
dst = cv2.Sobel(src, ddepth, dx, dy, ksize)
src:当前图像
ddepth:图像的深度,一般是-1
dx:水平方向
dy:竖直方向
ksize:是Sobel算子的大小
计算水平方向的:
import cv2 #opencv读取的格式是BGR
def cv_show(img,name):
cv2.imshow(name,img)
cv2.waitKey()
cv2.destroyAllWindows()
img = cv2.imread('D:\pie.png')
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
#cv2.CV_64F:图像中超出255的或者小于0的像素点不会被截断,而是保留
sobelx = cv2.convertScaleAbs(sobelx)
#白到黑是正数,黑到白就是负数了,所有的负数会被截断成0,所以要取绝对值
cv_show(sobelx,'sobelx')
sobelx = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
import cv2 #opencv读取的格式是BGR
def cv_show(img,name):
cv2.imshow(name,img)
cv2.waitKey()
cv2.destroyAllWindows()
img = cv2.imread('D:\pie.png')
sobelx = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
sobely = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
#cv2.CV_64F:图像中超出255的或者小于0的像素点不会被截断,而是保留
sobelx = cv2.convertScaleAbs(sobelx)
sobely = cv2.convertScaleAbs(sobely)
#白到黑是正数,黑到白就是负数了,所有的负数会被截断成0,所以要取绝对值
sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0)
#sobelx为水平方向,sobely为垂直方向,0.5权重,0是偏置项
cv_show(sobelxy,'sobelxy')
效果:
上述的处理可以同时进行两个方向的处理,当需要突出图像某一个方向的边缘信息时,也可以只进行其中一个方向的处理。不建议直接计算,分开计算的效果更好。
Scharr算子
可以看出Scharr算子核的数值要比Sobel算子要大,所以Scharr算子是对Sobel算子差异性的增强,但是Scharr算子仅作用与大小为3的内核,因此两者之间的在检测图像边缘的原理和使用方式上相同。
laplacian算子
Laplacian算子根据图像处理的原理,二阶导数可以用来进行边缘检测,因为图像是二维的,需要在两个方向上求导,使用Laplacian算子将会使求导过程变得简单。Laplacian算子对噪音点比较敏感,通常要和其它方法一起使用。
不同算子的效果:
import cv2 #opencv读取的格式是BGR
import numpy as np
import matplotlib.pyplot as plt#Matplotlib是RGB
def cv_show(img,name):
cv2.imshow(name,img)
cv2.waitKey()
cv2.destroyAllWindows()
#不同算子的差异
img = cv2.imread('D:/cat2.jpg',cv2.IMREAD_GRAYSCALE)
#sobel算子
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
sobelx = cv2.convertScaleAbs(sobelx)
sobely = cv2.convertScaleAbs(sobely)
sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0)
#Scharr算子
#Scharr算子不需要设置核的大小,默认大小为3
scharrx = cv2.Scharr(img,cv2.CV_64F,1,0)
scharry = cv2.Scharr(img,cv2.CV_64F,0,1)
scharrx = cv2.convertScaleAbs(scharrx)
scharry = cv2.convertScaleAbs(scharry)
scharrxy = cv2.addWeighted(scharrx,0.5,scharry,0.5,0)
#laplacian算子
#laplacian算子是中间的点和周围的点的比较,所以不需要考虑水平和垂直的问题
laplacian = cv2.Laplacian(img,cv2.CV_64F)
laplacian = cv2.convertScaleAbs(laplacian)
res = np.hstack((img,sobelxy,scharrxy,laplacian))
cv_show(res,'res')
效果:
Canny边缘检测算法是John F. Canny于 1986 年开发出来的一个多级边缘检测算法。
Canny边缘检测步骤:
import cv2 #opencv读取的格式是BGR
import numpy as np
import matplotlib.pyplot as plt#Matplotlib是RGB
def cv_show(img,name):
cv2.imshow(name,img)
cv2.waitKey()
cv2.destroyAllWindows()
img = cv2.imread('D:/cat.jpg',cv2.IMREAD_GRAYSCALE)
v1=cv2.Canny(img,150,200)
v2=cv2.Canny(img,50,100)
res = np.hstack((v1,v2))
cv_show(res,'res')
图像金字塔是图像多尺度表达的一种,是一种以多分辨率来解释图像的有效但概念简单的结构。一幅图像的图像金字塔是一系列以金字塔形状(自下而上)逐步降低,且来源于同一张原始图的图像分辨率集合。其通过梯次向下采样获得,直到达到某个终止条件才停止采样。我们将一层一层的图像比喻成金字塔,层级越高,则图像越小,分辨率越低。图像金字塔可以用与不同层时的特征提取,每层的特征不一样,起到的效果也不一样。
高斯金字塔
高斯金字塔:向下采样方法(缩小)
import cv2 #opencv读取的格式是BGR
import numpy as np
def cv_show(img,name):
cv2.imshow(name,img)
cv2.waitKey()
cv2.destroyAllWindows()
img = cv2.imread('D:/cat2.jpg')
up=cv2.pyrUp(img)#放大
img2=cv2.pyrDown(up)#缩小
res=np.hstack((img,img2))
cv_show(res,'comp')
原始图像相比于先放大后缩小的图像要清晰,因为在放大和缩小的过程中都会有损失,效果:
拉普拉斯金字塔
import cv2 #opencv读取的格式是BGR
def cv_show(img,name):
cv2.imshow(name,img)
cv2.waitKey()
cv2.destroyAllWindows()
img = cv2.imread('D:/cat2.jpg')
down = cv2.pyrDown(img)
down_up = cv2.pyrUp(down)
l_1 = img - down_up
cv_show(l_1,'11')
cv2.findContours(img,mode,method)
参数说明:
img:输入图像
mode:轮廓检索模式
1.RETR_EXTERNAL :只检索最外面的轮廓;
2.RETR_LIST:检索所有的轮廓,并将其保存到一条链表当中;
3.RETR_CCOMP:检索所有的轮廓,并将他们组织为两层:顶层是各部分的外部边界,第二层是空洞的边界;
4.RETR_TREE:检索所有的轮廓,并重构嵌套轮廓的整个层次;
method:轮廓逼近方法
1.CHAIN_APPROX_NONE:以Freeman链码的方式输出轮廓,所有其他方法输出多边形(顶点的序列)。
2.CHAIN_APPROX_SIMPLE:压缩水平的、垂直的和斜的部分,也就是,函数只保留他们的终点部分。
import cv2 #opencv读取的格式是BGR
import numpy as np
def cv_show(img,name):
cv2.imshow(name,img)
cv2.waitKey()
cv2.destroyAllWindows()
#使用二值图像。
img = cv2.imread('D:/cat.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#设置图像阈值,超过阈值部分取maxval(最大值),否则取0
ret, thresh = cv2.threshold(gray, 100, 255, cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
'''
检测函数,thresh:输入的二值图像
binary:前面处理的二值图像
contours:轮廓点
hierarchy:层级
'''
draw_img = img.copy()
res = cv2.drawContours(draw_img, contours, -1, (0, 0, 255), 2)
'''
#1是显示所以轮廓,1是显示第1个轮廓,2是显示第二个轮廓
(0, 0, 255)轮廓颜色,BGR格式
2是轮廓的大小
'''
cv_show(res,'res')
contours[5]表示第五个轮廓
cnt = contours[5]
#面积
area=cv2.contourArea(cnt)
print(area)
#周长,True表示闭合的,False表示不闭合
Perimeter=cv2.arcLength(cnt,True)
print(Perimeter)
轮廓近似通俗地说,我们采用一条曲线并减少其顶点数量,同时保留其大部分形状。
在轮廓近似前需要指定需要近似的轮廓,这里是contours[2],epsilon = value*cv2.arcLength(cnt,True)中value值越大近似效果越强,过大则近似为一点。
import cv2 #opencv读取的格式是BGR
import numpy as np
def cv_show(img,name):
cv2.imshow(name,img)
cv2.waitKey()
cv2.destroyAllWindows()
#使用二值图像。
img = cv2.imread('D:/mouse.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#设置图像阈值,超过阈值部分取maxval(最大值),否则取0
ret, thresh = cv2.threshold(gray, 100, 255, cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
cnt = contours[2]
draw_img = img.copy()
res1 = cv2.drawContours(draw_img, [cnt], -1, (0, 0, 255), 2)
draw_img2 = img.copy()
epsilon = 0.01*cv2.arcLength(cnt,True)
#轮廓近似
approx = cv2.approxPolyDP(cnt,epsilon,True)
res2 = cv2.drawContours(draw_img2, [approx], -1, (255, 0, 0), 2)
res = np.hstack((res1,res2))
cv_show(res,'res')
cv2.boundingRect(cnt)返回当前轮廓的边界框中心点的xy坐标和图片的宽度和高度,也就是x,y,w,h。
import cv2 #opencv读取的格式是BGR
import numpy as np
def cv_show(img,name):
cv2.imshow(name,img)
cv2.waitKey()
cv2.destroyAllWindows()
#使用二值图像。
img = cv2.imread('D:/mouse.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#设置图像阈值,超过阈值部分取maxval(最大值),否则取0
ret, thresh = cv2.threshold(gray, 100, 255, cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
cnt = contours[2]
x,y,w,h = cv2.boundingRect(cnt)
img = cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
cv_show(img,'img')
import cv2 #opencv读取的格式是BGR
import numpy as np
def cv_show(img,name):
cv2.imshow(name,img)
cv2.waitKey()
cv2.destroyAllWindows()
#使用二值图像。
img = cv2.imread('D:/contours.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#设置图像阈值,超过阈值部分取maxval(最大值),否则取0
ret, thresh = cv2.threshold(gray, 100, 255, cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
cnt = contours[2]
(x,y),radius = cv2.minEnclosingCircle(cnt)
center = (int(x),int(y))
radius = int(radius)
img = cv2.circle(img,center,radius,(0,255,0),2)
cv_show(img,'img')