【问题标题】:Resolution Manipulation for Template Matching in OpenCVOpenCV中模板匹配的分辨率操作
【发布时间】:2016-03-05 21:30:17
【问题描述】:

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

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

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')

这是我寻找第一个等式的示例页面:

生成特定独立方程的代码如下:

\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 中的.image() 方法修剪方程周围的空白。在原始页面上使用此修剪输出生成的模板匹配不会给出合理的结果。这是使用 pdfcrop/Mac 的 Preview.app 修剪/转换的输出:

.

从上面的页面直接裁剪方程效果很好。我会很感激一些解释和帮助。

编辑: 我还发现以下内容通过暴力破解不同的可能比例来使用模板匹配: http://www.pyimagesearch.com/2015/01/26/multi-scale-template-matching-using-python-opencv/

但是,由于我愿意处理多达 1000 个文档,因此这似乎是一种非常缓慢的方法。另外,我想应该有一种更合乎逻辑的方式来处理它,通过某种方式找到相关的尺度。

【问题讨论】:

    标签: python opencv pdf image-processing resolution


    【解决方案1】:

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

    python示例find_obj.py 提供的 OpenCV 与您给定示例的 ORB 功能一起使用。

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

    请注意,我没有使用裁剪后的公式进行搜索,而是使用了周围有一些白色像素的版本,因此关键点检测可以正常工作。它周围需要有一些空间,因为关键点必须完全在图像内。否则无法计算描述符。

    大图是您帖子的原图。

    补充一点:您总是会得到 一些 匹配项。如果您正在搜索的公式图像不在大图像中,则匹配将是无意义的。如果您需要理清这些误报,您有以下选择:


    编辑:既然你要求它,这里有一个版本,它围绕找到的公式而不是匹配项绘制边界框:

    #!/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))
    

    【讨论】:

    • 非常感谢您的详细回复。我无法运行 find_obj.py 代码,因为它需要通用包,但我找不到它。但是这个 find_obj 是否提供了包含较小图片的框周围的坐标?这对我来说是最重要的。
    • @Cupitor 示例本身并没有在其周围放置一个框。但是由于您在仅公式图像(仅图像边界)周围有框,并且在大图像中有相应的点,因此您可以通过计算由关键点匹配确定的变换矩阵轻松获得大图像中的框,并且然后扭曲盒子。
    • @Cupitor 常用包也在OpenCV的python示例目录下。但是我制作了一个修改过的独立版本的find_obj.py,它在找到的公式周围用红色绘制了边界框。我将代码添加到我的答案中。
    【解决方案2】:

    模板匹配的问题在于它只适用于非常受控的环境。这意味着如果您从实际图像中获取模板,它将完美地工作,但如果分辨率不同或即使图像稍微转动,它也将无法工作。

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

    【讨论】:

    • 谢谢。由于从角度来看绝对没有改变我的图片,所以在我看来应该有一个逻辑来纠正它。我应该补充一点,我无法在 OpenCV 中找到能够返回匹配的确切坐标的其他东西。主要是特征匹配!
    猜你喜欢
    • 2016-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-08
    • 2018-10-02
    • 2015-04-20
    相关资源
    最近更新 更多