简体   繁体   English

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

[英]Crop area from image using Pillow in Python

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

I want to crop a rectangle shape area from an image using Pillow in python.我想在 python 中使用 Pillow 从图像中裁剪一个矩形区域。 The problem is that the rectangle is not necessary parallel with the image margins so I cannot use the .crop((left, top, right, bottom)) function.问题是矩形不需要与图像边距平行,所以我不能使用 .crop((left, top, right, bottom)) 函数。

Is there a way to achieve this with Pillow?有没有办法用 Pillow 实现这一目标? (assuming we know the coordinates of all 4 points of rectangle) If not, how it can be done using a different Python library? (假设我们知道矩形的所有 4 个点的坐标)如果没有,如何使用不同的 Python 库来完成?

最终结果应该是这样的

You can use min rotated rectangle in OpenCV:您可以在 OpenCV 中使用最小旋转矩形:

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

As a result You have: center coordinates (x,y), width, height, angle of rotation of rectangle.结果你有:矩形的中心坐标(x,y),宽度,高度,旋转角度。 You can rotate whole image with angle from this rectangle.您可以从这个矩形角度旋转整个图像。 You image now will be rotated:您的图像现在将被旋转:

旋转图像

You can calculate new coordinates of four rectangle vertices (you got angle).您可以计算四个矩形顶点的新坐标(您有角度)。 Then just calculate normal rectangle for this points (normal rectangle = not minimal, without any rotation).然后只需计算这些点的正常矩形(正常矩形 = 不是最小的,没有任何旋转)。 With this rect You can crop Your rotated image.使用此矩形,您可以裁剪旋转后的图像。 In this crop image will be what You want if I understand You correctly.如果我对您的理解正确,则在此裁剪图像中将是您想要的。 Something like that:类似的东西:

结果

So You only need Opencv.所以你只需要Opencv。 Maybe there is some library with which You can do it easier.也许有一些图书馆可以让您更轻松地做到这一点。

Here's a solution based on scikit-image (not Pillow) that you might find useful.这是一个基于 scikit-image(不是 Pillow)的解决方案,您可能会觉得它很有用。

You could pass the vertices of the region you wish to crop to the function skimage.draw.polygon and then use the retrieved pixel coordinates to mask the original image (for example, through the alpha channel).您可以将要裁剪的区域的顶点传递给函数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)

蒙面图像

I adapted this opencv -based solution ( sub_image ) for use with PIL .我改编了这个基于opencv的解决方案( sub_image以与PIL一起使用。 It takes a (center, size, theta) rect which I'm getting from cv2.minAreaRect , but could be constructed mathmatically from points, etc.它需要一个(center, size, theta) rect,我从cv2.minAreaRect得到,但可以从点等数学上构造。

I've seen a few other solutions but they left some weird artifacts.我看过其他一些解决方案,但它们留下了一些奇怪的工件。

     
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.

相关问题 如何使用 Python 中的枕头以 1:1 的纵横比裁剪图像? - How can I crop an Image with 1:1 aspect ratio using pillow in Python? OpenCV Python:从图像中检索矩形主区域然后裁剪图像 - OpenCV Python: retrieve rectangle main area from image then crop image 我无法使用“枕头”的“裁剪”来剪切图像 - I can't cut of image using “crop” of “pillow” Python OpenCV - 将图像裁剪为灰色背景区域 - Python OpenCV - Crop image to area with gray background 使用Python / PIL裁剪图像的非对称区域 - Crop non symmetric area of an image with Python/PIL 如何使用 Python(枕头)从顶部淡化具有透明度的图像 - How to fade an image with transparency from the top using Python (Pillow) 为什么将 Image.save()(来自 Python 中的 Pillow)与变量一起使用不起作用? - Why using Image.save() (from Pillow in Python) with variables is not working? 使用Opencv和python从高分辨率图像中检测并裁剪图像 - Detect and crop the image from high resolution image using Opencv with python 使用 Python PIL/pillow 调整图像大小的问题 - Issue using Python PIL/pillow to resize image 使用Pillow在Python中将数组转换为图像(tif) - Converting Array into Image (tif) in Python using Pillow
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM