【问题标题】:Hololens barcode reader using UWP C#使用 UWP C# 的 Hololens 条码阅读器
【发布时间】:2019-10-25 13:52:49
【问题描述】:

这里我想知道如何从hololens读取条形码。

public sealed partial class ScanQrPage : Page
{
    public bool SoftwareTriggerStarted { get; set; } = false;
    bool isSelectionChanging = false;
    public bool IsScannerClaimed { get; set; } = false;
    public bool ScannerSupportsPreview { get; set; } = false;
    ClaimedBarcodeScanner claimedScanner = null;
    static readonly Guid rotationGuid = new Guid("C380465D-2271-428C-9B83-ECEA3B4A85C1");
    BarcodeScanner selectedScanner = null;
    MediaCapture mediaCapture;
    DeviceWatcher watcher;
    ObservableCollection<BarcodeScannerInfo> barcodeScanners = new ObservableCollection<BarcodeScannerInfo>();
    DisplayRequest displayRequest = new DisplayRequest();
    public ScanQrPage()
    {
        this.InitializeComponent();
        watcher = DeviceInformation.CreateWatcher(BarcodeScanner.GetDeviceSelector());
        watcher.Added += Watcher_Added;
        watcher.Removed += Watcher_Removed;
        watcher.Updated += Watcher_Updated;
        watcher.Start();

    }
    private async void StartSoftwareTriggerButton_Click(object sender, RoutedEventArgs e)
    {
        Grd_btn.Visibility = Visibility.Collapsed;
        scanQr.Visibility = Visibility.Visible;
        if (claimedScanner != null)
        {
            await claimedScanner.StartSoftwareTriggerAsync();

            SoftwareTriggerStarted = true;
            RaisePropertyChanged(nameof(SoftwareTriggerStarted));
        }
    }
    private async void StopSoftwareTriggerButton_Click(object sender, RoutedEventArgs e)
    {
        Grd_btn.Visibility = Visibility.Visible;
        scanQr.Visibility = Visibility.Collapsed;
        if (claimedScanner != null)
        {
            await claimedScanner.StopSoftwareTriggerAsync();
            result.Text = "";
            SoftwareTriggerStarted = false;
            RaisePropertyChanged(nameof(SoftwareTriggerStarted));
        }
    }
    private async void Watcher_Added(DeviceWatcher sender, DeviceInformation args)
    {
        await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
        {
            barcodeScanners.Add(new BarcodeScannerInfo(args.Name, args.Id));
            await SelectScannerAsync(args.Id.ToString());
        });
    }
    public event PropertyChangedEventHandler PropertyChanged;
    public void RaisePropertyChanged(string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
    private async void ClaimedScanner_DataReceived(ClaimedBarcodeScanner sender, BarcodeScannerDataReceivedEventArgs args)
    {
        await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
        {
            result.Text = DataHelpers.GetDataLabelString(args.Report.ScanDataLabel, args.Report.ScanDataType);
            var s2 = DataHelpers.GetDataString(args.Report.ScanData);
            var s3 = BarcodeSymbologies.GetName(args.Report.ScanDataType);
            var localSettings = Windows.Storage.ApplicationData.Current.LocalSettings;
            localSettings.Values["UserName"] = DataHelpers.GetDataLabelString(args.Report.ScanDataLabel, args.Report.ScanDataType);

            if (result.Text.ToString() != "Result") {
                Helper.Alert(result.Text.ToString());
            }
                //Frame.Navigate(typeof(Dashboard));
            else
                Helper.Alert("Please Scan a QR/BarCode to Login");
        });
    }
    private async Task SelectScannerAsync(string scannerDeviceId)
    {
        selectedScanner = await BarcodeScanner.FromIdAsync(scannerDeviceId);

        if (selectedScanner != null)
        {
            claimedScanner = await selectedScanner.ClaimScannerAsync();
            if (claimedScanner != null)
            {
                await claimedScanner.EnableAsync();
                ScannerSupportsPreview = !String.IsNullOrEmpty(selectedScanner.VideoDeviceId);
                RaisePropertyChanged(nameof(ScannerSupportsPreview));
                claimedScanner.DataReceived += ClaimedScanner_DataReceived;
                if (ScannerSupportsPreview)
                    await StartMediaCaptureAsync(selectedScanner.VideoDeviceId);
            }
            else
            {
                //rootPage.NotifyUser("Failed to claim the selected barcode scanner", NotifyType.ErrorMessage);
            }

        }
        else
        {
            //rootPage.NotifyUser("Failed to create a barcode scanner object", NotifyType.ErrorMessage);
        }

        IsScannerClaimed = claimedScanner != null;
        RaisePropertyChanged(nameof(IsScannerClaimed));

        isSelectionChanging = false;
    }
    private void Watcher_Removed(DeviceWatcher sender, DeviceInformationUpdate args)
    {
        // We don't do anything here, but this event needs to be handled to enable realtime updates.
        // See https://aka.ms/devicewatcher_added.
    }

    private void Watcher_Updated(DeviceWatcher sender, DeviceInformationUpdate args)
    {
        // We don't do anything here, but this event needs to be handled to enable realtime updates.
        //See https://aka.ms/devicewatcher_added.
    }
    private async Task StartMediaCaptureAsync(string videoDeviceId)
    {
        mediaCapture = new MediaCapture();

        // Register for a notification when something goes wrong
        mediaCapture.Failed += MediaCapture_Failed;

        var settings = new MediaCaptureInitializationSettings
        {
            VideoDeviceId = videoDeviceId,
            StreamingCaptureMode = StreamingCaptureMode.Video,
            SharingMode = MediaCaptureSharingMode.SharedReadOnly,
        };

        // Initialize MediaCapture
        bool captureInitialized = false;
        try
        {
            await mediaCapture.InitializeAsync(settings);
            captureInitialized = true;
        }
        catch (UnauthorizedAccessException)
        {
            //rootPage.NotifyUser("The app was denied access to the camera", NotifyType.ErrorMessage);
        }
        catch (Exception e)
        {
            //rootPage.NotifyUser("Failed to initialize the camera: " + e.Message, NotifyType.ErrorMessage);
        }

        if (captureInitialized)
        {
            // Prevent the device from sleeping while the preview is running.
            displayRequest.RequestActive();

            PreviewControl.Source = mediaCapture;
            await mediaCapture.StartPreviewAsync();
            await SetPreviewRotationAsync(DisplayInformation.GetForCurrentView().CurrentOrientation);
            //IsPreviewing = true;
            //RaisePropertyChanged(nameof(IsPreviewing));
        }
        else
        {
            mediaCapture.Dispose();
            mediaCapture = null;
        }
    }
    private async Task SetPreviewRotationAsync(DisplayOrientations displayOrientation)
    {
        bool isExternalCamera;
        bool isPreviewMirrored;

        // Figure out where the camera is located to account for mirroring and later adjust rotation accordingly.
        DeviceInformation cameraInformation = await DeviceInformation.CreateFromIdAsync(selectedScanner.VideoDeviceId);

        if ((cameraInformation.EnclosureLocation == null) || (cameraInformation.EnclosureLocation.Panel == Windows.Devices.Enumeration.Panel.Unknown))
        {
            isExternalCamera = true;
            isPreviewMirrored = false;
        }
        else
        {
            isExternalCamera = false;
            isPreviewMirrored = (cameraInformation.EnclosureLocation.Panel == Windows.Devices.Enumeration.Panel.Front);
        }

        PreviewControl.FlowDirection = isPreviewMirrored ? FlowDirection.RightToLeft : FlowDirection.LeftToRight;

        if (!isExternalCamera)
        {
            // Calculate which way and how far to rotate the preview.
            int rotationDegrees = 0;
            switch (displayOrientation)
            {
                case DisplayOrientations.Portrait:
                    rotationDegrees = 90;
                    break;
                case DisplayOrientations.LandscapeFlipped:
                    rotationDegrees = 180;
                    break;
                case DisplayOrientations.PortraitFlipped:
                    rotationDegrees = 270;
                    break;
                case DisplayOrientations.Landscape:
                default:
                    rotationDegrees = 0;
                    break;
            }

            // The rotation direction needs to be inverted if the preview is being mirrored.
            if (isPreviewMirrored)
            {
                rotationDegrees = (360 - rotationDegrees) % 360;
            }

            // Add rotation metadata to the preview stream to make sure the aspect ratio / dimensions match when rendering and getting preview frames.
            var streamProperties = mediaCapture.VideoDeviceController.GetMediaStreamProperties(MediaStreamType.VideoPreview);
            streamProperties.Properties[rotationGuid] = rotationDegrees;
            await mediaCapture.SetEncodingPropertiesAsync(MediaStreamType.VideoPreview, streamProperties, null);
        }
    }
    private void MediaCapture_Failed(MediaCapture sender, MediaCaptureFailedEventArgs errorEventArgs)
    {

    }

    private void Back_Tapped(object sender, TappedRoutedEventArgs e)
    {
        if (Frame.CanGoBack)
            Frame.GoBack();
    }

    private void ResultButton_Click(object sender, TappedRoutedEventArgs e)
    {
        if (result.Text != "Result")
        {
            Frame.Navigate(typeof(Dashboard));
        }
    }


}
public class BarcodeScannerInfo
{
    public BarcodeScannerInfo(String deviceName, String deviceId)
    {
        DeviceName = deviceName;
        DeviceId = deviceId;
    }

    public String Name => $"{DeviceName} ({DeviceId})";
    public String DeviceId { get; private set; }
    private string DeviceName;
}



public partial class DataHelpers
{
    public static string GetDataString(IBuffer data)
    {
        if (data == null)
        {
            return "No data";
        }

        // Just to show that we have the raw data, we'll print the value of the bytes.
        // Arbitrarily limit the number of bytes printed to 20 so the UI isn't overloaded.
        string result = CryptographicBuffer.EncodeToHexString(data);
        if (result.Length > 40)
        {
            result = result.Substring(0, 40) + "...";
        }
        return result;
    }

    public static string GetDataLabelString(IBuffer data, uint scanDataType)
    {
        // Only certain data types contain encoded text.
        // To keep this simple, we'll just decode a few of them.
        if (data == null)
        {
            return "No data";
        }

        // This is not an exhaustive list of symbologies that can be converted to a string.
        if (scanDataType == BarcodeSymbologies.Upca ||
            scanDataType == BarcodeSymbologies.UpcaAdd2 ||
            scanDataType == BarcodeSymbologies.UpcaAdd5 ||
            scanDataType == BarcodeSymbologies.Upce ||
            scanDataType == BarcodeSymbologies.UpceAdd2 ||
            scanDataType == BarcodeSymbologies.UpceAdd5 ||
            scanDataType == BarcodeSymbologies.Ean8 ||
            scanDataType == BarcodeSymbologies.TfStd ||
            scanDataType == BarcodeSymbologies.OcrA ||
            scanDataType == BarcodeSymbologies.OcrB)
        {
            // The UPC, EAN8, and 2 of 5 families encode the digits 0..9
            // which are then sent to the app in a UTF8 string (like "01234").
            return CryptographicBuffer.ConvertBinaryToString(BinaryStringEncoding.Utf8, data);
        }

        // Some other symbologies (typically 2-D symbologies) contain binary data that
        // should not be converted to text.
        //return string.Format("Decoded data unavailable. Raw label data: {0}", DataHelpers.GetDataString(data));
        return CryptographicBuffer.ConvertBinaryToString(BinaryStringEncoding.Utf8, data);
    }
}

这是我的代码,在我的 Windows 10 电脑上运行良好。

当我打包相同的代码并部署到 Hololens 中时,我无法 读取条形码/二维码。

是否有任何我需要启用的硬件规范或我在这里错过的任何其他规范?

【问题讨论】:

  • 功能下的webcam 是否启用?您是否正在使用同时访问相机的东西(例如 Vuforia)?
  • 是的,功能已启用。不,我不会将相机用于任何其他过程。
  • 我不熟悉这个东西……也许它与剪辑有关?您的二维码应该在多远的距离内被识别?可能是摄像头上Mixed Reality Camera ManagerNear Clip设置得太高了,这就是摄像头无法识别密码的原因?
  • 我正在尝试做同样的事情,如果我运行“BarcodeScanner.CheckHealth”,我会在 Hololens 中收到“无解码器”消息,对于 Windows,我遵循了这个:docs.microsoft.com/et-ee/windows/uwp/devices-sensors/… - 但是不知道如何在 Hololens 中这样做

标签: c# uwp qr-code barcode hololens


【解决方案1】:

@南达,

使用 HoloLens V1 读取条形码的挑战在于,相机只能在流式传输图像时进行固定对焦。它无法自动聚焦在条码上,因此很难使条码准确聚焦以成功读取。它可能适用于足够大的条形码,但我不希望它在标准尺寸的条形码上可靠。希望未来版本的 HoloLens 中的相机将具备条码解码所需的自动对焦功能。

特里·沃里克,微软

【讨论】:

    【解决方案2】:

    Hololens 2 现在能够进行连续自动对焦 (CAF)。因此,用于条形码读取的 windows.devices.pointofservice API 集现在可以与 UWP 应用充分配合。

    • 使用JustScanIt app 试用 Hololens 2
    • 免费演示 CAF 如何扫描条码
    • 它的帮助中包含所有相关 Microsoft 在线文档和 UWP 示例的链接。
    • 它使用 Windows 中的本地工业级 Digimarc 解码器来处理多种条码符号(QR、UPC、pdf417 等)
    • 真不错的博文:Windows 10 camera-based barcode scanner

    【讨论】:

      猜你喜欢
      • 2018-12-02
      • 1970-01-01
      • 1970-01-01
      • 2014-03-19
      • 1970-01-01
      • 1970-01-01
      • 2012-06-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多