图像处理基础 - SIFT 和 HOG
#data-science #图像处理基础和传统 CV 17

本节是另一课程的内容,但也可以视为 CV 导论从 Classic Vision II 那一节的一个补充

SIFT

早在遇到语义分割以前,传统 CV 在处理目标识别的 equivariance 的问题时就已经举步维艰,但仍然有一些很不错的方法;我们首先回顾希望目标识别满足的 equivariance:

  • scale
  • rotation
  • lighting

SIFT/Scale Invariant Feature Transform/尺度不变特征转换是较好地实现上面这几个等变性的一种方法。

关键点检测

LoG

对连续二元函数 f(x, y),其 Laplacian 算子是 \begin{aligned} \nabla \cdot {\nabla{f}} = \frac{\partial^2{f}}{\partial{x^2}}+ \frac{\partial^2{f}}{\partial{y^2}}\end{aligned},对离散二元函数 img,可以用卷积核 I = \begin{bmatrix} 0 & 1 & 0 \\ 1 & -4 & 1 \\ 0 & 1 & 0\end{bmatrix} 代替它;Laplacian 算子可以用来定位局部极值点,从而寻找 edge 或 key point

但是,Laplacian 算子同样能定位噪点,这会很大干扰结果,所以自然地想到先求 Gaussian 核平滑的结果;合并两步,我们只需求 Gaussian 核函数的 Laplacian 算子得到 LoG 算子:

\begin{aligned} \nabla \cdot {\nabla{G(x,y,\sigma)}} = \frac{\partial^2{G}}{\partial{x^2}}+ \frac{\partial^2{G}}{\partial{y^2}}\end{aligned} = \frac{x^2 + y^2 - 2\sigma^2}{2\pi \sigma^6} \cdot e^{-\frac{x^2 + y^2}{2\sigma^2}}

DoG

Gaussian 函数 \displaystyle G(x,y,\sigma) = \frac{1}{2\pi }\sigma^{-2} e^{-\frac{x^2 + y^2}{2} \sigma^{-2}}\sigma 求导得到

\frac{\partial{G}}{\partial{\sigma}} = \frac{x^2 + y^2 - 2\sigma^2}{2\pi\sigma^5} \cdot e^{-\frac{x^2 + y^2}{2\sigma^{2}} }

注意到 \displaystyle \frac{\partial{G}}{\partial{\sigma}} = \sigma \text{LoG},进一步推导有

G(x, y, k \sigma ) - G(x, y, \sigma) \approx (k - 1)\cdot \sigma^2\cdot \text{LoG}

这表明对两个不同方差的 Gaussian 函数求差(Diff of Gaussian, DoG)就能近似求 LoG,它的计算负担小于求 LoG

到今天大家不怎么在乎这点计算负担了

SIFT

简单了解这一工程实现,实现细节偶有差异,我们并不特别在乎。

高斯金字塔

从另一个角度说,启发自人眼近大远小、模糊远方的特征,我们想建立一种图像的尺度空间,满足在这个尺度空间上越远,就越模糊,越保留轮廓而抹去细节;高斯金字塔是这样一种尺度空间,采取了以下策略

  • 近大远小:下采样(其实就是池化 Pooling)
  • 模糊远方:高斯核 \displaystyle G(x, y, \sigma) = \frac{1}{\sqrt{2 \pi \sigma^2}} e^{-\frac{x^2 + y^2}{2 \sigma^2}} 平滑:L(x, y, \sigma) = G(x, y, \sigma) \otimes I(x, y)

具体地,采取了以下方式

  • 金字塔层数 O = [\log_2 \min(h, w)] - 2
  • 每一个 octave 有 6 层尺寸相同,模糊系数 \sigma 不同的图像
  • 每一个 octave 之间下采样 2 倍

Key points localization

  1. 阈值化:去除较小的噪点和一些不稳定点
  2. DoG 寻找极值点:在每个 Octave 中,和 (x, y, \sigma) 三个方向上周围的 26 个点比较,找到极值点
  3. 三元二阶泰勒展开找到亚像素精度的极值点位置
  4. 阈值化:去掉对比度不够的点
  5. 去除边缘效应
  6. 确定极值点方向:在 1.5 倍尺度为半径的圆内的所有像素(邻域窗口),高斯滤波加权,梯度方向多数投票

生成关键点描述符

我们现在有每个关键点的方向,需要给出一个特征向量描述这个关键点

  • 邻域窗口旋转至关键点方向
  • 邻域窗口划分为 4x4 子块
  • 每个窗口内计算 8 个方向的梯度直方图
  • 得到 128 维特征向量

匹配

最后,可以通过 SIFT 描述符的距离衡量两幅图像的相似程度

实现

很高兴 OpenCV 能直接实现它!

import cv2
from matplotlib import pyplot as plt

img = ...
sift = cv2.SIFT_create()
keypoints, descriptors = sift.detectAndCompute(img, None)

img_with_kps = cv2.drawKeypoints(img, keypoints, None, flag=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)

plt.figure()
plt.imshow(img_with_kps, cmap='gray')
plt.show()

image-ZGxi.png

匹配

直接使用 BFMatcher

kp1, desc1 = sift.detectAndCompute(img1, None)
kp2, desc2 = sift.detectAndCompute(img2, None)

bf = cv2.BFMatcher(cv2.NORM_L2, crossCheck=True)
matches = bf.match(desc1, desc2)

matches = sorted(matches, key=lambda x: x.distance)
matched_img = cv2.drawMatches(
    img1, kp1, 
    img2, kp2, 
    matches[:10], 
    None, 
    flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS
)

plt.figure()
plt.imshow(matched_img, cmap='gray')
plt.show()

image-cNsl.png

HOG

HOG/Histograms of Oriented Gradients/方向梯度直方图思想类似,过程相对简单:

  1. 图像灰度化
  2. 采用 Gamma 校正法进行对比度均衡
  3. 将图像划分为(例如 6x6)的小 cells
  4. 统计每个 cell 的梯度直方图,形成每个 cell 的 descriptor
  5. 将(例如 3x3 个)cell 组成一个 block,在 block 上再进行一次对比度均衡并将所有 cell 的 descriptor 组成该 block 的 HOG 特征
  6. 将 img 的所有 block 的 HOG 特征组成该 img 的 HOG 特征向量 (blocks, cells, bins)

2 是为了对光照和阴影有 invariance

将 HOG 与 SVM 组合可以得到一个目标分类器

实现

opencv 提供了 HOG 方法和预训练的用于行人检测的 SVM 分类器:

import cv2
from matplotlib import pyplot as plt

img = cv2.imread('pedestrian.jpg')
img = cv2.resize(img, fx=0.5, fy=0.5, dsize=None)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)

hog = cv2.HOGDescriptor()
hog.setSVMDetector(cv2.HOGDescriptor_getDefaultPeopleDetector())
boxes, weights = hog.detectMultiScale(gray, winStride=(8, 8), padding=(8, 8), scale=1.05)

for (x, y, w, h) in boxes:
    cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)

plt.figure()
plt.imshow(img)
plt.show()

image-yOaW.png

或者使用 scikit-image 库

from skimage import feature as ft
img = cv2.imread('pedestrian.jpg', cv2.IMREAD_GRAYSCALE)
features = ft.hog(img,orientations=6, pixels_per_cell=[6, 6], cells_per_block=[3, 3], visualize=True)
plt.imshow(features[1], cmap='gray')
plt.show()

image-RIVT.png

图像处理基础 - SIFT 和 HOG
http://localhost:8090/archives/vzGRJiZ0
作者
酱紫瑞
发布于
更新于
许可协议