Streams de saída, corte e zoom

Streams de saída

O subsistema da câmera opera exclusivamente no pipeline baseado em ANativeWindow para todas as resoluções e formatos de saída. Vários streams podem ser configurados de uma só vez para enviar um único frame a muitas alvos, como a GPU, o codificador de vídeo, o RenderScript ou os buffers visíveis pelo app (RAW Bayer, buffers YUV processados ou buffers codificados em JPEG).

Como otimização, esses streams de saída precisam ser configurados com antecedência, e apenas um número limitado pode existir por vez. Isso permite a pré-alocação de buffers de memória e a configuração do hardware da câmera. Assim, quando as solicitações são enviadas com vários ou diferentes pipelines de saída listados, não há atrasos ou latência na realização da solicitação.

Para mais informações sobre as combinações de saída de fluxo garantidas que dependem do nível de hardware compatível, consulte createCaptureSession().

Recorte

O corte da matriz de pixels completa (para zoom digital e outros casos de uso em que um FOV menor é desejável) é comunicado pela configuração ANDROID_SCALER_CROP_REGION. Essa é uma configuração por solicitação e pode mudar de acordo com cada solicitação, o que é essencial para implementar o zoom digital sem interrupções.

A região é definida como um retângulo (x, y, largura, altura), com (x, y) descrevendo o canto superior esquerdo do retângulo. O retângulo é definido no sistema de coordenadas da matriz de pixels ativa do sensor, sendo (0,0) o pixel no canto superior esquerdo da matriz de pixels ativa. Portanto, a largura e a altura não podem ser maiores do que as dimensões informadas no campo de informações estáticas ANDROID_SENSOR_ACTIVE_PIXEL_ARRAY. A largura e a altura mínimas permitidas são informadas pelo HAL pelo campo de informações estáticas ANDROID_SCALER_MAX_DIGITAL_ZOOM, que descreve o fator de zoom máximo com suporte. Portanto, a largura e a altura mínimas da região de corte são:

  {width, height} =
   { floor(ANDROID_SENSOR_ACTIVE_PIXEL_ARRAY[0] /
       ANDROID_SCALER_MAX_DIGITAL_ZOOM),
     floor(ANDROID_SENSOR_ACTIVE_PIXEL_ARRAY[1] /
       ANDROID_SCALER_MAX_DIGITAL_ZOOM) }

Se a região de corte precisar atender a requisitos específicos (por exemplo, ela precisa começar em coordenadas pares e a largura/altura precisa ser par), o HAL precisa fazer o arredondamento necessário e gravar a região de corte final usada nos metadados do resultado de saída. Da mesma forma, se o HAL implementar a estabilização de vídeo, ele vai precisar ajustar a região de corte do resultado para descrever a região realmente incluída na saída depois que a estabilização de vídeo for aplicada. Em geral, um app que usa a câmera precisa ser capaz de determinar o campo de visão recebido com base na região de corte, nas dimensões do sensor de imagem e na distância focal da lente.

Como a região de corte se aplica a todos os fluxos, que podem ter proporções diferentes, a região do sensor exata usada para cada fluxo pode ser menor que a região de corte. Especificamente, cada transmissão precisa manter pixels quadrados e a proporção ao cortar minimamente a região de corte definida. Se a proporção do stream for mais larga que a região de corte, ele precisará ser cortado verticalmente e, se a proporção do stream for mais estreita que a região de corte, ele precisará ser cortado horizontalmente.

Em todos os casos, o corte de stream precisa estar centralizado dentro da região de corte completa, e cada stream é cortado somente na horizontal ou vertical em relação à região de corte completa, nunca ambos.

Por exemplo, se dois streams forem definidos, um de 640 x 480 (aspecto 4:3) e outro de 1.280 x 720 (16:9), vamos demonstrar abaixo as regiões de saída esperadas para cada stream para algumas regiões de corte de amostra, em um sensor hipotético de 3 MP (2.000 x 1.500 pixels).

Região de corte: (500, 375, 1000, 750) (proporção 4:3)
Corte de transmissão 640x480: (500, 375, 1000, 750) (igual à região de corte)
Corte de transmissão 1280x720: (500, 469, 1000, 562)

crop-region-43-ratio

Figura 1. Proporção de 4:3

Região de corte: (500, 375, 1333, 750) (proporção 16:9)
Corte de stream de 640 x 480: (666, 375, 1.000, 750)
Corte de stream de 1280 x 720 (região de corte igual a 375, 7) (igual a 375)

proporção-cortante-169

Figura 2. Proporção de 16:9

Região de corte: (500, 375, 750, 750) (proporção 1:1)
Corte de transmissão 640x480: (500, 469, 750, 562)
Corte de transmissão 1280x720: (500, 543, 750, 414)

proporção-de-corco-11

Figura 3. Proporção 1:1

E um último exemplo, uma transmissão de proporção quadrada de 1024 x 1024 em vez da transmissão de 480p:
Região de corte: (500, 375, 1000, 750) (proporção 4:3)
Corte de transmissão de 1024 x 1024: (625, 375, 750, 750)
Corte de transmissão de 1280 x 720: (500, 469, 1000, 562)

crop-region-43-square-ratio

Figura 4. Proporção 4:3, quadrado

Reprocessamento

O suporte adicional para arquivos de imagem bruta é fornecido pelo suporte de reprocessamento para dados RAW Bayer. Esse suporte permite que o pipeline da câmera processe um buffer RAW e metadados capturados anteriormente (um frame inteiro gravado anteriormente) para produzir uma nova saída YUV ou JPEG renderizada.

Zoom

Em dispositivos com o Android 11 ou versões mais recentes, um app pode usar o zoom de uma câmera (digital e óptico) pela configuração ANDROID_CONTROL_ZOOM_RATIO.

A proporção de zoom é definida como um fator de ponto flutuante. Em vez de usar ANDROID_SCALER_CROP_REGION para cortar e aplicar zoom, um app pode usar ANDROID_CONTROL_ZOOM_RATIO para controlar o nível de zoom e usar ANDROID_SCALER_CROP_REGION para cortar horizontal e verticalmente para conseguir proporções diferentes do sensor de câmera nativo.

Um sistema de várias câmeras pode conter mais de uma lente com diferentes distâncias focais, e o usuário pode usar o zoom óptico alternando entre as lentes. O uso de ANDROID_CONTROL_ZOOM_RATIO traz benefícios nos cenários abaixo:

  • Zoom de uma lente grande angular para uma lente telefoto: uma proporção de ponto flutuante oferece melhor precisão em comparação com valores inteiros de ANDROID_SCALER_CROP_REGION.
  • Diminuir o zoom de uma lente grande angular para ultra grande angular: ANDROID_CONTROL_ZOOM_RATIO permite a redução de zoom (<1.0f), enquanto ANDROID_SCALER_CROP_REGION não.

Para ilustrar, confira vários cenários de diferentes relações de zoom, regiões de corte e streams de saída usando a mesma câmera hipotética definida na seção anterior.

Razão de zoom: 2,0; 1/4 do campo de visão original
Região de corte: (0, 0, 2000, 1500) (proporção 4:3)
Corte de transmissão 640 x 480: (0, 0, 2000, 1500) (igual à região de corte)
Corte de transmissão 1280 x 720: (0, 187, 2000, 1125)

proporção-zoom-2-crop-43

Figura 5. Zoom 2,0, proporção 4:3

Razão de zoom: 2,0; 1/4 do campo de visão original
Região cortada: (0, 187, 2000, 1125) (proporção de 16:9)
Corte de transmissão 640 x 480: (250, 187, 1500, 1125) (com colunas)
Corte de transmissão 1280 x 720: (0, 187, 2000, 1125) (igual à região cortada)

zoom-ratio-2-crop-169

Figura 6. Zoom 2.0, proporção 16:9

Proporção de zoom: 0,5; 4x do campo de visão original (mudado de lente grande angular para lente ultra grande angular)
Região de corte: (250, 0, 1500, 1500) (proporção 1:1)
Corte de transmissão 640x480: (250, 187, 1500, 1125) (letterbox)
Corte de transmissão 1280x720: (250, 328, 1500, 844) (letterbox)

images/zoom-ratio-0.5-crop-11

Figura 7. Zoom de 0,5, proporção de 1:1

Conforme visto nos gráficos acima, o sistema de coordenadas da região de corte muda para o campo de visualização efetivo após o zoom e é representado pelo retângulo com as seguintes dimensões: (0, 0, activeArrayWith, activeArrayHeight). O mesmo se aplica a regiões e rostos AE/AWB/AF. Essa mudança no sistema de coordenadas não se aplica à captura RAW e aos metadados relacionados, como intrinsicCalibration e lensShadingMap.

Usando o mesmo exemplo hipotético acima e supondo que o stream de saída no 1 (640 x 480) seja o stream do visor, o zoom de 2, 0x pode ser alcançado de duas maneiras:

  • zoomRatio = 2.0, scaler.cropRegion = (0, 0, 2000, 1500)
  • zoomRatio = 1.0 (padrão), scaler.cropRegion = (500, 375, 1000, 750)

Para que um app defina android.control.aeRegions como o quadrante superior esquerdo do campo de visão do visor, defina android.control.aeRegions como (0, 0, 1000, 750) com android.control.zoomRatio definido como 2.0. Como alternativa, o app pode definir android.control.aeRegions como a região equivalente de (500, 375, 1000, 750) para android.control.zoomRatio de 1.0.