Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Sebelum memulai di sini, kami sarankan Anda melihat artikel gambaran umum kamera Locatable kami yang berisi informasi gambaran umum dan tabel dengan detail kamera HoloLens 1 dan 2.
Menggunakan MediaFrameReference
Instruksi ini berlaku jika Anda menggunakan kelas MediaFrameReference untuk membaca bingkai gambar dari kamera.
Setiap bingkai gambar (baik foto atau video) menyertakan SpatialCoordinateSystem yang berakar pada kamera pada saat pengambilan, yang dapat diakses menggunakan properti CoordinateSystemmediaFrameReference Anda. Setiap bingkai berisi deskripsi model lensa kamera, yang dapat ditemukan di properti CameraIntrinsics . Bersama-sama, transformasi ini mendefinisikan untuk setiap piksel sinar dalam ruang 3D yang mewakili jalur yang diambil oleh foton yang menghasilkan piksel. Sinar ini dapat terkait dengan konten lain dalam aplikasi dengan mendapatkan transformasi dari sistem koordinat bingkai ke beberapa sistem koordinat lainnya (misalnya dari bingkai referensi stasioner).
Setiap bingkai gambar menyediakan hal berikut:
- Data Piksel (dalam format RGB/NV12/JPEG/dll)
- SpatialCoordinateSystem dari lokasi pengambilan
- Kelas CameraIntrinsics yang berisi mode lensa kamera
Sampel HolographicFaceTracking menunjukkan cara yang cukup mudah untuk mengkueri transformasi antara sistem koordinat kamera dan sistem koordinat aplikasi Anda sendiri.
Menggunakan Media Foundation
Jika Anda menggunakan Media Foundation secara langsung untuk membaca bingkai gambar dari kamera, Anda dapat menggunakan atribut MFSampleExtension_CameraExtrinsics setiap bingkai dan atribut MFSampleExtension_PinholeCameraIntrinsics untuk menemukan bingkai kamera yang relatif terhadap sistem koordinat aplikasi Anda yang lain, seperti yang ditunjukkan dalam kode sampel ini:
#include <winrt/windows.perception.spatial.preview.h>
#include <mfapi.h>
#include <mfidl.h>
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Foundation::Numerics;
using namespace winrt::Windows::Perception;
using namespace winrt::Windows::Perception::Spatial;
using namespace winrt::Windows::Perception::Spatial::Preview;
class CameraFrameLocator
{
public:
struct CameraFrameLocation
{
SpatialCoordinateSystem CoordinateSystem;
float4x4 CameraViewToCoordinateSystemTransform;
MFPinholeCameraIntrinsics Intrinsics;
};
std::optional<CameraFrameLocation> TryLocateCameraFrame(IMFSample* pSample)
{
MFCameraExtrinsics cameraExtrinsics;
MFPinholeCameraIntrinsics cameraIntrinsics;
UINT32 sizeCameraExtrinsics = 0;
UINT32 sizeCameraIntrinsics = 0;
UINT64 sampleTimeHns = 0;
// query sample for calibration and validate
if (FAILED(pSample->GetUINT64(MFSampleExtension_DeviceTimestamp, &sampleTimeHns)) ||
FAILED(pSample->GetBlob(MFSampleExtension_CameraExtrinsics, (UINT8*)& cameraExtrinsics, sizeof(cameraExtrinsics), &sizeCameraExtrinsics)) ||
FAILED(pSample->GetBlob(MFSampleExtension_PinholeCameraIntrinsics, (UINT8*)& cameraIntrinsics, sizeof(cameraIntrinsics), &sizeCameraIntrinsics)) ||
(sizeCameraExtrinsics != sizeof(cameraExtrinsics)) ||
(sizeCameraIntrinsics != sizeof(cameraIntrinsics)) ||
(cameraExtrinsics.TransformCount == 0))
{
return std::nullopt;
}
// compute extrinsic transform
const auto& calibratedTransform = cameraExtrinsics.CalibratedTransforms[0];
const GUID& dynamicNodeId = calibratedTransform.CalibrationId;
const float4x4 cameraToDynamicNode =
make_float4x4_from_quaternion(quaternion{ calibratedTransform.Orientation.x, calibratedTransform.Orientation.y, calibratedTransform.Orientation.z, calibratedTransform.Orientation.w }) *
make_float4x4_translation(calibratedTransform.Position.x, calibratedTransform.Position.y, calibratedTransform.Position.z);
// update locator cache for dynamic node
if (dynamicNodeId != m_currentDynamicNodeId || !m_locator)
{
m_locator = SpatialGraphInteropPreview::CreateLocatorForNode(dynamicNodeId);
if (!m_locator)
{
return std::nullopt;
}
m_frameOfReference = m_locator.CreateAttachedFrameOfReferenceAtCurrentHeading();
m_currentDynamicNodeId = dynamicNodeId;
}
// locate dynamic node
auto timestamp = PerceptionTimestampHelper::FromSystemRelativeTargetTime(TimeSpan{ sampleTimeHns });
auto coordinateSystem = m_frameOfReference.GetStationaryCoordinateSystemAtTimestamp(timestamp);
auto location = m_locator.TryLocateAtTimestamp(timestamp, coordinateSystem);
if (!location)
{
return std::nullopt;
}
const float4x4 dynamicNodeToCoordinateSystem = make_float4x4_from_quaternion(location.Orientation()) * make_float4x4_translation(location.Position());
return CameraFrameLocation{ coordinateSystem, cameraToDynamicNode * dynamicNodeToCoordinateSystem, cameraIntrinsics };
}
private:
GUID m_currentDynamicNodeId{ GUID_NULL };
SpatialLocator m_locator{ nullptr };
SpatialLocatorAttachedFrameOfReference m_frameOfReference{ nullptr };
};
Skenario Penggunaan Kamera yang Dapat Locatable
Menampilkan foto atau video di dunia tempat foto atau video diambil
Bingkai Kamera Perangkat dilengkapi dengan transformasi "Kamera Ke Dunia", yang dapat digunakan untuk menunjukkan dengan tepat di mana perangkat berada ketika gambar diambil. Misalnya, Anda dapat memposisikan ikon holografik kecil di lokasi ini (CameraToWorld.MultiplyPoint(Vector3.zero)) dan bahkan menggambar panah kecil ke arah yang dihadapi kamera (CameraToWorld.MultiplyVector(Vector3.forward)).
Kecepatan Bingkai
Menjaga kecepatan bingkai aplikasi interaktif sangat penting, terutama saat berhadapan dengan algoritma pengenalan gambar yang berjalan lama. Untuk alasan ini, kami biasanya menggunakan pola berikut:
- Utas Utama: mengelola objek kamera
- Utas Utama: meminta bingkai baru (asinkron)
- Utas Utama: meneruskan bingkai baru ke rangkaian pelacakan
- Utas Pelacakan: memproses gambar untuk mengumpulkan titik kunci
- Utas Utama: memindahkan model virtual agar sesuai dengan titik kunci yang ditemukan
- Utas Utama: ulangi dari langkah 2
Beberapa sistem penanda gambar hanya menyediakan satu lokasi piksel (yang lain menyediakan transformasi penuh dalam hal ini bagian ini tidak akan diperlukan), yang setara dengan sinar lokasi yang mungkin. Untuk sampai ke satu lokasi ketiga, kita kemudian dapat memanfaatkan beberapa sinar dan menemukan hasil akhir dengan perkiraan persimpangan mereka. Untuk melakukan ini, Anda harus:
- Dapatkan perulangan akan mengumpulkan beberapa gambar kamera
- Temukan titik fitur terkait, dan sinar dunianya
- Ketika Anda memiliki kamus fitur, masing-masing dengan beberapa sinar dunia, Anda dapat menggunakan kode berikut untuk memecahkan persimpangan sinar tersebut:
public static Vector3 ClosestPointBetweenRays(
Vector3 point1, Vector3 normalizedDirection1,
Vector3 point2, Vector3 normalizedDirection2) {
float directionProjection = Vector3.Dot(normalizedDirection1, normalizedDirection2);
if (directionProjection == 1) {
return point1; // parallel lines
}
float projection1 = Vector3.Dot(point2 - point1, normalizedDirection1);
float projection2 = Vector3.Dot(point2 - point1, normalizedDirection2);
float distanceAlongLine1 = (projection1 - directionProjection * projection2) / (1 - directionProjection * directionProjection);
float distanceAlongLine2 = (projection2 - directionProjection * projection1) / (directionProjection * directionProjection - 1);
Vector3 pointOnLine1 = point1 + distanceAlongLine1 * normalizedDirection1;
Vector3 pointOnLine2 = point2 + distanceAlongLine2 * normalizedDirection2;
return Vector3.Lerp(pointOnLine2, pointOnLine1, 0.5f);
}
Memosisikan adegan yang dimodelkan
Mengingat dua lokasi tag terlacak atau lebih, Anda dapat memposisikan adegan yang dimodelkan agar sesuai dengan skenario pengguna saat ini. Jika Anda tidak dapat mengasumsikan gravitasi, maka Anda akan memerlukan tiga lokasi tag. Dalam banyak kasus, kami menggunakan skema warna di mana bola putih mewakili lokasi tag terlacak real time, dan bola biru mewakili lokasi tag yang dimodelkan. Ini memungkinkan pengguna untuk mengukur kualitas penyelarasan secara visual. Kami berasumsi pengaturan berikut di semua aplikasi kami:
- Dua atau beberapa lokasi tag yang dimodelkan
- Satu 'ruang kalibrasi', yang dalam adegan adalah induk tag
- Pengidentifikasi fitur kamera
- Perilaku, yang memindahkan ruang kalibrasi untuk menyelaraskan tag yang dimodelkan dengan tag real-time (kami berhati-hati untuk memindahkan ruang induk, bukan penanda yang dimodelkan sendiri, karena koneksi lain relatif terhadap tag tersebut).
// In the two tags case:
Vector3 idealDelta = (realTags[1].EstimatedWorldPos - realTags[0].EstimatedWorldPos);
Vector3 curDelta = (modelledTags[1].transform.position - modelledTags[0].transform.position);
if (IsAssumeGravity) {
idealDelta.y = 0;
curDelta.y = 0;
}
Quaternion deltaRot = Quaternion.FromToRotation(curDelta, idealDelta);
trans.rotation = Quaternion.LookRotation(deltaRot * trans.forward, trans.up);
trans.position += realTags[0].EstimatedWorldPos - modelledTags[0].transform.position;
Lacak atau Identifikasi Tagged Stationary atau Memindahkan objek/wajah dunia nyata menggunakan LED atau pustaka pengenal lainnya
Contoh:
- Robot industri dengan LED (atau kode QR untuk objek bergerak lebih lambat)
- Mengidentifikasi dan mengenali objek di ruangan
- Mengidentifikasi dan mengenali orang-orang di dalam ruangan, misalnya menempatkan kartu kontak holografik di atas wajah