滑动窗口直方图#

直方图匹配可用于图像中的物体检测 [1]。本示例从 skimage.data.coins 图像中提取一枚硬币,并使用直方图匹配尝试在原始图像中定位它。

首先,提取包含目标硬币的图像的盒形区域,并计算其灰度值的直方图。

接下来,对于测试图像中的每个像素,计算围绕像素的图像区域的灰度值的直方图。 skimage.filters.rank.windowed_histogram 用于此任务,因为它使用高效的滑动窗口算法,能够快速计算这些直方图 [2]。将围绕图像中每个像素的区域的局部直方图与单个硬币的直方图进行比较,计算并显示相似性度量。

使用 numpy.histogram 在围绕硬币的盒形区域上计算单个硬币的直方图,而滑动窗口直方图使用略微不同的尺寸的圆盘形结构元素进行计算。这样做是为了演示,即使存在这些差异,该技术仍然能够找到相似性。

为了演示该技术的旋转不变性,对旋转 45 度的硬币图像版本执行了相同的测试。

参考文献#

Quantized image, Coin from 2nd row, 4th column, Original image with overlaid similarity, Rotated image with overlaid similarity
import numpy as np
import matplotlib
import matplotlib.pyplot as plt

from skimage import data, transform
from skimage.util import img_as_ubyte
from skimage.morphology import disk
from skimage.filters import rank


matplotlib.rcParams['font.size'] = 9


def windowed_histogram_similarity(image, footprint, reference_hist, n_bins):
    # Compute normalized windowed histogram feature vector for each pixel
    px_histograms = rank.windowed_histogram(image, footprint, n_bins=n_bins)

    # Reshape coin histogram to (1,1,N) for broadcast when we want to use it in
    # arithmetic operations with the windowed histograms from the image
    reference_hist = reference_hist.reshape((1, 1) + reference_hist.shape)

    # Compute Chi squared distance metric: sum((X-Y)^2 / (X+Y));
    # a measure of distance between histograms
    X = px_histograms
    Y = reference_hist

    num = (X - Y) ** 2
    denom = X + Y
    denom[denom == 0] = np.inf
    frac = num / denom

    chi_sqr = 0.5 * np.sum(frac, axis=2)

    # Generate a similarity measure. It needs to be low when distance is high
    # and high when distance is low; taking the reciprocal will do this.
    # Chi squared will always be >= 0, add small value to prevent divide by 0.
    similarity = 1 / (chi_sqr + 1.0e-4)

    return similarity


# Load the `skimage.data.coins` image
img = img_as_ubyte(data.coins())

# Quantize to 16 levels of grayscale; this way the output image will have a
# 16-dimensional feature vector per pixel
quantized_img = img // 16

# Select the coin from the 4th column, second row.
# Coordinate ordering: [x1,y1,x2,y2]
coin_coords = [184, 100, 228, 148]  # 44 x 44 region
coin = quantized_img[coin_coords[1] : coin_coords[3], coin_coords[0] : coin_coords[2]]

# Compute coin histogram and normalize
coin_hist, _ = np.histogram(coin.flatten(), bins=16, range=(0, 16))
coin_hist = coin_hist.astype(float) / np.sum(coin_hist)

# Compute a disk shaped mask that will define the shape of our sliding window
# Example coin is ~44px across, so make a disk 61px wide (2 * rad + 1) to be
# big enough for other coins too.
footprint = disk(30)

# Compute the similarity across the complete image
similarity = windowed_histogram_similarity(
    quantized_img, footprint, coin_hist, coin_hist.shape[0]
)

# Now try a rotated image
rotated_img = img_as_ubyte(transform.rotate(img, 45.0, resize=True))
# Quantize to 16 levels as before
quantized_rotated_image = rotated_img // 16
# Similarity on rotated image
rotated_similarity = windowed_histogram_similarity(
    quantized_rotated_image, footprint, coin_hist, coin_hist.shape[0]
)

fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(10, 10))

axes[0, 0].imshow(quantized_img, cmap='gray')
axes[0, 0].set_title('Quantized image')
axes[0, 0].axis('off')

axes[0, 1].imshow(coin, cmap='gray')
axes[0, 1].set_title('Coin from 2nd row, 4th column')
axes[0, 1].axis('off')

axes[1, 0].imshow(img, cmap='gray')
axes[1, 0].imshow(similarity, cmap='hot', alpha=0.5)
axes[1, 0].set_title('Original image with overlaid similarity')
axes[1, 0].axis('off')

axes[1, 1].imshow(rotated_img, cmap='gray')
axes[1, 1].imshow(rotated_similarity, cmap='hot', alpha=0.5)
axes[1, 1].set_title('Rotated image with overlaid similarity')
axes[1, 1].axis('off')

plt.tight_layout()
plt.show()

脚本的总运行时间: (0 分钟 1.659 秒)

由 Sphinx-Gallery 生成的画廊