Convex-Hull(凸包)を用いたBoundingBoxの求め方
Convex-Hull(凸包アルゴリズム)は、各プロットが内在するような最小の図形である。
ここでは、2次元の散布図でConvex-Hullを求めて、次にBoundingBoxを求める。
散布図
Convex-Hull
必要なPythonのライブラリ
import math import numpy as np import pandas as pd import matplotlib.pyplot as plt from scipy.spatial import ConvexHull
Convex-Hullアルゴリズム
#元のプロット points = np.random.normal(0, 10, (500, 2)) plt.scatter(points[:, 0], points[:, 1]) plt.show() #Convex-Hull hull = ConvexHull(points) points = hull.points hull_points = points[hull.vertices] hp = np.vstack((hull_points, hull_points[0])) plt.plot(hp[:,0], hp[:,1]) plt.scatter(points[:,0], points[:,1]) plt.show()
散布図
Convex-Hull
Bounding-Box
points = np.random.normal(0, 10, (500, 2))
#Convex-Hull
hull = ConvexHull(points)
points = hull.points
hull_points = points[hull.vertices]
edge_angles = np.zeros(len(hull_points) - 1)
for i in range(len(edge_angles)):
edge_x = hull_points[i + 1, 0] - hull_points[i, 0]
edge_y = hull_points[i + 1, 1] - hull_points[i, 1]
edge_angles[i] = abs(math.atan2(edge_y, edge_x) % (math.pi / 2))
edge_angles = np.unique(edge_angles)
min_bbox = (0, sys.maxsize, 0, 0, 0, 0, 0)
for i in range(len(edge_angles)):
# create Rotation matrix
R = np.array([[math.cos(edge_angles[i]), math.cos(edge_angles[i] - (math.pi / 2))],
[math.cos(edge_angles[i] + (math.pi / 2)), math.cos(edge_angles[i])]])
rot_points = np.dot(R, hull_points.T)
# min max
min_x = np.nanmin(rot_points[0], axis=0)
max_x = np.nanmax(rot_points[0], axis=0)
min_y = np.nanmin(rot_points[1], axis=0)
max_y = np.nanmax(rot_points[1], axis=0)
# width heigh
width = max_x - min_x
height = max_y - min_y
area = width * height
# store the smallest
if (area < min_bbox[1]):
min_bbox = (edge_angles[i], area, width, height, min_x, max_x, min_y, max_y)
angle = min_bbox[0]
R = np.array([[math.cos(angle), math.cos(angle - (math.pi / 2))],
[math.cos(angle + (math.pi / 2)), math.cos(angle)]])
proj_points = np.dot(R, hull_points.T)
min_x = min_bbox[4]
max_x = min_bbox[5]
min_y = min_bbox[6]
max_y = min_bbox[7]
center_x = (min_x + max_x) / 2
center_y = (min_y + max_y) / 2
center_point = np.dot([center_x, center_y], R)
corner_points = np.zeros((4, 2))
corner_points[0] = np.dot([max_x, min_y], R)
corner_points[1] = np.dot([min_x, min_y], R)
corner_points[2] = np.dot([min_x, max_y], R)
corner_points[3] = np.dot([max_x, max_y], R)

Gr = (corner_points[0,1] - corner_points[1, 1]) / (corner_points[0, 0] - corner_points[1, 0])
theta = math.atan(Gr)
R_coor = np.array([[ math.cos(theta), math.sin(theta) ],
[ -math.sin(theta), math.cos(theta)]])
a = np.dot(R_coor, points.T ).T
c = np.dot(R_coor, corner.T).T
plt.plot(c[:,0], c[:,1])
plt.scatter(a[:,0], a[:,1])
plt.show()

まとめ
散布図
Convex-Hull
Bounding-Box
Rotation Bounding-Box