【问题标题】:Matrix match in pythonpython中的矩阵匹配
【发布时间】:2018-11-13 18:20:11
【问题描述】:

如何在大矩阵中找到小矩阵的最佳“匹配”? 例如:

 small=[[1,2,3],
        [4,5,6],
        [7,8,9]]



    big=[[2,4,2,3,5],
         [6,0,1,9,0],
         [2,8,2,1,0],
         [7,7,4,2,1]]

匹配被定义为矩阵中数字的差异,因此位置 (1,1) 的匹配就好像从小的数字 5 将在大矩阵的数字 0 上(所以坐标中小矩阵的中心数字 (1 ,1) 的大矩阵。

位置 (1,1) 的匹配值为: m(1,1)=|2−1|+|4−2|+|2−3|+|6−4|+|0−5|+|1−6|+|2−7|+| 8−8|+|2−9|=28

目标是找到这些矩阵中可能的最小差异。

小矩阵总是有奇数行和奇数列,所以很容易找到它的中心。

【问题讨论】:

  • 这样的模板匹配几乎肯定已经存在于opencv中了。
  • 描述得很好 - 你在哪里编写代码来尝试解决这个问题?
  • 请不要破坏您的帖子。通过在 Stack Exchange 网络上发布,您已授予 SE 分发该内容的不可撤销的权利(在 CC BY-SA 3.0 license 下)。根据 SE 政策,任何破坏行为都将被撤销。

标签: python python-3.x matrix similarity


【解决方案1】:

您可以遍历可行的行和列,并使用small 压缩big 的切片以计算差异之和,并使用min 找到差异中的最小值:

from itertools import islice
min(
    (
        sum(
            sum(abs(x - y) for x, y in zip(a, b))
            for a, b in zip(
                (
                    islice(r, col, col + len(small[0]))
                    for r in islice(big, row, row + len(small))
                ),
                small
            )
        ),
        (row, col)
    )
    for row in range(len(big) - len(small) + 1)
    for col in range(len(big[0]) - len(small[0]) + 1)
)

或一行:

min((sum(sum(abs(x - y) for x, y in zip(a, b)) for a, b in zip((islice(r, col, col + len(small[0])) for r in islice(big, row, row + len(small))), small)), (row, col)) for row in range(len(big) - len(small) + 1) for col in range(len(big[0]) - len(small[0]) + 1))

返回:(24, (1, 0))

【讨论】:

  • pylint:行太长。
  • 我已经用分解版本更新了答案。
  • 喜欢您的解决方案!虽然有一些问题:对于矩阵
  • @IvanHlivan 我明白了。我已将您的示例数据放在这里:repl.it/repls/FrontFoolhardyExtraction,正如您所看到的(通过单击“运行”按钮),最小的差异确实发生在 (0, 16)。你是怎么得出它应该是 (5, x) 的结论?那么 (5, x) 中的这个“x”到底是什么?
  • 对不起,我的错。比较其他结果。
【解决方案2】:

手工完成:

small=[[1,2,3],
       [4,5,6],
       [7,8,9]]


big=[[2,4,2,3,5],
     [6,0,1,9,0],
     [2,8,2,1,0],
     [7,7,4,2,1]]

# collect all the sums    
summs= [] 

# k and j are the offset into big

for k in range(len(big)-len(small)+1):
    # add inner list for one row
    summs.append([])
    for j in range(len(big[0])-len(small[0])+1):
        s = 0
        for row in range(len(small)):
            for col in range(len(small[0])):
                s += abs(big[k+row][j+col]-small[row][col])
        # add to the inner list
        summs[-1].append(s)

print(summs)

输出:

[[28, 29, 38], [24, 31, 39]]

如果您只对较大坐标中的坐标感兴趣,请将 (rowoffset,coloffset,sum) 的元组存储起来,并且不要将列表放入列表中。你可以这样使用min() 和一个键:

summs = []
for k in range(len(big)-len(small)+1):
    for j in range(len(big[0])-len(small[0])+1):
        s = 0
        for row in range(len(small)):
            for col in range(len(small[0])):
                s += abs(big[k+row][j+col]-small[row][col])
        summs .append( (k,j,s) )  # row,col, sum

print ("Min value for bigger matrix at ", min(summs , key=lambda x:x[2]) )

输出:

Min value for bigger matrix at  (1, 0, 24)

如果您有“绘图”,则只会返回具有最小行的列偏移量。

【讨论】:

    【解决方案3】:

    另一种可能的解决方案是,返回big 矩阵中的最小差异和坐标:

    small=[[1,2,3],
           [4,5,6],
           [7,8,9]]
    
    big=[[2,4,2,3,5],
         [6,0,1,9,0],
         [2,8,2,1,0],
         [7,7,4,2,1]]
    
    def difference(small, matrix):
        l = len(small)
        return sum([abs(small[i][j] - matrix[i][j]) for i in range(l) for j in range(l)])
    
    def getSubmatrices(big, smallLength):
        submatrices = []
        bigLength = len(big)
        step = (bigLength // smallLength) + 1
        for i in range(smallLength):
            for j in range(step):
                tempMatrix = [big[j+k][i:i+smallLength] for k in range(smallLength)]
                submatrices.append([i+1,j+1,tempMatrix])
        return submatrices
    
    def minDiff(small, big):
        submatrices = getSubmatrices(big, len(small))
        diffs = [(x,y, difference(small, submatrix)) for x, y, submatrix in submatrices]
        minDiff = min(diffs, key=lambda elem: elem[2])
        return minDiff
    
    y, x, diff = minDiff(small, big)
    
    print("Minimum difference: ", diff)
    print("X = ", x)
    print("Y = ", y)
    

    输出:

    Minimum difference:  24
    X =  1
    Y =  2
    

    【讨论】:

      【解决方案4】:

      我会使用 numpy 来帮助解决这个问题。

      首先我会将数组转换为 numpy 数组

      import numpy as np
      
      small = np.array([[1,2,3], [4,5,6], [7,8,9]])
      big = np.array([[2,4,2,3,5], [6,0,1,9,0], [2,8,2,1,0], [7,7,4,2,1]])
      

      然后我会初始化一个数组来存储测试结果(可选:一个字典)

      result_shape = np.array(big.shape) - np.array(small.shape) + 1
      results = np.zeros((result_shape[0], result_shape[1]))
      result_dict = {}
      

      然后迭代小矩阵可以定位到大矩阵的位置,计算差值:

      insert = np.zeros(big.shape)
      for i in range(results.shape[0]):
          for j in range(results.shape):
              insert[i:small.shape[0] + i, j:small.shape[1] + j] = small
              results[i, j] = np.sum(np.abs(big - insert)[i:3+i, j:3+j])
              # Optional dictionary 
              result_dict['{}{}'.format(i, j)] = np.sum(np.abs(big - insert)[i:3+i, j:3+j])
      

      那么你可以print(results)获取:

      [[ 28.  29.  38.]
       [ 24.  31.  39.]]
      

      和/或由于小矩阵相对于大矩阵的位置存储在字典的键中,您可以通过键操作获得小矩阵相对于大矩阵的位置差异最小的位置:

      pos_min = [int(i) for i in list(min(result_dict, key=result_dict.get))]
      

      如果你print(pos_min),你会得到:

      [1, 0]
      

      然后,如果您需要任何内容​​的索引,您可以在需要时对其进行迭代。希望这会有所帮助!

      【讨论】:

        猜你喜欢
        • 2015-06-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-01-21
        • 2013-07-26
        • 2018-05-18
        • 2021-12-29
        • 2019-12-10
        相关资源
        最近更新 更多