2016-03-05 254 views
1

我正在尝试使用模板匹配来查找从LaTeX生成的给定pdf文档中的公式。当我通过here使用代码时,当我从原始页面裁剪图片(转换为jpeg或png)时,我只得到非常好的匹配,但是当我单独编译方程代码并生成它的jpg/png输出时,匹配出错了。OpenCV中模板匹配的分辨率操作

我相信原因与分辨率有关,但由于我是该领域的业余爱好者,因此我无法合理地将生成的jpg从独立公式中生成为具有与整个页面相同的jpg像素结构。下面是被复制的代码(或多或少)从OpenCV中的上述网站,这对于蟒一个实现:

import cv2 
from PIL import Image 

img = cv2.imread('location of the original image', 0) 
img2 = img.copy() 
template = cv2.imread('location of the patch I look for',0) 
w, h = template.shape[::-1] 

# All the 6 methods for comparison in a list 
methods = ['cv2.TM_CCOEFF', 'cv2.TM_CCOEFF_NORMED', 'cv2.TM_CCORR', 
      'cv2.TM_CCORR_NORMED', 'cv2.TM_SQDIFF', 'cv2.TM_SQDIFF_NORMED'] 

method = eval(methods[0]) 

# Apply template Matching 
res = cv2.matchTemplate(img,template,method) 
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res) 
# If the method is TM_SQDIFF or TM_SQDIFF_NORMED, take minimum 
if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]: 
    top_left = min_loc 
else: 
    top_left = max_loc 
bottom_right = (top_left[0] + w, top_left[1] + h) 
print top_left, bottom_right 

img = Image.open('location of the original image') 

#cropping the original image with the found coordinates to make a qualitative comparison 
cropped = img.crop((top_left[0], top_left[1], bottom_right[0], bottom_right[1])) 
cropped.save('location to save the cropped image using the coordinates found by template matching') 

这里是一个示例页面,我寻找第一个方程: enter image description here

,以产生特定的独立方程的代码如下:

\documentclass[preview]{standalone} 
\usepackage{amsmath} 
\begin{document}\begin{align*} 
(\mu_1+\mu_2)(\emptyset) = \mu_1(\emptyset) + \mu_2(\emptyset) = 0 + 0 =0 
\label{eq_0} 
\end{align*} 
\end{document} 

其中我编译和后面或者使用pdfcrop或使用图像配修剪方程周围的白色空间()方法在PythonMagick。在原始页面上使用此修剪输出生成的模板匹配没有给出合理的结果。这里是使用pdfcrop/Mac's Preview.app的修剪/转换输出:

enter image description here

直接从上面的页面中裁剪方程是完美的。我会感谢一些解释和帮助。

编辑: 我还发现它通过穷举可能的不同尺度使用模板匹配的情况如下: http://www.pyimagesearch.com/2015/01/26/multi-scale-template-matching-using-python-opencv/

但是因为我愿意尽可能多的处理如文件1000,这似乎是一个很慢的方法去。此外,我想应该有一个更合理的方式来处理它,通过某种方式找到相关的尺度。

回答

2

除了模板匹配,您可以使用features,即关键点与描述符。它们是比例不变的,因此您不需要遍历图像的不同缩放版本。

python示例find_obj.py 伴随OpenCV提供的ORB功能适用于您的示例。

python find_obj.py --feature=brisk rB4Yy_big.jpg ZjBAA.jpg 

result

请注意,我没有使用公式的修剪版本搜索,但与它周围的一些白色像素的版本,所以关键点检测可以正常工作。它周围需要有一些空间,因为关键点必须完全位于图像内部。否则描述符不能被计算。

padded formula

大的图像是从您的文章原始。

一个额外的评论:你总是会得到一些比赛。如果您正在搜索的公式图像不存在于大图像中,则匹配将是无意义的。如果你需要理清这些误报,您有以下选择:


编辑:既然你问吧,这里是绘制围绕发现式的,而不是比赛的边框版本:

#!/usr/bin/env python 

# Python 2/3 compatibility 
from __future__ import print_function 

import numpy as np 
import cv2 

def init_feature(): 
    detector = cv2.BRISK_create() 
    norm = cv2.NORM_HAMMING 
    matcher = cv2.BFMatcher(norm) 
    return detector, matcher 

def filter_matches(kp1, kp2, matches, ratio = 0.75): 
    mkp1, mkp2 = [], [] 
    for m in matches: 
     if len(m) == 2 and m[0].distance < m[1].distance * ratio: 
      m = m[0] 
      mkp1.append(kp1[m.queryIdx]) 
      mkp2.append(kp2[m.trainIdx]) 
    p1 = np.float32([kp.pt for kp in mkp1]) 
    p2 = np.float32([kp.pt for kp in mkp2]) 
    kp_pairs = zip(mkp1, mkp2) 
    return p1, p2, kp_pairs 

def explore_match(win, img1, img2, kp_pairs, status = None, H = None): 
    h1, w1 = img1.shape[:2] 
    h2, w2 = img2.shape[:2] 
    vis = np.zeros((max(h1, h2), w1+w2), np.uint8) 
    vis[:h1, :w1] = img1 
    vis[:h2, w1:w1+w2] = img2 
    vis = cv2.cvtColor(vis, cv2.COLOR_GRAY2BGR) 

    if H is not None: 
     corners = np.float32([[0, 0], [w1, 0], [w1, h1], [0, h1]]) 
     corners = np.int32(cv2.perspectiveTransform(corners.reshape(1, -1, 2), H).reshape(-1, 2) + (w1, 0)) 
     cv2.polylines(vis, [corners], True, (0, 0, 255)) 

    cv2.imshow(win, vis) 
    return vis 

if __name__ == '__main__': 

    img1 = cv2.imread('rB4Yy_big.jpg' , 0) 
    img2 = cv2.imread('ZjBAA.jpg', 0) 
    detector, matcher = init_feature() 

    kp1, desc1 = detector.detectAndCompute(img1, None) 
    kp2, desc2 = detector.detectAndCompute(img2, None) 

    raw_matches = matcher.knnMatch(desc1, trainDescriptors = desc2, k = 2) 
    p1, p2, kp_pairs = filter_matches(kp1, kp2, raw_matches) 
    if len(p1) >= 4: 
     H, status = cv2.findHomography(p1, p2, cv2.RANSAC, 5.0) 
     print('%d/%d inliers/matched' % (np.sum(status), len(status))) 
     vis = explore_match('find_obj', img1, img2, kp_pairs, status, H) 
     cv2.waitKey() 
     cv2.destroyAllWindows() 
    else: 
     print('%d matches found, not enough for homography estimation' % len(p1)) 

bounding box

+0

非常感谢您的详细回复。我无法运行find_obj.py代码,因为它需要常用软件包,我无法找到它。但find_obj是否提供了包含较小图片的框的坐标?这对我来说是最重要的。 – Cupitor

+0

@Cupitor示例本身并未在其周围放置一个框。但是由于在公式专用图像(仅限于图像边界)周围有方框,并且在大图像中有相应的点,因此可以通过计算由关键点匹配确定的变换矩阵和然后翘曲盒子。 –

+1

@Cupitor公共包也在OpenCV的python示例目录中。但是我做了一个修改过的'find_obj.py'独立版本,它以红色绘制找到的公式的边界框。我将代码添加到我的答案中。 –

0

模板匹配的问题在于它只能在非常受控制的环境中工作。意思是说,如果你从实际的图像中获取模板,它会很好地工作,但如果分辨率不同或者图像稍微转动一点,它将不起作用。

我建议你找到更适合这个问题的另一种算法。在OpenCV docs中,您可以找到针对您的问题的一些特定算法。

+0

谢谢您。由于从角度来看,我的照片绝对没有改变,在我看来,应该有一个逻辑来纠正它。我应该补充说,我无法在OpenCV中找到其他能够返回匹配的确切坐标的其他内容。这大多是功能匹配! – Cupitor