我想在python中使用Pillow从图像中裁剪出矩形区域。问题在于矩形不必与图像边缘平行,因此我不能使用.crop((left,top,right,bottom))函数。
有没有办法用枕头来做到这一点? (假设我们知道矩形的所有4个点的坐标) 如果没有,如何使用其他Python库来完成?
答案 0 :(得分:2)
您可以在OpenCV中使用最小旋转矩形:
rect = cv2.minAreaRect(cnt)
box = cv2.boxPoints(rect)
box = np.int0(box)
结果是,您具有:中心坐标(x,y),宽度,高度,矩形的旋转角度。您可以从此矩形角度旋转整个图像。您的图片现在将被旋转:
您可以计算四个矩形顶点的新坐标(角度)。然后,仅计算此点的法线矩形(法线矩形=不小,没有任何旋转)。使用此矩形,您可以裁剪旋转的图像。如果我正确理解您的话,这张照片将是您想要的。像这样:
因此您只需要Opencv。也许有些库可以使您更轻松地完成工作。
答案 1 :(得分:2)
这是一个基于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)
答案 2 :(得分:0)
我将this opencv
-based solution (sub_image
)改用于PIL
。我需要从(center, size, theta)
获得的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))