On my project I want to clip pv_module image into rotated rectangle polygons using matplotlib.
My problem is that on many of the rotation azimuths the image is not clipped well, so the image fit only to the polygon rectangle short side.
import matplotlib.patches as mp
import matplotlib.pyplot as plt
import numpy as np
from PIL import Image
def set_pv_modules_envelope(module_poly: list) -> list:
"""
compute bounding box for the polygon.
"""
xs = [p[0] for p in module_poly]
ys = [p[1] for p in module_poly]
x_min_poly, x_max_poly = min(xs), max(xs)
y_min_poly, y_max_poly = min(ys), max(ys)
return [x_min_poly, x_max_poly, y_min_poly, y_max_poly]
def rotate_point(point, angle_degrees):
angle_radians = np.radians(angle_degrees)
rotation_matrix = np.array([
[np.cos(angle_radians), -np.sin(angle_radians)],
[np.sin(angle_radians), np.cos(angle_radians)]
])
return np.dot(rotation_matrix, point)
poly = [(0, 0), (5, 0), (5, 10), (0, 10)]
rotate_angle = 90
target_polygon = np.array([rotate_point(point, rotate_angle) for point in poly])
pv_module_img = plt.imread("..\\module_img.png")
pv_module_img_uint8 = (pv_module_img * 255).astype(np.uint8)
pv_module_img_reshaped = np.squeeze(pv_module_img_uint8)
rotated = Image.fromarray(pv_module_img_reshaped).rotate(rotate_angle)
fig, ax = plt.subplots(figsize=(8, 6))
extent = set_pv_modules_envelope(target_polygon)
patch = mp.Polygon(target_polygon, closed=True)
ax.add_patch(patch)
ax.imshow(
rotated,
extent=extent,
clip_path=patch,
clip_on=True,
zorder=3
)
plt.axis("scaled")
plt.axis("off")
plt.show()
But for 90 degree I receive the following clip:
and for 45 degree I receive this:
This is the original image.