2026.05.14征图日记14(和mentor掰扯)

上午没啥事,app也搞得差不多了,就去牛客上看了几篇react和agent的八股,没事的时候不仅要摸鱼,还要为秋招做准备,下午如果还没事的话我就要开始刷leetcode了,不说了,八股看得差不多我要去逛linuxdo了~

上午leader还让我去公司大门接人,正好昨天晚上预约的流量卡上门办理也来了,回去和leader回报了一下就下去办流量卡了。39¥月租280G流量,归属地是广东惠州,江苏人还不让办

下午把App的检测结果页面的分享按钮删掉了,之后再考虑怎么提高测量精度和怎么让用户在拍完照片之后不会因为调用LiDAR卡一下,产生不好的体验。之后就是把图片的来源界定了一下,只有开启LiDAR测量+来源是拍照的才会调用LiDAR。其他情况都不调用~

关于用户拍照完不要卡一下的问题,解决方案就是我们自己写一个相机拍照页面,不用原生的。这样就可以把拍照和LiDAR同时调用,另外还要解决图片裁剪的问题。具体为:用户进入拍照页面,点击拍照,后台异步调用LiDAR,图片准备好之后拿到深度数据,直接推理

思考过后这个方案太过复杂,所以我就只把LiDAR的ts调用DepthCapture搞成异步的

周末准备去连云港逛逛,主要是看海~,一个人坐在海边,吹着风,发呆~

下午还和mentor对了一下App的需求,主要就是这个标定法在工业场景下的应用,现场需要一个东西来测定缺陷面积。大概率是固定机位,所以想要只需要一次标定+固定标定点,就可以应对全部了。但仔细想,如果是固定标定点,那么是不是就意味着是固定机位,如果都是固定机位了,那就不需要标定了!?提需求的时候能不能长长脑子????!!!!

还是照着它的方式实现一下把,不管了,不过再仔细想想,他这个方案的进度会比直接给距离好,并且在后续维护的时候也更方便,就不用再次拿尺子测距离,只需要在手机上重新标定一下就好了。

之后就是把检测结果界面的缺陷文字信息全部统一改成NG1、NG2、NG3……因为模型判断可能不是准确的,索性就直接用NG代替了


今日工作内容:
1、App的标定界面与结果界面交互优化
2、App持久化标定数据
3、App的历史记录测量方法隔离
4、固定机位一次标定测量方案设计

下阶段计划
1、优化App的激光雷达调用流程
2、优化App交互逻辑


设置默认标定点

Goal

在移动端设置页的标定法下,新增”设置默认标定”功能:用户拍一张参照物照片,画标定线 + 输入参照物长度,保存为全局默认。后续缺陷检测时自动预填该标定数据,用户只需确认即可完成面积计算。

Requirements

1. settingsStore 扩展

新增持久化字段:

  • defaultCalibrationLine: CalibrationLine | null — 默认标定线(归一化坐标)
  • 保留现有 defaultReferenceLengthMm — 默认参照物长度(已有字段,现在在 Modal 内设置)

不需要存储参考图片分辨率:CalibrationOverlay 使用归一化坐标 [0,1],computeLinePixelLength 动态用当前图片分辨率计算像素长度。compressImage 统一将长边压缩到 4096px,同一拍摄条件下不同图片的 scale 一致。

2. SettingsScreen — 设置默认标定入口

在标定法下(measurementMethod === 'calibration'),移除现有的”默认参照物长度”独立输入框,替换为:

  • 单个按钮(GradientButton)
  • 按钮文字动态变化:
    • 未设置时:显示”设置默认标定”
    • 已设置时:显示”已设置标定 - XXmm(点击修改)”(XX 为当前参照物长度)
  • 点击 → 弹出全屏 Modal

3. 全屏 Modal — 标定设置

Modal 内部结构:

1
2
3
4
5
6
7
8
9
┌──────────────────────────┐
│ 取消 设置默认标定 完成 │ ← 顶部栏
├──────────────────────────┤
│ │
│ [拍照] [从相册选择] │ ← 选择图片(未选图时显示)
│ │
│ CalibrationOverlay │ ← 选图后显示
│ (拖拽标定线 + 参照物长度)│
└──────────────────────────┘

交互流程:

  1. 打开 Modal → 显示”拍照”和”从相册选择”两个按钮
  2. 用户拍照/选图 → 图片显示在 CalibrationOverlay 中
  3. 用户拖拽标定线对齐参照物 + 输入参照物长度
  4. 点击”完成” → 校验长度 > 0 → 保存到 settingsStore
  5. 点击”取消” → 关闭不保存

使用 react-native-image-crop-pickeropenCamera / openPicker,复用现有的图片压缩流程。

4. ResultScreen — 预填默认标定

核心原则:默认标定数据只能在设置页修改,ResultScreen 永远不写入 settingsStore。

行为变更

  • 点击”测定缺陷面积”时,draftLine 初始化优先级:
    1. settingsStore.defaultCalibrationLine(如果存在)
    2. inferenceStore.calibrationLine(当前会话标定,如果存在)
    3. 默认位置 {start: {x:0.2, y:0.45}, end: {x:0.8, y:0.45}}
  • draftRefLength 初始化优先级:
    1. settingsStore.defaultReferenceLengthMm(如果 > 0)
    2. inferenceStore.referenceLengthMm(如果 > 0)
    3. 默认值 25
  • 用户在 Modal 中确认后,数据仅保存到 inferenceStore,不触碰 settingsStore
  • 已有的”重新标定”按钮保持不变

clearAll 行为不变calibrationLine 清空,referenceLengthMm 保留。下次打开标定 Modal 时会从 settingsStore 重新读取默认值。

5. 预设导出/导入(JSON 文件)

允许用户导出当前默认标定配置为 JSON 文件,并从文件导入标定配置。支持跨设备传输。

导出内容(JSON 格式):

1
2
3
4
5
6
{
"version": 1,
"type": "calibration-preset",
"defaultCalibrationLine": { "start": {"x": 0.3, "y": 0.5}, "end": {"x": 0.7, "y": 0.5} },
"defaultReferenceLengthMm": 25
}

UI 布局:在设置页标定法区域,”设置默认标定”按钮下方新增一行两个小按钮:

  • “导出预设” — 需要已设置标定才能点击,否则 Toast 提示”请先设置标定”
  • “导入预设” — 始终可点击

导出流程

  1. 从 settingsStore 读取 defaultCalibrationLine + defaultReferenceLengthMm
  2. 序列化为 JSON 字符串
  3. 写入临时文件 calibration-preset.json
  4. 调用 react-native-share 打开 iOS 分享面板
  5. 用户可选择隔空投送、邮件、微信、保存到文件等

导入流程

  1. 调用 react-native-document-picker 打开文件选择器(.json 类型)
  2. 读取文件内容
  3. 校验 JSON 格式:type === 'calibration-preset'version 存在、defaultCalibrationLine 结构正确、defaultReferenceLengthMm > 0
  4. 校验通过 → 写入 settingsStore,Toast 提示”导入成功”
  5. 校验失败 → Alert 提示”文件格式不正确”

新增依赖

  • react-native-share — iOS 分享面板
  • react-native-document-picker — 文件选择器
  • iOS pod install 后生效

6. i18n

新增 key(中英文):

  • settings.calibrationSetup — “设置默认标定” / “Set Default Calibration”
  • settings.calibrationSetupDone — “已设置标定 - mm(点击修改)” / “Calibration Set - mm (tap to change)”
  • settings.calibrationSetupTitle — “设置默认标定” / “Set Default Calibration”
  • settings.pickImage — “拍照” / “Take Photo”
  • settings.pickFromLibrary — “从相册选择” / “Choose from Library”
  • settings.exportPreset — “导出预设” / “Export Preset”
  • settings.importPreset — “导入预设” / “Import Preset”
  • settings.exportNoCalibration — “请先设置标定” / “Please set calibration first”
  • settings.importSuccess — “导入成功” / “Import successful”
  • settings.importInvalidFormat — “文件格式不正确” / “Invalid file format”

复用已有 key:measurement.referenceLengthmeasurement.dragHintmeasurement.finishCalibrationcommon.cancelcommon.done

Acceptance Criteria

  • 设置页标定法下显示”设置默认标定”按钮(替代原有参照物长度输入框)
  • 已设置时按钮显示”已设置标定 - XXmm(点击修改)”
  • 点击按钮弹出全屏 Modal,可拍照或从相册选图
  • Modal 中 CalibrationOverlay 正确显示,支持拖拽标定线和输入参照物长度
  • 点击”完成”保存标定线 + 参照物长度到 settingsStore MMKV
  • 设置页显示”导出预设”/“导入预设”按钮
  • 导出生成 JSON 文件并通过 iOS 分享面板分享
  • 导入从文件选择器读取 JSON,校验后写入 settingsStore
  • ResultScreen 点击”测定缺陷面积”时,如果存在默认标定,Modal 预填充标定数据
  • 用户可在 ResultScreen 中调整或覆盖默认标定(仅影响当前会话)
  • 未设置默认标定时,现有标定流程不受影响
  • i18n 中英文完整支持
  • lint / typecheck 通过

Decision (ADR-lite)

Context: 标定法每次检测都要手动画标定线,效率低。用户在固定检测条件下,参照物和拍摄距离一致。

Decision: 在设置页提供一次性的标定设置流程(拍照+画线),保存归一化标定线到 settingsStore。检测时预填充到标定 Modal,用户确认后应用。

Consequences:

  • 归一化坐标 + compressImage 统一压缩 = 不同图片间 scale 一致(同拍摄条件)
  • 用户仍需每次确认,避免因条件变化导致误标定
  • 只支持单个默认标定,不做多预设管理

Out of Scope

  • 多套标定预设管理(只做单个默认标定)
  • 参考图片保存/预览(仅保存标定线和长度,不保存参考照片)
  • 非标定法的流程改动
  • 距离法和 LiDAR 法的任何改动

Technical Notes

可复用组件

  • CalibrationOverlaycomponents/result/CalibrationOverlay.tsx):接口独立,props 为 imageUri/imageWidth/imageHeight/line/onLineChange/referenceLengthMm/onReferenceLengthChange/pixelLength,可直接在 Modal 中复用
  • react-native-image-crop-pickeropenCamera / openPicker 返回 path/width/height/size/cropRect
  • compressImage()utils/image.ts):压缩到 4096px 长边

标定精度分析

  • calibrateArea 公式:A = N × (L_mm / L_px)²
  • L_px = computeLinePixelLength(line, imageW, imageH) — 使用归一化坐标 × 图片分辨率
  • compressImage 长边统一 4096px → 同拍摄条件下,标定线的 mm/px 比例跨图片一致
  • 不同拍摄距离会导致 scale 变化,这是标定法的固有假设

数据流

1
2
3
4
5
6
7
8
9
10
11
SettingsScreen → 全屏 Modal → 拍照/选图 → CalibrationOverlay
→ 保存 defaultCalibrationLine + defaultReferenceLengthMm → settingsStore → MMKV
(默认标定只在设置页写入,ResultScreen 不会修改)

ResultScreen → handleMeasureArea()
→ 读取 settingsStore.defaultCalibrationLine(优先)
或 inferenceStore.calibrationLine(回退)
→ 预填到 draftLine/draftRefLength → CalibrationOverlay (Modal)
→ 用户确认 → inferenceStore.setCalibrationLine + setReferenceLengthMm
→ 触发面积计算
(仅写入 inferenceStore,不触碰 settingsStore)

修改文件清单

  1. mobile/src/store/settingsStore.ts — 新增 defaultCalibrationLine 字段 + setter
  2. mobile/src/screens/SettingsScreen.tsx — 移除独立参照物长度输入,新增按钮 + Modal + 拍照/标定/导出导入交互
  3. mobile/src/screens/ResultScreen.tsx — draft 初始化逻辑改为优先使用 settingsStore 默认值
  4. mobile/src/i18n/locales/zh.ts + en.ts — 新增 i18n key
  5. mobile/package.json — 新增 react-native-sharereact-native-document-picker 依赖