Opcje konfiguracji

Konfigurujesz każdy przypadek użycia AparatuX, aby kontrolować różne aspekty użycia na jego temat.

Na przykład w przypadku rejestrowania obrazów możesz określić docelowy format obrazu i tryb lampy błyskowej. Oto przykład:

Kotlin

val imageCapture = ImageCapture.Builder()
    .setFlashMode(...)
    .setTargetAspectRatio(...)
    .build()

Java

ImageCapture imageCapture =
    new ImageCapture.Builder()
        .setFlashMode(...)
        .setTargetAspectRatio(...)
        .build();

Oprócz opcji konfiguracyjnych w niektórych przypadkach użycia interfejsy API udostępniają dynamicznie zmienić ustawienia po utworzeniu przypadku użycia. Informacje na temat: do konkretnych przypadków użycia znajdziesz w sekcji Implementowanie podgląd, Analiza obrazy i Obrazy .

CameraXConfig,

Dla uproszczenia Aparat X ma domyślne konfiguracje, takie jak wewnętrzne wykonawców i moduły obsługi, które nadają się do większości zastosowań. Jeśli jednak aplikacja ma specjalne wymagania lub preferuje ich dostosowanie konfiguracje, CameraXConfig to interfejs do tego celu.

Dzięki CameraXConfig aplikacja może wykonywać te czynności:

Model wykorzystania

Aby dowiedzieć się, jak używać właściwości CameraXConfig, wykonaj te czynności:

  1. Utwórz obiekt CameraXConfig z własnymi konfiguracjami.
  2. Zaimplementuj tag CameraXConfig.Provider w Application oraz zwraca obiekt CameraXConfig w getCameraXConfig().
  3. Dodaj zajęcia Application do pliku AndroidManifest.xml jako opisane tutaj.

Na przykład ten przykładowy kod ogranicza logowanie w aplikacji CameraX do błędów tylko wiadomości:

Kotlin

class CameraApplication : Application(), CameraXConfig.Provider {
   override fun getCameraXConfig(): CameraXConfig {
       return CameraXConfig.Builder.fromConfig(Camera2Config.defaultConfig())
           .setMinimumLoggingLevel(Log.ERROR).build()
   }
}

Zachowaj lokalną kopię obiektu CameraXConfig, jeśli aplikacja tego wymaga i poznanie konfiguracji kamery X.

Ogranicznik aparatu

Podczas pierwszego wywołania funkcji ProcessCameraProvider.getInstance() CameraX wylicza i zapyta o cechy aparatów dostępnych na urządzenia. KameraX musi komunikować się z komponentami sprzętowymi, Może to zająć niezbyt dużo czasu dla każdej kamery, zwłaszcza niższych urządzeń. Jeśli aplikacja używa tylko określonych aparatów na urządzeniu, takich jak domyślny przedni aparat, w aparacie CameraX możesz ustawić ignorowanie innych kamer, co może zmniejszyć czas oczekiwania na uruchomienie kamer używanych przez Twoją aplikację.

Jeśli CameraSelector zaliczono do CameraXConfig.Builder.setAvailableCamerasLimiter() odfiltrowuje kamerę, więc AparatX zachowuje się tak, jakby ona nie istniała. Dla: poniższy kod ogranicza aplikację do korzystania wyłącznie domyślny tylny aparat:

Kotlin

class MainApplication : Application(), CameraXConfig.Provider {
   override fun getCameraXConfig(): CameraXConfig {
       return CameraXConfig.Builder.fromConfig(Camera2Config.defaultConfig())
              .setAvailableCamerasLimiter(CameraSelector.DEFAULT_BACK_CAMERA)
              .build()
   }
}

Wątki

Wiele interfejsów API platformy, na których opiera się aplikacja CameraX, wymaga blokowania komunikację międzyprocesową (IPC) za pomocą sprzętu, który czasami może trwać setki, na odpowiedź w ciągu milisekund. Z tego powodu CameraX wywołuje te interfejsy API tylko z wątki w tle, dzięki czemu wątek główny nie zostanie zablokowany, a UI pozostaje płynny. CameraX wewnętrznie zarządza wątkami działającymi w tle, zachowanie wydaje się przejrzyste. Niektóre aplikacje wymagają jednak ścisłej kontroli wątków. CameraXConfig zezwala aplikacji na ustawianie wątków w tle używane przez CameraXConfig.Builder.setCameraExecutor(). oraz CameraXConfig.Builder.setSchedulerHandler()

Wykonawca aparatu

Wykonawca kamery jest też używany we wszystkich wewnętrznych wywołaniach interfejsu API platformy aparatu oraz , jak w przypadku wywołań zwrotnych z tych interfejsów API. CameraX przydziela Executor. Jeśli jednak Twoja aplikacja wymaga większej kontroli nad wątkami, użyj funkcji CameraXConfig.Builder.setCameraExecutor()

Moduł obsługi algorytmu szeregowania

Moduł obsługi algorytmu szeregowania służy do planowania zadań wewnętrznych w stałych odstępach czasu, np. ponawiać próby otwarcia aparatu, gdy nie jest on dostępny. Ten moduł obsługi nie wykonuje zadań, a jedynie wysyła je do wykonawcy kamery. Jest także na starszych platformach API, które wymagają Handler na potrzeby wywołań zwrotnych. W takich przypadkach wywołania zwrotne są nadal wysyłane tylko bezpośrednio do wykonawcy kamery. Aparat X zarządza wewnętrznymi zasobami HandlerThread, aby wykonać te zadania, ale możesz go zastąpić kodem CameraXConfig.Builder.setSchedulerHandler().

Logowanie

Rejestrowanie w CameraX pozwala aplikacjom filtrować komunikaty logcat, , aby unikać szczegółowych komunikatów w kodzie produkcyjnym. Aparat X obsługuje 4 poziomy rejestrowania, od najbardziej szczegółowego do najpoważniejszego:

  • Log.DEBUG (domyślnie)
  • Log.INFO
  • Log.WARN
  • Log.ERROR

Zapoznaj się z dokumentacją dziennika Androida. . Używaj CameraXConfig.Builder.setMinimumLoggingLevel(int) aby ustawić odpowiedni poziom logowania dla aplikacji.

Automatyczny wybór

CameraX automatycznie udostępnia funkcje właściwe dla urządzenia, która działa. Na przykład AparatX automatycznie określa najlepszej rozdzielczości, jeśli nie została określona nie jest obsługiwane. Biblioteka zajmuje się tym wszystkim, eliminując na potrzeby napisania kodu przeznaczonego na konkretne urządzenie.

Celem aplikacji CameraX jest pomyślne zainicjowanie sesji kamery. Oznacza to, że W zależności od możliwości urządzenia CameraX ogranicza rozdzielczość i formaty obrazu. Do naruszenia zabezpieczeń może dojść, ponieważ:

  • Urządzenie nie obsługuje żądanej rozdzielczości.
  • na urządzeniu występują problemy ze zgodnością, na przykład starsze urządzenia, które wymagają w pewnych rozdzielczościach, aby działać prawidłowo.
  • Na niektórych urządzeniach pewne formaty są dostępne tylko w określonych aspektach współczynników proporcji.
  • Urządzenie preferuje „najbliższy model 16” JPEG lub wideo kodowanie. Więcej informacji: SCALER_STREAM_CONFIGURATION_MAP

Chociaż AparatX tworzy sesję i zarządza nią, zawsze sprawdzaj zwracały rozmiary obrazów na danych wyjściowych przypadku użycia w kodzie i odpowiednio je dostosuj.

Obrót

Domyślnie obrót kamery jest ustawiony na obrót domyślnego wyświetlacza. podczas tworzenia przypadku użycia. W tym domyślnym przypadku Aparat X generuje pozwala aplikacji dopasować się do tego, czego oczekujesz podgląd. Aby obsługiwać wiele reklam displayowych, możesz zmienić rotację na wartość niestandardową. przez przekazanie bieżącej orientacji wyświetlacza podczas konfigurowania przypadku użycia Obiekty lub dynamicznie po ich utworzeniu.

Aplikacja może ustawić rotację docelową za pomocą ustawień konfiguracji. Następnie może aktualizować ustawienia rotacji za pomocą metod z interfejsów API przypadków użycia (takich jak ImageAnalysis.setTargetRotation()), nawet wtedy, gdy cykl życia jest uruchomiony. Możesz użyć tej opcji, gdy aplikacja jest zablokowany w trybie pionowym, więc ponowna konfiguracja nie jest przeprowadzana rotacji, ale w przypadku zastosowania zdjęcia lub analizy muszą one być świadome aktualnego obrotu urządzenia. Na przykład świadomość rotacji może być potrzebna więc twarze są poprawnie zorientowane na potrzeby wykrywania twarzy lub zdjęcia są ustawione w orientacji poziomej lub w orientacji pionowej.

Dane zrobionych obrazów mogą być przechowywane bez informacji o rotacji. Dane EXIF zawiera informacje o obrocie, dzięki czemu aplikacje galerii mogą wyświetlać obraz ustaw prawidłową orientację po zapisaniu.

Aby wyświetlić dane podglądu w prawidłowej orientacji, możesz użyć metadanych dane wyjściowe z Preview.PreviewOutput() do tworzenia przekształceń.

Przeanalizuj przykładowy kod poniżej, aby dowiedzieć się, jak ustawić rotację w przypadku zdarzenia orientacji:

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();
}

W zależności od ustawionego obrotu w każdym przypadku użycia obracamy dane obrazu. bezpośrednio lub dostarcza metadane obrotu konsumentom nieobróconego obrazu. i skalowalnych danych.

  • Podgląd: podawane są dane wyjściowe metadanych, aby zapewnić rotację środowiska docelowego rozdzielczość jest znana za pomocą Preview.getTargetRotation().
  • ImageAnalysis (Analiza obrazu): dostarcza metadane, dzięki czemu obraz jest buforowany. są znane w odniesieniu do współrzędnych wyświetlania.
  • ImageCapture: metadane Exif obrazu, bufor lub zarówno bufor, jak i metadane są zmieniane, by uwzględnić ustawienie rotacji. Zmieniona wartość zależy od wdrożenia HAL.

Przytnij jako prostokąt

Domyślnie prostokąt przycinania jest pełnym prostokątem bufora. Możesz go dostosować w ten sposób: ViewPort i UseCaseGroup Według użycia przez grupowanie i określając widoczny obszar, aparatX gwarantuje, że przypadki użycia w grupie wskazują na ten sam obszar czujnika aparatu.

Fragment kodu poniżej pokazuje, jak używać tych 2 klas:

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 określa pole bufora widoczne dla użytkowników. Następnie AparatX oblicza obliczenia największego możliwego prostokąta przycinania na podstawie właściwości widocznego obszaru załączonych przypadków użycia. Zwykle do uzyskania efektu WYSIWYG wystarczy skonfigurować na podstawie przypadku użycia podglądu. Prosty sposób na uzyskanie widocznego obszaru to aby użyć narzędzia PreviewView.

Poniższe fragmenty kodu pokazują, jak pobrać obiekt ViewPort:

Kotlin

val viewport = findViewById<PreviewView>(R.id.preview_view).viewPort

Java

ViewPort viewPort = ((PreviewView)findViewById(R.id.preview_view)).getViewPort();

W poprzednim przykładzie dane aplikacji uzyskane dzięki ImageAnalysis i Wartość ImageCapture odpowiada temu, co widzi użytkownik w elemencie PreviewView, przy założeniu, że Typ skali PreviewView jest ustawiony na domyślny FILL_CENTER. Po zastosowaniu prostokąta przycinania i obrót do bufora wyjściowego – obraz ze wszystkich przypadków użycia jest taki sam, choć możliwe, że ma różną rozdzielczość. Więcej o tym, jak zastosować informacje o przekształceniu, dowiesz się z artykułu Transform (Przekształć) dane wyjściowe.

Wybór aparatu

CameraX automatycznie wybiera najlepszy aparat dla danej aplikacji do wymagań i przypadków użycia. Jeśli chcesz użyć innego urządzenia niż to, dostępnych jest kilka opcji:

Poniższy przykładowy kod pokazuje, jak utworzyć CameraSelector do wpływać na wybór urządzenia:

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)

Wybierz kilka kamer jednocześnie

Począwszy od CameraX 1.3, można również wybrać wiele aparatów jednocześnie. Możesz na przykład powiązać przedni i tylny aparat, aby robić zdjęcia lub nagrywać filmów z obu perspektyw.

Gdy jest używana funkcja Równoczesna kamera, urządzenie może obsługiwać 2 kamery. z różnymi obiektywami w tym samym czasie, albo obsługiwać dwa tylne aparaty o tej samej nazwie. Poniższy blok kodu pokazuje, jak ustawić dwie kamery, gdy wywołującego funkcję bindToLifecycle i dowiedzieć się, jak uzyskać obydwa obiekty aparatu ze zwróconego ConcurrentCamera obiekt.

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);

Rozdzielczość aparatu

Możesz pozwolić, by Aparat X ustawiał rozdzielczość zdjęcia na podstawie kombinacji możliwości urządzenia, obsługiwany sprzęt poziomu usługi, przypadku użycia i współczynnika proporcji. Możesz też określić konkretny adres, lub określony format obrazu w przypadkach, które umożliwiają konfiguracji.

Automatyczna rozdzielczość

CameraX może automatycznie określić najlepsze ustawienia rozdzielczości na podstawie przypadków użycia opisanych w zasadzie cameraProcessProvider.bindToLifecycle(). Kiedykolwiek należy określić wszystkie przypadki użycia wymagane do jednoczesnego działania w jednym w pojedynczym wywołaniu bindToLifecycle(). AparatX określa rozdzielczość na podstawie zbioru przypadków użycia po uwzględnieniu na poziomie sprzętowym i uwzględniając różnice w zależności od urządzenia (gdy urządzenie przekracza lub nie spełnia konfiguracji strumienia ). Dzięki temu aplikacja będzie działać na wielu różnych urządzeniach minimalizując liczbę ścieżek kodu przeznaczonych na konkretne urządzenia.

Domyślny współczynnik proporcji w przypadku przechwytywania i analizy obrazów to 4:3.

Przypadki użycia mają konfigurowalny współczynnik proporcji, co pozwala aplikacji określić z odpowiednim współczynnikiem proporcji. Dane wyjściowe AparatuX są generowane w celu: format obrazu musi być ściśle dopasowany do formatu obsługiwanego przez urządzenie. Jeśli ta rozdzielczość nie jest obsługiwana, ale ta, która spełnia większość warunków zaznaczono. Aplikacja określa więc sposób wyświetlania kamery na a AparatX określa najlepsze ustawienia rozdzielczości, na różnych urządzeniach.

Aplikacja może na przykład wykonywać dowolne z tych czynności:

  • W przypadku zastosowania określ docelową rozdzielczość 4:3 lub 16:9
  • Określ niestandardową rozdzielczość, w której CameraX będzie próbował znaleźć najbliższą dopasuj do
  • Określ współczynnik proporcji kadrowania na potrzeby obrazu ImageCapture

Aparat X automatycznie wybiera rozdzielczość wewnętrznej powierzchni aparatu Camera2. Rozdzielczości znajdziesz w poniższej tabeli:

Przypadek użycia Rozdzielczość powierzchni wewnętrznej Rozdzielczość danych wyjściowych
Podgląd Współczynnik proporcji: rozdzielczość, która najlepiej pasuje do docelowego obrazu . Rozdzielczość powierzchni wewnętrznej. Podane metadane umożliwiają przycięcie widoku danych, i obrócić, aby dostosować go do docelowego współczynnika proporcji.
Rozdzielczość domyślna: najwyższa rozdzielczość podglądu lub najwyższa. preferowanej przez urządzenie rozdzielczości, która jest zgodna z formatem obrazu podglądu.
Maksymalna rozdzielczość:rozmiar podglądu oznacza najlepszy rozmiar. do rozdzielczości ekranu urządzenia lub do 1080p (1920 x 1080), zależnie od tego, która wartość jest mniejsza.
Analiza obrazu Format obrazu: rozdzielczość, która najlepiej pasuje do docelowego obrazu . Rozdzielczość powierzchni wewnętrznej.
Rozdzielczość domyślna: domyślne ustawienie rozdzielczości docelowej to 640x480. Dostosowywanie docelowej rozdzielczości i odpowiednich formatów obrazu pozwala uzyskać najlepszą możliwą rozdzielczość.
Maksymalna rozdzielczość: maksymalna rozdzielczość wyjściowa aparatu Format YUV_420_888, który jest pobierany z StreamConfigurationMap.getOutputSizes(). Domyślna rozdzielczość docelowa to 640 x 480, więc jeśli chcesz uzyskać rozdzielczość większą niż 640 x 480, musisz użyć setTargetResolution() oraz setTargetAspectRatio() aby uzyskać najbardziej zbliżoną rozdzielczość.
Robienie zdjęć Format obrazu: format obrazu, który najlepiej pasuje do ustawienia. Rozdzielczość powierzchni wewnętrznej.
Rozdzielczość domyślna: najwyższa dostępna rozdzielczość preferowanej przez urządzenie rozdzielczości, która odpowiada formatowi obrazu w Zrób zdjęcie.
Maksymalna rozdzielczość: maksymalna rozdzielczość wyjściowa aparatu w format JPEG. Używaj StreamConfigurationMap.getOutputSizes() .

Określ rozdzielczość

Podczas tworzenia przypadków użycia możesz ustawić określone rozdzielczości setTargetResolution(Size resolution) zgodnie z tym kodem przykład:

Kotlin

val imageAnalysis = ImageAnalysis.Builder()
    .setTargetResolution(Size(1280, 720))
    .build()

Java

ImageAnalysis imageAnalysis =
  new ImageAnalysis.Builder()
    .setTargetResolution(new Size(1280, 720))
    .build();

Nie możesz ustawić jednocześnie docelowego formatu obrazu i rozdzielczości docelowej tych kwestii. Powoduje to zgłoszenie żądania IllegalArgumentException podczas tworzenia konfiguracji. obiektu.

Wyraź rozdzielczość Size we współrzędnej po obróceniu obsługiwanych rozmiarów zgodnie z rotacją docelową. Na przykład plik urządzenie z naturalną orientacją pionową w naturalnej rotacji celu obraz pionowy może mieć rozdzielczość 480 x 640, a to samo urządzenie obrócone o 90 stopni w przypadku kierowania poziomego można określić rozdzielczość 640 x 480 pikseli.

Docelowa rozdzielczość ma na celu ustalenie minimalnej granicy obrazu i ich rozwiązania. Rzeczywista rozdzielczość obrazu to najbliższa dostępna rozdzielczość rozmiar nie mniejszy niż docelowa rozdzielczość, zgodnie z Implementacja za pomocą aparatu.

Jeśli jednak nie ma rozwiązania równego jest większa niż rozdzielczość docelowa, najbliższa dostępna rozdzielczość jest mniejsza niż wybieramy rozdzielczość docelową. Rozdzielczości o tym samym współczynniku proporcji przesłane Size mają wyższy priorytet niż rozdzielczości różnych formatów obrazu.

Aparat X stosuje najlepszą odpowiednią rozdzielczość na podstawie liczby żądań. Jeśli główna potrzeba to spełnienie współczynnika proporcji, określ tylko setTargetAspectRatio, a Aparat X określa rozdzielczość odpowiednią na potrzeby urządzenia. jeśli aplikacja potrzebuje określonej rozdzielczości, aby utworzyć obraz. (np. małe lub średnie obrazy oparte na możliwości przetwarzania na urządzeniu), użyj funkcji setTargetResolution(Size resolution).

Jeśli aplikacja wymaga dokładnej rozdzielczości, zapoznaj się z tabelą w sekcji createCaptureSession() aby określić, jakie maksymalne rozdzielczości są obsługiwane przez poszczególne poziomy sprzętowe. Do Sprawdź rozdzielczości obsługiwane przez bieżące urządzenie, patrz StreamConfigurationMap.getOutputSizes(int)

Jeśli Twoja aplikacja działa na Androidzie 10 lub nowszym, możesz używać isSessionConfigurationSupported() aby zweryfikować konkretny punkt SessionConfiguration.

Steruj wyjściem kamery

Oprócz tego, że w zależności od potrzeb można skonfigurować wyjścia z kamery do indywidualnego użycia, CameraX implementuje również poniższe interfejsy, aby operacje kamery typowe dla wszystkich powiązanych przypadków użycia:

  • CameraControl umożliwia konfigurować często używane funkcje aparatu.
  • CameraInfo umożliwia wysyłanie zapytań i stanów tych wspólnych cech.

Następujące funkcje aparatu są obsługiwane przez funkcję CameraControl:

  • Zoom
  • Latarka
  • Ostrość i pomiar (dotknij, aby ustawić ostrość)
  • Kompensacja ekspozycji

Pobieranie instancji CameraControl i CameraInfo

Pobierz instancje CameraControl i CameraInfo za pomocą polecenia Obiekt Camera zwrócony przez ProcessCameraProvider.bindToLifecycle() Oto przykład:

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()

Możesz na przykład przesłać powiększenie i inne operacje CameraControl po Dzwonię pod numer bindToLifecycle(). Po zatrzymaniu lub zniszczeniu działania używanego do powiązania instancja kamery, CameraControl nie może już wykonywać operacji i zwraca błąd ListenableFuture.

Zoom

CameraControl umożliwia zmianę poziomu powiększenia na dwa sposoby:

  • setZoomRatio() ustawia powiększenie.

    Współczynnik musi się mieścić w zakresie od CameraInfo.getZoomState().getValue().getMinZoomRatio() i CameraInfo.getZoomState().getValue().getMaxZoomRatio() W przeciwnym razie funkcja zwraca błąd ListenableFuture.

  • setLinearZoom() ustawia bieżące powiększenie na wartość powiększenia liniowego z zakresu od 0 do 1,0.

    Zaletą powiększenia liniowego jest to, że przekształca on pole widzenia ze zmianami powiększenia. Dzięki temu idealnie nadaje się do użycia Slider wyświetlenie.

CameraInfo.getZoomState() zwraca LiveData bieżącego stanu powiększenia. Wartość zmienia się, gdy kamera zostanie zainicjowany albo poziom powiększenia zostanie ustawiony przy użyciu elementu setZoomRatio() lub setLinearZoom() Wywołanie dowolnej z tych metod ustawia wsteczne wartości ZoomState.getZoomRatio() oraz ZoomState.getLinearZoom() Jest to przydatne, jeśli chcesz wyświetlić tekst współczynnika powiększenia obok suwaka. Wystarczy, że będziesz obserwować ZoomState LiveData, aby aktualizować obie wersje bez konieczności wykonywania konwersji.

Pole ListenableFuture zwrócone przez oba interfejsy API umożliwia aplikacjom zostanie powiadomiony, gdy powtarzające się żądanie z określoną wartością powiększenia zostanie . Ponadto jeśli ustawisz nową wartość powiększenia podczas poprzedniej operacji, wciąż trwa, nie uda się ListenableFuture poprzedniej operacji powiększenia natychmiast.

Latarka

CameraControl.enableTorch(boolean) włącza lub wyłącza latarkę.

CameraInfo.getTorchState() może posłużyć do odpytywania bieżącego stanu lampy. Możesz sprawdzić zwrócona wartość autor: CameraInfo.hasFlashUnit() aby ustalić, czy jest dostępna latarka. Jeśli nie, dzwonię CameraControl.enableTorch(boolean) sprawia, że zwrócona wartość ListenableFuture ma wartość natychmiast z nieudanym wynikiem i ustawia stan lampki na TorchState.OFF

Gdy latarka jest włączona, pozostaje włączona podczas robienia zdjęć i nagrywania filmów bez względu na ustawienie flashMode. flashMode in ImageCapture działa tylko wtedy, gdy latarka jest wyłączona.

Ostrość i pomiar

CameraControl.startFocusAndMetering() uruchamia autofokus i pomiar ekspozycji, ustawiając regiony pomiaru AF/AE/AWB na podstawie danej właściwości FocusMeteringAction. Jest to często stosowane, by zaimplementować metodę kliknięcia funkcję ostrości” w wielu aplikacjach aparatu.

Punkt mierniczy

Na początek utwórz MeteringPoint za pomocą MeteringPointFactory.createPoint(float x, float y, float size) MeteringPoint oznacza pojedynczy punkt kamery Surface Przechowujemy go w znormalizowanej postaci. tak, aby można było go łatwo przekonwertować na współrzędne czujnika w celu określenia Regiony AF/AE/AWB.

Rozmiar MeteringPoint mieści się w zakresie od 0 do 1, a rozmiar domyślny to 0,15f. Podczas wywoływania funkcji MeteringPointFactory.createPoint(float x, float y, float size) aparat CameraX tworzy prostokątny obszar wyśrodkowany na (x, y) dla podanego obszaru size

Ten kod pokazuje, jak utworzyć 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 i FocusMeteringAction

Do wywołania startFocusAndMetering() aplikacje muszą utworzyć FocusMeteringAction, składający się z co najmniej jednego elementu MeteringPoints z opcjonalnym trybem pomiaru kombinacje z FLAG_AF FLAG_AE FLAG_AWB. jest to kod ilustrujący to użycie:

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)

Jak pokazano w poprzednim kodzie, startFocusAndMetering() przyjmuje FocusMeteringAction składające się z jednego MeteringPoint dla AF/AE/AWB w regionach pomiaru, a inny MeteringPoint – tylko w przypadku AF i AE.

Wewnętrznie AparatX przekształca go w Aparat 2. MeteringRectangles i ustawia odpowiednie wartości CONTROL_AF_REGIONS / CONTROL_AE_REGIONS / CONTROL_AWB_REGIONS do żądania przechwytywania.

Ponieważ nie każde urządzenie obsługuje AF/AE/AWB i wielu regionów, AparatX FocusMeteringAction. Aparat X używa maksymalnej liczby z obsługiwanych punktów MeteringPoints w kolejności dodania punktów. Wszystkie Punkty MeteringPoint dodane po maksymalnej liczbie punktów są ignorowane. Jeśli na przykład plik FocusMeteringAction jest wyposażony w 3 punkty MeteringPoints na platformie obsługującej tylko 2, używane są tylko 2 pierwsze punkty MeteringPoint. Ostatni MeteringPoint to zignorowane przez aparatX.

Kompensacja ekspozycji

Kompensacja ekspozycji jest przydatna, gdy aplikacje muszą precyzyjnie dostosować ekspozycję (EV) poza wynikami automatycznej ekspozycji (AE). Kompensacja ekspozycji są łączone w następujący sposób, aby określić niezbędną ekspozycję dla bieżące warunki obrazu:

Exposure = ExposureCompensationIndex * ExposureCompensationStep

Aparat X udostępnia Camera.CameraControl.setExposureCompensationIndex() do ustawiania kompensacji ekspozycji jako wartości indeksu.

Dodatnie wartości indeksu powodują rozjaśnienie obrazu, a ujemne – przyciemnianie . Aplikacje mogą wysyłać zapytania do obsługiwanego zakresu przez CameraInfo.ExposureState.exposureCompensationRange() opisane w następnej sekcji. Jeśli wartość jest obsługiwana, zwracana jest wartość Działanie ListenableFuture kończy się, gdy wartość zostanie włączona w kolumnie żądania przechwytywania; jeśli podany indeks jest poza obsługiwanym zakresem, setExposureCompensationIndex() powoduje, że zwrócona wartość ListenableFuture jest możesz wykonać natychmiast z nieudanym wynikiem.

CameraX zachowuje tylko najnowsze zapisane zdjęcia (setExposureCompensationIndex()) i wywoływanie funkcji wielokrotnie przed poprzednim żądaniem skutkuje anulowaniem.

Poniższy fragment kodu ustawia indeks kompensacji ekspozycji i rejestruje zwrotny po zrealizowaniu żądania zmiany ekspozycji:

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() pobiera bieżącą ExposureState w tym:

    • Obsługa kontroli kompensacji ekspozycji.
    • Bieżący indeks kompensacji ekspozycji.
    • Zakres indeksu kompensacji ekspozycji.
    • Krok kompensacji ekspozycji używany w wartości kompensacji ekspozycji obliczeń.

Na przykład ten kod inicjuje ustawienia ekspozycji SeekBar z obecnym ExposureState wartości:

Kotlin

val exposureState = camera.cameraInfo.exposureState
binding.seekBar.apply {
   isEnabled = exposureState.isExposureCompensationSupported
   max = exposureState.exposureCompensationRange.upper
   min = exposureState.exposureCompensationRange.lower
   progress = exposureState.exposureCompensationIndex
}

Dodatkowe materiały

Więcej informacji o aparacie AparatX znajdziesz w tych dodatkowych materiałach.

Ćwiczenia z programowania

  • Pierwsze kroki z AparatemX
  • Przykładowy kod

  • Przykładowe aplikacje CameraX
  • Społeczność programistów

    Grupa dyskusyjna dotyczące aparatu Android CameraX