Opencv学习笔记——图像处理(二)


一、图像梯度-Sobel算子

图像梯度
图像梯度是指图像某像素在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算子、laplacian算子

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')

效果:
在这里插入图片描述

扫描二维码关注公众号,回复: 15580802 查看本文章

三、Canny边缘检测

Canny边缘检测算法是John F. Canny于 1986 年开发出来的一个多级边缘检测算法。
Canny边缘检测步骤:

  1. 使用高斯滤波器,以平滑图像,滤除噪声。
  2. 计算图像中每个像素点的梯度强度和方向。
  3. 应用非极大值(Non-Maximum Suppression)抑制,以消除边缘检测带来的杂散响应。
  4. 应用双阈值(Double-Threshold)检测来确定真实的和潜在的边缘。
    高斯滤波
    用高斯滤波去除掉图像中的噪音点。
    在这里插入图片描述
    梯度和方向
    计算梯度的大小和方向,用的是sobel算子
    在这里插入图片描述
    非极大值抑制
    用一个核逐一遍历像素点,判断当前像素点是否是周围像素点中具有相同梯度方向的最大值,并根据判断结果决定是否抑制该点。也就是把一下小的梯度值去掉,保留大的梯度值。
    在这里插入图片描述
    在这里插入图片描述
    双阈值检测
    设定一个小的梯度值minval和一个大的梯度值minval,小于minval的梯度值舍弃掉,大于maxval的则保留,大于minval小于maxval的如果连接有大于maxval的认为它是边界则保留,如果没有则舍弃。
    在这里插入图片描述
    代码:
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:压缩水平的、垂直的和斜的部分,也就是,函数只保留他们的终点部分。

1.绘制轮廓

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')

效果:
在这里插入图片描述

2.轮廓特征

contours[5]表示第五个轮廓

cnt = contours[5]
#面积
area=cv2.contourArea(cnt)
print(area)
#周长,True表示闭合的,False表示不闭合
Perimeter=cv2.arcLength(cnt,True)
print(Perimeter)

3.轮廓近似

轮廓近似通俗地说,我们采用一条曲线并减少其顶点数量,同时保留其大部分形状。
在轮廓近似前需要指定需要近似的轮廓,这里是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')

效果:
在这里插入图片描述

4.边界矩形

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')

效果:
在这里插入图片描述

5.外接圆

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')

效果:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Thousand_drive/article/details/124572612