feat(scanQRcode): add center crop zoom and bilinear sampling for preview
新增扫码预览的中心裁切放大功能,支持自定义裁切比例,同时使用双线性插值提升画面缩放质量
This commit is contained in:
parent
807f940cfb
commit
15c502c959
@ -37,6 +37,11 @@ namespace Kill.UI.Pages
|
||||
[Tooltip("扫描处理线程数")]
|
||||
public bool useAsyncScan = true;
|
||||
|
||||
[Header("中心裁切放大")]
|
||||
[Tooltip("截取画面中心区域的比例(0-1),值越小放越大,推荐0.55~0.7")]
|
||||
[Range(0.3f, 1.0f)]
|
||||
public float centerCropRatio = 0.65f;
|
||||
|
||||
[Header("自动对焦")]
|
||||
[Tooltip("启用自动对焦")]
|
||||
public bool enableAutoFocus = true;
|
||||
@ -264,42 +269,67 @@ namespace Kill.UI.Pages
|
||||
|
||||
/// <summary>
|
||||
/// 从相机画面裁切并旋转,生成预览画面
|
||||
/// 支持中心裁切放大:只截取画面中心区域,放大到预览尺寸
|
||||
/// </summary>
|
||||
private void CutAndRotateCameraFrame(int camW, int camH, int targetW, int targetH)
|
||||
{
|
||||
// 相机横向 1920x1080,需要顺时针旋转90度变成 1080x1920
|
||||
// 预览框横向 1080x680
|
||||
// 从旋转后的 1080x1920 中截取中间 1080x680 区域
|
||||
// 从旋转后的 1080x1920 中截取中间区域并放大
|
||||
|
||||
// 计算裁切区域(在原始相机画面上的坐标)
|
||||
// 旋转后高度是 camW(1920),需要截取 targetH(680) 高度
|
||||
// 从中间截取:起始Y = (1920 - 680) / 2 = 620
|
||||
int cropY = (camW - targetH) / 2; // 620
|
||||
// 计算中心裁切区域大小(基于 centerCropRatio)
|
||||
int sourceCropH = Mathf.Max(1, Mathf.RoundToInt(camW * centerCropRatio));
|
||||
int sourceCropW = Mathf.Max(1, Mathf.RoundToInt(camH * centerCropRatio));
|
||||
int cropY = (camW - sourceCropH) / 2;
|
||||
int cropX = (camH - sourceCropW) / 2;
|
||||
|
||||
// 计算缩放比例
|
||||
float scaleY = (float)sourceCropH / targetH;
|
||||
float scaleX = (float)sourceCropW / targetW;
|
||||
|
||||
// 获取相机像素数据
|
||||
Color32[] cameraPixels = webCamTexture.GetPixels32();
|
||||
Color32[] targetPixels = new Color32[targetW * targetH];
|
||||
|
||||
// 顺时针旋转90度并裁切
|
||||
// 原始坐标 (x, y) -> 顺时针旋转90度后 (y, camW-1-x)
|
||||
// 目标 (x, y) 对应源:
|
||||
// srcX = cropY + y (在裁切区域内纵向移动)
|
||||
// srcY = x (横向直接对应,不翻转)
|
||||
// 顺时针旋转90度 + 中心裁切 + 缩放
|
||||
// 目标像素 (x, y) 对应源坐标:
|
||||
// srcX = cropY + (targetH-1-y) * scaleY (裁切区域内纵向缩放)
|
||||
// srcY = cropX + x * scaleX (裁切区域内横向缩放)
|
||||
for (int y = 0; y < targetH; y++)
|
||||
{
|
||||
for (int x = 0; x < targetW; x++)
|
||||
{
|
||||
// 目标像素在预览图中的位置 (x, y)
|
||||
// 对应原始相机中的位置
|
||||
int srcX = cropY + (targetH - 1 - y); // 从裁切区域底部开始,向上取像素(修复上下颠倒)
|
||||
int srcY = x; // 横向直接对应
|
||||
float srcX = cropY + (targetH - 1 - y) * scaleY;
|
||||
float srcY = cropX + x * scaleX;
|
||||
|
||||
if (srcX >= 0 && srcX < camW && srcY >= 0 && srcY < camH)
|
||||
{
|
||||
int srcIndex = srcY * camW + srcX;
|
||||
int dstIndex = y * targetW + x;
|
||||
targetPixels[dstIndex] = cameraPixels[srcIndex];
|
||||
}
|
||||
// 双线性插值采样
|
||||
int sx = (int)srcX;
|
||||
int sy = (int)srcY;
|
||||
float fx = srcX - sx;
|
||||
float fy = srcY - sy;
|
||||
int sx1 = Mathf.Min(sx + 1, camW - 1);
|
||||
int sy1 = Mathf.Min(sy + 1, camH - 1);
|
||||
|
||||
int idx00 = sy * camW + sx;
|
||||
int idx10 = sy * camW + sx1;
|
||||
int idx01 = sy1 * camW + sx;
|
||||
int idx11 = sy1 * camW + sx1;
|
||||
|
||||
Color32 c00 = cameraPixels[idx00];
|
||||
Color32 c10 = cameraPixels[idx10];
|
||||
Color32 c01 = cameraPixels[idx01];
|
||||
Color32 c11 = cameraPixels[idx11];
|
||||
|
||||
float r = (1-fx)*(1-fy)*c00.r + fx*(1-fy)*c10.r + (1-fx)*fy*c01.r + fx*fy*c11.r;
|
||||
float g = (1-fx)*(1-fy)*c00.g + fx*(1-fy)*c10.g + (1-fx)*fy*c01.g + fx*fy*c11.g;
|
||||
float b = (1-fx)*(1-fy)*c00.b + fx*(1-fy)*c10.b + (1-fx)*fy*c01.b + fx*fy*c11.b;
|
||||
|
||||
targetPixels[y * targetW + x] = new Color32(
|
||||
(byte)Mathf.Clamp(r, 0, 255),
|
||||
(byte)Mathf.Clamp(g, 0, 255),
|
||||
(byte)Mathf.Clamp(b, 0, 255),
|
||||
255
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user