2017-09-26 218 views
0

我有两个面,一个大surface imagePython的OpenCV的:使用matchTemplate

和一个较小的一个enter image description here

我试图将它们视为灰度图像,以适应template matching tutorial这些表面。

我需要更新教程以在x和y中独立缩放,我已经完成了这个工作,但添加了一个额外的循环。我的代码是:

import pandas as pd 
import numpy as np 
import cv2 
import matplotlib.pyplot as plt 
import matplotlib.patches as patches 

# If True shows each iteration of the template matching 
Visualise = True 

# Load in image and template 
image = pd.read_excel('TemplateMatching_exampleData.xlsx',sheetname="radial_template").as_matrix().astype(np.float32) 
template = pd.read_excel('TemplateMatching_exampleData.xlsx',sheetname="radial_image").as_matrix().T.astype(np.float32) 

# Save a raw copy of the template 
template_raw = template 

# Rescale the template to approximate the same range in values as the image 
template = template - np.mean(template) 
template = (template/np.max(template)) * np.max(image) 

# Get the height and width of the template 
(tH, tW) = template.shape[:2] 

# initialize the bookkeeping variable to keep track of the matched region 
found = None 

# If visualise = True then initialise the figure to show the iteration 
if Visualise: 
    fig1 = plt.figure() 
    ax1 = fig1.add_subplot(111) 

# loop over the scales of the image 
for scale_width in np.linspace(0.1, 2, 20): 
    for scale_height in np.linspace(0.1, 3, 20)[::-1]: 
     # resize the image according to the scale, and keep track 
     # of the ratio of the resizing 
     resized = cv2.resize(image, (int(image.shape[0] * scale_height), int(image.shape[1] * scale_width))) 
     r_h = image.shape[0]/float(resized.shape[0]) 
     r_w = image.shape[1]/float(resized.shape[1]) 

     # if the resized image is smaller than the template, then break 
     # from the loop 
     if resized.shape[0] < tH or resized.shape[1] < tW: 
      break 

     # apply template matching to find the template in the image 
     result = cv2.matchTemplate(resized, template, cv2.TM_CCOEFF) 
     (_, maxVal, _, maxLoc) = cv2.minMaxLoc(result) 

     # check to see if the iteration should be visualized 
     if Visualise: 
      ax1.clear() 
      ax1.imshow(resized) 
      ax1.add_patch(patches.Rectangle((maxLoc[0], maxLoc[1]), tW, tH, fill=False, edgecolor = 'red')) 
      plt.show() 
      plt.draw() 
      plt.pause(0.05) # fig1.waitforbuttonpress() 

     # if we have found a new maximum correlation value, then update 
     # the bookkeeping variable 
     if found is None or maxVal > found[0]: 
      found = (maxVal, maxLoc, r_w, r_h, scale_width, scale_height) 

# unpack the bookkeeping varaible and compute the (x, y) coordinates 
# of the bounding box based on the resized ratio 
(_, maxLoc, r_w, r_h, scale_width, scale_height) = found 
(startX, startY) = (int(maxLoc[0] * r_w), int(maxLoc[1] * r_h)) 
(endX, endY) = (int((maxLoc[0] + tW) * r_w), int((maxLoc[1] + tH) * r_h)) 

# draw a bounding box around the detected result and display the image 
figure = plt.figure() 
ax1 = figure.add_subplot(111) 
ax1.imshow(image) 
ax1.add_patch(patches.Rectangle((startX,startY), endX-startX, endY-startY, fill=False, edgecolor = 'red')) 
plt.show() 
plt.draw() 

# show the matching image segment and template together 
plt.figure() 
plt.subplot(121) 
plt.imshow(image[startX:endX, startY:endY]) 
plt.title('Image') 
plt.subplot(122) 
plt.imshow(template) 
plt.title('Template') 

但是什么我发现的是,“最佳组合”是在最大scale_width值总是发现,不管是什么我将该值设置为是,但我想不通为什么。我猜这是衡量体质如何的结果,但我对cv2.matchTemplate了解不多,因此我一直在苦苦思索这几天。

请你能帮我解决我的代码吗?

我已将我的数据从我的Excel文件复制到this GoogleDocs document

+0

1.它可能会更好用标准差(简单地'numpy.std(阵列)')不仅仅是由最大规模来划分;通过std dev移动均值和潜水给你一个0均值和单位标准dev的分布。 2.您应该缩放模板和图像以获得相似的分布。 3.您可以共享Excel数据在公共谷歌片或类似的,或缩放的灰阶值恰好浮子0 UINT8 0和1之间或之间和255,并将它们保存为OpenCV的'imwrite()'和公布这些灰度图像为我们加载。 –

+0

谢谢,我在主帖中添加了数据链接 – jlt199

+0

查看电子表格中的值,您是否实际缩放了'image'或仅仅是'template'?因为由'max'被划分后,你的模板将有'1',而你的'image'有像一个最大值'10000',所以你不会得到任何接近的比赛的最大值。请尝试按比例两者,无论是与标准方差就像我提到的,甚至只是天真地转移/他们两个大规模进入0和1,看看你是否得到比赛的方式。因为否则,只要关闭该教程并扩展您的模板应该会相对较好。 –

回答

2

一个问题开始,你可以解决

所以第一关有一些簿记需要做---似乎imagetemplate以Excel文档切换,进而似乎template是实际上旋转了90度。为了得到工作的东西,我会手动将模板缩放到合适的大小,并确保可以找到模板。请注意,我将每张表导出为.csv文件并更正了名称。

此外,我设置图像的平均值为零,标准偏差为1,只需将平均值减去标准偏差即可。这应该使图像保持大致相同的分布,以便在原始阵列中沿着高度不同的值进行良好匹配。

import cv2 
import numpy as np 

img = np.genfromtxt('radial_img.csv', delimiter=',').astype(np.float32) 
tmp = np.genfromtxt('radial_tmp.csv', delimiter=',').astype(np.float32) 
tmp = np.rot90(tmp) 
tmp = cv2.resize(tmp, None, fx=0.5, fy=0.33) 

img = (img - np.mean(img))/np.std(img) 
tmp = (tmp - np.mean(tmp))/np.std(tmp) 

ccorr = cv2.matchTemplate(img, tmp, cv2.TM_CCORR) 
tl = cv2.minMaxLoc(ccorr)[3] 
h, w = tmp.shape[:2] 
br = (tl[0]+w, tl[1]+h) 

matched = cv2.normalize(img, None, alpha=0, beta=1, norm_type=cv2.NORM_MINMAX) 
matched = cv2.merge([matched, matched, matched]) 
cv2.rectangle(matched, tl, br, (0, 255, 0)) 
cv2.imshow('matched0.png', matched) 
cv2.waitKey() 

Matched with manual resize

太好了!有用!请注意,这里的模板实际上非常小,比它应该小一点,但我们仍然有粗略的位置,所以我们知道我们正处在正确的轨道上。

通过多种尺寸

现在,我们只需要创建你做这些循环和多次调整模板,直到我们得到最佳匹配循环。但是请注意,模板匹配的方法都具有与模板大小相关的比例,所以较小的模板将具有较小的误差。因此,我们需要使用_NORMED方法来确保结果大部分是规模不变的。我认为使用列表理解来构建所有调整大小的图像,然后遍历所有这些图像更清晰,而不是创建多个for循环。我们可以随时保存最佳结果,然后在完成后显示最佳结果。请注意,这里的所有标准化都严格用于可视化;使用OpenCV功能没有必要:

import cv2 
import numpy as np 

img = np.genfromtxt('radial_img.csv', delimiter=',').astype(np.float32) 
tmp = np.genfromtxt('radial_tmp.csv', delimiter=',').astype(np.float32) 
tmp = np.rot90(tmp) 

img = (img - np.mean(img))/np.std(img) 
tmp = (tmp - np.mean(tmp))/np.std(tmp) 

sz_ranges = np.linspace(0.1, 2.0, 19) 
resized_tmps = [cv2.resize(tmp, None, fx=i, fy=j) 
       for i in sz_ranges for j in sz_ranges] 
n_tmps = len(resized_tmps) 

for rs_tmp, k in zip(resized_tmps, range(n_tmps)): 
    ccorr = cv2.matchTemplate(img, rs_tmp, cv2.TM_CCORR_NORMED) 
    match_val, match_loc = cv2.minMaxLoc(ccorr)[1::2] 
    if k == 0: 
     best_match_val = match_val 
    if match_val > best_match_val: 
     best_match_val = match_val 
     best_match_loc = match_loc 
     best_match = k 

best_match_tmp = resized_tmps[best_match] 
best_match_tmp = cv2.normalize(best_match_tmp, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8) 
best_match_tmp = cv2.merge([best_match_tmp, best_match_tmp, best_match_tmp]) 

h, w = best_match_tmp.shape[:2] 
best_match_loc_end = (best_match_loc[0]+w, best_match_loc[1]+h) 
matched = cv2.normalize(img, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8) 
matched = cv2.merge([matched, matched, matched]) 
cv2.rectangle(matched, best_match_loc, best_match_loc_end, (0, 255, 0)) 

cv2.imshow('matched1.png', matched) 
cv2.waitKey() 

cv2.imshow('besttmp.png', best_match_tmp) 
cv2.waitKey() 

而且,它的工作原理!

Matched after auto-resizing

下面是相匹配的最佳模板:

Best matched template

其中通过目测看起来是正确的。最佳匹配模板的高度和宽度为(85, 99)这基本上只是有点横向拉伸的原始模板。

+0

非常感谢,这是我可以要求的最详细,最有用的答案:D – jlt199