numpy scipy/sklearn中图像的距离矩阵(使用自定义度量)

i7uq4tfw  于 11个月前  发布在  其他
关注(0)|答案(1)|浏览(102)

考虑以下两个图像之间的自定义度量(注意:我知道这很糟糕,这是一个例子)。对于图像上方的每个3*3内核,它会查看匹配的像素数并计算该内核的比率。最后,它输出1 - max(ratio)

def custom_metric(a, b):
    w, h = a.shape
    ratio = []
    for i in range(w // ksize):
        for j in range(h // ksize):
            kernel_diff = a[i*ksize:(i+1)*ksize, j*ksize:(j+1)*ksize] - b[i*ksize:(i+1)*ksize, j*ksize:(j+1)*ksize]
            ratio.append( np.mean(kernel_diff == 0) )
    return 1 - max(ratio)

a = np.array([
    [1,0,0,0,0,1],
    [0,0,1,0,0,0],
    [0,0,0,0,0,0],
    [0,0,0,0,1,0],
    [0,1,0,0,0,1],
    [0,0,0,0,0,0]
])

b = np.array([
    [0,1,0,0,0,0],
    [0,0,1,0,0,1],
    [1,0,0,0,1,0],
    [0,0,0,0,1,0],
    [0,0,0,1,0,1],
    [0,0,0,1,1,1]
])

print(custom_metric(a, b)) # outputs 1/9 because of the bottom left window

字符串
我见过的scipy / sklearn中计算距离矩阵的所有函数都将shape(n_samples_X,n_features)数组作为输入,比如sklearn的pairwise_distances。是否有一个函数允许更高维的数组,例如shape(n_samples_X,width,height),我可以调用我的度量?

mcdcgff0

mcdcgff01#

尝试将特征展平到单个轴上。而不是将数据整形为(samples, height * width * channels * ...)的2D数组。这将适用于任意数量的维度,然后您可以将其提供给sklearn
在本例中,尝试a_reshaped = a.reshape([len(a), -1])。这将通过将高度轴和宽度轴移动到相同的维度上,给予您一个形状为(samples, height * width)的2D数组。
演示了如何将高度和宽度扁平化为一维,同时保持每个补丁的连续性。还演示了如何在扁平化的数组上运行OP的度量。

#Reshapes array to 1 x features, preserving
#patch contiguity
def special_flatten(arr, k):
    kr, kc = k.tolist()
    nrow = arr.shape[0] // kr
    ncol = arr.shape[1] // kc
    return (
        arr
        .reshape(nrow, kr, ncol, kc)
        .swapaxes(1, 2)
        .reshape(nrow, ncol, kr * kc)
        .reshape(nrow * ncol, kr * kc)
        .reshape(1, -1)
    )

#Computes OP's custom metric for a single sample
# but using the reshaped array
def custom_metric(a, b):
    k_area = k.prod()
    sample_num = 0
    ratio = []
    for patch_num in range(a.shape[1] // k_area):
        start = patch_num * k_area
        end = start + k_area
        
        a_vals = a[sample_num, start:end]
        b_vals = b[sample_num, start:end]
        diff = a_vals - b_vals
        ratio.append( (diff == 0).mean() )
    
    return 1 - max(ratio)

字符串
使用方法:

a = np.array([
    [1,0,0,0,0,1],
    [0,0,1,0,0,0],
    [0,0,0,0,0,0],
    [0,0,0,0,1,0],
    [0,1,0,0,0,1],
    [0,0,0,0,0,0]
])

b = np.array([
    [0,1,0,0,0,0],
    [0,0,1,0,0,1],
    [1,0,0,0,1,0],
    [0,0,0,0,1,0],
    [0,0,0,1,0,1],
    [0,0,0,1,1,1]
])

k = np.array([3, 3]) #the kernel
a_flat = special_flatten(a, k) #reshape to 1 x feats
b_flat = special_flatten(b, k)
custom_metric(a_flat, b_flat) # 1 / 9


上面的代码不是必需的,但我使用了一些额外的测试代码来检查整形结果:

a = np.array([[1.1, 1.2,  2.1, 2.2],
              [1.3, 1.4,  2.3, 2.4],
              
              [3.1, 3.2,  4.1, 4.2],
              [3.3, 3.4,  4.3, 4.4]])

kr = kc = 2
nrow = a.shape[0] // kr
ncol = a.shape[1] // kc
a_r = (
    a
    .reshape(nrow, kr, ncol, kc)
    .swapaxes(1, 2)
    .reshape(nrow, ncol, kr * kc)
    .reshape(nrow * ncol, kr * kc)
    .reshape(1, -1)
)
a_r
# a_r is 1.1 1.2 1.3 1.4  2.1 2.2 2.3 2.4  3.1 3.2 3.3 3.4  4.1 4.2 4.3 4.4

patch_area = kr * kc
for patch_num in range(a_r.size // patch_area):
    print(patch_num, ':', a_r[0, patch_num * patch_area:(patch_num + 1)*patch_area] )

#Yields:
#
# 0 : [1.1 1.2 1.3 1.4]
# 1 : [2.1 2.2 2.3 2.4]
# 2 : [3.1 3.2 3.3 3.4]
# 3 : [4.1 4.2 4.3 4.4]

相关问题