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算子及函数

  1. dst = cv2.Sobel(img,ddepth,dx,dy,[ksize])
  2. ddepth = -1 or cv2.CV_64F( 保留负数的值 ) ,表示处理结果与原图相一致
  3. dst = cv2.convertScaleAbs(img,[,alpha[,beta]]) 将原始图片转换成256色位图。
  4. dx=0,dy=1;dx=1,dy=0;dx=1,dy=1(效果不好);
  5. 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算子及函数

  1. scharr算子是弥补Sobel算子的不足,scharr算子效果更好。它们不同之处在于系数。
  2. dst = cv2.Scharr(img,ddepth,dx,dy)
  3. ddepth = -1,-67–>0 ; ddepth = cv2.CV_64F,-67–>-67–>abs(-67)=67
  4. scharr_xy = cv2.addWeighted(scharr_x,alpha1,scharr_y,alpha2,0)
  5. cv2.Scharr(img,ddepth,dx,dy)==cv2.Sobel(img,ddepth,dx,dy,-1) # -1 代表用Scharr算子求梯度。
  6. 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算子

  1. laplacian算子类似于sobel算子的二阶导数。
  2. 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算法

  1. 平滑:模糊削弱噪声
  2. 计算梯度:梯度包括大小和方向,由x和y方向合成。
  3. 细化边缘:利用非极大值抑制,只有局部最大值保留为边缘。
  4. 双阈值抑制:根据大小两个阈值,高于大阈值的为确定的边缘(强边缘);低于小阈值的不是边缘;处于两者之间的像素点(弱边缘)下一步确定。
  5. 边缘追踪:对于弱边缘,如果和强边缘相连,则也为边缘,否则不是边缘。
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 基础理论

  1. 向下取样:高斯卷积+删除所有的偶数col,row,得到原图像的1/4.
  2. 向上取样:col,row扩大为原来的2倍–>新增的col,row用0填充–>高斯卷积核*4,
  3. 向下取样与向上取样不可逆。
  4. img = cv2.pyrDown(src)
  5. 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 拉普拉斯金字塔

  1. 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()
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值