繁体   English   中英

在 Python 中使用 Pillow 从图像中裁剪区域

[英]Crop area from image using Pillow in Python

带有不平行于边距的线条的矩形

我想在 python 中使用 Pillow 从图像中裁剪一个矩形区域。 问题是矩形不需要与图像边距平行,所以我不能使用 .crop((left, top, right, bottom)) 函数。

有没有办法用 Pillow 实现这一目标? (假设我们知道矩形的所有 4 个点的坐标)如果没有,如何使用不同的 Python 库来完成?

最终结果应该是这样的

您可以在 OpenCV 中使用最小旋转矩形:

rect = cv2.minAreaRect(cnt)
box = cv2.boxPoints(rect)
box = np.int0(box)

结果你有:矩形的中心坐标(x,y),宽度,高度,旋转角度。 您可以从这个矩形角度旋转整个图像。 您的图像现在将被旋转:

旋转图像

您可以计算四个矩形顶点的新坐标(您有角度)。 然后只需计算这些点的正常矩形(正常矩形 = 不是最小的,没有任何旋转)。 使用此矩形,您可以裁剪旋转后的图像。 如果我对您的理解正确,则在此裁剪图像中将是您想要的。 类似的东西:

结果

所以你只需要Opencv。 也许有一些图书馆可以让您更轻松地做到这一点。

这是一个基于 scikit-image(不是 Pillow)的解决方案,您可能会觉得它很有用。

您可以将要裁剪的区域的顶点传递给函数skimage.draw.polygon ,然后使用检索到的像素坐标来屏蔽原始图像(例如,通过 alpha 通道)。

import numpy as np
from skimage import io, draw

img = io.imread('https://i.stack.imgur.com/x5Ym4.png')

vertices = np.asarray([[150, 140],
                       [300, 240],
                       [210, 420],
                       [90, 320],
                       [150, 150]])

rows, cols = draw.polygon(vertices[:, 0], vertices[:, 1])

crop = img.copy()
crop[:, :, -1] = 0
crop[rows, cols, -1] = 255

io.imshow(crop)

蒙面图像

我改编了这个基于opencv的解决方案( sub_image以与PIL一起使用。 它需要一个(center, size, theta) rect,我从cv2.minAreaRect得到,但可以从点等数学上构造。

我看过其他一些解决方案,但它们留下了一些奇怪的工件。

     
def crop_tilted_rect(image, rect):
    """ crop rect out of image, handing rotation
    
    rect in this case is a tuple of ((center_x, center_y), (width, height), theta),
    which I get from opencv's cv2.minAreaRect(contour)
    """
    # Get center, size, and angle from rect
    center, size, theta = rect
    width, height = [int(d) for d in size]

    if 45 < theta <= 90:
        theta = theta - 90
        width, height = height, width

    theta *= math.pi / 180 # convert to rad
    v_x = (math.cos(theta), math.sin(theta))
    v_y = (-math.sin(theta), math.cos(theta))
    s_x = center[0] - v_x[0] * (width / 2) - v_y[0] * (height / 2)
    s_y = center[1] - v_x[1] * (width / 2) - v_y[1] * (height / 2)
    mapping = np.array([v_x[0],v_y[0], s_x, v_x[1],v_y[1], s_y])
    return image.transform((width, height), Image.AFFINE, data=mapping, resample=0, fill=1, fillcolor=(255,255,255))

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM