UAV/utils/grid_divider.py

207 lines
8.4 KiB
Python
Raw Normal View History

2024-12-23 11:31:20 +08:00
import logging
from geopy.distance import geodesic
2024-12-23 14:21:42 +08:00
import matplotlib.pyplot as plt
import os
2024-12-23 11:31:20 +08:00
class GridDivider:
"""划分九宫格,并将图片分配到对应网格"""
2024-12-23 14:21:42 +08:00
def __init__(self, overlap=0.1, output_dir=None):
2024-12-23 11:31:20 +08:00
self.overlap = overlap
2024-12-23 14:21:42 +08:00
self.output_dir = output_dir
2024-12-23 11:31:20 +08:00
self.logger = logging.getLogger('UAV_Preprocess.GridDivider')
self.logger.info(f"初始化网格划分器,重叠率: {overlap}")
2024-12-31 20:37:35 +08:00
self.num_grids_width = 0 # 添加网格数量属性
self.num_grids_height = 0
2024-12-23 11:31:20 +08:00
def divide_grids(self, points_df, grid_size=500):
2024-12-31 22:29:24 +08:00
"""计算边界框并划分网格
Returns:
tuple: (grids, translations)
- grids: 网格边界列表
- translations: 网格平移量字典
"""
2024-12-31 20:37:35 +08:00
self.logger.info("开始划分网格")
2024-12-23 14:21:42 +08:00
2024-12-23 11:31:20 +08:00
min_lat, max_lat = points_df['lat'].min(), points_df['lat'].max()
min_lon, max_lon = points_df['lon'].min(), points_df['lon'].max()
2024-12-23 14:21:42 +08:00
2024-12-23 11:31:20 +08:00
# 计算区域的实际距离(米)
width = geodesic((min_lat, min_lon), (min_lat, max_lon)).meters
height = geodesic((min_lat, min_lon), (max_lat, min_lon)).meters
2024-12-23 14:21:42 +08:00
2024-12-31 20:37:35 +08:00
self.logger.info(f"区域宽度: {width:.2f}米, 高度: {height:.2f}")
2024-12-23 11:31:20 +08:00
# 计算需要划分的网格数量
2024-12-31 20:37:35 +08:00
self.num_grids_width = max(int(width / grid_size), 1)
self.num_grids_height = max(int(height / grid_size), 1)
2024-12-23 14:21:42 +08:00
2024-12-23 11:31:20 +08:00
# 计算每个网格对应的经纬度步长
2024-12-31 20:37:35 +08:00
lat_step = (max_lat - min_lat) / self.num_grids_height
lon_step = (max_lon - min_lon) / self.num_grids_width
2024-12-23 11:31:20 +08:00
grids = []
2024-12-31 22:29:24 +08:00
grid_translations = {} # 存储每个网格相对于第一个网格的平移量
2024-12-31 20:37:35 +08:00
2024-12-31 22:29:24 +08:00
# 先创建所有网格
2024-12-31 20:37:35 +08:00
for i in range(self.num_grids_height):
for j in range(self.num_grids_width):
2024-12-23 11:31:20 +08:00
grid_min_lat = min_lat + i * lat_step - self.overlap * lat_step
2024-12-31 20:37:35 +08:00
grid_max_lat = min_lat + (i + 1) * lat_step + self.overlap * lat_step
2024-12-23 11:31:20 +08:00
grid_min_lon = min_lon + j * lon_step - self.overlap * lon_step
2024-12-31 20:37:35 +08:00
grid_max_lon = min_lon + (j + 1) * lon_step + self.overlap * lon_step
2024-12-31 21:37:44 +08:00
grid_id = (j, i) # 使用(width_idx, height_idx)元组作为网格标识
2024-12-31 22:29:24 +08:00
grid_bounds = (grid_min_lat, grid_max_lat, grid_min_lon, grid_max_lon)
grids.append(grid_bounds)
2024-12-31 20:37:35 +08:00
2024-12-23 11:31:20 +08:00
self.logger.debug(
2024-12-31 21:37:44 +08:00
f"网格[{j},{i}]: 纬度[{grid_min_lat:.6f}, {grid_max_lat:.6f}], "
2024-12-23 11:31:20 +08:00
f"经度[{grid_min_lon:.6f}, {grid_max_lon:.6f}]"
)
2024-12-31 22:29:24 +08:00
# 计算每个网格相对于第一个网格的平移量
reference_grid = grids[0]
for i in range(self.num_grids_height):
for j in range(self.num_grids_width):
grid_id = (j, i)
grid_idx = i * self.num_grids_width + j
if grid_idx == 0: # 参考网格
grid_translations[grid_id] = (0, 0)
else:
translation = self.calculate_grid_translation(reference_grid, grids[grid_idx])
grid_translations[grid_id] = translation
self.logger.debug(
f"网格[{j},{i}]相对于参考网格的平移量: x={translation[0]:.2f}m, y={translation[1]:.2f}m"
)
2024-12-23 14:21:42 +08:00
self.logger.info(
2024-12-31 20:37:35 +08:00
f"成功划分为 {len(grids)} 个网格 ({self.num_grids_width}x{self.num_grids_height})")
2024-12-23 14:21:42 +08:00
# 添加可视化调用
self.visualize_grids(points_df, grids)
2024-12-31 22:29:24 +08:00
return grids, grid_translations
2024-12-23 11:31:20 +08:00
2024-12-31 20:37:35 +08:00
2024-12-23 11:31:20 +08:00
def assign_to_grids(self, points_df, grids):
"""将点分配到对应网格"""
self.logger.info(f"开始将 {len(points_df)} 个点分配到网格中")
2024-12-23 14:21:42 +08:00
2024-12-31 21:37:44 +08:00
grid_points = {} # 使用字典存储每个网格的点
2024-12-23 11:31:20 +08:00
points_assigned = 0
multiple_grid_points = 0
2024-12-23 14:21:42 +08:00
2024-12-31 21:37:44 +08:00
for i in range(self.num_grids_height):
for j in range(self.num_grids_width):
grid_points[(j, i)] = [] # 使用(width_idx, height_idx)元组
2024-12-23 11:31:20 +08:00
for _, point in points_df.iterrows():
point_assigned = False
2024-12-31 21:37:44 +08:00
for i in range(self.num_grids_height):
for j in range(self.num_grids_width):
grid_idx = i * self.num_grids_width + j
min_lat, max_lat, min_lon, max_lon = grids[grid_idx]
if min_lat <= point['lat'] <= max_lat and min_lon <= point['lon'] <= max_lon:
grid_points[(j, i)].append(point.to_dict())
if point_assigned:
multiple_grid_points += 1
else:
points_assigned += 1
point_assigned = True
2024-12-23 11:31:20 +08:00
# 记录每个网格的点数
2024-12-31 21:37:44 +08:00
for grid_id, points in grid_points.items():
self.logger.info(f"网格 {grid_id} 包含 {len(points)} 个点")
2024-12-23 11:31:20 +08:00
self.logger.info(
f"点分配完成: 总点数 {len(points_df)}, "
f"成功分配 {points_assigned} 个点, "
f"{multiple_grid_points} 个点被分配到多个网格"
)
2024-12-23 14:21:42 +08:00
2024-12-23 11:31:20 +08:00
return grid_points
2024-12-23 14:21:42 +08:00
def visualize_grids(self, points_df, grids):
"""可视化网格划分和GPS点的分布"""
self.logger.info("开始可视化网格划分")
plt.figure(figsize=(12, 8))
# 绘制GPS点
plt.scatter(points_df['lon'], points_df['lat'],
c='blue', s=10, alpha=0.6, label='GPS点')
# 绘制网格
2024-12-31 21:37:44 +08:00
for i in range(self.num_grids_height):
for j in range(self.num_grids_width):
grid_idx = i * self.num_grids_width + j
min_lat, max_lat, min_lon, max_lon = grids[grid_idx]
plt.plot([min_lon, max_lon, max_lon, min_lon, min_lon],
[min_lat, min_lat, max_lat, max_lat, min_lat],
'r-', alpha=0.5)
# 在网格中心添加网格编号
center_lon = (min_lon + max_lon) / 2
center_lat = (min_lat + max_lat) / 2
plt.text(center_lon, center_lat, f"({j},{i})", # 显示(width_idx, height_idx)
horizontalalignment='center', verticalalignment='center')
2024-12-23 14:21:42 +08:00
plt.title('网格划分与GPS点分布图')
plt.xlabel('经度')
plt.ylabel('纬度')
plt.legend()
plt.grid(True)
# 如果提供了输出目录,保存图像
if self.output_dir:
save_path = os.path.join(
self.output_dir, 'filter_imgs', 'grid_division.png')
plt.savefig(save_path, dpi=300, bbox_inches='tight')
self.logger.info(f"网格划分可视化图已保存至: {save_path}")
plt.close()
2024-12-31 22:29:24 +08:00
def get_grid_center(self, grid_bounds) -> tuple:
"""计算网格中心点的经纬度
Args:
grid_bounds: (min_lat, max_lat, min_lon, max_lon)
Returns:
(center_lat, center_lon)
"""
min_lat, max_lat, min_lon, max_lon = grid_bounds
return ((min_lat + max_lat) / 2, (min_lon + max_lon) / 2)
def calculate_grid_translation(self, reference_grid: tuple, target_grid: tuple) -> tuple:
"""计算目标网格相对于参考网格的平移距离(米)
Args:
reference_grid: 参考网格的边界 (min_lat, max_lat, min_lon, max_lon)
target_grid: 目标网格的边界 (min_lat, max_lat, min_lon, max_lon)
Returns:
(x_translation, y_translation): 在米制单位下的平移量
"""
ref_center = self.get_grid_center(reference_grid)
target_center = self.get_grid_center(target_grid)
# 计算经度方向的距离x轴
x_distance = geodesic(
(ref_center[0], ref_center[1]),
(ref_center[0], target_center[1])
).meters
# 如果目标在参考点西边,距离为负
if target_center[1] < ref_center[1]:
x_distance = -x_distance
# 计算纬度方向的距离y轴
y_distance = geodesic(
(ref_center[0], ref_center[1]),
(target_center[0], ref_center[1])
).meters
# 如果目标在参考点南边,距离为负
if target_center[0] < ref_center[0]:
y_distance = -y_distance
return (x_distance, y_distance)