图像模版匹配算法NCC的数学原理及实现
背景
NCC(Normalized Cross-Correlation,归一化互相关)是一种常用于图像处理中的模板匹配算法。其数学原理是计算模板图像与目标图像局部区域之间的相似度,通过最大化NCC值找到最匹配的位置。
NCC的计算公式如下:
NCC ( u , v ) = ∑ x , y ( T ( x , y ) − T ˉ ) ( I ( x + u , y + v ) − I ˉ u , v ) ∑ x , y ( T ( x , y ) − T ˉ ) 2 ∑ x , y ( I ( x + u , y + v ) − I ˉ u , v ) 2 \text{NCC}(u, v) = \frac{\sum_{x, y} (T(x, y) - \bar{T})(I(x+u, y+v) - \bar{I}_{u,v})}{\sqrt{\sum_{x, y} (T(x, y) - \bar{T})^2 \sum_{x, y} (I(x+u, y+v) - \bar{I}_{u,v})^2}} NCC(u,v)=∑x,y(T(x,y)−Tˉ)2∑x,y(I(x+u,y+v)−Iˉu,v)2∑x,y(T(x,y)−Tˉ)(I(x+u,y+v)−Iˉu,v)
其中:
- T ( x , y ) T(x, y) T(x,y) 是模板图像的像素值。
- I ( x + u , y + v ) I(x+u, y+v) I(x+u,y+v) 是目标图像在位置 ( u , v ) (u, v) (u,v) 处的像素值。
- T ˉ \bar{T} Tˉ 是模板图像的平均值。
- I ˉ u , v \bar{I}_{u,v} Iˉu,v 是目标图像在位置 ( u , v ) (u, v) (u,v) 处对应窗口的平均值。
数学原理
NCC(Normalized Cross-Correlation,归一化互相关)是一种常用于图像处理中的模板匹配算法。其数学原理是计算模板图像与目标图像局部区域之间的相似度,通过最大化NCC值找到最匹配的位置。
NCC的计算公式如下:
NCC ( u , v ) = ∑ x , y ( T ( x , y ) − T ˉ ) ( I ( x + u , y + v ) − I ˉ u , v ) ∑ x , y ( T ( x , y ) − T ˉ ) 2 ∑ x , y ( I ( x + u , y + v ) − I ˉ u , v ) 2 \text{NCC}(u, v) = \frac{\sum_{x, y} (T(x, y) - \bar{T})(I(x+u, y+v) - \bar{I}_{u,v})}{\sqrt{\sum_{x, y} (T(x, y) - \bar{T})^2 \sum_{x, y} (I(x+u, y+v) - \bar{I}_{u,v})^2}} NCC(u,v)=∑x,y(T(x,y)−Tˉ)2∑x,y(I(x+u,y+v)−Iˉu,v)2∑x,y(T(x,y)−Tˉ)(I(x+u,y+v)−Iˉu,v)
该公式可以分解为以下几个部分:
1. 均值计算
模板图像的均值:
T ˉ = 1 N ∑ x , y T ( x , y ) \bar{T} = \frac{1}{N} \sum_{x, y} T(x, y) Tˉ=N1x,y∑T(x,y)
目标图像局部区域的均值:
I ˉ u , v = 1 N ∑ x , y I ( x + u , y + v ) \bar{I}_{u,v} = \frac{1}{N} \sum_{x, y} I(x+u, y+v) Iˉu,v=N1x,y∑I(x+u,y+v)
其中,( N ) 是模板图像中的像素总数。
2. 零均值图像
为了计算相关性,我们需要将图像去均值:
T ′ ( x , y ) = T ( x , y ) − T ˉ T'(x, y) = T(x, y) - \bar{T} T′(x,y)=T(x,y)−Tˉ
I u , v ′ ( x , y ) = I ( x + u , y + v ) − I ˉ u , v I'_{u,v}(x, y) = I(x+u, y+v) - \bar{I}_{u,v} Iu,v′(x,y)=I(x+u,y+v)−Iˉu,v
3. 分子部分:互相关
互相关是零均值图像的乘积的和:
∑ x , y T ′ ( x , y ) I u , v ′ ( x , y ) = ∑ x , y ( T ( x , y ) − T ˉ ) ( I ( x + u , y + v ) − I ˉ u , v ) \sum_{x, y} T'(x, y) I'_{u,v}(x, y) = \sum_{x, y} (T(x, y) - \bar{T})(I(x+u, y+v) - \bar{I}_{u,v}) x,y∑T′(x,y)Iu,v′(x,y)=x,y∑(T(x,y)−Tˉ)(I(x+u,y+v)−Iˉu,v)
4. 分母部分:标准差的乘积
标准差衡量了图像的强度变化:
模板图像的标准差:
σ T = 1 N ∑ x , y ( T ( x , y ) − T ˉ ) 2 \sigma_T = \sqrt{\frac{1}{N} \sum_{x, y} (T(x, y) - \bar{T})^2} σT=N1x,y∑(T(x,y)−Tˉ)2
目标图像局部区域的标准差:
σ I u , v = 1 N ∑ x , y ( I ( x + u , y + v ) − I ˉ u , v ) 2 \sigma_{I_{u,v}} = \sqrt{\frac{1}{N} \sum_{x, y} (I(x+u, y+v) - \bar{I}_{u,v})^2} σIu,v=N1x,y∑(I(x+u,y+v)−Iˉu,v)2
5. 归一化互相关(NCC)
将互相关除以标准差的乘积,可以得到归一化互相关:
NCC ( u , v ) = ∑ x , y ( T ( x , y ) − T ˉ ) ( I ( x + u , y + v ) − I ˉ u , v ) ∑ x , y ( T ( x , y ) − T ˉ ) 2 ∑ x , y ( I ( x + u , y + v ) − I ˉ u , v ) 2 \text{NCC}(u, v) = \frac{\sum_{x, y} (T(x, y) - \bar{T})(I(x+u, y+v) - \bar{I}_{u,v})}{\sqrt{\sum_{x, y} (T(x, y) - \bar{T})^2 \sum_{x, y} (I(x+u, y+v) - \bar{I}_{u,v})^2}} NCC(u,v)=∑x,y(T(x,y)−Tˉ)2∑x,y(I(x+u,y+v)−Iˉu,v)2∑x,y(T(x,y)−Tˉ)(I(x+u,y+v)−Iˉu,v)
用到的原理和著名公式
均值计算:
- 均值是信号处理中的基本概念,用于去除数据中的直流成分,使数据更容易分析。
标准差:
- 标准差是统计学中的一个重要概念,用于衡量数据的离散程度。在图像处理中,标准差反映了图像强度的变化。
互相关(Cross-Correlation):
- 互相关是信号处理中的一个重要工具,用于衡量两个信号之间的相似度。它是卷积的变种,去除了翻转操作。
归一化:
- 归一化是为了消除量纲的影响,使得不同尺度的数据可以进行比较。在NCC中,通过归一化,可以确保相似度的度量不受图像强度变化的影响。
例子:在640x480图像上寻找16x16目标图像
考虑一个具体的例子:在640x480的图像上寻找16x16的目标图像。我们按照上述公式进行操作:
- 计算模板图像和目标图像局部区域的均值。
- 去均值,得到零均值图像。
- 计算互相关,得到分子部分。
- 计算标准差,得到分母部分。
- 计算NCC,找到NCC值最大的点,即最佳匹配位置。
代码实现
下面是一个使用OpenCV库在640x480的图像上寻找16x16目标图像的NCC算法实现的示例:
import cv2
import numpy as np
def ncc_matching(template, image):
# 转换图像为浮点数
template = np.float32(template)
image = np.float32(image)
# 获取模板和图像的尺寸
th, tw = template.shape[:2]
ih, iw = image.shape[:2]
# 计算模板的均值
template_mean = np.mean(template)
template = template - template_mean
# 计算目标图像每个窗口的均值
image_mean = cv2.boxFilter(image, ddepth=-1, ksize=(tw, th), normalize=True)
# 计算目标图像每个窗口减去均值后的结果
image = image - image_mean
# 计算NCC分子
numerator = cv2.filter2D(image, ddepth=-1, kernel=template[::-1, ::-1])
# 计算NCC分母
template_norm = np.sqrt(np.sum(template**2))
image_norm = np.sqrt(cv2.filter2D(image**2, ddepth=-1, kernel=np.ones((th, tw))))
denominator = template_norm * image_norm
# 避免分母为0的情况
denominator[denominator == 0] = 1e-10
# 计算NCC值
ncc = numerator / denominator
# 找到NCC值最大的点
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(ncc)
return max_loc, max_val
# 生成测试图像
image = np.random.randint(0, 256, (480, 640), dtype=np.uint8)
template = image[200:216, 300:316]
# 进行NCC匹配
location, value = ncc_matching(template, image)
# 输出匹配结果
print(f"Best match location: {location}, NCC value: {value}")
# 在图像上绘制匹配结果
result_image = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR)
cv2.rectangle(result_image, location, (location[0] + template.shape[1], location[1] + template.shape[0]), (0, 255, 0), 2)
# 显示结果图像
cv2.imshow("Result", result_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
代码解析
- 导入库:导入必要的OpenCV和NumPy库。
- 预处理图像:将图像和模板转换为浮点数,以便进行精确的数学计算。
- 计算均值:计算模板和目标图像每个窗口的均值。
- 去均值:将模板和目标图像每个窗口的均值减去。
- 计算NCC分子:使用滤波器计算目标图像与模板的互相关。
- 计算NCC分母:计算模板和目标图像每个窗口的L2范数。
- 计算NCC值:将分子除以分母,得到NCC值。
- 找到最佳匹配:使用OpenCV的minMaxLoc函数找到NCC值最大的点,即最佳匹配位置。
- 绘制结果:在目标图像上绘制匹配结果,并显示。