You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在UWP中实现带Bounding Box触摸转语音的Microsoft.Media.OCR实时相机?

在UWP中实现带Bounding Box触摸转语音的实时相机OCR(基于Microsoft.Media.OCR)

我来帮你梳理下完整的实现流程,这和你在Android上的核心逻辑一致,但UWP有自己的API体系,咱们一步步拆解:

一、先搞定项目配置与权限

UWP应用需要提前声明必要权限,否则相机和语音功能会失效:

  1. 打开Package.appxmanifest,在功能标签页勾选:
    • 网络摄像头(Webcam)
    • 麦克风(Microphone)(用于文本转语音播放)
  2. 在应用程序UI标签页,确保支持的旋转方向和你的相机预览需求匹配(避免后续坐标错乱)

二、实现实时相机预览捕获

用MediaCapture类来获取相机预览流,显示在CaptureElement控件中:

private MediaCapture _mediaCapture;
private bool _isPreviewing = false;

private async Task InitializeCameraAsync()
{
    _mediaCapture = new MediaCapture();
    var settings = new MediaCaptureInitializationSettings
    {
        StreamingCaptureMode = StreamingCaptureMode.Video,
        PhotoCaptureSource = PhotoCaptureSource.VideoPreview
    };

    await _mediaCapture.InitializeAsync(settings);
    captureElement.Source = _mediaCapture;

    await _mediaCapture.StartPreviewAsync();
    _isPreviewing = true;

    // 启动OCR识别循环
    StartOcrProcessingLoop();
}

三、用Microsoft.Media.OCR做实时文本识别

Microsoft.Media.OCR是UWP原生的OCR库,需要先获取预览帧,转换成它支持的SoftwareBitmap格式,再进行识别:

  1. 首先添加Microsoft.Media.OCR NuGet包(如果没装的话)
  2. 编写识别逻辑:
private OcrEngine _ocrEngine;
private async void StartOcrProcessingLoop()
{
    // 初始化OCR引擎,指定识别语言(比如中文:Language.GetLanguage("zh-CN"))
    _ocrEngine = OcrEngine.TryCreateFromLanguage(Language.GetLanguage("zh-CN"));
    if (_ocrEngine == null)
    {
        // 处理不支持该语言的情况,可 fallback 到英文
        _ocrEngine = OcrEngine.TryCreateFromLanguage(Language.GetLanguage("en-US"));
        if (_ocrEngine == null) return;
    }

    while (_isPreviewing)
    {
        // 每隔300ms识别一次,避免性能过载
        await Task.Delay(300);

        // 获取当前预览帧,匹配OCR支持的Bgra8格式
        var previewFrame = await _mediaCapture.GetPreviewFrameAsync(new VideoFrame(BitmapPixelFormat.Bgra8, (int)captureElement.ActualWidth, (int)captureElement.ActualHeight));
        var softwareBitmap = previewFrame.SoftwareBitmap;

        // 执行OCR识别
        var ocrResult = await _ocrEngine.RecognizeAsync(softwareBitmap);
        if (ocrResult.Status == OcrStatus.Succeeded)
        {
            // 把识别结果传递给绘制Bounding Box的方法
            UpdateBoundingBoxes(ocrResult);
        }
    }
}

四、绘制可触摸的Bounding Box覆盖层

我们需要在相机预览上层放一个Canvas控件,用来绘制每个识别文本块的矩形,同时处理触摸事件:

  1. XAML布局示例:
<Grid>
    <CaptureElement x:Name="captureElement" Stretch="Uniform"/>
    <Canvas x:Name="ocrCanvas" Background="Transparent" PointerPressed="OcrCanvas_PointerPressed"/>
</Grid>
  1. 绘制Bounding Box的代码:
private List<OcrWord> _recognizedWords = new List<OcrWord>();

private void UpdateBoundingBoxes(OcrResult ocrResult)
{
    ocrCanvas.Children.Clear();
    _recognizedWords.Clear();

    foreach (var line in ocrResult.Lines)
    {
        foreach (var word in line.Words)
        {
            _recognizedWords.Add(word);

            // 转换坐标:OCR返回的Rect基于预览帧,需适配Canvas的显示尺寸
            var scaleX = ocrCanvas.ActualWidth / captureElement.ActualWidth;
            var scaleY = ocrCanvas.ActualHeight / captureElement.ActualHeight;
            var scaledRect = new Rect(
                word.BoundingRect.X * scaleX,
                word.BoundingRect.Y * scaleY,
                word.BoundingRect.Width * scaleX,
                word.BoundingRect.Height * scaleY
            );

            // 创建绿色边框的矩形
            var rect = new Rectangle
            {
                Stroke = new SolidColorBrush(Colors.Green),
                StrokeThickness = 2,
                Width = scaledRect.Width,
                Height = scaledRect.Height
            };
            Canvas.SetLeft(rect, scaledRect.Left);
            Canvas.SetTop(rect, scaledRect.Top);

            ocrCanvas.Children.Add(rect);
        }
    }
}

五、触摸Bounding Box触发文本转语音

在Canvas的PointerPressed事件里,判断触摸点落在哪个Word的Rect里,然后用SpeechSynthesizer播放文本:

private async void OcrCanvas_PointerPressed(object sender, PointerRoutedEventArgs e)
{
    var pointerPos = e.GetCurrentPoint(ocrCanvas).Position;
    var scaleX = ocrCanvas.ActualWidth / captureElement.ActualWidth;
    var scaleY = ocrCanvas.ActualHeight / captureElement.ActualHeight;

    // 遍历所有识别的单词,找到触摸点所在的Bounding Box
    var touchedWord = _recognizedWords.FirstOrDefault(word =>
    {
        var scaledRect = new Rect(
            word.BoundingRect.X * scaleX,
            word.BoundingRect.Y * scaleY,
            word.BoundingRect.Width * scaleX,
            word.BoundingRect.Height * scaleY
        );
        return scaledRect.Contains(pointerPos);
    });

    if (touchedWord != null)
    {
        // 文本转语音播放
        var synthesizer = new SpeechSynthesizer();
        var stream = await synthesizer.SynthesizeTextToStreamAsync(touchedWord.Text);
        var mediaElement = new MediaElement();
        mediaElement.SetSource(stream, stream.ContentType);
        mediaElement.Play();
    }
}

关键注意事项

  • 性能优化:不要每帧都执行OCR,设置合理的识别间隔(200-500ms),避免UI卡顿
  • 坐标适配:相机预览分辨率和UI控件尺寸可能不一致,一定要做缩放转换,否则Bounding Box会错位
  • 设备旋转:如果设备横竖屏切换,需要通过DisplayInformation.OrientationChanged事件调整预览帧方向,避免OCR结果偏移
  • 异常处理:要捕获相机初始化、OCR识别时的异常,比如相机权限被拒绝的情况

内容的提问来源于stack exchange,提问作者Rahul Kishan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 04:07:39