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

文章目录

  • 一、图像梯度-Sobel算子
  • 二、图像梯度-Scharr算子、laplacian算子
  • 三、Canny边缘检测
  • 四、图像金字塔
  • 五、图像轮廓
    • 1.绘制轮廓
    • 2.轮廓特征
    • 3.轮廓近似
    • 4.边界矩形
    • 5.外接圆


一、图像梯度-Sobel算子

图像梯度
图像梯度是指图像某像素在x和y两个方向上的变化率(与相邻像素比较),是一个二维向量,由2个分量组成X轴的变化、Y轴的变化 。图像梯度可以把图像看成二维离散函数,图像梯度其实就是这个二维离散函数的求导。图像边缘一般都是通过对图像进行梯度运算来实现的。
Sobel算子
Opencv学习笔记——图像处理(二)_第1张图片
函数:

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

效果:
Opencv学习笔记——图像处理(二)_第2张图片
计算垂直方向的,修改上面代码中的:

sobelx = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)

效果:Opencv学习笔记——图像处理(二)_第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')

效果:
Opencv学习笔记——图像处理(二)_第4张图片
上述的处理可以同时进行两个方向的处理,当需要突出图像某一个方向的边缘信息时,也可以只进行其中一个方向的处理。不建议直接计算,分开计算的效果更好。

二、图像梯度-Scharr算子、laplacian算子

Scharr算子
Opencv学习笔记——图像处理(二)_第5张图片
可以看出Scharr算子核的数值要比Sobel算子要大,所以Scharr算子是对Sobel算子差异性的增强,但是Scharr算子仅作用与大小为3的内核,因此两者之间的在检测图像边缘的原理和使用方式上相同。
laplacian算子
Opencv学习笔记——图像处理(二)_第6张图片
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边缘检测

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

  1. 使用高斯滤波器,以平滑图像,滤除噪声。
  2. 计算图像中每个像素点的梯度强度和方向。
  3. 应用非极大值(Non-Maximum Suppression)抑制,以消除边缘检测带来的杂散响应。
  4. 应用双阈值(Double-Threshold)检测来确定真实的和潜在的边缘。
    高斯滤波
    用高斯滤波去除掉图像中的噪音点。
    Opencv学习笔记——图像处理(二)_第7张图片
    梯度和方向
    计算梯度的大小和方向,用的是sobel算子
    Opencv学习笔记——图像处理(二)_第8张图片
    非极大值抑制
    用一个核逐一遍历像素点,判断当前像素点是否是周围像素点中具有相同梯度方向的最大值,并根据判断结果决定是否抑制该点。也就是把一下小的梯度值去掉,保留大的梯度值。
    Opencv学习笔记——图像处理(二)_第9张图片
    Opencv学习笔记——图像处理(二)_第10张图片
    双阈值检测
    设定一个小的梯度值minval和一个大的梯度值minval,小于minval的梯度值舍弃掉,大于maxval的则保留,大于minval小于maxval的如果连接有大于maxval的认为它是边界则保留,如果没有则舍弃。
    Opencv学习笔记——图像处理(二)_第11张图片
    代码:
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')

效果(左边是梯度值大,右边是梯度值小):
Opencv学习笔记——图像处理(二)_第12张图片

四、图像金字塔

图像金字塔是图像多尺度表达的一种,是一种以多分辨率来解释图像的有效但概念简单的结构。一幅图像的图像金字塔是一系列以金字塔形状(自下而上)逐步降低,且来源于同一张原始图的图像分辨率集合。其通过梯次向下采样获得,直到达到某个终止条件才停止采样。我们将一层一层的图像比喻成金字塔,层级越高,则图像越小,分辨率越低。图像金字塔可以用与不同层时的特征提取,每层的特征不一样,起到的效果也不一样。
Opencv学习笔记——图像处理(二)_第13张图片
高斯金字塔
高斯金字塔:向下采样方法(缩小)
Opencv学习笔记——图像处理(二)_第14张图片

高斯金字塔:向上采样方法(放大)
Opencv学习笔记——图像处理(二)_第15张图片

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

原始图像相比于先放大后缩小的图像要清晰,因为在放大和缩小的过程中都会有损失,效果:
Opencv学习笔记——图像处理(二)_第16张图片
拉普拉斯金字塔

拉普拉斯金字塔每层都是用输入减去缩小后放大的图像Opencv学习笔记——图像处理(二)_第17张图片

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

效果:
Opencv学习笔记——图像处理(二)_第18张图片

五、图像轮廓

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

效果:
Opencv学习笔记——图像处理(二)_第19张图片

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

效果:
Opencv学习笔记——图像处理(二)_第20张图片

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

效果:
Opencv学习笔记——图像处理(二)_第21张图片

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

效果:
Opencv学习笔记——图像处理(二)_第22张图片

你可能感兴趣的:(Opencv学习笔记,opencv,图像处理,计算机视觉)