Sobel滤波边缘提取
1、设计能够提取X方向、Y方向的Sobel滤波器,将上述滤波器和图像进行卷积,生成X方向和Y方向边缘图像。
思想:
X方向卷积因子: [ − 1 0 + 1 − 2 0 + 2 − 1 0 + 1 ] \left[ \begin{matrix}-1&0&+1\\ -2&0&+2\\-1&0&+1 \end{matrix} \right] ⎣⎡−1−2−1000+1+2+1⎦⎤
Y方向卷积因子: [ + 1 + 2 + 1 0 0 0 − 1 − 2 − 1 ] \left[ \begin{matrix} +1&+2&+1\\0&0&0\\-1&-2&-1\\\end{matrix}\right] ⎣⎡+10−1+20−2+10−1⎦⎤
G x = [ − 1 0 + 1 − 2 0 + 2 − 1 0 + 1 ] Gx = \left[ \begin{matrix}-1&0&+1\\ -2&0&+2\\-1&0&+1 \end{matrix} \right] Gx=⎣⎡−1−2−1000+1+2+1⎦⎤*image
G y = [ + 1 + 2 + 1 0 0 0 − 1 − 2 − 1 ] G_y = \left[ \begin{matrix} +1&+2&+1\\0&0&0\\-1&-2&-1\\\end{matrix}\right] Gy=⎣⎡+10−1+20−2+10−1⎦⎤*image
def convolve(img,fill):#彩色图像分为RGB
rgb_r = img[:,:,0]
rgb_g = img[:,:,1]
rgb_b = img[:,:,2]
pro_rgb_r = pre_convolve(rgb_r,fill)#每层进行卷积操作
pro_rgb_g = pre_convolve(rgb_g,fill)
pro_rgb_b = pre_convolve(rgb_b,fill)
img_pro = np.dstack((pro_rgb_r,pro_rgb_g,pro_rgb_b))#合并三层,返回图像
return img_pro
def pre_convolve(img,fill):
fill_height = fill.shape[0]#卷积高
fill_width = fill.shape[1]#卷积宽
img_height = img.shape[0]#图像高
img_width = img.shape[1]#图像宽
#图像进行卷积后的图像大小
img_pro_height = img_height - fill_height + 1
img_pro_width = img_width - fill_width + 1
pro_rgb = np.zeros((img_pro_height,img_pro_width),dtype='uint8')
for i in range(img_pro_height):#计算Gx点乘A Gy点乘A
for j in range(img_pro_width):
pro_rgb[i][j] = pro_statistic(img[i:i + fill_height,j:j + fill_width],fill)#sobel计算
return pro_rgb
def pro_statistic(img,fill):
res = (img * fill).sum()
if(res > 255):
res = 255
elif(res < 0):
res = abs(res) # 让负边缘也显现出来
return res
# 索贝尔算子 边缘检测
#Gx卷积因子
sobel_x = np.array([[-1,0,1],
[-2,0,2],
[-1,0,1]])
#Gy卷积因子
sobel_y = np.array([[1,2,1],
[0,0,0],
[-1,-2,-1]])
img = cv2.imread('./1.jpg')
res1 = convolve(img,sobel_x)#提取X方向的Sobel边缘图像
res2 = convolve(img,sobel_y)#提取Y方向的Sobel边缘图像
cv2.imshow('img', res1)
cv2.waitKey(0)
cv2.imshow('img', res2)
cv2.waitKey(0)
2、基于X方向和Y方向的边缘,生成总体梯度幅值(边缘)图和角度相位图。
思想:
利用 G = G x 2 + G y 2 G = \sqrt{G_x^2+G_y^2} G=Gx2+Gy2生成总体梯度幅值的边缘图
def fu_zhi(res1,res2):
#将X方向边缘图分解为为RGB三层
res1_rgb_r = res1[:,:,0]
res1_rgb_g = res1[:,:,1]
res1_rgb_b = res1[:,:,2]
#将Y方向边缘图分解为为RGB三层
res2_rgb_r = res2[:,:,0]
res2_rgb_g = res2[:,:,1]
res2_rgb_b = res2[:,:,2]
#获得边缘图的高与宽
high = res1_rgb_r.shape[0]#图像高
width = res1_rgb_r.shape[1]#图形宽
#初始化基于X和Y方向边缘图
res3_r = np.zeros((high, width),dtype='uint8')
res3_g = np.zeros((high, width),dtype='uint8')
res3_b = np.zeros((high, width),dtype='uint8')
#公式 sqrt(Gx^2 + Gy^2)
for i in range(high):
for j in range(width):
res3_r[i][j] = np.uint8(np.sqrt(pow(res1_rgb_r[i][j], 2) + pow(res2_rgb_r[i][j], 2)))
res3_g[i][j] = np.uint8(np.sqrt(pow(res1_rgb_g[i][j], 2) + pow(res2_rgb_g[i][j], 2)))
res3_b[i][j] = np.uint8(np.sqrt(pow(res1_rgb_b[i][j], 2) + pow(res2_rgb_b[i][j], 2)))
res3 = np.dstack((res3_r, res3_g, res3_b)) # 合并三层,返回图像
return res3
思想:
θ = a r c t a n ( G y G x ) \theta = arctan(\frac{G_y}{G_x}) θ=arctan(GxGy)计算梯度角度,
将[0,180]分为9等分,即[0,20]量化为index0,[20,40]量化为index1,[40,60]量化为index2,[60,80]量化为index3,[80,100]量化为index4,[100,120]量化为index5,[120,140]量化为index6,[140,160]量化为index7,[160,180]量化为index8。
将图像分为N*N个区域(cell),在cell上做出index对应的直方图。
C*C个cell为一个block,对每个block内cell的直方图进行归一化,获得特征值:KaTeX parse error: Got function '\sum' with no arguments as argument to '\sqrt' at position 25: …ac {h(t)}{\sqrt\̲s̲u̲m̲ ̲h(t)+ε}
将得到的h(t)可视化,cell内每个index的方向画一条线,值越大,颜色越白,值越小,颜色越黑。
import cv2
import numpy as np
import matplotlib.pyplot as plt
#获得直方图
def HOG(img):
#将图像装换为灰度图
def BGR2GRAY(img):
gray = 0.2126 * img[..., 2] + 0.7152 * img[..., 1] + 0.0722 * img[..., 0]
return gray
#获得GxGy大小
def get_gradXY(gray):
H, W = gray.shape
#矩阵前后进行padding填充
gray = np.pad(gray, (1, 1), 'edge')
#获得Gx
gx = gray[1:H + 1, 2:] - gray[1:H + 1, :W]
#获得Gy
gy = gray[2:, 1:W + 1] - gray[:H, 1:W + 1]
# replace 0 with
gx[gx == 0] = 1e-6
return gx, gy
#获得梯度大小和方向
def get_MagGrad(gx, gy):
# 获得梯度大小
magnitude = np.sqrt(gx ** 2 + gy ** 2)
# 获得梯度方向
gradient = np.arctan(gy / gx)
gradient[gradient < 0] = np.pi / 2 + gradient[gradient < 0] + np.pi / 2
return magnitude, gradient
#梯度
def quantization(gradient):
#准备量化表
gradient_quantized = np.zeros_like(gradient, dtype=np.int)
#量化单元
d = np.pi / 9
#量化
for i in range(9):#在d*i和d*(i+1)之间定义为i
gradient_quantized[np.where((gradient >= d * i) & (gradient <= d * (i + 1)))] = i
return gradient_quantized
#获得梯度直方图
def gradient_histogram(gradient_quantized, magnitude, N=8):
#获得梯度矩阵的高和宽
H, W = magnitude.shape
# get cell num
cell_N_H = H // N# //除完取整
cell_N_W = W // N
histogram = np.zeros((cell_N_H, cell_N_W, 9), dtype=np.float32)
# each pixel
for y in range(cell_N_H):
for x in range(cell_N_W):
for j in range(N):
for i in range(N):
histogram[y, x, gradient_quantized[y * 4 + j, x * 4 + i]] += magnitude[y * 4 + j, x * 4 + i]
return histogram
#直方图均衡化
def normalization(histogram, C=3, epsilon=1):
cell_N_H, cell_N_W, _ = histogram.shape
## each histogram
for y in range(cell_N_H):
for x in range(cell_N_W):
histogram[y, x] /= np.sqrt(np.sum(histogram[max(y - 1, 0): min(y + 2, cell_N_H),
max(x - 1, 0): min(x + 2, cell_N_W)] ** 2) + epsilon)
return histogram
# 1. BGR -> Gray
gray = BGR2GRAY(img)
# 1. Gray -> Gradient x and y
gx, gy = get_gradXY(gray)
# 2. get gradient magnitude and angle
magnitude, gradient = get_MagGrad(gx, gy)
# 3. Quantization
gradient_quantized = quantization(gradient)
# 4. Gradient histogram
histogram = gradient_histogram(gradient_quantized, magnitude)
# 5. Histogram normalization
histogram = normalization(histogram)
return histogram
# draw HOG
def draw_HOG(img, histogram):
# Grayscale
def BGR2GRAY(img):
gray = 0.2126 * img[..., 2] + 0.7152 * img[..., 1] + 0.0722 * img[..., 0]
return gray
def draw(gray, histogram, N=8):
# get shape
H, W = gray.shape
cell_N_H, cell_N_W, _ = histogram.shape
## Draw
out = gray[1: H + 1, 1: W + 1].copy().astype(np.uint8)
for y in range(cell_N_H):
for x in range(cell_N_W):
cx = x * N + N // 2
cy = y * N + N // 2
x1 = cx + N // 2 - 1
y1 = cy
x2 = cx - N // 2 + 1
y2 = cy
h = histogram[y, x] / np.sum(histogram[y, x])
h /= h.max()
for c in range(9):
# get angle
angle = (20 * c + 10) / 180. * np.pi
rx = int(np.sin(angle) * (x1 - cx) + np.cos(angle) * (y1 - cy) + cx)
ry = int(np.cos(angle) * (x1 - cx) - np.cos(angle) * (y1 - cy) + cy)
lx = int(np.sin(angle) * (x2 - cx) + np.cos(angle) * (y2 - cy) + cx)
ly = int(np.cos(angle) * (x2 - cx) - np.cos(angle) * (y2 - cy) + cy)
# color is HOG value
c = int(255. * h[c])
# draw line
cv2.line(out, (lx, ly), (rx, ry), (c, c, c), thickness=1)
return out
# get gray
gray = BGR2GRAY(img)
# draw HOG
out = draw(gray, histogram)
return out
if __name__ == "__main__":
# Read image
img = cv2.imread("1.jpg").astype(np.float32)
#获得直方图
histogram = HOG(img)
#画出直方图
out = draw_HOG(img, histogram)
# Save result
cv2.imwrite("out.jpg", out)
cv2.imshow("result", out)
cv2.waitKey(0)
cv2.destroyAllWindows()