如何在UWP中实现带Bounding Box触摸转语音的Microsoft.Media.OCR实时相机?
在UWP中实现带Bounding Box触摸转语音的实时相机OCR(基于Microsoft.Media.OCR)
我来帮你梳理下完整的实现流程,这和你在Android上的核心逻辑一致,但UWP有自己的API体系,咱们一步步拆解:
一、先搞定项目配置与权限
UWP应用需要提前声明必要权限,否则相机和语音功能会失效:
- 打开
Package.appxmanifest,在功能标签页勾选:- 网络摄像头(Webcam)
- 麦克风(Microphone)(用于文本转语音播放)
- 在应用程序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格式,再进行识别:
- 首先添加
Microsoft.Media.OCRNuGet包(如果没装的话) - 编写识别逻辑:
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控件,用来绘制每个识别文本块的矩形,同时处理触摸事件:
- XAML布局示例:
<Grid> <CaptureElement x:Name="captureElement" Stretch="Uniform"/> <Canvas x:Name="ocrCanvas" Background="Transparent" PointerPressed="OcrCanvas_PointerPressed"/> </Grid>
- 绘制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
相关产品推荐
相关产品推荐

