{"record":{"id":"910c28b6998c0454","repo":"babalae/better-genshin-impact","slug":"3-channels","errorCode":null,"errorMessage":"图像通道数必须为3,当前为{channels}","messagePattern":"图像通道数必须为3,当前为(.+?)","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"BetterGenshinImpact/Core/Recognition/OCR/Engine/OcrUtils.cs","lineNumber":72,"sourceCode":"    ///     <br />\n    ///     标准化:\n    ///     Z-Score Normalization\n    /// </summary>\n    public static Tensor<float> NormalizeToTensorDnn(Mat src,\n        float? scale, // scale float32\n        float[]? mean, //mean\n        float[]? std, //std\n        out IMemoryOwner<float> tensorMemoryOwner, bool swapRb = false, bool crop = false, Size size = default)\n\n    {\n        scale ??= 0.00392156862745f;\n        mean ??= [0.485f, 0.456f, 0.406f];\n        std ??= [0.229f, 0.224f, 0.225f];\n        using var rt = new ResourcesTracker();\n        // 获取图像参数\n        var channels = src.Channels();\n        if (channels != 3)\n            throw new ArgumentException($\"图像通道数必须为3,当前为{channels}\");\n        // var data = rt.T(OcrOperationImpl.NormalizeImageOperation(src, scale, mean, std));\n        var stdMat = rt.NewMat();\n        Mat[] bgr = [];\n        try\n        {\n            bgr = src.Split();\n            for (var i = 0; i < bgr.Length; ++i)\n                bgr[i].ConvertTo(bgr[i], MatType.CV_32FC1, 1 / std[i],\n                    (0.0 - mean[i]) / std[i] / (float)scale);\n            Cv2.Merge(bgr, stdMat);\n        }\n        finally\n        {\n            foreach (var channel in bgr) channel.Dispose();\n        }\n\n        //stdMat.GetArray<float>(out var data);\n        // 使用DNN模块创建blob","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/babalae/better-genshin-impact/blob/a7cb36712dcb409be610257d877fcea3597e9d6b/BetterGenshinImpact/Core/Recognition/OCR/Engine/OcrUtils.cs#L54-L90","documentation":"OcrUtils.NormalizeToTensorDnn preprocesses a Mat for the PaddleOCR detection model, which expects a 3-channel BGR image. If src.Channels() != 3 (e.g. a 4-channel BGRA capture, a 1-channel grayscale, or an empty Mat) it throws ArgumentException before splitting, which would otherwise index mean/std arrays incorrectly or crash.","triggerScenarios":"Feeding a screenshot Mat with alpha (4 channels); a grayscale Mat; an empty/uninitialized Mat (channels 0); a Mat loaded from a PNG with transparency.","commonSituations":"Capture pipeline producing BGRA instead of BGR; image loaded via ImRead without IMREAD_COLOR; downscaling/conversion step that changed channel count; ROI extraction returning an empty Mat.","solutions":["Convert to 3-channel BGR before calling: Cv2.CvtColor(src, src, ColorConversionCodes.BGRA2BGR).","Load images with Cv2.ImRead(path, ImReadModes.Color).","Guard for empty Mat and invalid channels upstream and skip/correct."],"exampleFix":"// before\nvar tensor = OcrUtils.NormalizeToTensorDnn(srcMat, ...);\n\n// after\nif (srcMat.Channels() == 4)\n    Cv2.CvtColor(srcMat, srcMat, ColorConversionCodes.BGRA2BGR);\nvar tensor = OcrUtils.NormalizeToTensorDnn(srcMat, ...);","handlingStrategy":"validation","validationCode":"if (srcMat.Channels() == 4)\n    Cv2.CvtColor(srcMat, srcMat, ColorConversionCodes.BGRA2BGR);\nelse if (srcMat.Channels() == 1)\n    Cv2.CvtColor(srcMat, srcMat, ColorConversionCodes.GRAY2BGR);\nvar tensor = OcrUtils.NormalizeToTensorDnn(srcMat, scale, mean, std, out var owner);","typeGuard":"static bool IsThreeChannel(OpenCvSharp.Mat m) => !m.Empty() && m.Channels() == 3;","tryCatchPattern":null,"preventionTips":["Standardize capture Mats to 3-channel BGR before OCR preprocessing.","Load images with ImReadModes.Color.","Guard against empty Mats upstream."],"tags":["ocr","paddleocr","opencv","argument-validation","image-processing"],"backgroundTag":null,"analyzedSha":"a7cb36712dcb409be610257d877fcea3597e9d6b","analyzedAt":"2026-08-13T16:44:57.548Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}