数字化利器,扔掉getdata吧
这个图片数字化程序具有以下功能特点:
主要功能:
1. 图片加载与显示
- 支持多种图片格式(JPG、PNG、BMP等)
- 自动缩放以适应窗口
- 支持滚动查看大图片
2. 坐标系设置
- 三步设置法:
- 点击设置原点(红色标记)
- 点击设置X轴正方向(蓝色箭头)
- 点击设置Y轴正方向(绿色箭头)
- 可自定义实际坐标值
- 支持任意角度的坐标系
3. 交互式数据拾取
- 点击图片即可拾取数据点
- 实时显示鼠标位置坐标
- 自动转换为实际坐标值
- 数据点用橙色标记并编号
4. 数据管理
- 表格形式显示所有拾取点
- 支持撤销上一个点
- 支持清除所有点
- 实时更新坐标显示
5. 数据导出
- CSV格式:适合Excel处理
- JSON格式:包含完整坐标系信息
- TXT格式:纯文本格
6. 实时放大镜窗口
- 独立的浮动窗口,始终保持在最前面
- 实时显示鼠标周围的放大图像
- 可调节放大倍数(2x-20x)
- 十字准线:虚线十字帮助精确定位
- 中心标记:红色圆圈标记当前像素位置
- 坐标显示:在放大镜中显示当前坐标
- 复选框快速开关放大镜
- 鼠标离开图片时自动隐藏
- 滑块实时调节放大倍数
7. 快捷键支持
- M键:快速切换放大镜
- 空格键:切换拾取模式
- Ctrl+Z:撤销上一个点
- Delete:清除所有点
- 使用高效的图像裁剪和缩放算法
- 避免不必要的重绘
- 平滑的鼠标跟随效果
使用步骤:
- 打开图片:点击"打开图片"按钮选择要数字化的图片
- 设置坐标系:
- 点击"设置原点",在图片上点击原点位置
- 点击"设置X轴",点击X轴正方向上的一个点
- 点击"设置Y轴",点击Y轴正方向上的一个点
- 可在右侧输入实际坐标值并点击"应用坐标值"
- 拾取数据:
- 点击"开始拾取点"进入拾取模式
- 在图片上依次点击需要数字化的点
- 点击"停止拾取点"结束拾取
- 保存数据:点击"保存数据"选择格式并保存
技术特点:
- 精确的坐标转换:使用线性变换实现像素坐标到实际坐标的精确转换
- 友好的用户界面:清晰的操作提示和状态显示
- 灵活的坐标系:支持任意角度和比例的坐标系
- 完整的数据记录:同时保存像素坐标和实际坐标
这个程序特别适合用于:
- 科学图表数据提取
- 工程图纸数字化
- 地图坐标采集
- 实验数据记录
程序使用纯Python标准库和PIL库,无需额外安装复杂依赖,运行稳定可靠。
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
from PIL import Image, ImageTk, ImageDraw
import json
import csv
import math
from dataclasses import dataclass
from typing import List, Tuple, Optional@dataclass
class Point:"""数据点类"""pixel_x: floatpixel_y: floatreal_x: floatreal_y: floatname: str = ""class MagnifierWindow:"""放大镜窗口类"""def __init__(self, parent, digitizer):self.parent = parentself.digitizer = digitizerself.window = Noneself.canvas = Noneself.magnifier_image = Noneself.magnifier_photo = Noneself.magnification = 5.0 # 放大倍数self.magnifier_size = 200 # 放大镜窗口大小self.crosshair_color = 'red'self.is_active = Falsedef create_window(self):"""创建放大镜窗口"""if self.window is not None:returnself.window = tk.Toplevel(self.parent)self.window.title("放大镜")self.window.geometry(f"{self.magnifier_size}x{self.magnifier_size + 40}")self.window.resizable(False, False)# 设置窗口始终在最前面self.window.attributes('-topmost', True)# 创建Canvasself.canvas = tk.Canvas(self.window, width=self.magnifier_size, height=self.magnifier_size,bg='white',highlightthickness=1,highlightbackground='gray')self.canvas.pack()# 添加控制面板control_frame = ttk.Frame(self.window)control_frame.pack(fill=tk.X)# 放大倍数控制ttk.Label(control_frame, text="放大倍数:").pack(side=tk.LEFT, padx=5)self.mag_var = tk.DoubleVar(value=self.magnification)mag_scale = ttk.Scale(control_frame, from_=2, to=20, variable=self.mag_var,orient=tk.HORIZONTAL,length=100,command=self.update_magnification)mag_scale.pack(side=tk.LEFT, padx=5)self.mag_label = ttk.Label(control_frame, text=f"{self.magnification:.1f}x")self.mag_label.pack(side=tk.LEFT, padx=5)# 关闭按钮ttk.Button(control_frame, text="关闭", command=self.close).pack(side=tk.RIGHT, padx=5)# 绑定窗口关闭事件self.window.protocol("WM_DELETE_WINDOW", self.close)def update_magnification(self, value):"""更新放大倍数"""self.magnification = float(value)self.mag_label.config(text=f"{self.magnification:.1f}x")def show(self):"""显示放大镜"""if not self.window:self.create_window()self.is_active = Trueself.window.deiconify()def hide(self):"""隐藏放大镜"""if self.window:self.window.withdraw()self.is_active = Falsedef close(self):"""关闭放大镜"""if self.window:self.window.destroy()self.window = Noneself.canvas = Noneself.is_active = Falsedef update(self, pixel_x, pixel_y):"""更新放大镜内容"""if not self.is_active or not self.canvas or not self.digitizer.image:returntry:# 计算源图像区域source_size = self.magnifier_size / self.magnificationhalf_size = source_size / 2# 计算裁剪区域,确保坐标有效x1 = max(0, pixel_x - half_size)y1 = max(0, pixel_y - half_size)x2 = min(self.digitizer.image.width, pixel_x + half_size)y2 = min(self.digitizer.image.height, pixel_y + half_size)# 确保x1 < x2 和 y1 < y2if x1 >= x2 or y1 >= y2:return# 裁剪图像区域crop_box = (int(x1), int(y1), int(x2), int(y2))cropped = self.digitizer.image.crop(crop_box)# 放大图像magnified = cropped.resize((self.magnifier_size, self.magnifier_size),Image.Resampling.LANCZOS)# 转换为PhotoImageself.magnifier_photo = ImageTk.PhotoImage(magnified)# 清除Canvas并显示图