From ab82c811920085a70034b9643581f584538063ae Mon Sep 17 00:00:00 2001 From: along Date: Mon, 6 Jan 2025 20:12:48 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BA=A4=E4=BA=92=E5=BC=8F?= =?UTF-8?q?=E5=88=A0=E9=99=A4=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gps_selector.py | 235 ++++++++++++++++++++++++++++++++++++++++++ tools/gps_selector.py | 134 ------------------------ 2 files changed, 235 insertions(+), 134 deletions(-) create mode 100644 gps_selector.py delete mode 100644 tools/gps_selector.py diff --git a/gps_selector.py b/gps_selector.py new file mode 100644 index 0000000..4feeb55 --- /dev/null +++ b/gps_selector.py @@ -0,0 +1,235 @@ +from utils.gps_extractor import GPSExtractor +import os +import sys +import shutil +from pathlib import Path +import matplotlib.pyplot as plt +from matplotlib.widgets import RectangleSelector +import pandas as pd +from matplotlib.font_manager import FontProperties + + +class GPSSelector: + def __init__(self, image_dir: str, output_dir: str = None): + # 移除中文字体设置 + self.image_dir = image_dir + self.output_dir = output_dir + self.gps_points = None + self.selected_points = [] + self.fig, self.ax = plt.subplots(figsize=(12, 8)) + self.scatter = None + self.rs = None + self.setup_plot() + + def extract_gps(self): + """提取GPS数据""" + extractor = GPSExtractor(self.image_dir) + self.gps_points = extractor.extract_all_gps() + print(f"成功提取 {len(self.gps_points)} 个GPS点") + + def setup_plot(self): + """设置绘图""" + self.ax.set_title('GPS Points - Use mouse to drag and select points to delete') + self.ax.set_xlabel('Longitude') + self.ax.set_ylabel('Latitude') + self.ax.grid(True) + + # 设置坐标轴使用相同的比例 + self.ax.set_aspect('equal') + + # 设置矩形选择器 + self.rs = RectangleSelector( + self.ax, self.on_select, + interactive=True, + useblit=True, + button=[1], # 只响应左键 + props=dict(facecolor='red', alpha=0.3) + ) + + # 添加按钮回调 + self.fig.canvas.mpl_connect('key_press_event', self.on_key_press) + + # 添加缩放和平移功能 + self.fig.canvas.mpl_connect('scroll_event', self.on_scroll) + self.fig.canvas.mpl_connect('button_press_event', self.on_press) + self.fig.canvas.mpl_connect('button_release_event', self.on_release) + self.fig.canvas.mpl_connect('motion_notify_event', self.on_motion) + + # 用于平移功能的变量 + self._pan_start = None + + def plot_gps_points(self): + """绘制GPS点""" + if self.scatter is not None: + self.scatter.remove() + + # 计算经纬度的范围 + lon_range = self.gps_points['lon'].max() - self.gps_points['lon'].min() + lat_range = self.gps_points['lat'].max() - self.gps_points['lat'].min() + + # 设置合适的图形大小,保持经纬度的真实比例 + aspect_ratio = lon_range / lat_range + fig_width = 12 + fig_height = fig_width / aspect_ratio + self.fig.set_size_inches(fig_width, fig_height) + + self.scatter = self.ax.scatter( + self.gps_points['lon'], + self.gps_points['lat'], + c='blue', + s=20, + alpha=0.6 + ) + + # 设置适当的显示范围,添加一些边距 + margin = 0.1 + x_margin = lon_range * margin + y_margin = lat_range * margin + + self.ax.set_xlim([ + self.gps_points['lon'].min() - x_margin, + self.gps_points['lon'].max() + x_margin + ]) + self.ax.set_ylim([ + self.gps_points['lat'].min() - y_margin, + self.gps_points['lat'].max() + y_margin + ]) + + # 关闭自动缩放 + self.ax.autoscale(False) + + # 使用更精确的刻度 + self.ax.ticklabel_format(useOffset=False, style='plain') + + self.fig.canvas.draw_idle() + + def on_select(self, eclick, erelease): + """矩形选择回调""" + x1, y1 = eclick.xdata, eclick.ydata + x2, y2 = erelease.xdata, erelease.ydata + + # 获取选中区域内的点 + mask = ( + (self.gps_points['lon'] >= min(x1, x2)) & + (self.gps_points['lon'] <= max(x1, x2)) & + (self.gps_points['lat'] >= min(y1, y2)) & + (self.gps_points['lat'] <= max(y1, y2)) + ) + + selected = self.gps_points[mask] + self.selected_points.extend(selected['file'].tolist()) + + # 从数据中移除选中的点 + self.gps_points = self.gps_points[~mask] + + # 更新绘图 + self.plot_gps_points() + print(f"选中 {len(selected)} 个点,剩余 {len(self.gps_points)} 个点") + + def on_key_press(self, event): + """键盘事件回调""" + if event.key == 'enter': + self.save_results() + plt.close() + elif event.key == 'escape': + plt.close() + + def save_results(self): + """保存结果""" + if not self.output_dir: + return + + # 创建输出目录 + os.makedirs(self.output_dir, exist_ok=True) + removed_dir = os.path.join(self.output_dir, "removed_images") + os.makedirs(removed_dir, exist_ok=True) + + # 移动被删除的图像 + for img_name in self.selected_points: + src = os.path.join(self.image_dir, img_name) + dst = os.path.join(removed_dir, img_name) + shutil.move(src, dst) + + # 保存剩余点的信息 + self.gps_points.to_csv( + os.path.join(self.output_dir, "remaining_points.csv"), + index=False + ) + + print(f"已移动 {len(self.selected_points)} 张图片到 {removed_dir}") + print(f"保留 {len(self.gps_points)} 个点") + + def run(self): + """运行选择器""" + self.extract_gps() + self.plot_gps_points() + plt.show() + + def on_scroll(self, event): + """鼠标滚轮缩放""" + if event.inaxes != self.ax: + return + + # 获取当前视图范围 + cur_xlim = self.ax.get_xlim() + cur_ylim = self.ax.get_ylim() + + # 缩放因子 + base_scale = 1.1 + xdata = event.xdata + ydata = event.ydata + + if event.button == 'up': + # 放大 + scale_factor = 1/base_scale + else: + # 缩小 + scale_factor = base_scale + + # 设置新的视图范围 + new_width = (cur_xlim[1] - cur_xlim[0]) * scale_factor + new_height = (cur_ylim[1] - cur_ylim[0]) * scale_factor + + self.ax.set_xlim([xdata - new_width * (xdata - cur_xlim[0]) / (cur_xlim[1] - cur_xlim[0]), + xdata + new_width * (cur_xlim[1] - xdata) / (cur_xlim[1] - cur_xlim[0])]) + self.ax.set_ylim([ydata - new_height * (ydata - cur_ylim[0]) / (cur_ylim[1] - cur_ylim[0]), + ydata + new_height * (cur_ylim[1] - ydata) / (cur_ylim[1] - cur_ylim[0])]) + + self.fig.canvas.draw_idle() + + def on_press(self, event): + """鼠标按下事件""" + if event.inaxes != self.ax or event.button != 3: # 只响应右键 + return + self._pan_start = (event.xdata, event.ydata) + + def on_release(self, event): + """鼠标释放事件""" + self._pan_start = None + + def on_motion(self, event): + """鼠标移动事件""" + if self._pan_start is None or event.inaxes != self.ax: + return + + # 计算移动距离 + dx = event.xdata - self._pan_start[0] + dy = event.ydata - self._pan_start[1] + + # 更新视图范围 + cur_xlim = self.ax.get_xlim() + cur_ylim = self.ax.get_ylim() + + self.ax.set_xlim(cur_xlim - dx) + self.ax.set_ylim(cur_ylim - dy) + + self.fig.canvas.draw_idle() + + +if __name__ == "__main__": + # 使用示例 + selector = GPSSelector( + image_dir=r"C:\datasets\134\code\images", + output_dir=r"C:\datasets\ODM_output\134" + ) + selector.run() diff --git a/tools/gps_selector.py b/tools/gps_selector.py deleted file mode 100644 index 16a9950..0000000 --- a/tools/gps_selector.py +++ /dev/null @@ -1,134 +0,0 @@ -import os -import sys -import shutil -from pathlib import Path -import matplotlib.pyplot as plt -from matplotlib.widgets import RectangleSelector -import pandas as pd - -# 添加项目根目录到系统路径 -project_root = str(Path(__file__).parent.parent) -sys.path.append(project_root) - -from utils.gps_extractor import GPSExtractor - -class GPSSelector: - def __init__(self, image_dir: str, output_dir: str = None): - self.image_dir = image_dir - self.output_dir = output_dir - self.gps_points = None - self.selected_points = [] - self.fig, self.ax = plt.subplots(figsize=(12, 8)) - self.scatter = None - self.rs = None - self.setup_plot() - - def extract_gps(self): - """提取GPS数据""" - extractor = GPSExtractor(self.image_dir) - self.gps_points = extractor.extract_all_gps() - print(f"成功提取 {len(self.gps_points)} 个GPS点") - - def setup_plot(self): - """设置绘图""" - self.ax.set_title('GPS Points - 使用鼠标拖动选择要删除的点') - self.ax.set_xlabel('Longitude') - self.ax.set_ylabel('Latitude') - self.ax.grid(True) - - # 设置矩形选择器 - self.rs = RectangleSelector( - self.ax, self.on_select, - interactive=True, - useblit=True, - button=[1], # 只响应左键 - props=dict(facecolor='red', alpha=0.3) - ) - - # 添加按钮回调 - self.fig.canvas.mpl_connect('key_press_event', self.on_key_press) - - def plot_gps_points(self): - """绘制GPS点""" - if self.scatter is not None: - self.scatter.remove() - - self.scatter = self.ax.scatter( - self.gps_points['lon'], - self.gps_points['lat'], - c='blue', - s=20, - alpha=0.6 - ) - self.fig.canvas.draw_idle() - - def on_select(self, eclick, erelease): - """矩形选择回调""" - x1, y1 = eclick.xdata, eclick.ydata - x2, y2 = erelease.xdata, erelease.ydata - - # 获取选中区域内的点 - mask = ( - (self.gps_points['lon'] >= min(x1, x2)) & - (self.gps_points['lon'] <= max(x1, x2)) & - (self.gps_points['lat'] >= min(y1, y2)) & - (self.gps_points['lat'] <= max(y1, y2)) - ) - - selected = self.gps_points[mask] - self.selected_points.extend(selected['file'].tolist()) - - # 从数据中移除选中的点 - self.gps_points = self.gps_points[~mask] - - # 更新绘图 - self.plot_gps_points() - print(f"选中 {len(selected)} 个点,剩余 {len(self.gps_points)} 个点") - - def on_key_press(self, event): - """键盘事件回调""" - if event.key == 'enter': - self.save_results() - plt.close() - elif event.key == 'escape': - plt.close() - - def save_results(self): - """保存结果""" - if not self.output_dir: - return - - # 创建输出目录 - os.makedirs(self.output_dir, exist_ok=True) - removed_dir = os.path.join(self.output_dir, "removed_images") - os.makedirs(removed_dir, exist_ok=True) - - # 移动被删除的图像 - for img_name in self.selected_points: - src = os.path.join(self.image_dir, img_name) - dst = os.path.join(removed_dir, img_name) - shutil.move(src, dst) - - # 保存剩余点的信息 - self.gps_points.to_csv( - os.path.join(self.output_dir, "remaining_points.csv"), - index=False - ) - - print(f"已移动 {len(self.selected_points)} 张图片到 {removed_dir}") - print(f"保留 {len(self.gps_points)} 个点") - - def run(self): - """运行选择器""" - self.extract_gps() - self.plot_gps_points() - plt.show() - - -if __name__ == "__main__": - # 使用示例 - selector = GPSSelector( - image_dir=r"E:\datasets\UAV\1619\project\images", - output_dir=r"E:\datasets\UAV\1619\filtered" - ) - selector.run() \ No newline at end of file