• C# Camera2 实现扫描识别二维码及Texture预览


    前几天做了电脑端二维码识别,突然想在手机上做一个二维码识别功能,发现过程还是有点麻烦,问题主要出现在要实现预览,预览界面的视频比例问题,最终也未能完美解决,实际效果尚可

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        tools:showIn="@layout/activity_main">
    
        <Button
            android:id="@+id/btnQRCodeScan"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="扫描二维码" />
    
        <TextureView
          android:id="@+id/textureQRCodeScan"
          android:layout_gravity="center"
          android:layout_width="match_parent"
          android:layout_height="match_parent" />
    
        <TextView
          android:id="@+id/textviewQRCodeScan"
          android:visibility="gone"
          android:layout_width="match_parent"
          android:layout_height="match_parent" />
    </LinearLayout>

    MainActivity代码:

    using System;
    using Android.App;
    using Android.OS;
    using Android.Runtime;
    using Android.Support.Design.Widget;
    using Android.Support.V4.App;
    using Android.Support.V4.Content;
    using Android.Support.V7.App;
    using Android.Views;
    using Android.Widget;
    using System.Linq;
    using static Android.Manifest;
    using Android.Content;
    using Android.Provider;
    using Android.Graphics;
    using Android.Hardware.Camera2;
    using System.Collections.Generic;
    using System.Threading;
    using System.Threading.Tasks;
    using Android.Net.Wifi.Aware;
    using Android.Util;
    
    namespace QRCodeScanner
    {
        [Activity(Label = "@string/app_name", Theme = "@style/AppTheme.NoActionBar", MainLauncher = true)]
        public class MainActivity : AppCompatActivity
        {
            private static CameraCaptureSession cameraSession = null;
            private static readonly object sessionLocker = new object();
    
            public class CameraStateListener : CameraDevice.StateCallback
            {
                TextureView textureView = null;
    
                public CameraStateListener(TextureView texture)
                {
                    textureView = texture; 
                }
    
                public override void OnOpened(CameraDevice cameraDevice)
                {
                    var surfaces = new List<Surface> { new Surface(textureView.SurfaceTexture) };
                    var createCaptureSessionCallback = new CameraCaptureSessionStateListener(cameraDevice, textureView);
                    cameraDevice.CreateCaptureSession(surfaces, createCaptureSessionCallback, null);
                }
    
                public override void OnDisconnected(CameraDevice cameraDevice)
                {
                    
                }
    
                public override void OnError(CameraDevice cameraDevice, CameraError error)
                {
                    
                }
            }
    
            public class CameraCaptureSessionStateListener : CameraCaptureSession.StateCallback
            {
                private CameraDevice cameraDevice = null;
                private TextureView textureView = null;
    
                public CameraCaptureSessionStateListener(CameraDevice camera, TextureView texture)
                {
                    cameraDevice = camera;
                    textureView = texture;
                }
    
                public override void OnConfigureFailed(CameraCaptureSession session)
                {
                    //do nothing
                }
    
                public override void OnConfigured(CameraCaptureSession session)
                {
                    var requestBuilder = cameraDevice.CreateCaptureRequest(CameraTemplate.Preview);
                    requestBuilder.AddTarget(new Surface(textureView.SurfaceTexture));
                    var request = requestBuilder.Build();
    
                    lock (sessionLocker)
                    {
                        cameraSession = session;
                        cameraSession.SetRepeatingRequest(request, null, null);
                    }
                }
            }
    
            private void stopCapture()
            {
                lock (sessionLocker)
                {
                    if (cameraSession != null)
                    {
                        cameraSession.StopRepeating();
                        cameraSession = null;
                    }
                }
            }
    
            protected override void OnCreate(Bundle savedInstanceState)
            {
                base.OnCreate(savedInstanceState);
                SetContentView(Resource.Layout.activity_main);
    
                Android.Support.V7.Widget.Toolbar toolbar = FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.toolbar);
                SetSupportActionBar(toolbar);
    
                FloatingActionButton fab = FindViewById<FloatingActionButton>(Resource.Id.fab);
                fab.Click += FabOnClick;
    
                var btnQRCodeScan = FindViewById<Button>(Resource.Id.btnQRCodeScan);
                btnQRCodeScan.Click += BtnQRCodeScan_Click;
    
                var timer = new Timer(new TimerCallback(delegate (object state) 
                {
                    this.RunOnUiThread(() => 
                    {
                        var textureQRCodeScan = FindViewById<TextureView>(Resource.Id.textureQRCodeScan);
                        var textviewQRCodeScan = FindViewById<TextView>(Resource.Id.textviewQRCodeScan);
                        var image = textureQRCodeScan.Bitmap;
                        if (image == null)
                            return;
    
                        lock (sessionLocker)
                        {
                            if (cameraSession == null)
                                return;
                        }
    
                        var task = new Task(()=> {
    
                            lock (sessionLocker)
                            {
                                if (cameraSession == null)
                                    return;
                            }
    
                            var sw = new System.Diagnostics.Stopwatch();
                            sw.Start();
    
                            var data = ReadQRCode(image);
    
                            sw.Stop();
    
                            System.Diagnostics.Debug.Print("time cost:" + sw.ElapsedMilliseconds);
    
                            if (data.Length > 0)
                            {
                                this.RunOnUiThread(() => {
                                    stopCapture();
                                    System.Diagnostics.Debug.Print("data:" + data);
                                    FindViewById<TextureView>(Resource.Id.textureQRCodeScan).Visibility = ViewStates.Gone;
                                    FindViewById<TextView>(Resource.Id.textviewQRCodeScan).Text = data;
                                    FindViewById<TextView>(Resource.Id.textviewQRCodeScan).Visibility = ViewStates.Visible;
                                    FindViewById<Button>(Resource.Id.btnQRCodeScan).Visibility = ViewStates.Visible;
                                });
                                
                            }
    
                        });
    
                        task.Start();
    
                    });
                }), null, 0, 200);
            }
    
            public override bool OnCreateOptionsMenu(IMenu menu)
            {
                MenuInflater.Inflate(Resource.Menu.menu_main, menu);
                return true;
            }
    
            public override bool OnOptionsItemSelected(IMenuItem item)
            {
                int id = item.ItemId;
                if (id == Resource.Id.action_settings)
                {
                    return true;
                }
    
                return base.OnOptionsItemSelected(item);
            }
    
            private void FabOnClick(object sender, EventArgs eventArgs)
            {
                View view = (View) sender;
                Snackbar.Make(view, "Replace with your own action", Snackbar.LengthLong)
                    .SetAction("Action", (Android.Views.View.IOnClickListener)null).Show();
            }
    
            private void BtnQRCodeScan_Click(object sender, EventArgs e)
            {
                if (Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.M)
                {
                    var permission = new string[] { Permission.Camera, "android.hardware.camera.autofocus" };
                    var requestPermissions = permission.Where(p => ContextCompat.CheckSelfPermission(this, p) != Android.Content.PM.Permission.Granted).ToList();
                    if (requestPermissions.Count > 0)
                        ActivityCompat.RequestPermissions(this, requestPermissions.ToArray(), 1);
                }
    
                var textureQRCodeScan = FindViewById<TextureView>(Resource.Id.textureQRCodeScan);
                textureQRCodeScan.Visibility = ViewStates.Visible;
                var textviewQRCodeScan = FindViewById<TextView>(Resource.Id.textviewQRCodeScan);
                textviewQRCodeScan.Visibility = ViewStates.Gone;
                textviewQRCodeScan.Text = string.Empty;
                var btnQRCodeScan = FindViewById<Button>(Resource.Id.btnQRCodeScan);
                btnQRCodeScan.Visibility = ViewStates.Gone;
    
                var cameraManager = (Android.Hardware.Camera2.CameraManager)GetSystemService(Context.CameraService);
                var cameraID = cameraManager.GetCameraIdList()[0];
                var characteristics = cameraManager.GetCameraCharacteristics(cameraID);
                var map = characteristics.Get(CameraCharacteristics.ScalerStreamConfigurationMap) as Android.Hardware.Camera2.Params.StreamConfigurationMap;
                var jpegSizes = map.GetOutputSizes((int)ImageFormatType.Jpeg);
                var sizes = new List<KeyValuePair<int, int>>();
                for (var i = 0; i < jpegSizes.Length; i++)
                {
                    sizes.Add(new KeyValuePair<int, int>(jpegSizes[i].Width, jpegSizes[i].Height));
                    System.Diagnostics.Debug.Print(jpegSizes[i].Width.ToString() + "X" + jpegSizes[i].Height.ToString());
                }
    
                var metrics = new DisplayMetrics();
                WindowManager.DefaultDisplay.GetMetrics(metrics);
                
                var screenWidth = metrics.WidthPixels;
                var screenHeight = metrics.HeightPixels;
    
                var ratedSizes = sizes.Select(x => new { size = x, rate = (float)x.Key / (float)x.Value })
                    .Select(x => new { size = x, differ = Math.Abs(x.rate - (float)screenWidth / (float)screenHeight) }).ToList();
    
                var bestSize = ratedSizes.Where(x => x.differ == ratedSizes.Min(y => y.differ)).First().size.size;
    
                int videoWidth = bestSize.Key;
                int videoHeight = bestSize.Value;
    
                var textureWidth = textureQRCodeScan.MeasuredWidth;
                var textureHeight = textureQRCodeScan.MeasuredHeight;
    
                //以高为基准进行缩放,宽度未超出,则以高为基准进行缩放
                if (videoWidth * textureHeight / videoHeight > textureWidth)
                {
                    textureQRCodeScan.LayoutParameters.Width = videoWidth * textureHeight / videoHeight;
                    textureQRCodeScan.LayoutParameters.Height = textureQRCodeScan.MeasuredHeight;
                }
                //以宽为基准进行缩放
                else
                {
                    textureQRCodeScan.LayoutParameters.Width = textureQRCodeScan.MeasuredWidth;
                    textureQRCodeScan.LayoutParameters.Height = textureWidth * videoHeight / videoWidth;
                }
    
                cameraManager.OpenCamera(cameraID, new CameraStateListener(textureQRCodeScan), null);
    
            }
    
            /// <summary>
            /// 生成二维码
            /// </summary>
            /// <param name="data"></param>
            /// <param name="height"></param>
            /// <param name="width"></param>
            /// <param name="margin"></param>
            /// <returns></returns>
            public static byte[] CreateQRCode(string data, int height = 100
                            , int width = 100, int margin = 0)
            {
                byte[] bytes = null;
                var barcodeWriter = new ZXing.Android.BarcodeWriter()
                {
    
                    Format = ZXing.BarcodeFormat.QR_CODE,
                    Options = new ZXing.QrCode.QrCodeEncodingOptions()
                    {
                        Height = height,
                        Width = width,
                        Margin = margin
                    }
                };
                using (var image = barcodeWriter.Write(data))
                {
                    using (var stream = new System.IO.MemoryStream())
                    {
                        image.Compress(Bitmap.CompressFormat.Png, 100, stream);
                        bytes = stream.ToArray();
                    }
                }
                return bytes;
            }
    
            /// <summary>
            /// 识别二维码
            /// </summary>
            /// <param name="bytes"></param>
            /// <returns></returns>
            public static string ReadQRCode(Bitmap image)
            {
                var result = string.Empty;
                var barcodeReader = new ZXing.Android.BarcodeReader();
                var decoded = barcodeReader.Decode(image);
                if (decoded != null)
                    result = decoded.Text;
                return result;
            }
        }
    }
    桂棹兮兰桨,击空明兮溯流光。
  • 相关阅读:
    SNOI2017炸弹
    tarjan进阶
    BZOJ3331压力
    将多个对象合并为一个对象
    原型模式详解
    HTML5
    isAnimated函数
    让函数执行的各种方式
    zepto源码注解
    mobileTech
  • 原文地址:https://www.cnblogs.com/nanfei/p/15090803.html
Copyright © 2020-2023  润新知