# lidar-manager

LiDAR 点云投影、颜色管理、降采样、缓存、距离/强度过滤，输出一张渲染后的图片。

## 安装

```bash
pip install lidar-manager
```

## 功能特性

- **lidar2cam 投影**：内参、外参、针孔/鱼眼畸变
- **颜色管理**：按距离/强度着色，内置多套配色（jet、viridis、rainbow 等），可直接选用
- **过滤管理**：按强度或距离阈值/范围过滤
- **降采样**：uniform / random / voxel / distance_based
- **缓存**：去畸变与点云投影缓存，减少重复计算
- **输出**：一张渲染后的图片（点云叠加在图像上）

当前版本：**0.0.6**。版本更新与变更见 [version_update.md](version_update.md)。

## 输入与输出

- **输入**：点云、图像、内参、外参、颜色管理（配色方案）、过滤管理（可选：强度/距离范围）
- **输出**：一张渲染后的图片

## 快速开始

```python
import numpy as np
from lidar_manager import (
    ProjectionManager,
    ImageProcessor,
    get_default_color_scheme,
    list_default_scheme_names,
)

# 内置配色名称
print(list_default_scheme_names())  # ['jet', 'viridis', 'rainbow', ...]

# 获取默认配色（BGR 列表）
colors = get_default_color_scheme("jet")

# 构造投影管理器
K = np.eye(3)  # 3x3 内参
K[0, 0] = K[1, 1] = 1000
K[0, 2], K[1, 2] = 960, 540
T = np.eye(4)  # 4x4 外参 lidar2cam

pm = ProjectionManager(
    image_processor=ImageProcessor(K),
    initial_distance_range=(0, 100),
)
pm.update_intrinsic(K)
pm.update_extrinsic(T)

# 处理图像（去畸变）
image = np.zeros((1080, 1920, 3), dtype=np.uint8)  # 你的图像
proc_image, _ = pm.process_image(image)
pm.update_image_size(proc_image.shape[1], proc_image.shape[0])

# 更新配色
pm.update_color_scheme(colors)

# 点云 Nx3 或 Nx4 (x,y,z[, intensity])
points = np.random.randn(10000, 4).astype(np.float32)
points[:, 3] = np.clip(points[:, 3], 0, 255)  # intensity

# 投影并可选范围过滤
pm.project_points(
    points,
    color_type="distance",
    range_filter_params={"min_val": 5.0, "max_val": 80.0, "mode": "distance"},
)

# 输出：一张渲染后的图片
rendered = pm.render_to_image(proc_image, point_size=2, point_opacity=1.0)
# 保存或显示 rendered
```

## 接口说明

### 投影与渲染

- **project_points(points, color_type="distance", attr_range=None, color_filter_params=None, range_filter_params=None)**  
  唯一投影入口：将点云投影到当前图像并构建内部映射表。可传入 `range_filter_params`（如 `{"min_val": 5.0, "max_val": 80.0, "mode": "distance"}`）做全局距离/强度范围过滤；返回过滤后的映射表或 None。

- **render_to_image(image, point_size=2, point_opacity=1.0, use_background_mode=True)**  
  将当前映射表中的点云渲染到图像上，返回叠加后的图像。

### 按像素查询

- **find_nearest_point(px, py, search_radius=5)**  
  返回像素 (px, py) 处或邻域内**最近**的一个 3D 点（按 lidar 距离），返回 dict（含 pixel, xyz, cam_xyz, attr, normalized, color）；无点时返回 None。

- **get_lidar_3d_at_pixel(px, py, search_radius=5, distance_range=None, intensity_range=None, color_filter=None, return_attributes=False)**  
  按像素位置与可选的**距离/强度/颜色**过滤条件，筛选该位置附近的 lidar 3D 点列表。需先调用 `project_points`。  
  - `distance_range=(min_d, max_d)`：仅保留距离在 [min_d, max_d] 米内的点。  
  - `intensity_range=(min_i, max_i)`：仅保留强度在该区间内的点。  
  - `color_filter={"reference_color": [B,G,R], "threshold": float}`：仅保留与参考色 BGR 距离 ≤ threshold 的点。  
  - `return_attributes=False` 时返回 `List[Tuple[x,y,z]]`，`True` 时返回 `List[Dict]`（含 xyz、distance、intensity、pixel、color 等）。无点时返回 `[]`。

### 颜色与展示接口（供 UI 使用）

以下接口便于界面展示与交互，无需依赖内部实现。

**状态与查询**

- **get_current_color_type()**：返回当前着色属性 `"distance"` 或 `"intensity"`。
- **get_color_scheme()**：返回当前 BGR 颜色列表（无配色时返回 None）。
- **get_filtered_point_count()**：返回当前过滤后的映射表点数。

**映射表与按像素**

- **get_filtered_mapping()**：返回当前过滤后的映射表（只读），字段含 pixel_2d、xyz_3d、distance、intensity、color_bgr、normalized、cam_xyz。
- **get_points_at_pixel(px, py)**：返回该像素处所有映射点，`List[Dict]`（含 pixel, xyz, cam_xyz, attr, normalized, color），供 PnP 选点等。
- **get_points_in_radius(px, py, radius)**：返回像素邻域内映射点（按 LiDAR 距离排序），`List[Dict]`，与 `find_nearest_point` 互补。

**投影后范围过滤与配色**

- **apply_range_filter(min_val, max_val, mode)**：对当前映射表按属性范围过滤，`mode` 为 `"distance"` 或 `"intensity"`，用于颜色区间过滤等。
- **clear_filters()**：清除当前范围/属性过滤。
- **update_color_scheme(colors, recompute_normalized=False)**：更新配色方案（BGR 列表）；切换配色或缩配色区间后调用。

**归一化范围（V0.0.5）**

- **set_normalization_range(min_val, max_val, color_type=None)**：设置归一化使用的属性范围（距离单位米或强度值），并重算 normalized 与颜色；用于手动模式。`color_type` 可选 `"distance"` / `"intensity"`，不传则保持当前着色属性。
- **recompute_normalized_and_colors(use_auto_range=False)**：根据当前映射表重新计算归一化值与颜色。`use_auto_range=True` 时使用当前点云实际属性范围（自适应）；`False` 时使用已通过 `set_normalization_range` 设置的范围。需在 `project_points` 之后调用。

**可选**

- **get_color_stats_for_colormap(num_bins, min_val, max_val)**：返回 `{"point_counts", "rendered_counts", "global_range"}`，供配色查看器一次获取统计与范围。
- **get_points_and_colors_for_render()**：与 `render_to_image` 相同逻辑（每像素最近点），返回 `(points_2d, colors_bgr)`，供自绘或导出；无数据时返回 `(None, None)`。

典型场景：配色切换、颜色区间过滤、配色查看器、按像素选点（PnP）等。

### 其它常用接口

- **update_intrinsic(K)** / **update_extrinsic(T)** / **update_image_size(width, height)**：更新内参、外参、图像尺寸。
- **get_visible_points()**：返回当前可见点的数组（xyz + 当前属性）。
- **get_global_attr_range()**：返回归一化使用的全局属性范围 (min_val, max_val)。
- **set_normalization_range(min_val, max_val, color_type=None)** / **recompute_normalized_and_colors(use_auto_range=False)**：见上文「归一化范围（V0.0.5）」。

### 日志（V0.0.6）

本库日志命名空间为 `lidar_manager`，子模块为 `lidar_manager.xxx.yyy`。应用可单独控制本库日志级别，不影响 root logger：

```python
import logging
import lidar_manager

# 方式一：标准库
logging.getLogger("lidar_manager").setLevel(logging.DEBUG)

# 方式二：包 API
lidar_manager.set_level(logging.DEBUG)
# 或获取包根 logger 后自行添加 handler
lidar_manager.get_logger().addHandler(logging.StreamHandler())
```

- **get_logger()**：返回包根 logger（`lidar_manager`）。
- **set_level(level)**：设置包根 logger 的级别（如 `logging.DEBUG`）。
- **get_module_logger(name)**：子模块内部使用；应用一般无需直接调用。

## 依赖

- Python >= 3.10
- numpy, opencv-python, PyYAML, open3d

## License

MIT
