Configure cada caso de uso do CameraX para controlar diferentes aspectos das operações do caso de uso.
Por exemplo, com o caso de uso de captura de imagem, é possível configurar a proporção desejada e um modo de flash. O código a seguir mostra um exemplo:
Kotlin
val imageCapture = ImageCapture.Builder() .setFlashMode(...) .setTargetAspectRatio(...) .build()
Java
ImageCapture imageCapture = new ImageCapture.Builder() .setFlashMode(...) .setTargetAspectRatio(...) .build();
Além das opções de configuração, alguns casos de uso expõem APIs para mudar as configurações de forma dinâmica após a criação deles. Para informações sobre a configuração específica dos casos de uso individuais, consulte Implementar uma visualização, Análise de imagem e Captura de imagem.
CameraXConfig
Para simplificar, o CameraX tem configurações padrão, como gerenciadores e executores internos adequados para a maioria dos cenários de uso. No entanto, caso o aplicativo tenha requisitos especiais ou prefira personalizar essas configurações, a CameraXConfig
é a interface ideal.
Com a CameraXConfig
, o aplicativo pode fazer o seguinte:
- Otimizar a latência da inicialização usando
setAvailableCameraLimiter()
. - Fornecer o executor do aplicativo ao CameraX usando
setCameraExecutor()
. - Substituir o gerenciador do programador padrão usando
setSchedulerHandler()
. - Mudar o nível de geração de registros usando
setMinimumLoggingLevel()
.
Modelo de uso
O procedimento a seguir descreve como usar a CameraXConfig
:
- Crie um objeto
CameraXConfig
com as configurações personalizadas. - Implemente a interface
CameraXConfig.Provider
na sua classeApplication
e retorne o objetoCameraXConfig
no métodogetCameraXConfig()
. - Adicione a classe
Application
ao arquivoAndroidManifest.xml
, conforme descrito nesta página.
Veja como o exemplo de código a seguir restringe a geração de registros do CameraX apenas a mensagens de erro:
Kotlin
class CameraApplication : Application(), CameraXConfig.Provider { override fun getCameraXConfig(): CameraXConfig { return CameraXConfig.Builder.fromConfig(Camera2Config.defaultConfig()) .setMinimumLoggingLevel(Log.ERROR).build() } }
Mantenha uma cópia local do objeto CameraXConfig
se o aplicativo precisa saber qual é a configuração do CameraX após a definição.
Limitador de câmeras
Durante a primeira invocação de ProcessCameraProvider.getInstance()
, o CameraX enumera e consulta as características das câmeras disponíveis no dispositivo. Como o CameraX precisa se comunicar com componentes de hardware, esse processo pode levar um tempo incomum para cada câmera, principalmente em dispositivos mais simples. Se o aplicativo usa apenas câmeras específicas no dispositivo, como a frontal padrão, é possível configurar o CameraX para ignorar as outras, o que pode reduzir a latência de inicialização das câmeras usadas pelo aplicativo.
Se a classe CameraSelector
transmitida para o CameraXConfig.Builder.setAvailableCamerasLimiter()
filtrar uma câmera, o CameraX vai se comportar como se ela não existisse. Por exemplo, o código a seguir limita o aplicativo a usar apenas a câmera traseira padrão do dispositivo:
Kotlin
class MainApplication : Application(), CameraXConfig.Provider { override fun getCameraXConfig(): CameraXConfig { return CameraXConfig.Builder.fromConfig(Camera2Config.defaultConfig()) .setAvailableCamerasLimiter(CameraSelector.DEFAULT_BACK_CAMERA) .build() } }
Linhas de execução
Muitas das APIs de plataforma em que o CameraX foi criado exigem o bloqueio da comunicação entre processos (IPC) com hardwares que às vezes podem levar centenas de milissegundos para responder. Por isso, o CameraX só chama essas APIs por linhas de execução em segundo plano, o que garante que a linha de execução principal não seja bloqueada e que a IU continue fluida. O CameraX gerencia internamente essas linhas de execução em segundo plano para que esse comportamento pareça transparente. No entanto, alguns aplicativos exigem um controle rigoroso das linhas de execução. A CameraXConfig
permite que um aplicativo defina as linhas de execução em segundo plano que serão usadas por CameraXConfig.Builder.setCameraExecutor()
e CameraXConfig.Builder.setSchedulerHandler()
.
Executor da câmera
O executor da câmera é usado para todas as chamadas de API internas da plataforma da câmera, assim como para os callbacks dessas APIs. O CameraX aloca e gerencia uma interface Executor
interna para realizar essas tarefas. No entanto, se o aplicativo exigir um controle mais rigoroso das linhas de execução, use CameraXConfig.Builder.setCameraExecutor()
.
Gerenciador do programador
O gerenciador do programador é usado para programar tarefas internas em intervalos fixos, como abrir a câmera novamente quando ela não estiver disponível. Esse gerenciador não executa jobs e só os envia para o executor da câmera. Às vezes, ele também é usado em plataformas de API legadas que exigem uma classe Handler
para callbacks. Nesses casos, os callbacks ainda são enviados diretamente apenas para o executor da câmera. O CameraX aloca e gerencia uma classe HandlerThread
interna para realizar essas tarefas, mas ela pode ser substituída usando CameraXConfig.Builder.setSchedulerHandler()
.
Geração de registros
A geração de registros do CameraX permite que os aplicativos filtrem mensagens do Logcat, já que é recomendável evitar mensagens muito detalhadas no código de produção. O CameraX oferece suporte para quatro níveis de geração de registros, do mais detalhado ao mais simples:
Log.DEBUG
(padrão)Log.INFO
Log.WARN
Log.ERROR
Consulte a documentação sobre registros do Android para ver descrições detalhadas desses níveis de registro. Use CameraXConfig.Builder.setMinimumLoggingLevel(int)
para definir o nível de geração de registros adequado para seu aplicativo.
Seleção automática
O CameraX fornece automaticamente uma funcionalidade específica do dispositivo em que seu app está sendo executado. Por exemplo, o CameraX determinará automaticamente a melhor resolução a ser usada se você não especificar nenhuma ou se a resolução especificada não for compatível. Tudo isso é processado pela biblioteca, eliminando a necessidade de criar um código específico para o dispositivo.
O objetivo do CameraX é inicializar uma sessão de câmera. Isso significa que o CameraX compromete a resolução e a proporção com base na capacidade do dispositivo. Isso pode acontecer pelos seguintes motivos:
- O dispositivo não é compatível com a resolução escolhida.
- O dispositivo tem problemas de compatibilidade, como dispositivos legados que precisam de determinadas resoluções para funcionar corretamente.
- Em alguns dispositivos, determinados formatos estão disponíveis apenas em algumas proporções.
- O dispositivo prefere um "mod16 mais próximo" para codificação JPEG ou de vídeo.
Consulte
SCALER_STREAM_CONFIGURATION_MAP
para ver mais informações.
Embora o CameraX crie e gerencie a sessão, sempre verifique os tamanhos de imagem retornados na saída do caso de uso no seu código e faça as modificações necessárias.
Rotação
Por padrão, a rotação da câmera é definida para corresponder à rotação da tela padrão durante a criação do caso de uso. Nesse caso padrão, o CameraX produz saídas para permitir que o app corresponda facilmente ao que você espera da visualização. É possível mudar a rotação para um valor personalizado que seja compatível com dispositivos de várias telas transmitindo a orientação atual da tela ao configurar os objetos de caso de uso ou de forma dinâmica, depois de terem sido criados.
Seu app pode definir a rotação desejada usando as configurações. Em seguida, ele pode atualizar as configurações de rotação usando os métodos das APIs de caso de uso (como ImageAnalysis.setTargetRotation()
), mesmo que o ciclo de vida esteja em execução. Você poderá usar isso quando o app estiver fixo no modo retrato para que nenhuma reconfiguração ocorra na rotação, mas o caso de uso de foto ou de análise precisará ser informado sobre a rotação atual do dispositivo. Por exemplo, os dados de rotação podem ser necessários para que os rostos fiquem na orientação correta para detecção facial ou as fotos sejam definidas como paisagem ou retrato.
Os dados das imagens capturadas podem ser armazenados sem informações de rotação. Os dados Exif contêm informações de rotação para que os aplicativos da galeria possam exibir a imagem na orientação correta depois de salvá-la.
Para exibir dados de visualização com a orientação correta, é possível usar a
saída de metadados de
Preview.PreviewOutput()
para criar transformações.
A amostra a seguir traz um exemplo de como definir a rotação em um evento de orientação:
Kotlin
override fun onCreate() { val imageCapture = ImageCapture.Builder().build() val orientationEventListener = object : OrientationEventListener(this as Context) { override fun onOrientationChanged(orientation : Int) { // Monitors orientation values to determine the target rotation value val rotation : Int = when (orientation) { in 45..134 -> Surface.ROTATION_270 in 135..224 -> Surface.ROTATION_180 in 225..314 -> Surface.ROTATION_90 else -> Surface.ROTATION_0 } imageCapture.targetRotation = rotation } } orientationEventListener.enable() }
Java
@Override public void onCreate() { ImageCapture imageCapture = new ImageCapture.Builder().build(); OrientationEventListener orientationEventListener = new OrientationEventListener((Context)this) { @Override public void onOrientationChanged(int orientation) { int rotation; // Monitors orientation values to determine the target rotation value if (orientation >= 45 && orientation < 135) { rotation = Surface.ROTATION_270; } else if (orientation >= 135 && orientation < 225) { rotation = Surface.ROTATION_180; } else if (orientation >= 225 && orientation < 315) { rotation = Surface.ROTATION_90; } else { rotation = Surface.ROTATION_0; } imageCapture.setTargetRotation(rotation); } }; orientationEventListener.enable(); }
Com base na rotação definida, cada caso de uso fará a rotação dos dados da imagem diretamente ou fornecerá metadados de rotação aos consumidores dos dados de imagem não alterados.
- Visualização: a saída de metadados é fornecida para que a rotação da resolução
desejada seja conhecida usando
Preview.getTargetRotation()
. - ImageAnalysis: a saída de metadados é fornecida para que as coordenadas do buffer de imagem sejam conhecidas em relação às coordenadas de exibição.
- ImageCapture: os metadados, o buffer ou os metadados Exif da imagem serão alterados para observar a configuração de rotação. O valor alterado depende da implementação da HAL.
Retângulo de corte
Por padrão, o retângulo de corte é o retângulo de buffer completo. É possível personalizá-lo com
ViewPort
e
UseCaseGroup
. Ao agrupar casos
de uso e definir a janela de visualização, o CameraX garante que os retângulos de corte de todos
os casos de uso no grupo apontem para a mesma área no sensor da câmera.
O snippet de código a seguir mostra como usar essas duas classes:
Kotlin
val viewPort = ViewPort.Builder(Rational(width, height), display.rotation).build() val useCaseGroup = UseCaseGroup.Builder() .addUseCase(preview) .addUseCase(imageAnalysis) .addUseCase(imageCapture) .setViewPort(viewPort) .build() cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, useCaseGroup)
Java
ViewPort viewPort = new ViewPort.Builder( new Rational(width, height), getDisplay().getRotation()).build(); UseCaseGroup useCaseGroup = new UseCaseGroup.Builder() .addUseCase(preview) .addUseCase(imageAnalysis) .addUseCase(imageCapture) .setViewPort(viewPort) .build(); cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, useCaseGroup);
ViewPort
define o retângulo de buffer visível para os usuários finais. Depois, o CameraX calcula
o maior retângulo de corte possível com base nas propriedades da janela de visualização e dos
casos de uso anexados. Geralmente, para atingir um efeito WYSIWYG, você precisa configurar
a janela de visualização com base no caso de uso de visualização. Uma maneira simples de acessar a janela de visualização é
usar PreviewView
.
Os snippets de código a seguir mostram como acessar o objeto ViewPort
:
Kotlin
val viewport = findViewById<PreviewView>(R.id.preview_view).viewPort
Java
ViewPort viewPort = ((PreviewView)findViewById(R.id.preview_view)).getViewPort();
No exemplo anterior, o que o app recebe de ImageAnalysis
e
ImageCapture
corresponde ao que o usuário final vê na PreviewView
, supondo que o
tipo de escala de PreviewView
esteja definido como o padrão, FILL_CENTER
. Depois de aplicar
o retângulo de corte e a rotação ao buffer de saída, a imagem de todos os casos de uso
será a mesma, embora possivelmente com resoluções diferentes. Para mais
informações sobre como aplicar as informações de transformação, consulte Saída
de transformação.
Seleção de câmera
O CameraX seleciona automaticamente o melhor dispositivo de câmera para os requisitos e casos de uso do aplicativo. Caso você queira usar um dispositivo diferente do selecionado, há algumas opções:
- Solicitar a câmera frontal padrão com
CameraSelector.DEFAULT_FRONT_CAMERA
- Solicitar a câmera traseira padrão com
CameraSelector.DEFAULT_BACK_CAMERA
- Filtrar a lista de dispositivos disponíveis por
CameraCharacteristics
comCameraSelector.Builder.addCameraFilter()
O exemplo de código a seguir ilustra como criar um CameraSelector
para influenciar a seleção de um dispositivo:
Kotlin
fun selectExternalOrBestCamera(provider: ProcessCameraProvider):CameraSelector? { val cam2Infos = provider.availableCameraInfos.map { Camera2CameraInfo.from(it) }.sortedByDescending { // HARDWARE_LEVEL is Int type, with the order of: // LEGACY < LIMITED < FULL < LEVEL_3 < EXTERNAL it.getCameraCharacteristic(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL) } return when { cam2Infos.isNotEmpty() -> { CameraSelector.Builder() .addCameraFilter { it.filter { camInfo -> // cam2Infos[0] is either EXTERNAL or best built-in camera val thisCamId = Camera2CameraInfo.from(camInfo).cameraId thisCamId == cam2Infos[0].cameraId } }.build() } else -> null } } // create a CameraSelector for the USB camera (or highest level internal camera) val selector = selectExternalOrBestCamera(processCameraProvider) processCameraProvider.bindToLifecycle(this, selector, preview, analysis)
Resolução da câmera
Você pode permitir que o CameraX defina uma resolução de imagem com base em uma combinação dos recursos do dispositivo, nível de hardware com suporte, caso de uso e proporção. Como alternativa, é possível definir uma resolução específica ou uma proporção específica em casos de uso compatíveis com essa configuração.
Resolução automática
O CameraX pode determinar automaticamente as melhores configurações de resolução com base nos
casos de uso especificados em cameraProcessProvider.bindToLifecycle()
. Sempre que possível, especifique todos os casos de uso necessários para serem executados simultaneamente em uma única sessão de uma única chamada bindToLifecycle()
. O CameraX determinará resoluções com base no conjunto de casos de uso vinculados considerando o nível de hardware compatível e contabilizando a variação específica do dispositivo, em que um dispositivo pode exceder ou não cumprir as configurações de fluxo disponíveis.
A intenção é permitir que o aplicativo seja executado em uma ampla variedade de dispositivos, minimizando os caminhos de código específicos do dispositivo.
A proporção padrão para os casos de uso de captura e análise de imagens é de 4:3.
Os casos de uso têm uma proporção configurável para permitir que o aplicativo especifique a proporção desejada com base no design da IU. A saída do CameraX será produzida para corresponder às proporções solicitadas tanto quanto possível. Se não houver uma correspondência exata com a resolução compatível, aquela que atender à maioria das condições será selecionada. Assim, o aplicativo determina como a câmera aparecerá no app, e o CameraX define as melhores configurações de resolução para diferentes dispositivos.
Por exemplo, um app pode:
- especificar uma resolução desejada de 4:3 ou 16:9 para um caso de uso;
- especificar uma resolução personalizada em que o CameraX tentará encontrar a correspondência mais próxima;
- especificar uma proporção de corte para
ImageCapture
.
O CameraX escolherá automaticamente as resoluções de superfície internas do Camera2. A tabela a seguir mostra as resoluções:
Caso de uso | Resolução de superfície interna | Resolução de dados de saída |
---|---|---|
Visualização | Proporção: a resolução que melhor se ajusta à configuração desejada. | Resolução de superfície interna. Os metadados são fornecidos para permitir uma visualização para cortar, redimensionar e girar até chegar à proporção desejada. |
Resolução padrão: a resolução de visualização mais alta ou a resolução preferencial por dispositivo mais alta correspondente à proporção acima. | ||
Resolução máxima: o tamanho de visualização, referente ao melhor tamanho correspondente à resolução de tela do dispositivo ou a 1080 p (1920x1080), o que for menor. | ||
Análise de imagem | Proporção: a resolução que melhor se ajusta à configuração desejada. | Resolução de superfície interna. |
Resolução padrão: a configuração de resolução padrão é de 640 x 480. O ajuste da resolução e da proporção correspondente resultará em uma resolução mais compatível. | ||
Resolução máxima: a resolução máxima de saída do dispositivo da câmera no
formato YUV_420_888, que é extraída do método
StreamConfigurationMap.getOutputSizes() .
A resolução desejada é definida como 640 x 480 por padrão. Portanto, se você quiser uma
resolução maior que 640 x 480, use os métodos
setTargetResolution()
e
setTargetAspectRatio()
para usar uma das resoluções compatíveis mais aproximada.
|
||
Captura de imagem | Proporção: a proporção que melhor se adapta à configuração. | Resolução de superfície interna. |
Resolução padrão: a resolução mais alta disponível ou a resolução preferencial do dispositivo mais alta correspondente à proporção acima. | ||
Resolução máxima: a resolução máxima de saída do dispositivo da câmera
em formato JPEG. Use o método
StreamConfigurationMap.getOutputSizes()
para extrair esse valor.
|
Especificar uma resolução
Você pode definir resoluções específicas ao criar casos de uso com o método setTargetResolution(Size resolution)
, conforme mostrado na amostra de código a seguir:
Kotlin
val imageAnalysis = ImageAnalysis.Builder() .setTargetResolution(Size(1280, 720)) .build()
Java
ImageAnalysis imageAnalysis = new ImageAnalysis.Builder() .setTargetResolution(new Size(1280, 720)) .build();
Não é possível definir a proporção e a resolução desejadas no mesmo caso
de uso. Fazer isso gerará uma IllegalArgumentException
ao criar o
objeto de configuração.
Expresse o Size
da resolução no frame da
coordenada depois de girar os tamanhos compatíveis pela rotação desejada. Por exemplo, um
dispositivo com orientação natural de retrato na rotação natural
pode especificar uma imagem de retrato de 480 x 640, enquanto o mesmo dispositivo, girado 90 graus e
na orientação de paisagem, pode especificar 640 x 480.
A resolução desejada tenta estabelecer um limite mínimo para a resolução da
imagem. A resolução real da imagem será a disponível mais próxima que não seja menor que a resolução desejada, conforme determinado pela implementação da câmera. No entanto, se não houver uma resolução igual ou maior que a resolução desejada, será escolhida a resolução mais próxima disponível da desejada, ainda que menor. As resoluções com a mesma proporção do Size
fornecido têm prioridade mais alta que as resoluções de proporções diferentes.
O CameraX aplicará a melhor resolução adequada com base nas solicitações. Se a principal necessidade for atender à proporção, especifique apenas setTargetAspectRatio
, e o CameraX determinará uma resolução específica adequada, com base no dispositivo. Use setTargetResolution(Size resolution)
se a necessidade principal do app for especificar uma resolução para tornar o processamento de imagens mais eficiente, por exemplo, em uma imagem de tamanho pequeno ou médio com base na capacidade de processamento do dispositivo.
Se o app exigir uma resolução exata, consulte a tabela em
createCaptureSession()
para determinar quais resoluções máximas são compatíveis com cada nível de hardware. Para
verificar as resoluções específicas compatíveis com o dispositivo atual, consulte
StreamConfigurationMap.getOutputSizes(int)
.
Se o app está sendo executado no Android 10 ou mais recente, você pode usar
isSessionConfigurationSupported()
para verificar uma SessionConfiguration
específica.
Controlar a saída da câmera
Além de permitir que você configure a saída da câmera conforme necessário para cada caso de uso individual, o CameraX também implementa as interfaces abaixo para oferecer suporte a operações de câmera comuns a todos os casos de uso vinculados:
CameraControl
permite a configuração de recursos comuns de câmera.CameraInfo
permite consultar os estados desses recursos comuns de câmera.
Estes são os recursos de câmera compatíveis com o CameraControl:
- Zoom
- Lanterna
- Foco e medição (toque para focar)
- Compensação de exposição
Receber instâncias de CameraControl e CameraInfo
Recupere instâncias do CameraControl
e da CameraInfo
usando o objeto Camera
retornado por ProcessCameraProvider.bindToLifecyle()
. O código a seguir mostra um exemplo:
Kotlin
val camera = processCameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview) // For performing operations that affect all outputs. val cameraControl = camera.cameraControl // For querying information and states. val cameraInfo = camera.cameraInfo
Java
Camera camera = processCameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview) // For performing operations that affect all outputs. CameraControl cameraControl = camera.getCameraControl() // For querying information and states. CameraInfo cameraInfo = camera.getCameraInfo()
Por exemplo, você pode enviar zoom e outras operações do CameraControl
após chamar bindToLifecycle()
. Depois que você interrompe ou destrói a atividade usada para vincular a instância da câmera, o CameraControl
não executa mais operações e retorna um ListenableFuture
com falha.
Zoom
O CameraControl oferece dois métodos para mudar o nível de zoom:
setZoomRatio()
define o zoom pela proporção.A proporção precisa estar no intervalo de
CameraInfo.getZoomState().getValue().getMinZoomRatio()
eCameraInfo.getZoomState().getValue().getMaxZoomRatio()
. Caso contrário, a função retorna umListenableFuture
com falha.setLinearZoom()
define o zoom atual com um valor de zoom linear de 0 a 1,0.A vantagem do zoom linear é que ele garante que o campo de visão (FOV, na sigla em inglês) seja dimensionado com as mudanças. Por isso, esse recurso é ideal para uso com a visualização
Slider
.
CameraInfo.getZoomState()
retorna um LiveData do estado atual do zoom. O valor muda quando a câmera é inicializada ou se o nível de zoom é definido usando setZoomRatio()
ou setLinearZoom()
. A chamada de qualquer um dos métodos define os valores com base em ZoomState.getZoomRatio()
e ZoomState.getLinearZoom()
. Isso é útil se você quer exibir o texto da proporção de zoom ao lado de um controle deslizante. Basta observar os LiveData
do ZoomState
para atualizar os dois valores sem precisar fazer uma conversão.
O ListenableFuture
retornado por ambas as APIs oferece a opção de notificar o aplicativo quando uma solicitação recorrente com o valor de zoom especificado for concluída. Além disso, se você define um novo valor de zoom enquanto a operação anterior ainda está em execução, o ListenableFuture
da operação de zoom anterior falha imediatamente.
Lanterna
CameraControl.enableTorch(boolean)
ativa ou desativa a lanterna.
CameraInfo.getTorchState()
pode ser usado para consultar o estado atual da lanterna. Confira o valor retornado por CameraInfo.hasFlashUnit()
para determinar se uma lanterna está disponível. Caso contrário, chamar CameraControl.enableTorch(boolean)
faz com que o ListenableFuture
retornado seja concluído imediatamente com um resultado com falha e define o estado da lanterna como TorchState.OFF
.
Quando a lanterna está ativada, ela permanece assim durante a captura de fotos e vídeos, independentemente da configuração do flashMode. O flashMode
na ImageCapture
funciona apenas quando a lanterna está desativada.
Foco e medição
CameraControl.startFocusAndMetering()
aciona a medição de foco e exposição automáticos definindo regiões de medição de AF/AE/AWB (foco, exposição e balanço de branco automáticos) com base na FocusMeteringAction determinada. Isso é usado com frequência para implementar o recurso "toque para focar" em muitos apps de câmera.
MeteringPoint
Para começar, crie um MeteringPoint
usando MeteringPointFactory.createPoint(float x, float y, float size)
. Um MeteringPoint
representa um único ponto na Surface
da câmera. Ele é armazenado em uma forma normalizada para que possa ser facilmente convertido em coordenadas do sensor para especificar regiões de AF/AE/AWB.
O tamanho do MeteringPoint
varia de 0 a 1, com tamanho padrão de 0,15f. Ao chamar MeteringPointFactory.createPoint(float x, float y, float size)
, o CameraX cria uma região retangular centralizada em (x, y)
para o size
fornecido.
O código a seguir demonstra como criar um MeteringPoint
.
Kotlin
// Use PreviewView.getMeteringPointFactory if PreviewView is used for preview. previewView.setOnTouchListener((view, motionEvent) -> { val meteringPoint = previewView.meteringPointFactory .createPoint(motionEvent.x, motionEvent.y) … } // Use DisplayOrientedMeteringPointFactory if SurfaceView / TextureView is used for // preview. Please note that if the preview is scaled or cropped in the View, // it’s the application's responsibility to transform the coordinates properly // so that the width and height of this factory represents the full Preview FOV. // And the (x,y) passed to create MeteringPoint may need to be adjusted with // the offsets. val meteringPointFactory = DisplayOrientedMeteringPointFactory( surfaceView.display, camera.cameraInfo, surfaceView.width, surfaceView.height ) // Use SurfaceOrientedMeteringPointFactory if the point is specified in // ImageAnalysis ImageProxy. val meteringPointFactory = SurfaceOrientedMeteringPointFactory( imageWidth, imageHeight, imageAnalysis)
startFocusAndMetering e FocusMeteringAction
Para invocar startFocusAndMetering()
, os aplicativos precisam criar uma FocusMeteringAction
, que consiste em um ou mais MeteringPoints
com combinações opcionais de modo de medição de FLAG_AF
, FLAG_AE
e FLAG_AWB
. O código a seguir demonstra esse uso.
Kotlin
val meteringPoint1 = meteringPointFactory.createPoint(x1, x1) val meteringPoint2 = meteringPointFactory.createPoint(x2, y2) val action = FocusMeteringAction.Builder(meteringPoint1) // default AF|AE|AWB // Optionally add meteringPoint2 for AF/AE. .addPoint(meteringPoint2, FLAG_AF | FLAG_AE) // The action will be canceled in 3 seconds (if not set, default is 5s). .setAutoCancelDuration(3, TimeUnit.SECONDS) .build() val result = cameraControl.startFocusAndMetering(action) // Adds listener to the ListenableFuture if you need to know the focusMetering result. result.addListener({ // result.get().isFocusSuccessful returns if the auto focus is successful or not. }, ContextCompat.getMainExecutor(this)
Como mostrado no código acima, startFocusAndMetering()
usa uma FocusMeteringAction
composta por um MeteringPoint
para as regiões de medição de AF/AE/AWB e outro pelo MeteringPoint apenas para AF e AE.
Internamente, o CameraX a converte em MeteringRectangles
da Camera2 e define os CONTROL_AF_REGIONS
/ CONTROL_AE_REGIONS
/ CONTROL_AWB_REGIONS
correspondentes à solicitação de captura.
Como nem todos os dispositivos são compatíveis com AF/AE/AWB e várias regiões, o CameraX executa a FocusMeteringAction
da melhor forma possível. O CameraX vai usar o número máximo permitido de MeteringPoints, na ordem em que os pontos foram adicionados. Todos os MeteringPoints adicionados após a contagem máxima são ignorados. Por exemplo, se uma FocusMeteringAction
for fornecida com três MeteringPoints em uma plataforma que aceita apenas dois, apenas os dois primeiros MeteringPoints vão ser usados. O MeteringPoint
final é ignorado pelo CameraX.
Compensação de exposição
A compensação de exposição é útil quando os aplicativos precisam ajustar valores de exposição (EV) além do resultado de saída da exposição automática (AE, na sigla em inglês). Os valores de compensação de exposição são combinados da seguinte maneira para determinar a exposição necessária para as condições atuais da imagem:
Exposure = ExposureCompensationIndex * ExposureCompensationStep
O CameraX fornece a função Camera.CameraControl.setExposureCompensationIndex()
para definir a compensação de exposição como um valor de índice.
Valores de índice positivos deixam a imagem mais clara, enquanto valores negativos escurecem a imagem. Os aplicativos podem consultar o intervalo compatível CameraInfo.ExposureState.exposureCompensationRange()
descrito na próxima seção. Se o valor tiver suporte, o ListenableFuture
retornado vai ser concluído quando o valor for ativado na solicitação de captura. Se o índice especificado estiver fora do intervalo com suporte, setExposureCompensationIndex()
vai fazer com que o ListenableFuture
retornado seja concluído imediatamente com um resultado de falha.
O CameraX mantém apenas a solicitação setExposureCompensationIndex()
pendente mais recente. Chamar a função várias vezes antes que a solicitação anterior seja executada resulta no cancelamento dela.
O snippet a seguir define um índice de compensação de exposição e registra um callback para quando a solicitação de mudança de exposição foi executada.
Kotlin
camera.cameraControl.setExposureCompensationIndex(exposureCompensationIndex) .addListener({ // Get the current exposure compensation index, it may be // different from the asked value in case this request was // canceled by a newer setting request. val currentExposureIndex = camera.cameraInfo.exposureState.exposureCompensationIndex … }, mainExecutor)
Camera.CameraInfo.getExposureState()
recupera oExposureState
atual, incluindo:- A compatibilidade com o controle de compensação de exposição.
- O índice de compensação de exposição atual.
- O intervalo do índice de compensação de exposição.
- A etapa usada no cálculo do valor de compensação de exposição.
Por exemplo, o código a seguir inicializa as configurações de uma exposição SeekBar
com os valores dos ExposureState
atuais.
Kotlin
val exposureState = camera.cameraInfo.exposureState binding.seekBar.apply { isEnabled = exposureState.isExposureCompensationSupported max = exposureState.exposureCompensationRange.upper min = exposureState.exposureCompensationRange.lower progress = exposureState.exposureCompensationIndex }
Outros recursos
Para saber mais sobre o CameraX, consulte os seguintes recursos.
Codelab
Exemplo de código
Comunidade de desenvolvedores
Grupo de discussão do CameraX do Android