这里想探索图像匹配问题的处理,即在一个大图中找一个小图的位置。相关的文献有很多。这里参照论文(孙远,周刚慧,赵立初,施鹏飞 灰度图像匹配的快速算法 上海交通大学学报)将图像投影成一维字符串,并使用KMP算法查找匹配。
一些具体实现写在了注释中。
import numpy as np
from PIL import Image
def mtx_similar1(arr1:np.ndarray, arr2:np.ndarray) ->float:
'''
计算矩阵相似度的一种方法。将矩阵展平成向量,计算向量的乘积除以模长。
注意有展平操作。
:param arr1:矩阵1
:param arr2:矩阵2
:return:实际是夹角的余弦值,ret = (cos+1)/2
'''
farr1 = arr1.ravel()
farr2 = arr2.ravel()
len1 = len(farr1)
len2 = len(farr2)
if len1 > len2:
farr1 = farr1[:len2]
else:
farr2 = farr2[:len1]
#~如果矩阵的维度、向量的模长不一样。
numer = np.sum(farr1 * farr2)
denom = np.sqrt(np.sum(farr1**2) * np.sum(farr2**2))
similar = numer / denom # 这实际是夹角的余弦值
return (similar+1) / 2 # 姑且把余弦函数当线性
def mtx_similar2(arr1:np.ndarray, arr2:np.ndarray) ->float:
'''
计算对矩阵1的相似度。相减之后对元素取平方再求和。因为如果越相似那么为0的会越多。
如果矩阵大小不一样会在左上角对齐,截取二者最小的相交范围。
:param arr1:矩阵1
:param arr2:矩阵2
:return:相似度(0~1之间)
'''
if arr1.shape != arr2.shape:
minx = min(arr1.shape[0],arr2.shape[0])
miny = min(arr1.shape[1],arr2.shape[1])
differ = arr1[:minx,:miny] - arr2[:minx,:miny]
else:
differ = arr1 - arr2
numera = np.sum(differ**2)
denom = np.sum(arr1**2)
similar = 1 - (numera / denom)
return similar
def mtx_similar3(arr1:np.ndarray, arr2:np.ndarray) ->float:
'''
From CS231n: There are many ways to decide whether
two matrices are similar; one of the simplest is the Frobenius norm. In case
you haven't seen it before, the Frobenius norm of two matrices is the square
root of the squared sum of differences of all elements; in other words, reshape
the matrices into vectors and compute the Euclidean distance between them.
difference = np.linalg.norm(dists - dists_one, ord='fro')
:param arr1:矩阵1
:param arr2:矩阵2
:return:相似度(0~1之间)
'''
if arr1.shape != arr2.shape:
minx = min(arr1.shape[0],arr2.shape[0])
miny = min(arr1.shape[1],arr2.shape[1])
differ = arr1[:minx,:miny] - arr2[:minx,:miny]
#~如果矩阵的大小不一样
else:
differ = arr1 - arr2
dist = np.linalg.norm(differ, ord='fro')
len1 = np.linalg.norm(arr1)
len2 = np.linalg.norm(arr2) # 普通模长
denom = (len1 + len2) / 2
similar = 1 - (dist / denom)
return similar
import random
def find_position_process(page:str,pic:str):
'''
问题:在一个大图中查找一个小图/模板图
这是基础但低效的算法,效率之低而几乎不会用——在我的电脑上一张一千多像素宽度的图查一个400*400图用了超过20min。
:param page:大图
:param pic:小图
:return:打印匹配度较高的位置
'''
pageArr = np.array(Image.open(page).convert('L'))
picArr = np.array(Image.open(pic).convert('L')) # 首先转换成灰度图像
hei,wid = picArr.shape
# if hei > 600:
# #太大了,裁一个400*400以内的小块,用之预比较
# hStart = int(random.uniform(0,hei-400))
# if wid > 400:
# wStart = int(random.uniform(0,wid-400))
# smallArr = picArr[hStart:hStart + 400, wStart:wStart + 400]
# else:
# smallArr = picArr[hStart:hStart + 400,:]
# elif wid > 600:
# wStart = int(random.uniform(0,wid-400))
# smallArr = picArr[:, wStart:wStart+400] # 好吧,实际上保证是比较块一定在600*600以内
# else:
#……发现可能大的子图比较的反而快
smallArr = picArr
sHei, sWid = smallArr.shape
for i in range(0,hei - sHei):
if i%100 == 0:
print('do i:', i)
for k in range(0, wid - sWid):
sim = mtx_similar2(smallArr, pageArr[i: i+sHei, k: k+sWid])
if sim >