OpenCV 8~10
8 图像梯度
各种算子
'''
# 1 Prewitt算子
-1 -1 -1
0 0 0
1 1 1
-1 0 1
-1 0 1
-1 0 1
# 2 Roberts算子
-1 0
0 1
0 -1
1 0
# 3 Sobel-Feldman算子
-1 -1 -1
-2 0 2
-1 0 1
-1 -2 -1
0 0 0
1 2 1
# 4 Scharr算子
-3 -1 3
-10 0 10
-3 0 3
-3 -10 -3
0 0 0
3 10 3
# 5 Laplacian算子
0 1 0
1 -4 1
0 1 0
0 -1 0
-1 4 -1
0 -1 0
1 1 1
1 -8 1
1 1 1
-1 -1 -1
-1 8 -1
-1 -1 -1
# 6 LoG算子
1. 高斯模糊图像
2. Laplacian二阶梯度
'''
8.1 Prewitt、Roberts算子
# 1 Prewitt算子
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('')
kx = np.array([[1, 1, 1], [0, 0, 0], [-1, -1, -1]], dtype=np.float32)
ky = np.array([[-1,0, 1], [-1,0, 1], [-1, 0, 1]], dtype=np.float32)
imgx = cv2.filter2D(img, cv.CV_16S, kx)
imgy = cv2.filter2D(img, cv.CV_16S, ky)
absX = cv2.convertScaleAbs(imgx)
absY = cv2.convertScaleAbs(imgy)
img_prewitt = cv2.add(absX, absY) # np.uint8
plt.imshow(img_prewitt)
# 2 Roberts算子
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('')
kx = np.array([[-1, 0], [0, 1]], dtype=np.float32)
ky = np.array([[0, -1], [1, 0]], dtype=np.float32)
imgx = np.abs(cv.filter2D(img, cv.CV_16S, kx))
imgy = np.abs(cv.filter2D(img, cv.CV_16S, ky))
img_robert = cv.convertScaleAbs(np.abs(imgx) + np.abs(imgy))
plt.imshow(img_robert)
8.2 sobel理论基础
sobel算子计算不同方向的梯度
a1 a2 a3
a4 a5 a6
a7 a8 a9
# 水平方向梯度
a5 = (a3-a1)+2(a6-a4)+(a9-a7)
# 垂直方向梯度,如果a5很大,说明a5是边界
a5 = (a1-a7)+2(a2-a8)+(a3-a9)
# 近似剃度
G = np.sqrt(G_x^2+G_y^2) or G = np.abs(G_x) + np.abs(G_y)
8.3 sobel算子及函数
- dst = cv2.Sobel(img,ddepth,dx,dy,[ksize])
- ddepth = -1 or cv2.CV_64F( 保留负数的值 ) ,表示处理结果与原图相一致
- dst = cv2.convertScaleAbs(img,[,alpha[,beta]]) 将原始图片转换成256色位图。
- dx=0,dy=1;dx=1,dy=0;dx=1,dy=1(效果不好);
- cv2.addWeighted(img1,alpha1,img2,alpha2,0)
# 只显示正的梯度
import cv2
import numpy as np
img1 = cv2.imread('')
img2_x = cv2.Sobel(img,-1,1,0)
cv2.imshow('img1',img1)
cv2.imshow('img2_x',img2_x)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 修正负梯度为0,只显示正的梯度
import cv2
import numpy as np
img1 = cv2.imread('')
img2_x = cv2.Sobel(img,cv2.CV_64F,1,0)
cv2.imshow('img1',img1)
cv2.imshow('img2_x',img2_x)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 只显示正的梯度
import cv2
import numpy as np
img1 = cv2.imread('')
img2_x = cv2.Sobel(img,cv2.CV_64F,1,0)
img2_x = cv2.convertScaleAbs(img2_x) # 负值转为uint8
cv2.imshow('img1',img1)
cv2.imshow('img2_x',img2_x)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 计算x、y轴的梯度
import cv2
import numpy as np
img1 = cv2.imread('')
img2_x = cv2.Sobel(img,cv2.CV_64F,1,0)
img2_x = cv2.convertScaleAbs(img2_x) # 负值转为uint8
img2_y = cv2.Sobel(img,cv2.CV_64F,0,1)
img2_y = cv2.convertScaleAbs(img2_y) # 负值转为uint8
img_xy1 = cv2.addWeighted(img2_x,0.5,img2_y,0.5,0)
img_xy2 = cv2.Sobel(img,cv2.CV_64F,1,1) #
img_xy2 = cv2.convertScaleAbs(img_xy2) # 效果不好
cv2.imshow('img1',img1)
cv2.imshow('img2_x',img2_x)
cv2.imshow('img2_y',img2_y)
cv2.imshow('img2_xy1',img2_xy1)
cv2.imshow('img2_xy2',img2_xy2)
cv2.waitKey(0)
cv2.destroyAllWindows()
8.4 scharr算子及函数
- scharr算子是弥补Sobel算子的不足,scharr算子效果更好。它们不同之处在于系数。
- dst = cv2.Scharr(img,ddepth,dx,dy)
- ddepth = -1,-67–>0 ; ddepth = cv2.CV_64F,-67–>-67–>abs(-67)=67
- scharr_xy = cv2.addWeighted(scharr_x,alpha1,scharr_y,alpha2,0)
- cv2.Scharr(img,ddepth,dx,dy)==cv2.Sobel(img,ddepth,dx,dy,-1) # -1 代表用Scharr算子求梯度。
- dx,dy不能同时为1,否则报错。
a1 a2 a3
a4 a5 a6
a7 a8 a9
# 水平方向梯度
a5 = 3(a3-a1)+10(a6-a4)+3(a9-a7)
# 垂直方向梯度,如果a5很大,说明a5是边界
a5 = 3(a1-a7)+10(a2-a8)+3(a3-a9)
# 近似剃度
G = np.sqrt(G_x^2+G_y^2) or G = np.abs(G_x) + np.abs(G_y)
# x轴方向的梯度
import cv2
import numpy as np
img1 = cv2.imread('')
img2_x = cv2.Scharr(img,cv2.CV_64F,1,0)
img2_x = cv2.convertScaleAbs(img2_x) # 负值转为uint8
cv2.imshow('img1',img1)
cv2.imshow('img2_x',img2_x)
cv2.waitKey(0)
cv2.destroyAllWindows()
# y轴方向的梯度
import cv2
import numpy as np
img1 = cv2.imread('')
img2_y = cv2.Scharr(img,cv2.CV_64F,0,1)
img2_y = cv2.convertScaleAbs(img2_y) # 负值转为uint8
cv2.imshow('img1',img1)
cv2.imshow('img2_y',img2_y)
cv2.waitKey(0)
cv2.destroyAllWindows()
# x轴y轴方向的梯度
import cv2
import numpy as np
img1 = cv2.imread('')
img2_x = cv2.Scharr(img,cv2.CV_64F,1,0)
img2_x = cv2.convertScaleAbs(img2_x) # 负值转为uint8
img2_y = cv2.Scharr(img,cv2.CV_64F,0,1)
img2_y = cv2.convertScaleAbs(img2_y) # 负值转为uint8
img_xy = cv2.addWeighted(img2_x,0.5,img2_y,0.5,0)
cv2.imshow('img1',img1)
cv2.imshow('img2_x',img2_x)
cv2.imshow('img2_y',img2_y)
cv2.imshow('img_xy',img_xy)
cv2.waitKey(0)
cv2.destroyAllWindows()
# Sobel算子计算Scharrx轴y轴方向的梯度
import cv2
import numpy as np
img1 = cv2.imread('')
img2_x = cv2.Sobel(img,cv2.CV_64F,1,0,-1)
img2_x = cv2.convertScaleAbs(img2_x) # 负值转为uint8
img2_y = cv2.Sobel(img,cv2.CV_64F,0,1,-1)
img2_y = cv2.convertScaleAbs(img2_y) # 负值转为uint8
img_xy = cv2.addWeighted(img2_x,0.5,img2_y,0.5,0)
cv2.imshow('img1',img1)
cv2.imshow('img2_x',img2_x)
cv2.imshow('img2_y',img2_y)
cv2.imshow('img_xy',img_xy)
cv2.waitKey(0)
cv2.destroyAllWindows()
8.5 laplacian算子
- laplacian算子类似于sobel算子的二阶导数。
- img1 = cv2.Laplacian(img,ddepth)
0 1 0
1 -4 1
0 1 0
a1 a2 a3
a4 a5 a6
a7 a8 a9
a5 = a2+a4+a6+a8-4*a5
import cv2
import numpy as np
img1 = cv2.imread('')
img2 = cv2.Laplacian(img,cv2.CV_64F)
img2 = cv2.convertScaleAbs(img2) # 负值转为uint8
cv2.imshow('img1',img1)
cv2.imshow('img2',img2)
cv2.waitKey(0)
cv2.destroyAllWindows()
8.6 LOG算子
import cv2
import numpy as np
img = cv2.imread('')
img_g = cv.GaussianBlur(img, (3,3), 0)
img_log = cv2.Laplacian(img_g,cv2.CV_64F)
img_log = cv2.convertScaleAbs(img_log) # 负值转为uint8
cv2.imshow('img1',img1)
cv2.imshow('img_log',img_log)
cv2.waitKey(0)
cv2.destroyAllWindows()
9 canny边缘检测
9.1 canny边缘检测原理
import cv2
import numpy as np
img = cv2.imread('',1)
heigh,width,_ = img.shape
gray = cv2.cvtColor(img,cv.COLOR_BAYER_BG2GRAY)
imgG = cv2.GaussianBlur(gray,[3,3],0)
dst = cv2.Canny(img,50,50)
cv2.imshow('dst',dst)
cv2.waitKey(3)
cv2.destroyAllWindows()
9.2 canny算法
- 平滑:模糊削弱噪声
- 计算梯度:梯度包括大小和方向,由x和y方向合成。
- 细化边缘:利用非极大值抑制,只有局部最大值保留为边缘。
- 双阈值抑制:根据大小两个阈值,高于大阈值的为确定的边缘(强边缘);低于小阈值的不是边缘;处于两者之间的像素点(弱边缘)下一步确定。
- 边缘追踪:对于弱边缘,如果和强边缘相连,则也为边缘,否则不是边缘。
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('',1)
# 1 梯度:梯度包括大小和方向,由x和y方向合成
# Gaussian 滤波
img_blur = cv.GaussianBlur(img, (5,5), 2)
# 梯度
gradx = cv.Sobel(img_blur, cv.CV_64F, 1, 0)
grady = cv.Sobel(img_blur, cv.CV_64F, 0, 1)
T = np.arctan(grady /(gradx + 1e-3))
R = np.abs(gradx) + np.abs(grady)
# 2 非极大值抑制
## 如果中心点为该梯度方向上的最大值,则保留,否则为0.
h, w = R.shape
img_thin = np.zeros_like(R, dtype=np.float64)
for i in range(1, h - 1): # 不包含边缘
for j in range(1, w - 1):
theta = T[i,j]
if -np.pi / 8 <= theta < np.pi / 8:
if R[i,j] == max([R[i,j], R[i,j-1], R[i,j+1]]):
img_thin[i,j] = R[i,j]
elif -3 * np.pi / 8 <= theta < -np.pi / 8:
if R[i,j] == max([R[i,j], R[i-1,j+1], R[i+1,j-1]]):
img_thin[i,j] = R[i,j]
elif np.pi / 8 <= theta < 3 * np.pi / 8:
if R[i,j] == max([R[i,j], R[i-1,j-1], R[i+1,j+1]]):
img_thin[i,j] = R[i,j]
else:
if R[i,j] == max([R[i,j], R[i-1,j], R[i+1,j]]):
img_thin[i,j] = R[i,j]
plt.imshow(np.abs(img_thin).clip(0,255))
# 3 边缘细化
th1 = 5
th2 = 30
maxv = 255
img_edge = np.zeros_like(img_thin)
h, w = img_thin.shape
for i in range(1, h - 1): # 不包含边缘
for j in range(1, w - 1):
if img_thin[i,j] >= th2: # 判断是否为强边缘
img_edge[i,j] = maxv
elif img_thin[i,j] > th1: # 中间部分
around = img_thin[i-1:i+2, j-1:j+2]
if around.max() >= th2: # 判断周围是否有强边缘
img_edge[i,j] = maxv
plt.imshow(img_edge)
10 图像金字塔
10.1 基础理论
- 向下取样:高斯卷积+删除所有的偶数col,row,得到原图像的1/4.
- 向上取样:col,row扩大为原来的2倍–>新增的col,row用0填充–>高斯卷积核*4,
- 向下取样与向上取样不可逆。
- img = cv2.pyrDown(src)
- img = cv2.pyrUp(src)
# 向下取样
import cv2
import numpy as np
img1 = cv2.imread('')
img2 = cv2.pyrDown(img1)
img3 = cv2.pyrDown(img2)
img4 = cv2.pyrDown(img3)
cv2.imshow('img1',img1)
cv2.imshow('img2',img2)
cv2.imshow('img3',img3)
cv2.imshow('img4',img4)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 向上取样
import cv2
import numpy as np
img1 = cv2.imread('')
img2 = cv2.pyrUp(img1)
img3 = cv2.pyrUp(img2)
img4 = cv2.pyrUp(img4)
cv2.imshow('img1',img1)
cv2.imshow('img2',img2)
cv2.imshow('img3',img3)
cv2.imshow('img4',img4)
cv2.waitKey(0)
cv2.destroyAllWindows()
10.2 取样可逆性研究
# Down-up
import cv2
import numpy as np
img1 = cv2.imread('')
img2 = cv2.pyrDown(img1)
img3 = cv2.pyrUp(img1)
cv2.imshow('img1',img1)
cv2.imshow('img2',img2)
cv2.imshow('img3',img3)
cv2.waitKey(0)
cv2.destroyAllWindows()
# up-Down
import cv2
import numpy as np
img1 = cv2.imread('')
img2 = cv2.pyrUp(img1)
img3 = cv2.pyrDown(img1)
cv2.imshow('img1',img1)
cv2.imshow('img2',img2)
cv2.imshow('img3',img3)
cv2.waitKey(0)
cv2.destroyAllWindows()
10.3 拉普拉斯金字塔
- L = G -PyrUp(PyrDown(G)) # 在高斯金字塔的基础上实现拉普拉斯金字塔。
# 一次拉普拉斯
import cv2
import numpy as np
img1 = cv2.imread('')
img2 = cv2.pyrDown(img1)
img3 = cv2.pyrUp(img2)
img4 = img1 - img3
cv2.imshow('img1',img1)
cv2.imshow('img4',img4)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 两次拉普拉斯
import cv2
import numpy as np
img1 = cv2.imread('')
img2 = cv2.pyrDown(img1)
img3 = cv2.pyrUp(img2)
img4 = img1 - img3
img5 = cv2.pyrDown(img4)
img6 = cv2.pyrUp(img5)
img7 = img4 - img6
cv2.imshow('img1',img1)
cv2.imshow('img4',img4)
cv2.imshow('img7',img7)
cv2.waitKey(0)
cv2.destroyAllWindows()