使用 ARKit 和 ZXing 在 Unity 中读取二维码
Read QR Code in Unity with ARKit and ZXing
我正在尝试使用以下库读取二维码:
- ARKit
- Z星
不过好像不太顺利。几个小时后,我仍然无法读出像样的二维码。
调试时,我应用纹理来查看我的结果。由于纹理 Y,它看起来是红色的,但除此之外,它还显示了 QR 码。
解释纹理不会 return ZXing 分析的任何数据。
这是我为此使用的以下代码:
#if UNITY_IOS && !UNITY_EDITOR
// Update is called once per frame
// BETTER: InvokeRepeating
void Update()
{
if (!done) {
ARTextureHandles handles = arSession.GetARVideoTextureHandles();
//ARTextureHandles handles = UnityARSessionNativeInterface.GetARSessionNativeInterface().GetARVideoTextureHandles();
if (handles.IsNull())
{
return;
}
if (handles.TextureY != System.IntPtr.Zero) {
ReadQRCode (handles.TextureY);
}
}
}
#endif
private void ReadQRCode(System.IntPtr mtlTexPtr)
{
Debug.Log("---------------");
Debug.Log("Scanning...");
Resolution currentResolution = Screen.currentResolution;
tex = (UnityEngine.Texture2D)GameObject.Find("Camera").GetComponent<UnityARVideo>().m_ClearMaterial.GetTexture("_textureCbCr");
tex.UpdateExternalTexture(mtlTexPtr);
try
{
if(barCodeReader == null) {
Debug.Log("Could not find barcorereader");
}
if(tex == null) {
Debug.Log("Could not find texture");
}
var data = barCodeReader.Decode(tex.GetPixels32(), currentResolution.width, currentResolution.height);
if (data != null)
{
Debug.Log("QR: " + data.Text);
}
else
{
Debug.Log("NO QR: " + "No QR code detected !");
}
}
catch (Exception e)
{
Debug.LogError("Error reading QR");
Debug.LogError(e.Message);
}
}
我同时使用过 ZXing 和 ARkit,但从未一起使用过。
试图让一些东西起作用,至少给你一些可能的提示。
作为您的 ARCameraManager 的子级,添加另一个(除了您的主 AR 相机之外)相机,并附加一个 ARVideo 脚本(删除诸如音频监听器、Flare 层和 guiLayer 之类的东西)同时添加以下脚本,即就在那里检索渲染纹理:
[RequireComponent(typeof(Camera))]
public class WebcamFetcher : MonoBehaviour
{
private RenderTexture _vertical;
private RenderTexture _horizontal;
private Camera _camera;
// Update is called once per frame
public RenderTexture RenderTexture
{
get
{
var orientation = Screen.orientation;
if (orientation == ScreenOrientation.Landscape || orientation == ScreenOrientation.LandscapeLeft || orientation == ScreenOrientation.LandscapeRight)
{
return _horizontal;
}
else
{
return _vertical;
}
}
}
// Use this for initialization
void Start ()
{
_camera = GetComponent<Camera>();
_horizontal = new RenderTexture(Screen.width, Screen.height, 24);
_vertical = new RenderTexture(Screen.height, Screen.width, 24);
}
// Update is called once per frame
void Update()
{
var orientation = Screen.orientation;
if (orientation == ScreenOrientation.Landscape || orientation == ScreenOrientation.LandscapeLeft || orientation == ScreenOrientation.LandscapeRight)
{
_camera.targetTexture = _horizontal;
}
else
{
_camera.targetTexture = _vertical;
}
}
}
然后使用如下脚本:
private string DecodeQR(Color32[] pixels, int width, int height)
{
try
{
IBarcodeReader barcodeReader = new BarcodeReader();
// decode the current frame
var result = barcodeReader.Decode(pixels, width, height);
if (result != null)
{
return result.Text;
}
}
catch (Exception ex) { Debug.LogError(ex.Message); }
return null;
}
[SerializeField] Text QrDisplay; // A text field to display detected QRs to
public void OnQrDetect() // a callback for a UI button
{
var texture = new Texture2D(_webcamFetcher.RenderTexture.width, _webcamFetcher.RenderTexture.height);
RenderTexture.active = _webcamFetcher.RenderTexture;
texture.ReadPixels(new Rect(Vector2.zero, new Vector2(_webcamFetcher.RenderTexture.width, _webcamFetcher.RenderTexture.height)), 0, 0);
var qrText = DecodeQR(texture.GetPixels32(), _webcamFetcher.RenderTexture.width, _webcamFetcher.RenderTexture.height);
if (qrText != null)
{
QrDisplay.text = qrText;
}
}
对我有用。纹理检索可能不是最有效的。
但它有效 -> 这是可能的。
经过进一步挖掘,我发现了一个与 OpenCV 类似的示例。
事实证明这对我来说速度很快。
public class FrameCapturer : MonoBehaviour {
// Script Inputs
public bool m_shouldCaptureOnNextFrame = false;
public Color32[] m_lastCapturedColors;
// Privates
Texture2D m_centerPixTex;
void Start()
{
Resolution currentResolution = Screen.currentResolution;
m_centerPixTex = new Texture2D(currentResolution.width, currentResolution.height, TextureFormat.RGBA32, false);
}
void OnPostRender()
{
if (m_shouldCaptureOnNextFrame)
{
Resolution res = Screen.currentResolution;
m_lastCapturedColors = GetRenderedColors();
m_shouldCaptureOnNextFrame = false;
}
}
// Helpers
Color32[] GetRenderedColors()
{
Resolution currentResolution = Screen.currentResolution;
m_centerPixTex.ReadPixels(new Rect(0, 0, currentResolution.width, currentResolution.height), 0, 0);
m_centerPixTex.Apply();
return m_centerPixTex.GetPixels32();
}
}
我把它连接到主摄像头上,AR 脚本也连接在下面。然后我的二维码 reader 我可以简单地使用以下内容:
public class QRCodeReader : MonoBehaviour
{
public Camera cam;
private BarcodeReader barCodeReader;
FrameCapturer m_pixelCapturer;
// Use this for initialization
void Start()
{
barCodeReader = new BarcodeReader();
Resolution currentResolution = Screen.currentResolution;
m_pixelCapturer = cam.GetComponent<FrameCapturer>();
}
void Update()
{
Resolution currentResolution = Screen.currentResolution;
try
{
Color32[] framebuffer = m_pixelCapturer.m_lastCapturedColors;
if (framebuffer.Length == 0)
{
return;
}
var data = barCodeReader.Decode(framebuffer, currentResolution.width, currentResolution.height);
if (data != null)
{
// QRCode detected.
Debug.Log(data);
Debug.Log("QR: " + data.Text);
//OnQrCodeRead(new QrCodeReadEventArgs() { text = data.Text });
}
}
catch (Exception e)
{
Debug.LogError("Error reading QR");
Debug.LogError(e.Message);
}
// skip 1 frame each time
// solves GetPixels() blocks for ReadPixels() to complete
// https://medium.com/google-developers/real-time-image-capture-in-unity-458de1364a4c
m_pixelCapturer.m_shouldCaptureOnNextFrame = true;
}
}
原始来源,我将此答案改编为:https://github.com/realityenhanced/ARKitExperiments/blob/master/Assets/Scripts/CaptureCenterPixel.cs
我正在尝试使用以下库读取二维码:
- ARKit
- Z星
不过好像不太顺利。几个小时后,我仍然无法读出像样的二维码。 调试时,我应用纹理来查看我的结果。由于纹理 Y,它看起来是红色的,但除此之外,它还显示了 QR 码。 解释纹理不会 return ZXing 分析的任何数据。
这是我为此使用的以下代码:
#if UNITY_IOS && !UNITY_EDITOR
// Update is called once per frame
// BETTER: InvokeRepeating
void Update()
{
if (!done) {
ARTextureHandles handles = arSession.GetARVideoTextureHandles();
//ARTextureHandles handles = UnityARSessionNativeInterface.GetARSessionNativeInterface().GetARVideoTextureHandles();
if (handles.IsNull())
{
return;
}
if (handles.TextureY != System.IntPtr.Zero) {
ReadQRCode (handles.TextureY);
}
}
}
#endif
private void ReadQRCode(System.IntPtr mtlTexPtr)
{
Debug.Log("---------------");
Debug.Log("Scanning...");
Resolution currentResolution = Screen.currentResolution;
tex = (UnityEngine.Texture2D)GameObject.Find("Camera").GetComponent<UnityARVideo>().m_ClearMaterial.GetTexture("_textureCbCr");
tex.UpdateExternalTexture(mtlTexPtr);
try
{
if(barCodeReader == null) {
Debug.Log("Could not find barcorereader");
}
if(tex == null) {
Debug.Log("Could not find texture");
}
var data = barCodeReader.Decode(tex.GetPixels32(), currentResolution.width, currentResolution.height);
if (data != null)
{
Debug.Log("QR: " + data.Text);
}
else
{
Debug.Log("NO QR: " + "No QR code detected !");
}
}
catch (Exception e)
{
Debug.LogError("Error reading QR");
Debug.LogError(e.Message);
}
}
我同时使用过 ZXing 和 ARkit,但从未一起使用过。
试图让一些东西起作用,至少给你一些可能的提示。
作为您的 ARCameraManager 的子级,添加另一个(除了您的主 AR 相机之外)相机,并附加一个 ARVideo 脚本(删除诸如音频监听器、Flare 层和 guiLayer 之类的东西)同时添加以下脚本,即就在那里检索渲染纹理:
[RequireComponent(typeof(Camera))]
public class WebcamFetcher : MonoBehaviour
{
private RenderTexture _vertical;
private RenderTexture _horizontal;
private Camera _camera;
// Update is called once per frame
public RenderTexture RenderTexture
{
get
{
var orientation = Screen.orientation;
if (orientation == ScreenOrientation.Landscape || orientation == ScreenOrientation.LandscapeLeft || orientation == ScreenOrientation.LandscapeRight)
{
return _horizontal;
}
else
{
return _vertical;
}
}
}
// Use this for initialization
void Start ()
{
_camera = GetComponent<Camera>();
_horizontal = new RenderTexture(Screen.width, Screen.height, 24);
_vertical = new RenderTexture(Screen.height, Screen.width, 24);
}
// Update is called once per frame
void Update()
{
var orientation = Screen.orientation;
if (orientation == ScreenOrientation.Landscape || orientation == ScreenOrientation.LandscapeLeft || orientation == ScreenOrientation.LandscapeRight)
{
_camera.targetTexture = _horizontal;
}
else
{
_camera.targetTexture = _vertical;
}
}
}
然后使用如下脚本:
private string DecodeQR(Color32[] pixels, int width, int height)
{
try
{
IBarcodeReader barcodeReader = new BarcodeReader();
// decode the current frame
var result = barcodeReader.Decode(pixels, width, height);
if (result != null)
{
return result.Text;
}
}
catch (Exception ex) { Debug.LogError(ex.Message); }
return null;
}
[SerializeField] Text QrDisplay; // A text field to display detected QRs to
public void OnQrDetect() // a callback for a UI button
{
var texture = new Texture2D(_webcamFetcher.RenderTexture.width, _webcamFetcher.RenderTexture.height);
RenderTexture.active = _webcamFetcher.RenderTexture;
texture.ReadPixels(new Rect(Vector2.zero, new Vector2(_webcamFetcher.RenderTexture.width, _webcamFetcher.RenderTexture.height)), 0, 0);
var qrText = DecodeQR(texture.GetPixels32(), _webcamFetcher.RenderTexture.width, _webcamFetcher.RenderTexture.height);
if (qrText != null)
{
QrDisplay.text = qrText;
}
}
对我有用。纹理检索可能不是最有效的。 但它有效 -> 这是可能的。
经过进一步挖掘,我发现了一个与 OpenCV 类似的示例。
事实证明这对我来说速度很快。
public class FrameCapturer : MonoBehaviour {
// Script Inputs
public bool m_shouldCaptureOnNextFrame = false;
public Color32[] m_lastCapturedColors;
// Privates
Texture2D m_centerPixTex;
void Start()
{
Resolution currentResolution = Screen.currentResolution;
m_centerPixTex = new Texture2D(currentResolution.width, currentResolution.height, TextureFormat.RGBA32, false);
}
void OnPostRender()
{
if (m_shouldCaptureOnNextFrame)
{
Resolution res = Screen.currentResolution;
m_lastCapturedColors = GetRenderedColors();
m_shouldCaptureOnNextFrame = false;
}
}
// Helpers
Color32[] GetRenderedColors()
{
Resolution currentResolution = Screen.currentResolution;
m_centerPixTex.ReadPixels(new Rect(0, 0, currentResolution.width, currentResolution.height), 0, 0);
m_centerPixTex.Apply();
return m_centerPixTex.GetPixels32();
}
}
我把它连接到主摄像头上,AR 脚本也连接在下面。然后我的二维码 reader 我可以简单地使用以下内容:
public class QRCodeReader : MonoBehaviour
{
public Camera cam;
private BarcodeReader barCodeReader;
FrameCapturer m_pixelCapturer;
// Use this for initialization
void Start()
{
barCodeReader = new BarcodeReader();
Resolution currentResolution = Screen.currentResolution;
m_pixelCapturer = cam.GetComponent<FrameCapturer>();
}
void Update()
{
Resolution currentResolution = Screen.currentResolution;
try
{
Color32[] framebuffer = m_pixelCapturer.m_lastCapturedColors;
if (framebuffer.Length == 0)
{
return;
}
var data = barCodeReader.Decode(framebuffer, currentResolution.width, currentResolution.height);
if (data != null)
{
// QRCode detected.
Debug.Log(data);
Debug.Log("QR: " + data.Text);
//OnQrCodeRead(new QrCodeReadEventArgs() { text = data.Text });
}
}
catch (Exception e)
{
Debug.LogError("Error reading QR");
Debug.LogError(e.Message);
}
// skip 1 frame each time
// solves GetPixels() blocks for ReadPixels() to complete
// https://medium.com/google-developers/real-time-image-capture-in-unity-458de1364a4c
m_pixelCapturer.m_shouldCaptureOnNextFrame = true;
}
}
原始来源,我将此答案改编为:https://github.com/realityenhanced/ARKitExperiments/blob/master/Assets/Scripts/CaptureCenterPixel.cs