```
feat(iOS): 更新MNN后端模型配置优化性能 将MNN主模型从Qwen3.5-4B(~2.64GiB)降级为Qwen3.5-2B(~1.1GiB),因为4B版本 实测运行过慢,影响用户体验。iPhone17+/SME2设备使用2B模型,保留MLX 兜底方案用于模拟器和备用场景,确保AI推理性能和存储效率的平衡。 ```
This commit is contained in:
@@ -3,7 +3,7 @@ import AVFoundation
|
||||
import UIKit
|
||||
import Combine
|
||||
|
||||
/// 异常项快拍 · 整幅单拍相机。
|
||||
/// 指标速记 · 整幅单拍相机。
|
||||
/// 全屏实时预览 + 一个快门 → 返回**整幅** upright UIImage(不裁剪)。
|
||||
/// 拍完后由 `RegionAdjustView` 在静态图上手动框选识别区域。
|
||||
/// 只在真机可用(模拟器无相机,`QuickRegionCaptureFlow` 退化到 PhotoPicker)。
|
||||
@@ -60,7 +60,7 @@ struct SingleShotCameraView: View {
|
||||
|
||||
Spacer()
|
||||
|
||||
Text("拍一张含异常指标的照片 · 拍完再框选")
|
||||
Text("拍一张含目标指标的照片 · 拍完再框选")
|
||||
.font(.tjScaled( 13, weight: .medium))
|
||||
.foregroundStyle(.white)
|
||||
.padding(.horizontal, 12)
|
||||
@@ -97,7 +97,7 @@ struct SingleShotCameraView: View {
|
||||
Text("相机权限未开启")
|
||||
.font(.tjH2())
|
||||
.foregroundStyle(.white)
|
||||
Text("异常项快拍需要相机。去「设置 → 康康 → 相机」打开后再回来。")
|
||||
Text("指标速记需要相机。去「设置 → 康康 → 相机」打开后再回来。")
|
||||
.font(.tjScaled( 13))
|
||||
.foregroundStyle(.white.opacity(0.7))
|
||||
.multilineTextAlignment(.center)
|
||||
@@ -352,49 +352,6 @@ enum RegionImageCropper {
|
||||
guard rect.width >= 1, rect.height >= 1, let cropped = cg.cropping(to: rect) else { return up }
|
||||
return UIImage(cgImage: cropped, scale: up.scale, orientation: .up)
|
||||
}
|
||||
|
||||
/// Qwen3-VL 局部图预处理:宽而矮的小框直接喂 VL 时,processor 再缩放容易把小字压没。
|
||||
/// 这里只用于 Qwen3-VL 分支,Apple Vision OCR 保持吃原始裁剪图。
|
||||
static func prepareForQwenVL(_ image: UIImage,
|
||||
minimumShortEdge: CGFloat = 448,
|
||||
maximumLongEdge: CGFloat = 2400,
|
||||
padding: CGFloat = 64) -> UIImage {
|
||||
let up = image.normalizedUp()
|
||||
guard let cg = up.cgImage else { return up }
|
||||
|
||||
let sourceSize = CGSize(width: cg.width, height: cg.height)
|
||||
guard sourceSize.width > 0, sourceSize.height > 0 else { return up }
|
||||
|
||||
let short = min(sourceSize.width, sourceSize.height)
|
||||
let long = max(sourceSize.width, sourceSize.height)
|
||||
var scale = max(1, minimumShortEdge / short)
|
||||
if long * scale > maximumLongEdge {
|
||||
scale = maximumLongEdge / long
|
||||
}
|
||||
|
||||
let contentSize = CGSize(
|
||||
width: max(1, (sourceSize.width * scale).rounded()),
|
||||
height: max(1, (sourceSize.height * scale).rounded())
|
||||
)
|
||||
let canvasSize = CGSize(
|
||||
width: contentSize.width + padding * 2,
|
||||
height: contentSize.height + padding * 2
|
||||
)
|
||||
|
||||
let format = UIGraphicsImageRendererFormat.default()
|
||||
format.scale = 1
|
||||
format.opaque = true
|
||||
let renderer = UIGraphicsImageRenderer(size: canvasSize, format: format)
|
||||
return renderer.image { ctx in
|
||||
UIColor.white.setFill()
|
||||
ctx.fill(CGRect(origin: .zero, size: canvasSize))
|
||||
|
||||
UIImage(cgImage: cg, scale: 1, orientation: .up).draw(
|
||||
in: CGRect(x: padding, y: padding,
|
||||
width: contentSize.width, height: contentSize.height)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension UIImage {
|
||||
|
||||
Reference in New Issue
Block a user