Я пытаюсь обнаружить края бумаги с помощью камеры, используя мой плагин OpenCV C ++ в Unity. Плагин, который я написал, обнаруживает угловые координаты пикселей плавно, я протестировал его повсюду, так что это не должно быть проблемой. сокращен. Больше, но это не совсем исправлено, потому что даже соотношение все еще немного отключено. Я не понимаю, DisplayMatrix должен составить сопоставление координат Texel с дисплеем, верно? (Он всегда нажимает на самолет, так что это нормально)private Vector2 fromRawCpuToViewport(Matrix4x4 displayMatrix, Vector2 cord)
{
float u = cord.x / camTex.width;
float v = cord.y / camTex.height;
Vector4 uv = new Vector4(u, v, 1f, 0f);
Vector4 mapped = displayMatrix.transpose * uv;
//if (mapped.w != 0f) //
Проективный разрыв прокомментируется, потому что в этом случае он не помогает, w всегда 0. < /p>
Весь код, который создает верхний прямоугольник в изображении: < /p>
// PaperDetector.cs
using System;
using System.Linq;
using System.Collections.Generic;
using Unity.Collections;
using UnityEngine;
using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.ARSubsystems;
using UnityEngine.UI;
[RequireComponent(typeof(ARCameraManager))]
public class PaperDetector : MonoBehaviour
{
/* ---------- Inspector refs ---------- */
[SerializeField] ARCameraManager cameraManager;
[SerializeField] ARRaycastManager raycastManager;
[SerializeField] ARPlaneManager arPlaneManager;
[SerializeField] RawImage debugImage;
[Header("Line Settings")]
[SerializeField] Material lineMaterial;
[SerializeField] float lineWidth = 0.005f;
/* ---------- internals ---------- */
Texture2D camTex;
lineSegment[] segments = new lineSegment[4];
static readonly List hits = new();
Vector3[] prevPos = new Vector3[4];
struct lineSegment
{
public LineRenderer lr;
public bool end0Fallback;
public bool end1Fallback;
}
void Awake()
{
InitLines();
arPlaneManager.planePrefab.active = true;
lineMaterial.renderQueue = 3100;
Debug.Log("PaperDetector initialized.");
}
void OnEnable() => cameraManager.frameReceived += OnFrame;
void OnDisable() => cameraManager.frameReceived -= OnFrame;
void OnFrame(ARCameraFrameEventArgs args)
{
Debug.Log("--------------------------------NEW FRAME---------------------------------\n"+
"--------------------------------------------------------------------------");
if (!cameraManager.TryAcquireLatestCpuImage(out var cpu))
return;
UpdateTexture(cpu);
byte[] rgba = camTex.GetRawTextureData().ToArray();
if (!PaperPlugin.FindPaperCorners(rgba, camTex.width, camTex.height, out Vector2[] imgCorners))
{
foreach (var seg in segments)
seg.lr.enabled = false;
Debug.LogWarning(" No paper corners detected.");
return;
}
Matrix4x4 displayMatrix;
if (!args.displayMatrix.HasValue)
{
Debug.LogWarning(" No display matrix available.");
return;
}
else
{
displayMatrix = args.displayMatrix.Value;
}
// 2) convert each raw image‐space corner → normalized UV → into the same UV space
Vector2[] viewportCorners = new Vector2[imgCorners.Length];
for(int i = 0; i < imgCorners.Length; i++)
{
viewportCorners = fromRawCpuToViewport(displayMatrix, imgCorners);
}
Vector2[] ordered = OrderCorners(viewportCorners);
for (int i = 0; i < viewportCorners.Length; ++i)
Debug.Log($"vp[{i}] = {viewportCorners}"); // should stay between 0-1
PlaceLinesFromViewport(ordered);
}
private Vector2 fromRawCpuToViewport(Matrix4x4 displayMatrix, Vector2 cord)
{
float u = cord.x / camTex.width;
float v = cord.y / camTex.height;
Vector4 uv = new Vector4(u, v, 1f, 0f);
Vector4 mapped = displayMatrix.transpose * uv;
//if (mapped.w != 0f) // a + b) / 4f;
return c.OrderBy(p => Mathf.Atan2(p.y - center.y, p.x - center.x)).ToArray();
}
void InitLines()
{
for (int i = 0; i < 4; ++i)
{
var go = new GameObject($"PaperEdge_{i}");
var lr = go.AddComponent();
lr.material = lineMaterial;
lr.useWorldSpace = true;
lr.loop = false;
lr.positionCount = 2;
lr.startWidth = lr.endWidth = lineWidth;
segments.lr = lr;
}
Debug.Log("LineRenderers initialized.");
}
void UpdateTexture(XRCpuImage img)
{
var p = new XRCpuImage.ConversionParams
{
inputRect = new RectInt(0, 0, img.width, img.height),
outputDimensions = new Vector2Int(img.width, img.height),
outputFormat = TextureFormat.RGBA32
};
if (camTex == null || camTex.width != img.width || camTex.height != img.height)
{
camTex = new Texture2D(img.width, img.height, TextureFormat.RGBA32, false);
Debug.Log($"Created camTex: {img.width}x{img.height}");
}
using var buf = new NativeArray(img.GetConvertedDataSize(p), Allocator.Temp);
img.Convert(p, buf);
camTex.LoadRawTextureData(buf);
camTex.Apply();
debugImage.texture = camTex;
img.Dispose();
}
void PlaceLinesFromViewport(Vector2[] vpCorners)
{
Vector3[] worldPos = new Vector3[vpCorners.Length];
bool[] usedFallback = new bool[vpCorners.Length];
for (int i = 0; i < vpCorners.Length; i++)
{
Vector2 vp = vpCorners;
var ray = Camera.main.ViewportPointToRay(vp);
Vector3 hitPt;
bool hitPlane = false;
if (raycastManager.Raycast(ray, hits, TrackableType.PlaneWithinPolygon))
{
var chosen = hits[0];
var plane = arPlaneManager.GetPlane(chosen.trackableId);
hitPt = chosen.pose.position;
hitPlane = true;
}
else
{
hitPt = ray.GetPoint(1.0f);
}
worldPos = hitPt;
prevPos = worldPos;
usedFallback = !hitPlane;
Debug.Log($" Corner[{i}] to World: {worldPos:F2} {(hitPlane ? "YES" : "NO")}");
}
for (int i = 0; i < 4; i++)
{
int j = (i + 1) % 4;
var seg = segments[i];
seg.lr.enabled = true;
seg.lr.SetPosition(0, worldPos[i]);
seg.lr.SetPosition(1, worldPos[j]);
bool anyFallback = usedFallback[i] || usedFallback[j];
Color col = anyFallback ? Color.yellow : Color.blue;
seg.lr.startColor = seg.lr.endColor = col;
Debug.Log($"Segment[{i}] From {worldPos[i]:F2} to {worldPos[j]:F2} Color: {(anyFallback ? "YELLOW" : "BLUE")}");
}
}
}
Подробнее здесь: https://stackoverflow.com/questions/796 ... id-ar-foun
Преобразовать координаты Unity xrcpuimage в координаты Viewport для Android AR Foundation ⇐ C#
-
- Похожие темы
- Ответы
- Просмотры
- Последнее сообщение
-
-
ViewPort-Fit = Cover не расширяет ViewPort в зону статуса (вокруг Notch) на сафари для iOS
Anonymous » » в форуме IOS - 0 Ответы
- 20 Просмотры
-
Последнее сообщение Anonymous
-