diff --git a/Assets/Scripts/UI/Pages/ConnectDevice/ScanQRcode.cs b/Assets/Scripts/UI/Pages/ConnectDevice/ScanQRcode.cs index a98cb43..d54be80 100644 --- a/Assets/Scripts/UI/Pages/ConnectDevice/ScanQRcode.cs +++ b/Assets/Scripts/UI/Pages/ConnectDevice/ScanQRcode.cs @@ -36,6 +36,11 @@ namespace Kill.UI.Pages public int scanResolutionWidth = 1080; [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("启用自动对焦")] @@ -264,42 +269,67 @@ namespace Kill.UI.Pages /// /// 从相机画面裁切并旋转,生成预览画面 + /// 支持中心裁切放大:只截取画面中心区域,放大到预览尺寸 /// 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 + ); } }