216 lines
6.7 KiB
Markdown
216 lines
6.7 KiB
Markdown
# XP.Camera 使用说明
|
||
|
||
基于 .NET 8 WPF 的工业相机控制与标定类库,采用工厂模式 + 统一接口设计,支持多品牌相机扩展。当前已实现 Basler pylon SDK 驱动。
|
||
|
||
## 环境要求
|
||
|
||
- .NET 8 SDK
|
||
- Windows 操作系统
|
||
- Basler pylon 8 SDK(已安装并配置环境变量)
|
||
|
||
## 项目结构
|
||
|
||
```
|
||
XP.Camera/
|
||
├── Core/ # 相机核心抽象
|
||
│ ├── ICameraController.cs # 控制器接口 + 工厂接口
|
||
│ ├── CameraFactory.cs # 统一工厂(根据品牌创建控制器)
|
||
│ ├── CameraModels.cs # CameraInfo、ImageGrabbedEventArgs、GrabErrorEventArgs
|
||
│ └── CameraExceptions.cs # CameraException、ConnectionLostException、DeviceNotFoundException
|
||
├── Basler/ # Basler 品牌实现
|
||
│ └── BaslerCameraController.cs # Basler pylon SDK 实现
|
||
├── Converters/ # 数据转换工具
|
||
│ └── PixelConverter.cs # 像素数据 → WPF BitmapSource 转换
|
||
├── Calibration/ # 相机标定模块
|
||
│ ├── CalibrationProcessor.cs # 九点标定(DLT 单应性矩阵,像素→世界坐标)
|
||
│ ├── ChessboardCalibrator.cs # 棋盘格标定(Zhang's 方法,内参 + 畸变校正)
|
||
│ ├── IDialogService.cs # ICalibrationDialogService 接口
|
||
│ ├── DefaultCalibrationDialogService.cs # 默认实现(标准 WPF MessageBox)
|
||
│ ├── CalibrationLocalizedStrings.cs # XAML 本地化绑定辅助
|
||
│ ├── Controls/ # 标定 UI 控件(UserControl)
|
||
│ │ ├── CalibrationControl.xaml/.cs # 九点标定界面
|
||
│ │ ├── ChessboardCalibrationControl.xaml/.cs # 棋盘格标定界面
|
||
│ │ └── ImageCanvasControl.xaml/.cs # 图像画布(缩放/平移)
|
||
│ ├── ViewModels/ # 标定视图模型
|
||
│ │ ├── CalibrationViewModel.cs
|
||
│ │ └── ChessboardCalibrationViewModel.cs
|
||
│ └── Resources/ # 本地化资源
|
||
│ ├── CalibrationResources.resx # 中文(默认)
|
||
│ ├── CalibrationResources.en-US.resx # 英文
|
||
│ └── CalibrationResources.Designer.cs
|
||
└── XP.Camera.csproj
|
||
```
|
||
|
||
所有相机核心类型在 `XP.Camera` 命名空间下,标定模块在 `XP.Camera.Calibration` 命名空间下。
|
||
|
||
## 项目引用
|
||
|
||
```xml
|
||
<ProjectReference Include="..\XP.Camera\XP.Camera.csproj" />
|
||
```
|
||
|
||
## 快速开始
|
||
|
||
### 1. 通过工厂创建控制器
|
||
|
||
```csharp
|
||
using XP.Camera;
|
||
|
||
ICameraFactory factory = new CameraFactory();
|
||
using ICameraController camera = factory.CreateController("Basler");
|
||
|
||
CameraInfo info = camera.Open();
|
||
Console.WriteLine($"已连接: {info.ModelName} (SN: {info.SerialNumber})");
|
||
```
|
||
|
||
### 2. 依赖注入方式(推荐)
|
||
|
||
在 Prism / DI 容器中注册:
|
||
|
||
```csharp
|
||
var config = AppConfig.Load();
|
||
containerRegistry.RegisterSingleton<ICameraFactory, CameraFactory>();
|
||
containerRegistry.RegisterSingleton<ICameraController>(() =>
|
||
new CameraFactory().CreateController(config.CameraType));
|
||
```
|
||
|
||
相机品牌通过配置文件 `config.json` 指定:
|
||
|
||
```json
|
||
{
|
||
"CameraType": "Basler"
|
||
}
|
||
```
|
||
|
||
### 3. 实时图像显示(WPF 绑定)
|
||
|
||
```csharp
|
||
_camera.ImageGrabbed += (s, e) =>
|
||
{
|
||
var bitmap = PixelConverter.ToBitmapSource(
|
||
e.PixelData, e.Width, e.Height, e.PixelFormat);
|
||
Application.Current.Dispatcher.Invoke(() => CameraImageSource = bitmap);
|
||
};
|
||
```
|
||
|
||
### 4. 软件触发采集流程
|
||
|
||
```csharp
|
||
camera.Open();
|
||
camera.SetExposureTime(10000); // 10ms
|
||
camera.StartGrabbing();
|
||
camera.ExecuteSoftwareTrigger();
|
||
camera.StopGrabbing();
|
||
camera.Close();
|
||
```
|
||
|
||
### 5. 使用标定模块
|
||
|
||
标定模块完全自包含,可独立使用,无需外部依赖。
|
||
|
||
#### 棋盘格标定(相机内参 + 畸变校正)
|
||
|
||
```csharp
|
||
using XP.Camera.Calibration;
|
||
using XP.Camera.Calibration.ViewModels;
|
||
using XP.Camera.Calibration.Controls;
|
||
|
||
// 使用默认对话框服务(标准 WPF MessageBox)
|
||
var dialogService = new DefaultCalibrationDialogService();
|
||
var viewModel = new ChessboardCalibrationViewModel(dialogService);
|
||
|
||
var window = new Window
|
||
{
|
||
Title = "棋盘格标定",
|
||
Width = 1600, Height = 900,
|
||
Content = new ChessboardCalibrationControl { DataContext = viewModel }
|
||
};
|
||
window.ShowDialog();
|
||
```
|
||
|
||
#### 九点标定(像素→世界坐标)
|
||
|
||
```csharp
|
||
var dialogService = new DefaultCalibrationDialogService();
|
||
var viewModel = new CalibrationViewModel(dialogService);
|
||
|
||
var window = new Window
|
||
{
|
||
Title = "九点标定",
|
||
Width = 1400, Height = 850,
|
||
Content = new CalibrationControl { DataContext = viewModel }
|
||
};
|
||
window.ShowDialog();
|
||
```
|
||
|
||
#### 纯算法调用(不使用 UI)
|
||
|
||
```csharp
|
||
// 棋盘格标定
|
||
var calibrator = new ChessboardCalibrator();
|
||
calibrator.CalibrateFromImages(imagePaths, boardWidth: 11, boardHeight: 8, squareSize: 15f, out string error);
|
||
calibrator.SaveCalibration("camera_calibration.json");
|
||
|
||
// 九点标定
|
||
var processor = new CalibrationProcessor();
|
||
processor.Calibrate(points);
|
||
var worldPoint = processor.PixelToWorld(new PointF(100, 200));
|
||
```
|
||
|
||
#### 自定义对话框服务
|
||
|
||
如需自定义弹框样式,实现 `ICalibrationDialogService` 接口即可:
|
||
|
||
```csharp
|
||
public class MyDialogService : ICalibrationDialogService
|
||
{
|
||
// 实现所有接口方法,使用自定义 UI 组件...
|
||
}
|
||
```
|
||
|
||
## 核心接口
|
||
|
||
### ICameraController
|
||
|
||
| 方法 | 说明 |
|
||
|------|------|
|
||
| `Open()` | 打开连接,返回 `CameraInfo` |
|
||
| `Close()` | 关闭连接(自动停止采集) |
|
||
| `StartGrabbing()` | 以软件触发模式启动采集 |
|
||
| `ExecuteSoftwareTrigger()` | 触发一帧采集 |
|
||
| `StopGrabbing()` | 停止采集 |
|
||
| `Get/SetExposureTime` | 曝光时间(微秒) |
|
||
| `Get/SetGain` | 增益值 |
|
||
| `Get/SetWidth/Height` | 图像尺寸 |
|
||
| `Get/SetPixelFormat` | 像素格式(Mono8 / BGR8 / BGRA8) |
|
||
|
||
### 事件
|
||
|
||
| 事件 | 说明 |
|
||
|------|------|
|
||
| `ImageGrabbed` | 成功采集一帧图像 |
|
||
| `GrabError` | 图像采集失败 |
|
||
| `ConnectionLost` | 相机连接意外断开 |
|
||
|
||
> 所有事件均在非 UI 线程触发,更新 WPF 界面时需通过 `Dispatcher.Invoke` 调度。
|
||
|
||
## 异常处理
|
||
|
||
| 异常类型 | 场景 |
|
||
|---------|------|
|
||
| `DeviceNotFoundException` | 无可用相机 |
|
||
| `ConnectionLostException` | 相机物理断开 |
|
||
| `CameraException` | SDK 操作失败(基类) |
|
||
|
||
## 扩展其他品牌相机
|
||
|
||
1. 在 `Basler/` 同级创建新文件夹,实现 `ICameraController` 接口
|
||
2. 在 `CameraFactory.cs` 中注册新品牌
|
||
3. 配置文件切换品牌即可,业务代码无需修改
|
||
|
||
## 线程安全
|
||
|
||
- 所有公共方法均线程安全
|
||
- 事件回调不持有内部锁,不会导致死锁
|
||
- `Open()` / `Close()` 幂等,重复调用安全
|