在整个图像处理的学习过程中可以看到,在很多应用中图像强度的变化情况是非常重要的信息。强度的变化可以用灰度图像I(对于彩色图像,通常对每个颜色通道分别计算导数)的x和y的方向导数和进行描述。
图像的梯度向量为:
梯度有两个重要的属性,一个是梯度的大小:
它描述了图像变化的强弱,一是梯度的角度:
它描述了图像中在每个点(像素)上强度变化最大的方向。NumPy中的arctan2()函数返回弧度表示的有符号角度,角度的变化区间为。
我们可以用离散近似的方式来计算图像的导数。图像的导数大多可以通过卷积简单地实现:
通常选择Prewitt滤波器:
Prewitt边缘算子是一种边缘样板算子,利用像素点上下,左右邻点灰度差,在边缘处达到极值检测边缘,对噪声具有平滑作用
使用Sobel滤波器,Sobel算法是一种较成熟的微分边缘检测算法,它计算简单,且能产生较好的检测效果,对噪声具有平滑作用,可以提供较为精确的边缘方向信息。
import cv2
from matplotlib import pyplot as plt
img = cv2.imread('img2.png', 0) # 后面参数为0表示取灰度图
img1 = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)#默认ksize=3
sobely = cv2.Sobel(img,cv2.CV_64F,0,1)
gm = cv2.sqrt(sobelx ** 2 + sobely ** 2)
plt.subplot(121),plt.imshow(img)
plt.subplot(122),plt.imshow(gm)
plt.show()
可以使用cv2.cartToPolar() ,可以同时返回幅度和相位
import cv2
from matplotlib import pyplot as plt
img = cv2.imread('img2.png', 0) # 后面参数为0表示取灰度图
# img1 = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)#默认ksize=3
sobely = cv2.Sobel(img,cv2.CV_64F,0,1)
gm = cv2.sqrt(sobelx ** 2 + sobely ** 2)
mag, angle = cv2.cartToPolar(sobelx, sobely, angleInDegrees=True)
plt.subplot(221),plt.imshow(img),plt.title('origin image')
plt.subplot(222),plt.imshow(gm),plt.title('mag image')
plt.subplot(223),plt.imshow(mag),plt.title('mag(opencv) image')
plt.subplot(224),plt.imshow(angle),plt.title('angle image')
plt.show()
梯度图像
from skimage import data,color,filters
import matplotlib.pyplot as plt
import numpy as np
original_img=data.chelsea()
gray_img=color.rgb2gray(original_img)
'''
#using system function
edge_img=filters.sobel(gray_img)
figure=plt.figure()
plt.subplot(131).set_title('original_img')
plt.imshow(original_img)
plt.subplot(132).set_title('gray_img')
plt.imshow(gray_img)
plt.subplot(133).set_title('sobel_img')
plt.imshow(edge_img)
plt.show()
'''
#self code
x_sobel=np.array([[-1,0,1],
[-2,0,2],
[-1,0,1]])
y_sobel=np.array([[-1,-2,-1],
[0,0,0],
[1,2,1]])
h,w=gray_img.shape
img=np.zeros([h+2,w+2])
img[2:h+2,2:w+2]=gray_img[0:h,0:w]
def sobel_cal(img,filter):
h,w=img.shape
img_filter=np.zeros([h,w])
for i in range(h-2):
for j in range(w-2):
img_filter[i][j]=img[i][j]*filter[0][0]+img[i][j+1]*filter[0][1]+img[i][j+2]*filter[0][2]+\
img[i+1][j]*filter[1][0]+img[i+1][j+1]*filter[1][1]+img[i+1][j+2]*filter[1][2]+\
img[i+2][j]*filter[2][0]+img[i+2][j+1]*filter[2][1]+img[i+2][j+2]*filter[2][2]
return img_filter
x_edge_img=sobel_cal(img,x_sobel)
y_edge_img=sobel_cal(img,y_sobel)
edge_img=np.zeros([h,w])
for i in range(h):
for j in range(w):
edge_img[i][j]=np.sqrt(x_edge_img[i][j]**2+y_edge_img[i][j]**2)/(np.sqrt(2))
plt.figure('imgs')
plt.subplot(321).set_title('original_img')
plt.imshow(original_img)
plt.subplot(322).set_title('gray_img')
plt.imshow(gray_img)
plt.subplot(323).set_title('x_edge_img')
plt.imshow(x_edge_img)
plt.subplot(324).set_title('y_edge_img')
plt.imshow(y_edge_img)
plt.subplot(325).set_title('edge_img')
plt.imshow(edge_img)
plt.show()
角度图像
from skimage import data,color,filters
import matplotlib.pyplot as plt
import numpy as np
original_img=data.chelsea()
gray_img=color.rgb2gray(original_img)
'''
#using system function
edge_img=filters.sobel(gray_img)
figure=plt.figure()
plt.subplot(131).set_title('original_img')
plt.imshow(original_img)
plt.subplot(132).set_title('gray_img')
plt.imshow(gray_img)
plt.subplot(133).set_title('sobel_img')
plt.imshow(edge_img)
plt.show()
'''
#self code
x_sobel=np.array([[-1,0,1],
[-2,0,2],
[-1,0,1]])
y_sobel=np.array([[-1,-2,-1],
[0,0,0],
[1,2,1]])
h,w=gray_img.shape
img=np.zeros([h+2,w+2])
img[2:h+2,2:w+2]=gray_img[0:h,0:w]
def sobel_cal(img,filter):
h,w=img.shape
img_filter=np.zeros([h,w])
for i in range(h-2):
for j in range(w-2):
img_filter[i][j]=img[i][j]*filter[0][0]+img[i][j+1]*filter[0][1]+img[i][j+2]*filter[0][2]+\
img[i+1][j]*filter[1][0]+img[i+1][j+1]*filter[1][1]+img[i+1][j+2]*filter[1][2]+\
img[i+2][j]*filter[2][0]+img[i+2][j+1]*filter[2][1]+img[i+2][j+2]*filter[2][2]
return img_filter
x_edge_img=sobel_cal(img,x_sobel)
y_edge_img=sobel_cal(img,y_sobel)
edge_img=np.zeros([h,w])
for i in range(h):
for j in range(w):
# edge_img[i][j]=np.sqrt(x_edge_img[i][j]**2+y_edge_img[i][j]**2)/(np.sqrt(2))
edge_img[i][j]=np.arctan2(x_edge_img[i][j],y_edge_img[i][j])
plt.figure('imgs')
plt.subplot(321).set_title('original_img')
plt.imshow(original_img)
plt.subplot(322).set_title('gray_img')
plt.imshow(gray_img)
plt.subplot(323).set_title('x_edge_img')
plt.imshow(x_edge_img)
plt.subplot(324).set_title('y_edge_img')
plt.imshow(y_edge_img)
plt.subplot(325).set_title('edge_img')
plt.imshow(edge_img)
plt.show()
import matplotlib.pyplot as plt
from skimage.io import imread
import numpy as np
import cv2
"""
1.清晰图像和模糊图像之间的梯度分布不同,清晰图像的梯度有明显的重尾分布,而模糊图像不存在这种梯度分布;
2.对清晰图像进行高斯模糊;
3.使用opencv进行计算梯度,包括幅度梯度和角度梯度;
4.绘制图像的梯度直方图;
5.并计算两张图像之间的梯度差,并绘制差值的直方图
"""
img = imread('img1.png')
# img = np.float32(img)/255.
img_blur = cv2.GaussianBlur(img, (15, 15), 0)
# img_blur = np.float32(img_blur)/255.
# 清晰图像的x,y方向的一阶导(梯度)
gx_ord = cv2.Sobel(img, cv2.CV_32F, 1, 0, ksize=1)
gy_ord = cv2.Sobel(img, cv2.CV_32F, 0, 1, ksize=1)
# 模糊图像的x,y方向的一阶导
gx_blur = cv2.Sobel(img_blur, cv2.CV_32F, 1, 0, ksize=1)
gy_blur = cv2.Sobel(img_blur, cv2.CV_32F, 0, 1, ksize=1)
# Calculate gradient magnitude and direction ( in degrees )
# cv2.cartToPolar这个函数计算二维向量(x,y)的幅度梯度和角度梯度
mag_ord, angle_ord = cv2.cartToPolar(gx_ord, gy_ord, angleInDegrees=True)
mag_blur, angle_blur = cv2.cartToPolar(gx_blur, gy_blur, angleInDegrees=True)
# bins_ord = angle_ord.max - angle_ord.min
# bins_blur = angle_blur.max - angle_blur.min
bins = np.arange(256) # np.histogram的默认bins值为10
hist_ord_mag, bins = np.histogram(mag_ord, bins)
hist_blur_mag, bins = np.histogram(mag_blur, bins)
hist_ord_angle, bins = np.histogram(angle_ord, bins)
hist_blur_angle, bins = np.histogram(angle_blur, bins)
# 计算清晰图像和模糊图像之间的幅度和角度的梯度差
mag_diff = mag_ord - mag_blur
angle_diff = angle_ord - angle_blur
hist_mag_diff, bins = np.histogram(mag_diff, bins)
hist_angle_diff, bins = np.histogram(angle_diff, bins)
width = 0.7 * (bins[1] - bins[0])
center = (bins[:-1] + bins[1:]) / 2
plt.subplot(331), plt.imshow(img), plt.title('ordinary')
plt.subplot(332), plt.imshow(img_blur), plt.title('blur')
plt.subplot(337), plt.title('ord_angle'), plt.bar(center, hist_ord_angle, align='center', width=width)
plt.subplot(338), plt.title('blur_angle'), plt.bar(center, hist_blur_angle, align='center', width=width)
plt.subplot(334), plt.title('ord_mag'), plt.bar(center, hist_ord_mag, align='center', width=width)
plt.subplot(335), plt.title('blur_mag'), plt.bar(center, hist_blur_mag, align='center', width=width)
plt.subplot(336), plt.title('mag_diff'), plt.bar(center, hist_mag_diff, align='center', width=width)
plt.subplot(339), plt.title('angel_diff'), plt.bar(center, hist_angle_diff, align='center', width=width)
plt.show()
参考文献
边缘检测算法总结及其python实现--一阶检测算子_RF-or的博客-CSDN博客_边缘算法python
【视觉入门】——空域图像增强(邻域运算部分):图像卷积、多种滤波器;二值图像分析及形态学图像处理_Vulcan_Q的博客-CSDN博客