Na tej stronie omawiamy architekturę systemu Aparat X, w tym jego strukturę, korzystanie z interfejsu API, korzystanie z cykli życia i łączenie przypadków użycia.
Struktura CameraX
Za pomocą aplikacji CameraX możesz połączyć się z kamerą urządzenia abstrakcja, czyli tzw. przypadek użycia. Dostępne są te przypadki użycia:
- Podgląd: akceptuje powierzchnię do wyświetlania podglądu, np.
PreviewView
- Analiza obrazu: udostępnia bufory dostępne dla procesora do analizy, takie jak systemów uczących się.
- Robienie zdjęć: robi i zapisuje zdjęcie.
- Nagrywanie obrazu wideo: nagrywanie obrazu i dźwięku za pomocą
VideoCapture
.
Przypadki użycia można łączyć i aktywne jednocześnie. Aplikacja może na przykład umożliwiać użytkownik widzi obraz widoczny przez kamerę w wersji testowej, przykład zastosowania analizy obrazów, który określa, czy osoby na zdjęciu są z uśmiechem i dołączać przykład użycia robienia zdjęć do robienia zdjęć.
Model interfejsu API
Aby korzystać z biblioteki, musisz określić te elementy:
- Pożądany przypadek użycia z opcjami konfiguracji.
- Co zrobić z danymi wyjściowymi przez dołączenie detektorów.
- zamierzony przepływ, np. kiedy włączyć kamery i kiedy generować dane; przez powiązanie przypadku użycia z architekturą Androida Cykle życia.
Aplikację CameraX można utworzyć na 2 sposoby:
CameraController
(świetnie, jeśli
najprostszy sposób korzystania z aparatu X) lub
CameraProvider
(świetnie, jeśli
potrzebują większej elastyczności).
Kontroler aparatu
CameraController
udostępnia większość podstawowych funkcji CameraX w jednym
zajęcia. Wymaga niewielkiego kodu konfiguracyjnego, a do tego automatycznie obsługuje aparat.
inicjowanie, zarządzanie przypadkami użycia, rotacja docelowa, skupienie na dotknięciu
ściągnij palce, aby powiększyć i nie tylko. Klasa betonu, która rozciąga się do obiektu CameraController
, to
LifecycleCameraController
Kotlin
val previewView: PreviewView = viewBinding.previewView var cameraController = LifecycleCameraController(baseContext) cameraController.bindToLifecycle(this) cameraController.cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA previewView.controller = cameraController
Java
PreviewView previewView = viewBinding.previewView; LifecycleCameraController cameraController = new LifecycleCameraController(baseContext); cameraController.bindToLifecycle(this); cameraController.setCameraSelector(CameraSelector.DEFAULT_BACK_CAMERA); previewView.setController(cameraController);
Domyślne wartości UseCase
w polu CameraController
to Preview
, ImageCapture
i
ImageAnalysis
. Aby wyłączyć funkcję ImageCapture
lub ImageAnalysis
albo ją wyłączyć
VideoCapture
włączone, użyj
setEnabledUseCases()
.
Więcej informacji o zastosowaniu CameraController
znajdziesz tutaj
Przykład skanera kodów QR
lub
Film CameraController
– podstawy.
Dostawca kamery
Aplikacja CameraProvider
jest nadal łatwa w użyciu, ale to dlatego, że to deweloper
po konfiguracji masz więcej możliwości dostosowania konfiguracji,
np. włączyć rotację obrazu wyjściowego
lub ustawić format obrazu wyjściowego
ImageAnalysis
Możesz też użyć niestandardowego ustawienia Surface
, aby umożliwić podgląd z aparatu
dla większej elastyczności. Natomiast w przypadku kontrolera CameraController należy używać
PreviewView
Użycie istniejącego kodu Surface
może być przydatne, jeśli
już zawiera dane wejściowe
do innych części aplikacji.
Konfigurujesz przypadki użycia za pomocą metod set()
i finalizujesz je za pomocą build()
. Każdy obiekt przypadku użycia udostępnia zestaw interfejsów API związanych z konkretnym przypadkiem użycia. Dla:
przykładowy przypadek użycia przechwytywania obrazu zawiera wywołanie metody takePicture()
.
Zamiast stosować konkretne wywołania metod uruchamiania i zatrzymywania w
onResume()
i onPause()
, aplikacja określa cykl życia, który należy powiązać
za pomocą aparatu,
cameraProvider.bindToLifecycle()
.
Ten cykl życia informuje następnie CameraX, kiedy skonfigurować sesję nagrywania
i dba o to, aby stan kamery odpowiednio się zmieniał, odpowiednio do zmian cyklu życia.
Instrukcje wdrażania w poszczególnych przypadkach użycia znajdziesz w artykule Implementacja podgląd, Analiza obrazy, obrazy Przechwytywanie i Przechwytywanie wideo
Przypadek użycia w wersji testowej wchodzi w interakcję z tagiem
Surface
w sieci reklamowej. Aplikacje
utwórz przypadek użycia z opcjami konfiguracji za pomocą tego kodu:
Kotlin
val preview = Preview.Builder().build() val viewFinder: PreviewView = findViewById(R.id.previewView) // The use case is bound to an Android Lifecycle with the following code val camera = cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview) // PreviewView creates a surface provider and is the recommended provider preview.setSurfaceProvider(viewFinder.getSurfaceProvider())
Java
Preview preview = new Preview.Builder().build(); PreviewView viewFinder = findViewById(R.id.view_finder); // The use case is bound to an Android Lifecycle with the following code Camera camera = cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview); // PreviewView creates a surface provider, using a Surface from a different // kind of view will require you to implement your own surface provider. preview.previewSurfaceProvider = viewFinder.getSurfaceProvider();
Więcej przykładowego kodu znajdziesz na oficjalnym przykładie aplikacji CameraX
Cykle życia aplikacji CameraX
Aparat CameraX obserwuje cykl życia, aby określić, kiedy otworzyć aparat, a kiedy utworzyć sesję przechwytywania i zatrzymać, a kiedy wyłączyć. Interfejsy API przypadku użycia zapewniają i wywołaniach zwrotnych, aby monitorować postępy.
Jak wyjaśniliśmy w sekcji Łączenie przypadków użycia, możesz powiązać niektóre kombinacje w jednym cyklu życia. Gdy aplikacja musi obsługiwać przypadki użycia, nie można łączyć, możesz wykonać jedną z tych czynności:
- Grupuj zgodne przypadki użycia w więcej niż jeden fragment, a następnie przełącz się między fragmenty
- Tworzenie niestandardowego komponentu cyklu życia i używanie go do ręcznego sterowania kamerą cykl życia
Jeśli odłączysz przykłady użycia widoku i kamery Właściciele cyklu życia (np.
jeśli zastosujesz niestandardowy cykl życia
lub zapas
fragment),
musi zagwarantować, że żadne przypadki użycia nie będą powiązane z Aparatem X za pomocą funkcji
ProcessCameraProvider.unbindAll()
.
lub oddzielając każdy przypadek użycia z osobna. Zamiast tego,
do danego cyklu życia, możesz pozwolić aplikacji CameraX
zarządzać otwieraniem i zamykaniem sesji przechwytywania oraz usuwaniem powiązań przypadków użycia.
Jeśli wszystkie funkcje kamery odpowiadają cyklowi życia
uwzględniających cykl życia, np.
AppCompatActivity
lub
AppCompat
, a następnie wykorzystując cykl życia tego komponentu przy wiązaniu
w odpowiednich przypadkach użycia.
gdy komponent uwzględniający cykl życia jest aktywny i bezpiecznie wyrzucony.
zużywanie zasobów, bo inaczej.
Właściciele niestandardowych cyklów życia
W bardziej zaawansowanych przypadkach możesz utworzyć
LifecycleOwner
, aby włączyć
bezpośrednio kontrolować cykl życia sesji w aplikacji CameraX, zamiast tworzyć powiązanie z
standardowy Android LifecycleOwner
.
Poniższy przykładowy kod pokazuje, jak utworzyć prosty niestandardowy element LifecycleOwner:
Kotlin
class CustomLifecycle : LifecycleOwner { private val lifecycleRegistry: LifecycleRegistry init { lifecycleRegistry = LifecycleRegistry(this); lifecycleRegistry.markState(Lifecycle.State.CREATED) } ... fun doOnResume() { lifecycleRegistry.markState(State.RESUMED) } ... override fun getLifecycle(): Lifecycle { return lifecycleRegistry } }
Java
public class CustomLifecycle implements LifecycleOwner { private LifecycleRegistry lifecycleRegistry; public CustomLifecycle() { lifecycleRegistry = new LifecycleRegistry(this); lifecycleRegistry.markState(Lifecycle.State.CREATED); } ... public void doOnResume() { lifecycleRegistry.markState(State.RESUMED); } ... public Lifecycle getLifecycle() { return lifecycleRegistry; } }
Za pomocą tego interfejsu LifecycleOwner
aplikacja może wprowadzać zmiany stanów w dowolny sposób
punkty w kodzie. Więcej informacji o wdrażaniu tej funkcji w aplikacji
można znaleźć w sekcji Implementowanie tagów niestandardowych
LifecycleOwner (Właściciel cyklu życia).
Równoczesne przypadki użycia
Przypadki użycia mogą działać jednocześnie. Przypadki użycia można sekwencyjnie powiązać z tagiem
cyklu życia, lepiej powiązać wszystkie przypadki użycia za pomocą jednego wywołania
CameraProcessProvider.bindToLifecycle()
Więcej informacji o najlepszych
dotyczące zmian konfiguracji można znaleźć w sekcji Obsługa konfiguracji
zmian.
W poniższym przykładowym kodzie aplikacja określa 2 przypadki użycia do utworzenia i jednocześnie. Określa też cykl życia, który będzie używany zarówno w przypadku aby rozpoczynały i kończyły się zgodnie z cyklem życia.
Kotlin
private lateinit var imageCapture: ImageCapture override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val cameraProviderFuture = ProcessCameraProvider.getInstance(this) cameraProviderFuture.addListener(Runnable { // Camera provider is now guaranteed to be available val cameraProvider = cameraProviderFuture.get() // Set up the preview use case to display camera preview. val preview = Preview.Builder().build() // Set up the capture use case to allow users to take photos. imageCapture = ImageCapture.Builder() .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY) .build() // Choose the camera by requiring a lens facing val cameraSelector = CameraSelector.Builder() .requireLensFacing(CameraSelector.LENS_FACING_FRONT) .build() // Attach use cases to the camera with the same lifecycle owner val camera = cameraProvider.bindToLifecycle( this as LifecycleOwner, cameraSelector, preview, imageCapture) // Connect the preview use case to the previewView preview.setSurfaceProvider( previewView.getSurfaceProvider()) }, ContextCompat.getMainExecutor(this)) }
Java
private ImageCapture imageCapture; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); PreviewView previewView = findViewById(R.id.previewView); ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ProcessCameraProvider.getInstance(this); cameraProviderFuture.addListener(() -> { try { // Camera provider is now guaranteed to be available ProcessCameraProvider cameraProvider = cameraProviderFuture.get(); // Set up the view finder use case to display camera preview Preview preview = new Preview.Builder().build(); // Set up the capture use case to allow users to take photos imageCapture = new ImageCapture.Builder() .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY) .build(); // Choose the camera by requiring a lens facing CameraSelector cameraSelector = new CameraSelector.Builder() .requireLensFacing(lensFacing) .build(); // Attach use cases to the camera with the same lifecycle owner Camera camera = cameraProvider.bindToLifecycle( ((LifecycleOwner) this), cameraSelector, preview, imageCapture); // Connect the preview use case to the previewView preview.setSurfaceProvider( previewView.getSurfaceProvider()); } catch (InterruptedException | ExecutionException e) { // Currently no exceptions thrown. cameraProviderFuture.get() // shouldn't block since the listener is being called, so no need to // handle InterruptedException. } }, ContextCompat.getMainExecutor(this)); }
Podane niżej kombinacje konfiguracji są obsługiwane (gdy (podgląd lub przechwytywanie wideo jest wymagany, ale nie obie te funkcje jednocześnie):
Podgląd lub przechwytywanie wideo | Robienie zdjęć | Analiza | Opisy |
---|---|---|---|
Udostępnij podgląd lub nagraj film, zrób zdjęcie i przeanalizuj je do strumienia obrazów. | |||
Zrób zdjęcie i przeanalizuj strumień obrazów. | |||
Udostępnij podgląd lub nagraj film i zrób zdjęcie. | |||
Udostępnij podgląd lub nagraj film i przeanalizuj obraz . |
Gdy wymagany jest zarówno podgląd, jak i przechwytywanie wideo: Kombinacje są obsługiwane warunkowo:
Podgląd | Nagrywanie wideo | Robienie zdjęć | Analiza | Wymagania specjalne |
---|---|---|---|---|
Gwarantowane dla wszystkich aparatów | ||||
OGRANICZONA (lub lepsza) kamera. | ||||
Aparat na poziomie LEVEL_3 (lub lepszym). |
Reklamy
- Każdy przypadek użycia może działać samodzielnie. Aplikacja może na przykład nagrywać wideo bez korzystania z podglądu.
- Po włączeniu rozszerzeń tylko
ImageCapture
iPreview
będzie działać. W zależności od wdrożenia OEM może nie udać się też dodaćImageAnalysis
; rozszerzenia nie mogą w przypadku użycia funkcjiVideoCapture
. Zajrzyj do Dokument z informacjami o rozszerzeniach . - W zależności od możliwości kamery niektóre z nich mogą obsługiwać takie połączenie z niższą rozdzielczością, ale niektóre z nich nie obsługują tej samej kombinacji. i większej rozdzielczości.
obsługiwany poziom sprzętu,
można pobrać z Camera2CameraInfo
. Na przykład ten kod
sprawdza, czy domyślny tylny aparat to urządzenie z systemem LEVEL_3
:
Kotlin
@androidx.annotation.OptIn(ExperimentalCamera2Interop::class) fun isBackCameraLevel3Device(cameraProvider: ProcessCameraProvider) : Boolean { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { return CameraSelector.DEFAULT_BACK_CAMERA .filter(cameraProvider.availableCameraInfos) .firstOrNull() ?.let { Camera2CameraInfo.from(it) } ?.getCameraCharacteristic(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL) == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3 } return false }
Java
@androidx.annotation.OptIn(markerClass = ExperimentalCamera2Interop.class) Boolean isBackCameraLevel3Device(ProcessCameraProvider cameraProvider) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { List\<CameraInfo\> filteredCameraInfos = CameraSelector.DEFAULT_BACK_CAMERA .filter(cameraProvider.getAvailableCameraInfos()); if (!filteredCameraInfos.isEmpty()) { return Objects.equals( Camera2CameraInfo.from(filteredCameraInfos.get(0)).getCameraCharacteristic( CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL), CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3); } } return false; }
Uprawnienia
Aplikacja musi mieć
CAMERA
. Do
wymaga zapisywania zdjęć w plikach,
WRITE_EXTERNAL_STORAGE
tylko na urządzeniach z Androidem 10 lub nowszym.
Więcej informacji o konfigurowaniu uprawnień aplikacji znajdziesz w sekcji Prośba Uprawnienia aplikacji.
Wymagania
Kamera X ma następujące minimalne wymagania dotyczące wersji:
- Interfejs API Androida, poziom 21
- Komponenty architektury Androida 1.1.1
W przypadku działań związanych z cyklem życia należy użyć funkcji
FragmentActivity
lub
AppCompatActivity
Deklarowanie zależności
Aby dodać zależność od CameraX, musisz dodać narzędzie Google Maven do swojego projektu.
Otwórz plik settings.gradle
swojego projektu i dodaj repozytorium google()
jak poniżej:
Odlotowe
dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() mavenCentral() } }
Kotlin
dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() mavenCentral() } }
Na końcu bloku kodu Android dodaj następujący ciąg:
Odlotowe
android { compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } // For Kotlin projects kotlinOptions { jvmTarget = "1.8" } }
Kotlin
android { compileOptions { sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 } // For Kotlin projects kotlinOptions { jvmTarget = "1.8" } }
Do pliku build.gradle
każdego modułu dodaj te elementy:
Odlotowy
dependencies { // CameraX core library using the camera2 implementation def camerax_version = "1.4.0-rc01" // The following line is optional, as the core library is included indirectly by camera-camera2 implementation "androidx.camera:camera-core:${camerax_version}" implementation "androidx.camera:camera-camera2:${camerax_version}" // If you want to additionally use the CameraX Lifecycle library implementation "androidx.camera:camera-lifecycle:${camerax_version}" // If you want to additionally use the CameraX VideoCapture library implementation "androidx.camera:camera-video:${camerax_version}" // If you want to additionally use the CameraX View class implementation "androidx.camera:camera-view:${camerax_version}" // If you want to additionally add CameraX ML Kit Vision Integration implementation "androidx.camera:camera-mlkit-vision:${camerax_version}" // If you want to additionally use the CameraX Extensions library implementation "androidx.camera:camera-extensions:${camerax_version}" }
Kotlin
dependencies { // CameraX core library using the camera2 implementation val camerax_version = "1.4.0-rc01" // The following line is optional, as the core library is included indirectly by camera-camera2 implementation("androidx.camera:camera-core:${camerax_version}") implementation("androidx.camera:camera-camera2:${camerax_version}") // If you want to additionally use the CameraX Lifecycle library implementation("androidx.camera:camera-lifecycle:${camerax_version}") // If you want to additionally use the CameraX VideoCapture library implementation("androidx.camera:camera-video:${camerax_version}") // If you want to additionally use the CameraX View class implementation("androidx.camera:camera-view:${camerax_version}") // If you want to additionally add CameraX ML Kit Vision Integration implementation("androidx.camera:camera-mlkit-vision:${camerax_version}") // If you want to additionally use the CameraX Extensions library implementation("androidx.camera:camera-extensions:${camerax_version}") }
Więcej informacji o konfigurowaniu aplikacji pod kątem zgodności z tymi wymaganiami: Więcej informacji: Deklarowanie .
Współdziałanie aparatu CameraX z Aparatem 2
Aparat X działa w ramach Aparatu 2, a Aparat X umożliwia odczyt, a nawet zapis z właściwościami w implementacji Camera2. Szczegółowe informacje znajdziesz tutaj: Pakiet Interop.
Aby dowiedzieć się więcej o tym, jak aplikacja AparatX skonfigurowała właściwości Aparatu2, użyj
Camera2CameraInfo
aby odczytać dane CameraCharacteristics
. Możesz też zapisać nazwę bazową aparatu 2
właściwości w jednej z dwóch ścieżek:
Użyj domeny
Camera2CameraControl
, która pozwala ustawić właściwościCaptureRequest
, takich jak tryb autofokus.Rozszerz aparat CameraX
UseCase
za pomocąCamera2Interop.Extender
Pozwala to ustawić właściwości w CaptureRequest, tak jakCamera2CameraControl
Daje też dostęp do dodatkowych ustawień, takich jak ustawienie przypadku użycia strumienia i optymalizować kamerę pod kątem scenariusza użytkowania. Więcej informacji znajdziesz w artykule Przypadki użycia strumienia. skuteczności reklam.
Poniższa próbka kodu wykorzystuje przypadki użycia strumienia do optymalizacji rozmowy wideo.
Użyj formatu Camera2CameraInfo
, aby sprawdzić, czy przypadek użycia strumienia rozmowy wideo jest dostępny. Następnie użyj
Camera2Interop.Extender
aby ustawić podstawowy przypadek użycia.
Kotlin
// Set underlying Camera2 stream use case to optimize for video calls. val videoCallStreamId = CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL.toLong() // Check available CameraInfos to find the first one that supports // the video call stream use case. val frontCameraInfo = cameraProvider.getAvailableCameraInfos() .first { cameraInfo -> val isVideoCallStreamingSupported = Camera2CameraInfo.from(cameraInfo) .getCameraCharacteristic( CameraCharacteristics.SCALER_AVAILABLE_STREAM_USE_CASES )?.contains(videoCallStreamId) val isFrontFacing = (cameraInfo.getLensFacing() == CameraSelector.LENS_FACING_FRONT) (isVideoCallStreamingSupported == true) && isFrontFacing } val cameraSelector = frontCameraInfo.cameraSelector // Start with a Preview Builder. val previewBuilder = Preview.Builder() .setTargetAspectRatio(screenAspectRatio) .setTargetRotation(rotation) // Use Camera2Interop.Extender to set the video call stream use case. Camera2Interop.Extender(previewBuilder).setStreamUseCase(videoCallStreamId) // Bind the Preview UseCase and the corresponding CameraSelector. val preview = previewBuilder.build() camera = cameraProvider.bindToLifecycle(this, cameraSelector, preview)
Java
// Set underlying Camera2 stream use case to optimize for video calls. Long videoCallStreamId = CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL.toLong(); // Check available CameraInfos to find the first one that supports // the video call stream use case. List<CameraInfo> cameraInfos = cameraProvider.getAvailableCameraInfos(); CameraInfo frontCameraInfo = null; for (cameraInfo in cameraInfos) { Long[] availableStreamUseCases = Camera2CameraInfo.from(cameraInfo) .getCameraCharacteristic( CameraCharacteristics.SCALER_AVAILABLE_STREAM_USE_CASES ); boolean isVideoCallStreamingSupported = Arrays.List(availableStreamUseCases) .contains(videoCallStreamId); boolean isFrontFacing = (cameraInfo.getLensFacing() == CameraSelector.LENS_FACING_FRONT); if (isVideoCallStreamingSupported && isFrontFacing) { frontCameraInfo = cameraInfo; } } if (frontCameraInfo == null) { // Handle case where video call streaming is not supported. } CameraSelector cameraSelector = frontCameraInfo.getCameraSelector(); // Start with a Preview Builder. Preview.Builder previewBuilder = Preview.Builder() .setTargetAspectRatio(screenAspectRatio) .setTargetRotation(rotation); // Use Camera2Interop.Extender to set the video call stream use case. Camera2Interop.Extender(previewBuilder).setStreamUseCase(videoCallStreamId); // Bind the Preview UseCase and the corresponding CameraSelector. Preview preview = previewBuilder.build() Camera camera = cameraProvider.bindToLifecycle(this, cameraSelector, preview)
Dodatkowe materiały
Więcej informacji o aparacie AparatX znajdziesz w tych dodatkowych materiałach.
Ćwiczenia z programowania
Przykładowy kod