查看全课大纲(第 49 / 93 节)
  1. 1.计算机视觉概述
  2. 2.计算机视觉应用场景
  3. 3.困难与挑战
  4. 4.开源库介绍
  5. 5.图像显示与存储
  6. 6.CLAHE
  7. 7.腐蚀膨胀与开闭运算
  8. 8.滤波与边缘填充
  9. 9.各种滤波
  10. 10.图像金字塔
  11. 11.傅里叶变换
  12. 12.短时傅里叶变换与小波变换
  13. 13.颜色特征与颜色直方图
  14. 14.几何特征_边缘
  15. 15.几何特征-角点与斑点
  16. 16.局部特征-SIFT特征描述子
  17. 17.局部特征-SURF特征描述子
  18. 18.局部特征-ORB特征描述子
  19. 19.其他特征描述子
  20. 20.传统图像分割技术
  21. 21.GraphCut
  22. 22.GrabCut
  23. 23.人脸检测的传统方法
  24. 24.行人检测的传统方法HOG+SVM
  25. 25.行人检测DPM
  26. 26.人工神经网络的架构
  27. 27.目标函数与梯度下降
  28. 28.误差反向传播
  29. 29.可手算的神经网络
  30. 30.改进目标函数与克服梯度消散
  31. 31.神经网络之传统神经网络与深度网络的差异
  32. 32.各种梯度下降算法
  33. 33.如何选择合适的梯度下降算法
  34. 34.避免过适应
  35. 35.CNN的架构
  36. 36.CNN的误差反向传播_卷积层
  37. 37.CNN的误差反向传播_池化层
  38. 38.分类所用的数据集
  39. 39.Alexnet详解
  40. 40.VGG详解
  41. 41.GoogLeNet_v1
  42. 42.BatchNormalization
  43. 43.GoogLeNet_v3v4
  44. 44.ResNet
  45. 45.ResNeXt
  46. 46.CNN设计准则
  47. 47.图像检索与推土机距离
  48. 48.基于颜色相似性
  49. 49.基于形状相似性
  50. 50.基于纹理相似性
  51. 51.基于局部特征相似性
  52. 52.DL的二值哈希编码
  53. 53.高维空间中检索KDTree
  54. 54.高维空间中检索LSH
  55. 55.目标识别任务综述
  56. 56.RCNN
  57. 57.SPP-Net
  58. 58.Fast R-CNN
  59. 59.Faster R-CNN
  60. 60.R-CNN系列模型回顾
  61. 61.R-FCN的设计思路
  62. 62.R-FCN的实现
  63. 63.YOLOv1
  64. 64.YOLOv2_9000
  65. 65.YOLOv3
  66. 66.图像分割应用场景与数据集
  67. 67.上采样的实现方式
  68. 68.FCN网络架构的由来
  69. 69.FCN构建细节
  70. 70.DeepLabv1
  71. 71.CRF
  72. 72.DeepLabv2
  73. 73.DeepLabv3
  74. 74.特定的医学影像分割任务
  75. 75.U-Net
  76. 76.3D U-Net
  77. 77.V-Net
  78. 78.DenseNet
  79. 79.病理切片分析任务及数据集
  80. 80.病理切片分析
  81. 81.图说任务及其传统处理方法
  82. 82.深度语言模型与RNN
  83. 83.LSTM及其变种
  84. 84.NIC模型
  85. 85.SAT模型
  86. 86.图说的性能指标
  87. 87.判别模型与生成模型
  88. 88.KL散度与JS散度
  89. 89.VAE
  90. 90.GAN的基本原理
  91. 91.DCGAN与CGAN
  92. 92.Wasserstein GAN
  93. 93.SRGAN

基于形状相似性

小象实战讲义 · 基于深度学习的计算机视觉

在图像检索中,颜色和纹理是重要的线索,但形状往往承载着物体最本质的识别信息。本节我们将学习如何量化图像的“形状”,并利用“金字塔梯度方向直方图”(PHOG)这一经典特征,实现基于形状相似性的图像检索。学完本节,你将能够理解并实现一个不依赖颜色、仅凭轮廓就能找到相似物体的检索系统。

💡 核心导读

  • 形状相似性:定义两幅图像“看上去像”的本质是轮廓和边缘结构的相似。
  • PHOG特征:融合图像金字塔与梯度方向直方图(HOG),在多尺度网格上统计边缘方向,形成189维的紧凑形状描述子。
  • 相似度计算:介绍两种适用于直方图特征的度量方法——标准化欧氏距离与直方图相交法。
  • 效果与局限:PHOG对正立、形状大体一致的物体检索效果良好,但对旋转、形变敏感。

形状相似性的定义与挑战

基于形状的相似性,直观来说就是“两幅图片看上去有点像”。这种“像”主要体现在物体的轮廓、边缘走向和整体结构上,而非颜色或纹理。例如,不同颜色的同一款手提包,或者不同款式的运动鞋,其基本形状轮廓是相似的。

然而,如何让计算机“看懂”形状并进行量化比较,是一个挑战。早期的思路是提取图像的边缘信息(例如使用Sobel、Canny等算子),然后对这些边缘的分布进行统计描述。PHOG特征正是这一思路的经典实现。

PHOG特征提取详解

PHOG,全称金字塔梯度方向直方图(Pyramid Histogram of Oriented Gradients),它巧妙地将图像金字塔(多尺度分析)和梯度方向直方图(局部形状描述)两个概念合二为一。

多尺度网格划分

“金字塔”意味着从粗到细的不同尺度观察图像:

  1. L0层(最粗):将整张图像视为1个网格(1×1)。
  2. L1层:将图像划分为2×2共4个网格。
  3. L2层(最细):将图像划分为4×4共16个网格。

这种划分确保了特征既能捕捉全局轮廓,又能关注局部细节。

梯度方向直方图统计

对于金字塔每一层的每一个网格,我们取出落在该网格内的边缘像素(由 Canny 边缘图确定),统计它们的梯度方向,形成一个直方图。

  • 梯度计算:通常使用Sobel算子计算每个像素在x和y方向的梯度,进而得到梯度幅值和方向角(0-360度)。
  • 方向量化:将360度的方向范围均匀划分为9个区间(bin),每个区间40度。统计每个网格内边缘像素的梯度方向落入这9个区间的数量(通常根据梯度幅值进行加权投票,幅值越大的像素贡献越大)。注意 PHOG 统计的是 Canny 边缘点而非网格内全部像素,这正是它描述“轮廓/形状”而非稠密纹理梯度的关键。

特征向量构建与维度

将每一层、每一个网格的9维直方图串联(Concatenate) 起来,就得到了最终的PHOG特征向量。

总维数 = (L0网格数 + L1网格数 + L2网格数) × 每个直方图的维度 = (1 + 4 + 16) × 9 = 21 × 9 = 189维

这个189维的向量就是图像形状的“数字指纹”。

提取流程与代码实现

完整的PHOG特征提取流程如下:

  1. 输入图像并转换为灰度图(颜色信息对形状检索是干扰)。
  2. 计算图像的梯度场(幅值和方向)。
  3. 对灰度图执行 Canny 边缘检测,得到边缘图(Canny 内部会先高斯平滑、再自行计算梯度,因此不能把已经算好的梯度图再喂给 Canny);Sobel 梯度场与 Canny 边缘图是从灰度图并行得到的两个分支,后续只有边缘像素参与统计。
  4. 构建图像金字塔,并在每一层的网格内对边缘像素的梯度方向做直方图统计(可按梯度幅值加权)。
  5. 将所有直方图串联成189维特征向量。

下面我们通过一个简化的示例,演示在单个尺度(如L2层的一个4x4网格)上如何计算梯度方向直方图。为了完全自包含和可运行,我们将在代码块内手动构造一个小型灰度图像。

import numpy as np
import cv2

# 1. 构造一个8x8的示例灰度图像(模拟一个简单边缘)
# 图像左边暗,右边亮,中间有一个垂直边缘
image = np.zeros((8, 8), dtype=np.uint8)
image[:, 0:4] = 50   # 左半部分灰度值50
image[:, 4:8] = 200  # 右半部分灰度值200
print("构造的8x8灰度图像 (左上角4x4区域):")
print(image[0:4, 0:4])
print("...(图像其余部分类似)")

# 2. 使用Sobel算子计算x和y方向的梯度 (需要转换为float类型计算)
image_float = image.astype(np.float32)
grad_x = cv2.Sobel(image_float, cv2.CV_32F, 1, 0, ksize=3)
grad_y = cv2.Sobel(image_float, cv2.CV_32F, 0, 1, ksize=3)

# 3. 计算梯度幅值和方向(角度,单位:度)
magnitude = np.sqrt(grad_x**2 + grad_y**2)
angle = np.arctan2(grad_y, grad_x) * 180 / np.pi  # 范围[-180, 180]
# 将角度转换到[0, 360)范围
angle[angle < 0] += 360

print("\n中心区域(第3-5行,第3-6列)的梯度方向角(度,取整):")
np.set_printoptions(precision=0, suppress=True)
print(angle[2:5, 2:6].astype(int))
构造的8x8灰度图像 (左上角4x4区域):
[[50 50 50 50]
 [50 50 50 50]
 [50 50 50 50]
 [50 50 50 50]]
...(图像其余部分类似)

中心区域(第3-5行,第3-6列)的梯度方向角(度,取整):
[[0 0 0 0]
 [0 0 0 0]
 [0 0 0 0]]

注意:这张图在垂直方向没有变化,只在水平方向有剧烈跳变(第 3 列灰度 50 → 第 4 列灰度 200,0 基),所以梯度只出现在这条竖直边缘的两侧:梯度方向是水平的(0°),对应的却是垂直边缘。上面打印的区域(第 2–5 列)恰好跨过这条边:第 2、5 列位于平坦区,梯度幅值为 0,方向角无定义、按约定显示为 0;第 3、4 列紧邻跳变,Sobel 响应幅值最大(600),方向角为 0°(即水平梯度方向)。因此打印出来的角度全是 0,但含义不同——一种是“没有边缘”,一种是“水平梯度方向的强边缘”。

接下来,我们模拟在某个网格(例如左上角2x2区域)内统计梯度方向直方图的过程。

import numpy as np

# 假设这是从某个图像L2层左上角提取的2x2子区域的梯度数据
# 为了演示,我们手动构造幅值和方向
sub_magnitude = np.array([[5.0, 1.0],
                          [2.0, 8.0]])
sub_angle = np.array([[45, 90],
                      [135, 0]])  # 单位:度

print("子区域梯度幅值:")
print(sub_magnitude)
print("\n子区域梯度方向(度):")
print(sub_angle)

# 定义9个方向区间 (0-360度,每40度一个bin)
bins = 9
bin_width = 360 / bins
# 初始化直方图
hist = np.zeros(bins)

# 遍历每个像素,根据其梯度幅值和方向投票
for i in range(sub_angle.shape[0]):
    for j in range(sub_angle.shape[1]):
        ang = sub_angle[i, j]
        mag = sub_magnitude[i, j]
        # 确定方向所属的bin索引 (0-8)
        bin_idx = int((ang % 360) // bin_width)
        # 累加幅值作为权重(也可直接计数)
        hist[bin_idx] += mag

print(f"\n该子区域的9维梯度方向直方图(按幅值加权):")
np.set_printoptions(precision=2, suppress=True)
print(hist)
子区域梯度幅值:
[[5. 1.]
 [2. 8.]]

子区域梯度方向(度):
[[ 45  90]
 [135   0]]

该子区域的9维梯度方向直方图(按幅值加权):
[8. 5. 1. 2. 0. 0. 0. 0. 0.]

解释:方向0度(第0个bin)有幅值8的贡献;方向45度(第1个bin)有幅值5的贡献;方向90度(第2个bin)有幅值1的贡献;方向135度(第3个bin)有幅值2的贡献。其他方向bin为0。这个9维向量就是该网格的形状描述。PHOG特征就是将所有这些网格的直方图连接起来。

形状相似度计算

提取到189维的PHOG特征向量后,如何计算两幅图像形状的相似度?这里介绍两种适用于直方图类特征的度量方法。

1. 标准化欧氏距离

普通的欧氏距离直接计算向量各维度差值的平方和。但对于直方图,不同维度(即不同方向区间)的数值分布可能方差差异很大。标准化欧氏距离通过除以各维度的标准差来消除这种量纲影响。

给定两个PHOG特征向量 P=[p1,p2,...,p189]P = [p_1, p_2, ..., p_{189}] 和 Q=[q1,q2,...,q189]Q = [q_1, q_2, ..., q_{189}],以及从训练集统计得到的每个维度上的标准差 σi\sigma_i,标准化欧氏距离定义为:

Dnorm(P,Q)=∑i=1189(pi−qiσi)2D_{\text{norm}}(P, Q) = \sqrt{ \sum_{i=1}^{189} \left( \frac{p_i - q_i}{\sigma_i} \right)^2 }

2. 直方图相交法

这是一种更直观、计算高效的方法,用于衡量两个直方图分布的相似性。对于两个直方图 PP 和 QQ,其相交度定义为:

Intersection⁡(P,Q)=∑i=1189min⁡(pi,qi)\operatorname{Intersection}(P, Q) = \sum_{i=1}^{189} \min(p_i, q_i)

直观理解:将两个直方图在每一个bin上“重叠”的部分取出来(即最小值),然后将所有bin的重叠部分相加。如果两个直方图完全一致,则相交值等于直方图的总和(通常经过归一化后为1)。差异越大,相交值越小。因此,我们可以用 1 - Intersection(P, Q) 作为一种距离度量。

这种方法巧妙地避免了平方运算,计算速度更快,且对直方图特征的相似性有很好的刻画。

import numpy as np

# 模拟两个简化版的PHOG特征向量(各10维,代替189维)
P = np.array([0.1, 0.2, 0.05, 0.0, 0.15, 0.1, 0.05, 0.1, 0.1, 0.15])
Q = np.array([0.15, 0.15, 0.1, 0.05, 0.1, 0.05, 0.1, 0.1, 0.15, 0.05])

# 假设各维度的标准差(通常从大量数据中计算)
sigma = np.array([0.05, 0.03, 0.04, 0.02, 0.05, 0.03, 0.04, 0.02, 0.05, 0.03])

# 计算标准化欧氏距离
diff = (P - Q) / sigma
norm_euclidean_dist = np.sqrt(np.sum(diff**2))

# 计算直方图相交度(假设特征已归一化,总和为1)
hist_intersection = np.sum(np.minimum(P, Q))
# 基于相交度的距离
intersection_dist = 1 - hist_intersection

print("特征向量 P:", P.round(3))
print("特征向量 Q:", Q.round(3))
print("\n标准化欧氏距离:", norm_euclidean_dist.round(4))
print("直方图相交度:", hist_intersection.round(4))
print("基于相交度的距离:", intersection_dist.round(4))
特征向量 P: [0.1  0.2  0.05 0.   0.15 0.1  0.05 0.1  0.1  0.15]
特征向量 Q: [0.15 0.15 0.1  0.05 0.1  0.05 0.1  0.1  0.15 0.05]

标准化欧氏距离: 5.389
直方图相交度: 0.75
基于相交度的距离: 0.25

PHOG检索的效果与局限性

基于PHOG的形状检索在实际应用中效果如何?从原课程展示的案例来看:

  • 优点:对于形状轮廓清晰、且姿态(如物体的站立方向)一致的物体,检索效果不错。例如,不同颜色的手提包、不同款式的鞋子(高帮/低帮、有鞋带/无鞋带),只要主体形状相似,都能被较好地检索出来。
  • 局限性:其模型隐含了一个强假设——图像中的物体都是“正着”存储的。例如,人都是站立的,包都是正放的。如果物体发生旋转(如人躺着)、严重形变或视角剧烈变化,PHOG特征会随之发生很大改变,导致检索效果下降。因此,它是一种相对“朴素”的形状匹配方法。

📝 动手练一练

  1. 概念辨析:PHOG特征中的“金字塔”具体指什么?它为什么能提升形状检索的鲁棒性?
  2. 手算练习:假设有两个3维的简化直方图 A=[0.3, 0.5, 0.2] 和 B=[0.4, 0.3, 0.3],请分别计算它们之间的标准化欧氏距离(假设三个维度的标准差均为0.1)和直方图相交度。
👉 点击查看参考答案
  1. 概念辨析:

    • PHOG中的“金字塔”指的是对图像进行多尺度网格划分,通常包括1×1(全局)、2×2和4×4(局部)等多个层次。
    • 这种多尺度结构提升了鲁棒性,因为它同时考虑了全局轮廓(粗网格)和局部细节(细网格)。即使图像发生轻微形变或局部遮挡,全局轮廓可能保持不变,而其他尺度的网格也能捕捉到未受影响的局部形状信息,使得整体特征更具判别力和稳定性。
  2. 手算练习:

    • 标准化欧氏距离: diff=(A−B)/σ=[−0.1,0.2,−0.1]/0.1=[−1,2,−1]\text{diff} = (A-B)/\sigma = [-0.1, 0.2, -0.1] / 0.1 = [-1, 2, -1] distance=(−1)2+22+(−1)2=1+4+1=6≈2.449\text{distance} = \sqrt{(-1)^2 + 2^2 + (-1)^2} = \sqrt{1+4+1} = \sqrt{6} \approx 2.449
    • 直方图相交度: min⁡(A,B)=[0.3,0.3,0.2]\min(A, B) = [0.3, 0.3, 0.2] intersection=0.3+0.3+0.2=0.8\text{intersection} = 0.3 + 0.3 + 0.2 = 0.8

本章小结

本节我们深入探讨了基于形状相似性的图像检索方法。通过引入PHOG特征,我们学会了如何将图像的边缘方向信息在多尺度网格上进行统计编码,形成一个189维的紧凑形状描述子。同时,掌握了标准化欧氏距离和直方图相交法这两种适用于比较直方图特征的相似度度量方式。PHOG是深度学习时代之前,利用手工特征进行形状分析的经典代表,其思想至今仍有启发意义。

📋 行动清单

  • 理解PHOG特征提取的完整流程:灰度化->计算梯度->金字塔网格划分->各网格内统计9bin方向直方图->串联。
  • 掌握标准化欧氏距离与直方图相交法的计算公式,并理解它们各自的适用场景。
  • 思考PHOG特征对物体旋转敏感的原因,并尝试构思如何改进使其具有旋转不变性。

—— 小象教研组