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.
Confira 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 o CameraSelector
transmitido
para
CameraXConfig.Builder.setAvailableCamerasLimiter()
filtrar uma câmera, o CameraX 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() } }
Conversas
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 esse motivo, o CameraX só chama essas APIs de
linhas de execução em segundo plano para que a linha de execução principal não seja bloqueada e a interface
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. O CameraXConfig
permite que um aplicativo defina as linhas de execução em segundo plano
que são usadas com
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()
.
Gerar registros
A geração de registros do CameraX permite que os aplicativos filtrem mensagens do Logcat, já que é recomendável evitar mensagens 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 conferir 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 aceita. Tudo isso é processado pela biblioteca, eliminando a necessidade de criar um código específico para o dispositivo.
O objetivo da 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. O comprometimento pode acontecer porque:
- 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 proporções específicas.
- O dispositivo prefere um "mod16 mais próximo" para codificação JPEG ou
de vídeo. Para saber mais, consulte
SCALER_STREAM_CONFIGURATION_MAP
.
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 os ajustes necessários.
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 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 mostrar 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 faz a rotação dos dados da imagem diretamente ou fornece 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 é apresentada 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 modificados 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 encontra 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)
Selecionar várias câmeras simultaneamente
A partir do CameraX 1.3, também é possível selecionar várias câmeras simultaneamente. Por exemplo, é possível vincular uma câmera frontal e traseira para tirar fotos ou gravar vídeos das duas perspectivas simultaneamente.
Ao usar o recurso de câmera simultânea, o dispositivo pode operar duas câmeras
com lentes voltadas para lugares diferentes ao mesmo tempo ou duas câmeras traseiras
ao mesmo tempo. O bloco de código a seguir mostra como definir duas câmeras ao
chamar bindToLifecycle
e como receber os dois objetos de câmera do objeto
ConcurrentCamera
retornado.
Kotlin
// Build ConcurrentCameraConfig val primary = ConcurrentCamera.SingleCameraConfig( primaryCameraSelector, useCaseGroup, lifecycleOwner ) val secondary = ConcurrentCamera.SingleCameraConfig( secondaryCameraSelector, useCaseGroup, lifecycleOwner ) val concurrentCamera = cameraProvider.bindToLifecycle( listOf(primary, secondary) ) val primaryCamera = concurrentCamera.cameras[0] val secondaryCamera = concurrentCamera.cameras[1]
Java
// Build ConcurrentCameraConfig SingleCameraConfig primary = new SingleCameraConfig( primaryCameraSelector, useCaseGroup, lifecycleOwner ); SingleCameraConfig secondary = new SingleCameraConfig( primaryCameraSelector, useCaseGroup, lifecycleOwner ); ConcurrentCamera concurrentCamera = mCameraProvider.bindToLifecycle(Arrays.asList(primary, secondary)); Camera primaryCamera = concurrentCamera.getCameras().get(0); Camera secondaryCamera = concurrentCamera.getCameras().get(1);
Resolução da câmera
Você pode permitir que o CameraX defina a resolução de imagem com base em uma combinação dos recursos do dispositivo, nível de hardware aceito, caso de uso e proporção. Também é possível definir uma resolução específica ou uma proporção específica em casos de uso aceitos por 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 determina resoluções
com base no conjunto de casos de uso vinculados considerando o nível de hardware aceito
pelo dispositivo e contabilizando a variação específica, em que um dispositivo
excede ou não cumpre as configurações de fluxo
disponíveis.
A intenção é permitir que o aplicativo seja executado em uma ampla variedade de dispositivos,
minimizando caminhos de código específicos.
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 interface. A saída do CameraX é 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 escolhe automaticamente as resoluções internas da plataforma 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 que uma visualização corte, dimensione e gire para a proporção desejada. |
Resolução padrão: a resolução de visualização mais alta ou a resolução preferencial do dispositivo que corresponde à proporção da visualização. | ||
Resolução máxima: o tamanho de visualização, referente ao melhor tamanho correspondente à resolução de tela do dispositivo ou a 1080p (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 resulta em uma resolução melhor aceita. | ||
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 chegar o mais próximo possível das resoluções aceitas.
|
||
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 do ImageCapture. | ||
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 gera 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 é 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 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 aplica a melhor resolução adequada com base nas solicitações. Se a
principal necessidade atender à proporção, especifique apenas setTargetAspectRatio
,
e o CameraX vai 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.bindToLifecycle()
.
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 faz o campo de visão (FOV, na sigla em inglês) escalar com mudanças no zoom. 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 might 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 is 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)
Conforme mostrado no código anterior,
startFocusAndMetering()
usa um FocusMeteringAction
que consiste em um MeteringPoint
para regiões de medição de AF/AE/AWB
e outro MeteringPoint apenas para PD 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 oferecem suporte a AF/AE/AWB e várias regiões, o CameraX executa
a FocusMeteringAction
da melhor forma possível. O CameraX usa o número máximo
de MeteringPoints com suporte, 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 serão 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 aceito por
CameraInfo.ExposureState.exposureCompensationRange()
descrito na próxima seção. Se o valor tiver suporte, o
ListenableFuture
retornado 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 might 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 o objeto atualExposureState
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 recursos a seguir.
Codelab
Exemplo de código
Comunidade de desenvolvedores
Grupo de discussão do CameraX do Android