ARFoundation使用ZXingQRCode扫码

一、下载和导入Zxing

Zxing下载地址:GitHub - micjahn/ZXing.Net: .Net port of the original java-based barcode reader and generator library zxing

使用zxing.unity.dll,将下载的dll文件添加到Plugins下:

二、unity设置

Project Settings-Player下勾选Allow ‘unsafe’ Code:

三、编写代码

1.使用ARCameraManager接收摄像帧

m_CameraManager.frameReceived += OnCameraFrameReceived;

2.读取摄像机图像信息

cameraManager.TryAcquireLatestCpuImage(out XRCpuImage image)

3.创建Texture2D,将摄像机图像信息转为Texture2D

var format = TextureFormat.RGBA32;

            if (m_CameraTexture == null || m_CameraTexture.width != image.width || m_CameraTexture.height != image.height)

            {

                m_CameraTexture = new Texture2D(image.width, image.height, format, false);

            }

            // Convert the image to format, flipping the image across the Y axis.

            // We can also get a sub rectangle, but we'll get the full image here.

            var conversionParams = new XRCpuImage.ConversionParams(image, format, m_Transformation);

            // Texture2D allows us write directly to the raw texture data

            // This allows us to do the conversion in-place without making any copies.

            var rawTextureData = m_CameraTexture.GetRawTextureData<byte>();

            try

            {

                image.Convert(conversionParams, new IntPtr(rawTextureData.GetUnsafePtr()), rawTextureData.Length);

            }

            finally

            {

                // We must dispose of the XRCpuImage after we're finished

                // with it to avoid leaking native resources.

                image.Dispose();

            }

            // Apply the updated texture data to our texture

            m_CameraTexture.Apply();

4.调用ZXing解码

// create a reader with a custom luminance source

        BarcodeReader barcodeReader = new BarcodeReader { AutoRotate = false, Options = new ZXing.Common.DecodingOptions { TryHarder = false } };

var result = barcodeReader.Decode(colors, width, height);

四、unity创建组件挂载

1.Hierarchy新建空对象,命名QR,Canvas下创建Text,显示结果

2.QRCodeScanning.cs

using System;

using Unity.Collections.LowLevel.Unsafe;

using UnityEngine;

using UnityEngine.UI;

using UnityEngine.XR.ARFoundation;

using UnityEngine.XR.ARSubsystems;

using ZXing;

namespace FrameworkDesign.Example

{

   

    public class QRCodeScanning : MonoBehaviour

    {

        [SerializeField]

        [Tooltip("The ARCameraManager which will produce frame events.")]

        ARCameraManager m_CameraManager;

        /// <summary>

        /// Get or set the <c>ARCameraManager</c>.

        /// </summary>

        public ARCameraManager cameraManager

        {

            get => m_CameraManager;

            set => m_CameraManager = value;

        }

        /**

        [SerializeField]

        RawImage m_RawCameraImage;

        /// <summary>

        /// The UI RawImage used to display the image on screen.

        /// </summary>

        public RawImage rawCameraImage

        {

            get => m_RawCameraImage;

            set => m_RawCameraImage = value;

        }

        */

        [SerializeField]

        Text m_ImageInfo;

        /// <summary>

        /// The UI Text used to display information about the image on screen.

        /// </summary>

        public Text imageInfo

        {

            get => m_ImageInfo;

            set => m_ImageInfo = value;

        }

        /**

        [SerializeField]

        Button m_TransformationButton;

        /// <summary>

        /// The button that controls transformation selection.

        /// </summary>

        public Button transformationButton

        {

            get => m_TransformationButton;

            set => m_TransformationButton = value;

        }

        */

        XRCpuImage.Transformation m_Transformation = XRCpuImage.Transformation.MirrorY;

        Texture2D m_CameraTexture;

        // create a reader with a custom luminance source

        BarcodeReader barcodeReader = new BarcodeReader { AutoRotate = false, Options = new ZXing.Common.DecodingOptions { TryHarder = false } };

        private bool snaped = false;

        /**

        /// <summary>

        /// Cycles the image transformation to the next case.

        /// </summary>

        public void CycleTransformation()

        {

            m_Transformation = m_Transformation switch

            {

                XRCpuImage.Transformation.None => XRCpuImage.Transformation.MirrorX,

                XRCpuImage.Transformation.MirrorX => XRCpuImage.Transformation.MirrorY,

                XRCpuImage.Transformation.MirrorY => XRCpuImage.Transformation.MirrorX | XRCpuImage.Transformation.MirrorY,

                _ => XRCpuImage.Transformation.None

            };

            if (m_TransformationButton)

            {

                m_TransformationButton.GetComponentInChildren<Text>().text = m_Transformation.ToString();

            }

        }

        */

        void OnEnable()

        {

            if (m_CameraManager != null)

            {

                m_CameraManager.frameReceived += OnCameraFrameReceived;

            }

        }

        void OnDisable()

        {

            if (m_CameraManager != null)

            {

                m_CameraManager.frameReceived -= OnCameraFrameReceived;

            }

        }

        unsafe void UpdateCameraImage()

        {

           

            // Attempt to get the latest camera image. If this method succeeds,

            // it acquires a native resource that must be disposed (see below).

            if (!cameraManager.TryAcquireLatestCpuImage(out XRCpuImage image))

            {

                return;

            }

            //Logger.Log("UpdateCameraImage");

            // Display some information about the camera image

            m_ImageInfo.text = string.Format(

                "Image info:\n\twidth: {0}\n\theight: {1}\n\tplaneCount: {2}\n\ttimestamp: {3}\n\tformat: {4}",

                image.width, image.height, image.planeCount, image.timestamp, image.format);

            // Once we have a valid XRCpuImage, we can access the individual image "planes"

            // (the separate channels in the image). XRCpuImage.GetPlane provides

            // low-overhead access to this data. This could then be passed to a

            // computer vision algorithm. Here, we will convert the camera image

            // to an RGBA texture and draw it on the screen.

            // Choose an RGBA format.

            // See XRCpuImage.FormatSupported for a complete list of supported formats.

            var format = TextureFormat.RGBA32;

            if (m_CameraTexture == null || m_CameraTexture.width != image.width || m_CameraTexture.height != image.height)

            {

                m_CameraTexture = new Texture2D(image.width, image.height, format, false);

            }

            // Convert the image to format, flipping the image across the Y axis.

            // We can also get a sub rectangle, but we'll get the full image here.

            var conversionParams = new XRCpuImage.ConversionParams(image, format, m_Transformation);

            // Texture2D allows us write directly to the raw texture data

            // This allows us to do the conversion in-place without making any copies.

            var rawTextureData = m_CameraTexture.GetRawTextureData<byte>();

            try

            {

                image.Convert(conversionParams, new IntPtr(rawTextureData.GetUnsafePtr()), rawTextureData.Length);

            }

            finally

            {

                // We must dispose of the XRCpuImage after we're finished

                // with it to avoid leaking native resources.

                image.Dispose();

            }

            // Apply the updated texture data to our texture

            m_CameraTexture.Apply();

            // Set the RawImage's texture so we can visualize it.

           // m_RawCameraImage.texture = m_CameraTexture;

            //Logger.Log("UpdateCameraImage2222222");

            //-----------------

            string res = DecodeQR(m_CameraTexture.GetPixels32(), m_CameraTexture.width, m_CameraTexture.height);

            //Logger.Log("DecodeQR22222222"+res);

            if (!string.IsNullOrEmpty(res))

            {

                imageInfo.text = "识别:"+res;

                Logger.Log("DecodeQR=" + res);

                OnDisable();

            }

        }

        static void UpdateRawImage(RawImage rawImage, XRCpuImage cpuImage, XRCpuImage.Transformation transformation)

        {

            // Get the texture associated with the UI.RawImage that we wish to display on screen.

            var texture = rawImage.texture as Texture2D;

            // If the texture hasn't yet been created, or if its dimensions have changed, (re)create the texture.

            // Note: Although texture dimensions do not normally change frame-to-frame, they can change in response to

            //    a change in the camera resolution (for camera images) or changes to the quality of the human depth

            //    and human stencil buffers.

            if (texture == null || texture.width != cpuImage.width || texture.height != cpuImage.height)

            {

                texture = new Texture2D(cpuImage.width, cpuImage.height, cpuImage.format.AsTextureFormat(), false);

                rawImage.texture = texture;

            }

            // For display, we need to mirror about the vertical access.

            var conversionParams = new XRCpuImage.ConversionParams(cpuImage, cpuImage.format.AsTextureFormat(), transformation);

            // Get the Texture2D's underlying pixel buffer.

            var rawTextureData = texture.GetRawTextureData<byte>();

            // Make sure the destination buffer is large enough to hold the converted data (they should be the same size)

            Debug.Assert(rawTextureData.Length == cpuImage.GetConvertedDataSize(conversionParams.outputDimensions, conversionParams.outputFormat),

                "The Texture2D is not the same size as the converted data.");

            // Perform the conversion.

            cpuImage.Convert(conversionParams, rawTextureData);

            // "Apply" the new pixel data to the Texture2D.

            texture.Apply();

            // Make sure it's enabled.

            rawImage.enabled = true;

        }

        void OnCameraFrameReceived(ARCameraFrameEventArgs eventArgs)

        {

            UpdateCameraImage();         

        }

      

        //--------------

        string DecodeQR(Color32[] colors, int width, int height)

        {

             try

            {

               // Logger.Log("DecodeQR");

                // decode the current frame

                var result = barcodeReader.Decode(colors, width, height);

                if (result != null)

                {

                    return result.Text;

                }

            }

            catch

            {

            }

            return null;

        }

        //------------------

    }

}

五、常见问题

六、参考文献

1. Unity 指导手册:

Unity - Manual: Unity User Manual 2021.3 (LTS)

2.ARFoundation示例:

GitHub - Unity-Technologies/arfoundation-samples: Example content for Unity projects based on AR Foundation

3.ARCore开发文档:

ARCore 和支持的开发环境概览  |  Google Developers

猜你喜欢

转载自blog.csdn.net/weixin_40239288/article/details/130339277