首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用PIL库查找子图像?

如何使用PIL库查找子图像?
EN

Stack Overflow用户
提问于 2013-07-10 17:14:45
回答 3查看 14.9K关注 0票数 19

我想使用PIL库从大图像中找到子图像。我还想知道它在哪里被发现的坐标?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-08-06 16:57:59

代码语言:javascript
复制
import cv2  
import numpy as np  
image = cv2.imread("Large.png")  
template = cv2.imread("small.png")  
result = cv2.matchTemplate(image,template,cv2.TM_CCOEFF_NORMED)  
print np.unravel_index(result.argmax(),result.shape)

这对我来说效果很好,而且效率很高。

票数 21
EN

Stack Overflow用户

发布于 2016-04-25 05:53:20

我只用了PIL就做到了这一点。

一些注意事项:

  1. ,这是一个像素完美的搜索。它只是寻找匹配的RGB像素。
  2. 为了简单起见,我删除了alpha/透明度通道。我只寻找RGB像素。
  3. 此代码将整个子图像像素数组加载到内存中,同时将大图像保留在内存之外。在我的系统上,Python为一个很小的40x30子图像保留了大约26 MiB的内存空间,通过一个1920x1200 screenshot.
  4. This的简单示例进行搜索效率不是很高,但是提高效率会增加复杂性。在这里,我让事情变得简单明了,易于understand.
  5. This示例在Windows和OSX上的工作。未在Linux上测试。它只截取主显示器的屏幕截图(用于多显示器设置)。

代码如下:

代码语言:javascript
复制
import os
from itertools import izip

from PIL import Image, ImageGrab


def iter_rows(pil_image):
    """Yield tuple of pixels for each row in the image.

    From:
    http://stackoverflow.com/a/1625023/1198943

    :param PIL.Image.Image pil_image: Image to read from.

    :return: Yields rows.
    :rtype: tuple
    """
    iterator = izip(*(iter(pil_image.getdata()),) * pil_image.width)
    for row in iterator:
        yield row


def find_subimage(large_image, subimg_path):
    """Find subimg coords in large_image. Strip transparency for simplicity.

    :param PIL.Image.Image large_image: Screen shot to search through.
    :param str subimg_path: Path to subimage file.

    :return: X and Y coordinates of top-left corner of subimage.
    :rtype: tuple
    """
    # Load subimage into memory.
    with Image.open(subimg_path) as rgba, rgba.convert(mode='RGB') as subimg:
        si_pixels = list(subimg.getdata())
        si_width = subimg.width
        si_height = subimg.height
    si_first_row = tuple(si_pixels[:si_width])
    si_first_row_set = set(si_first_row)  # To speed up the search.
    si_first_pixel = si_first_row[0]

    # Look for first row in large_image, then crop and compare pixel arrays.
    for y_pos, row in enumerate(iter_rows(large_image)):
        if si_first_row_set - set(row):
            continue  # Some pixels not found.
        for x_pos in range(large_image.width - si_width + 1):
            if row[x_pos] != si_first_pixel:
                continue  # Pixel does not match.
            if row[x_pos:x_pos + si_width] != si_first_row:
                continue  # First row does not match.
            box = x_pos, y_pos, x_pos + si_width, y_pos + si_height
            with large_image.crop(box) as cropped:
                if list(cropped.getdata()) == si_pixels:
                    # We found our match!
                    return x_pos, y_pos


def find(subimg_path):
    """Take a screenshot and find the subimage within it.

    :param str subimg_path: Path to subimage file.
    """
    assert os.path.isfile(subimg_path)

    # Take screenshot.
    with ImageGrab.grab() as rgba, rgba.convert(mode='RGB') as screenshot:
        print find_subimage(screenshot, subimg_path)

速度:

代码语言:javascript
复制
$ python -m timeit -n1 -s "from tests.screenshot import find" "find('subimg.png')"
(429, 361)
(465, 388)
(536, 426)
1 loops, best of 3: 316 msec per loop

运行上面的命令时,当timeit运行时,我对角线移动了包含子图像的窗口。

票数 9
EN

Stack Overflow用户

发布于 2013-07-18 03:46:48

听起来您想要执行对象检测,可能是通过模板匹配。这不是一个微不足道的问题,除非您正在寻找一个精确的逐像素匹配,而PIL不是用来做这类事情的。

Jan是对的,你应该试试OpenCV。它是一个健壮的计算机视觉库,具有良好的Python绑定。

下面是一个简短的Python语言示例,它在匹配的区域周围绘制了一个矩形:https://github.com/jungilhan/Tutorial/blob/master/OpenCV/templateMatching.py

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17566752

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档