Requisitos de dados de quadro de entrada para fontes de dados de quadro externas
Para que uma fonte de dados de quadro externa funcione corretamente, a parte mais importante e também mais desafiadora é garantir a precisão dos dados. Este documento descreve os requisitos de dados de quadro de entrada para fontes de dados de quadro externas.
Antes de começar
- Compreenda conceitos básicos como câmeras, quadro de entrada.
- Compreenda os conceitos básicos e tipos comuns de fontes de dados de quadro externas.
Tipos de dados de quadro de entrada
No Unity, uma fonte de dados de quadro externa geralmente precisa receber dados diferentes em dois momentos distintos. Com base no tempo de entrada dos dados externos e nas características dos dados, chamamos esses dois conjuntos de dados de:
- Dados de quadro da câmera (camera frame data)
- Dados de quadro de renderização (rendering frame data)
Diferentes tipos de fontes de dados de quadro externas têm necessidades distintas para esses dois conjuntos de dados:
- Extensão de entrada de dados de imagem e movimento do dispositivo: requer ambos os dados de quadro da câmera e dados de quadro de renderização
- Extensão de entrada de imagem: requer apenas dados de quadro da câmera
Dados de quadro da câmera
Requisitos de dados:
- Timestamp (timestamp)
- Dados de imagem bruta da câmera física (raw camera image data)
- Parâmetros intrínsecos (intrinsics, incluindo tamanho da imagem, distância focal, ponto principal. Se houver distorção, também são necessários o modelo de distorção e os parâmetros de distorção)
- Parâmetros extrínsecos (extrinsics, Tcw ou Twc, matriz calibrada, expressando o deslocamento físico da câmera física em relação à origem da pose do dispositivo/cabeça)
- Estado de rastreamento (tracking status)
- Pose do dispositivo (device pose)
Tempo dos dados:
- Ponto médio de exposição da câmera física
Uso dos dados:
- Hora da chamada da API: pode variar dependendo do design do código externo. Um método comum usado pela maioria dos dispositivos é consultar durante a atualização de renderização do motor 3D e, em seguida, decidir se processa mais os dados com base no timestamp dos dados do dispositivo.
- Thread de chamada da API: game thread do motor 3D ou qualquer outra thread (se todas as APIs externas usadas forem thread-safe).
Exemplo de chamada de API no Unity:
void TryInputCameraFrameData()
{
double timestamp;
if (timestamp == curTimestamp) { return; }
curTimestamp = timestamp;
PixelFormat format;
Vector2Int size;
Vector2Int pixelSize;
int bufferSize;
var bufferO = TryAcquireBuffer(bufferSize);
if (bufferO.OnNone) { return; }
var buffer = bufferO.Value;
IntPtr imageData;
buffer.tryCopyFrom(imageData, 0, 0, bufferSize);
var historicalHeadPose = new Pose();
MotionTrackingStatus trackingStatus = (MotionTrackingStatus)(-1);
using (buffer)
using (var image = Image.create(buffer, format, size.x, size.y, pixelSize.x, pixelSize.y))
{
HandleCameraFrameData(deviceCamera, timestamp, image, cameraParameters, historicalHeadPose, trackingStatus);
}
}
Renderizando dados de frame
Requisitos de dados:
- Timestamp
- Status de rastreamento
- Pose do dispositivo
Tempo dos dados:
- Momento de exibição na tela. TimeWarp não é contabilizado. Os dados de device pose do mesmo momento serão usados por fontes externas (por exemplo, SDK do dispositivo) para definir a transform da câmera virtual para renderizar o quadro atual.
Nota
TimeWarp (às vezes chamado de Reprojection ou ATW/PTW) é uma técnica comumente usada em headsets VR/AR para reduzir a latência. Ele distorce novamente a imagem após a renderização com base na pose mais recente da cabeça para compensar o movimento da cabeça durante a renderização. O EasyAR precisa do momento correspondente à pose usada para configurar a câmera virtual no início da renderização, não o momento real de exibição após o TimeWarp.
Uso dos dados:
- Hora da chamada da API: cada quadro de renderização do motor 3D
- Thread de chamada da API: game thread do motor 3D
Exemplo de chamada de API no Unity:
private void InputRenderFrameMotionData()
{
double timestamp = 0e-9;
var headPose = new Pose();
MotionTrackingStatus trackingStatus = (MotionTrackingStatus)(-1);
HandleRenderFrameData(timestamp, headPose, trackingStatus);
}
Detalhes dos requisitos de dados
Dados de imagem da câmera física:
- Sistema de coordenadas da imagem: os dados adquiridos quando o sensor está na horizontal também devem estar na horizontal. Os dados devem ser armazenados com origem no canto superior esquerdo, priorizando linhas. A imagem não deve ser invertida ou girada.
- FPS da imagem: dados normais de 30 ou 60 fps são aceitáveis. Se fps alto tiver impacto especial, a taxa de quadros mínima aceitável para resultados algorítmicos razoáveis é 2. Recomenda-se usar fps acima de 2, normalmente a taxa de quadros bruta é suficiente.
- Tamanho da imagem: para melhores resultados computacionais, o lado mais longo deve ser 960 ou maior. Normalmente, desencoraja-se o redimensionamento de imagem demorado no pipeline de dados; recomenda-se usar dados brutos diretamente, a menos que a cópia de dados em tamanho completo já seja inaceitavelmente longa. A resolução da imagem não pode ser menor que 640*480.
- Formato de pixel: priorizando efeito de rastreamento e considerando desempenho, a ordem de prioridade de formato geralmente é YUV > RGB > RGBA > Gray (componente Y em YUV). Ao usar dados YUV, é necessária a definição completa dos dados, incluindo detalhes de empacotamento e preenchimento. Comparado a imagens de canal único, o Mega funciona melhor com imagens coloridas, mas outros recursos não são muito afetados.
- Acesso aos dados: ponteiro de dados ou implementação equivalente. É melhor eliminar todas as cópias desnecessárias possíveis no pipeline de dados. No
HandleRenderFrameData, o EasyAR copia os dados uma vez e os usa de forma assíncrona posteriormente; após a conclusão dessa chamada síncrona, os dados de imagem não são mais usados. Observe a propriedade dos dados.
Timestamp:
- Todos os timestamps devem ser sincronizados por relógio, de preferência com sincronização de hardware. A unidade de dados é segundos, mas a precisão deve ser de nanossegundos ou a mais alta possível.
Estado de rastreamento:
- O estado de rastreamento é definido pelo dispositivo e precisa incluir o estado de perda de rastreamento (VIO indisponível). Mais níveis são melhores se disponíveis.
Pose do dispositivo:
- Todas as poses (incluindo a transform da câmera virtual no motor 3D) devem usar a mesma origem.
- Todas as poses e parâmetros extrínsecos devem usar o mesmo sistema de eixos coordenados.
- No Unity, o tipo de sistema de coordenadas para dados de pose deve ser o sistema de coordenadas do Unity ou o sistema de coordenadas do EasyAR. Se a extensão de entrada for implementada pelo EasyAR e usar outra definição de sistema de coordenadas, deve fornecer uma definição clara do sistema de coordenadas ou um método para converter para o sistema de coordenadas do Unity ou do EasyAR.
- No Unity, se usar o framework XR do Unity, apenas é necessário compatibilidade com o modo XROrigin.TrackingOriginMode.Device.
Parâmetros intrínsecos:
- Todos os valores devem corresponder aos dados da imagem. Se necessário, os parâmetros intrínsecos devem ser dimensionados antes da entrada no EasyAR.
- Se a extensão de entrada for implementada pelo EasyAR, deve ser indicado se os parâmetros intrínsecos mudam a cada quadro (a diferença é se a API correspondente deve ser chamada uma vez ou por quadro).
Parâmetros extrínsecos:
- Dados reais devem ser fornecidos em headsets.
- É uma matriz de calibração que expressa o deslocamento físico da câmera física em relação à origem da pose do dispositivo/cabeça. Se a pose do dispositivo e a pose da câmera física forem iguais, deve ser a matriz identidade.
- A interface correspondente para o Apple Vision Pro é: CameraFrame.Sample.Parameters.extrinsics. Note que sua definição de dados difere dos dados exigidos pela interface; o EasyAR converte internamente antes de usar.
- No Unity, o tipo de sistema de coordenadas para parâmetros extrínsecos deve ser o sistema de coordenadas do Unity ou o sistema de coordenadas do EasyAR. Se a extensão de entrada for implementada pelo EasyAR e usar outra definição de sistema de coordenadas, deve fornecer uma definição clara do sistema de coordenadas ou um método para converter para o sistema de coordenadas do Unity ou do EasyAR.
- Em dispositivos headset, geralmente existem múltiplos sistemas de coordenadas com definições diferentes. Essas diferenças podem incluir origem dos eixos, orientação, representação de mão direita/esquerda, etc. Os parâmetros extrínsecos devem ser calculados no mesmo sistema de coordenadas. Esta interface de dados requer uma transformação de coordenadas dentro do mesmo sistema de coordenadas, não uma matriz de transformação entre dois sistemas de coordenadas com definições diferentes.
Desempenho:
- Os dados devem ser fornecidos com a máxima eficiência. Na maioria das implementações, as chamadas de API ocorrem durante o processo de renderização. Portanto, é recomendado não bloquear chamadas de API, mesmo que operações demoradas sejam necessárias no nível inferior, ou usar essas APIs de forma sensata.
- Se a extensão de entrada for implementada pelo EasyAR, todas as chamadas de API demoradas devem ser documentadas.
Múltiplas câmeras:
- São necessários dados de pelo menos uma câmera. Esta câmera pode ser uma câmera RGB, uma câmera VST, uma câmera de posicionamento, etc. Em um headset, se apenas uma câmera for fornecida, geralmente recomenda-se usar a câmera RGB ou VST central ou próxima aos olhos.
- Usar múltiplas câmeras pode melhorar os resultados dos algoritmos do EasyAR. Os dados de quadro de todas as câmeras disponíveis em um determinado momento devem ser fornecidos simultaneamente, no mesmo instante de tempo.
O suporte a múltiplas câmeras ainda não está completo. Contate o EasyAR para mais detalhes.
Próximos passos
- Criar extensão de entrada de dados de imagem e movimento do dispositivo
- Criar extensão de entrada de imagem
- Criar pacote de extensão para headset
Tópicos relacionados
- Sistema de coordenadas do EasyAR
- Exemplo de workflow de extensão de entrada de imagem: Workflow_FrameSource_ExternalImageStream