Metadata-Version: 2.4
Name: mini-image-picker
Version: 0.0.2
Summary: 图像选点与可缩放平移视图组件（PySide6）：ZoomPanLabel、ImagePickerWindow、PickerSession，高内聚低耦合，兼容 D05 lidar-manager 图像更新与颜色过滤。
License-Expression: MIT
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: numpy
Requires-Dist: opencv-python
Requires-Dist: PySide6
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"
Requires-Dist: build; extra == "dev"
Requires-Dist: twine; extra == "dev"

# mini-image-picker

**版本：v0.0.2**

图像选点与可缩放平移视图组件（PySide6），高内聚低耦合。提供主窗口用 **ZoomPanLabel**、弹窗 **ImagePickerWindow**、**PickerSession** 状态与结果封装；可与 [D05 lidar-manager](https://pypi.org/project/lidar-manager/) 的图像更新与颜色过滤配合使用。

## 安装

```bash
pip install mini-image-picker
```

## 依赖

- Python >= 3.10
- numpy, opencv-python, PySide6

## 功能

- **ZoomPanLabel**：主窗口可缩放平移图像视图；`set_pixmap(pixmap, keep_view_state=True)` 更新图像并保留缩放/平移；`map_to_image_coord(pos)` 将 label 坐标转为图像像素坐标（选 3D 点、颜色过滤取像素等）。**视图状态**：`get_view_state()` 返回 `zoom_factor`、`pan_offset_x`、`pan_offset_y`，`set_view_state(...)` 恢复视图，便于保存/恢复而不依赖私有属性。**多次选择只保留最后一次**：仅维护一个活动点，点击即覆盖。配置 `zoom_pan_label.draw_confirmed_while_active=False` 时，有活动点只绘制活动点（只显示当前一个）；可编程调用 `set_active_point(coord)` / `set_active_point(None)` 设置或清除活动点（如主窗口 3D 选点待确认十字）。
- **ImagePickerWindow**：弹窗内图像选点（左键选点、微调、Enter 确认），仅维护一个待定点，再次点击/微调即覆盖，**多次选择只保留最后一次**；缩放/平移/十字准星/标记等由 config 配置。
- **PickerSession**：持有 ImagePickerWindow，提供 `get_state()`、`get_result()`、`get_summary()` 及信号 `points_changed`、`session_finished`，避免与主程序状态冲突。
- **两种选点方式**：**主窗口选点**：`label.set_pick_mode(True)` 后，在 ZoomPanLabel 上左键点击累计选点，通过 `label.get_picked_points()` 获取、`label.clear_picked_points()` 清空，并连接信号 `point_picked(coord)`。**弹窗选点**：通过 PickerSession 打开 ImagePickerWindow，选点结束后用 `session.get_result()` 获取。两套点列表独立，可分别获取。
- **光标样式**：config 中 `cursor_style` 可配置十字、中心点、外轮廓、文字四组件（有/无、大小、颜色、粗细、线型等）。弹窗选点时会按该配置绘制跟随光标。**CursorShowcaseWindow** 提供 4×5 种预设样式展示；**CursorStyleEditorDialog** 为单独 UI，可自定义光标样式并实时预览。
- **Config**：`get_default_config()` 返回全部可配置项默认值；初始化时传入 `config=my_config` 覆盖部分项即可。
- **坐标映射**：包已导出 `map_label_pos_to_image_coord(pos, pixmap, zoom, pan_offset, label_size)`，供无 label 实例时做坐标换算（如自定义控件、测试）。

## 与 D05 lidar-manager 的配合

- **图像更新**：主程序用 ProjectionManager 的 `project_points` + `render_to_image` 得到渲染图，转为 QPixmap 后调用 **`label.set_pixmap(pixmap, keep_view_state=True)`** 更新到 ZoomPanLabel；每次刷新均应使用 `keep_view_state=True`，避免视图跳动。
- **颜色过滤**：主程序在颜色过滤模式下临时接管 label 的点击（如替换 `mousePressEvent`），用 D07 的 **`map_to_image_coord(pos)`** 得到像素坐标再交给 lidar-manager；进入颜色过滤前若在 PnP 选点则 **suspend_picking()**，退出后 **resume_picking()**，保证互斥。

## 快速开始

```python
from PySide6 import QtWidgets
from mini_image_picker import ZoomPanLabel, ImagePickerWindow, PickerSession, get_default_config, get_default_cursor_style, CursorShowcaseWindow, CursorStyleEditorDialog
import numpy as np

app = QtWidgets.QApplication([])

# 主窗口用视图（与 D05 渲染结果配合）
label = ZoomPanLabel(config=get_default_config())
label.set_pixmap(qt_pixmap, keep_view_state=True)
# 点击时取图像坐标: xy = label.map_to_image_coord(event.pos())

# 弹窗选点
image_bgr = np.zeros((1080, 1920, 3), dtype=np.uint8)
session = PickerSession(image_bgr, config=get_default_config())
session.points_changed.connect(lambda: print("points:", session.get_result()))
session.session_finished.connect(app.quit)
session.show()
app.exec()
print("result:", session.get_result())
```

## License

MIT
