Kullanıcılar, üçüncü taraf uygulamalarının ışık koşullarından veya donanım katmanından bağımsız olarak cihazlarının yerel kamerasıyla aynı yüksek doğrulukta fotoğraf ve video çekmesini bekler. Genişleyen Android ekosisteminde bu tutarlılığı sağlamak için önemli mimari hususları göz önünde bulundurmak gerekir. Bu oturumda, cihaz özelliklerini en üst düzeye çıkarırken tüm form faktörlerinde güvenilir kalan sağlam ve profesyonel yakalama ardışık düzenlerinin nasıl oluşturulacağı gösterilmektedir.
CameraX'teki en son gelişmeleri inceleyerek hareketli fotoğraflar ve Google Play Hizmetleri aracılığıyla cihaz üzerinde yapay zeka geliştirmeleri gibi son teknoloji özellikleri nasıl entegre edeceğinizi ve Jetpack XR SDK'yı kullanarak uzamsal deneyimleri nasıl oluşturacağınızı göstereceğiz. Ayrıca, seçtiğiniz kodlama aracısının bu konuşmadaki kavramları ve daha fazlasını otomatik olarak uygulamasını sağlayan CameraX becerimizi de inceleyeceğiz.
CameraXViewfinder, kamera önizlemelerini katlanabilir cihazlar gibi farklı form faktörlerine uyarlar. CameraX 1.7'de hareketle kontrol ve ekran flaşı desteği eklenmiştir.ProjectedDeviceContext parametresini iletmek, CameraX'in doğrudan akıllı gözlükten görüntü yakalamasına olanak tanır.Transkript
Herkese merhaba.
Oturumumuza hoş geldiniz.
Ben Aman, yanımda da Scott var.
Bugün, CameraX ve cihaz üzerinde zeka ile cihazlardaki kamera deneyimlerinizi nasıl geliştirebileceğinizden bahsedeceğimiz için çok heyecanlıyız.
Hadi başlayalım.
Telefonlarınızı nasıl kullandığınızı düşünün.
Anları yakalamak ve sevdiklerimizle paylaşmak için sık sık telefon kamerasını kullanırız.
Kamera, akıllı telefon deneyiminin merkezinde yer almaya başladı.
Aslında iyi bir kamera, akıllı telefon satın alırken genellikle önemli bir faktördür.
Bugün, premium kamera deneyimleri oluşturmak için iki geniş temayı ele alacağız.
Öncelikle bazı CameraX özelliklerini inceleyeceğiz, ardından cihaz üzerinde makine öğrenimi tekniklerinden bazılarını öğreneceğiz.
CameraX ile başlayalım.
Jetpack CameraX, Android'deki kamera deneyimini destekler.
CameraX'in yanı sıra Android platformu çerçevesinin bir parçası olan Camera1 ve Camera2 de vardır.
Peki, hangi kitaplığı kullanmalısınız?
Camera1, Android'deki orijinal kamera API'siydi.
Bu API artık kullanımdan kaldırıldığından yeni uygulamaların Camera2 veya CameraX'i kullanması gerekir.
Kamera2, Kamera1'in yerini aldı.
Karmaşık kullanım alanları için düşük seviyeli kamera kontrolüne ihtiyacınız varsa Camera2 iyi bir seçenektir.
Ancak cihaza özel yapılandırmaları kendiniz yapmanız gerekir.
Son olarak, Jetpack CameraX, Camera2'yi temel alır.
Tutarlı bir API sağlar ve cihaza özel yapılandırmaları otomatik olarak yönetir.
Çoğu geliştirici için önerilen seçenek budur.
Çok önemli bir duyurumuz var.
Camera1'i devre dışı bırakmayı planlıyoruz. Bu süreç, önümüzdeki yıl Android 18'de Google Play politika yaptırımlarıyla başlayacak.
Eski Camera1 API'yi kullanmaya devam ediyorsanız CameraX veya Camera2'ye geçmeniz gerekir.
Peki neden CameraX'i kullanmalısınız?
İlk olarak, Android 7 ve sonraki sürümleri desteklediği için etkin Android cihazların yaklaşık %99'uyla uyumludur.
İkinci olarak, kullanımı kolaydır ve daha az kodla önizleme, yakalama ve kaydetme gibi yaygın kullanım alanları için basit API'ler sağlar.
Üçüncü olarak, katlanabilir cihazlarda ve tabletlerde oldukça yaygın olan önizleme uzaması gibi cihaza özgü sorunları azaltarak cihazlar arasında tutarlı bir deneyim sunar.
Son olarak, gece modu ve portre gibi gelişmiş OEM özelliklerinin uygulanmasını basitleştirir.
Şimdi Scott'ı CameraX özelliklerinden bahsetmesi için davet etmek istiyorum.
Söz sende, Scott.
Teşekkürler, Aman.
Herkese merhaba.
Adım Scott.
Bugün, profesyonel düzeyde bir kamera deneyimi oluşturmanızı sağlayacak çeşitli CameraX özelliklerini ele alacağız.
İlk olarak Uyarlanabilir Vizör'den bahsedelim.
Bu özellik, farklı form faktörleri ve ekran boyutlarında herkese açık kullanıcı adı önizlemesini kolaylaştırmak için tasarlanmıştır.
Kullanıcılar artık katlanabilir telefon, telefon, dizüstü bilgisayar ve XR cihazlar gibi çeşitli cihazlara sahip.
Bu nedenle, yeni form faktörlerine uyum sağlayan bir kamera deneyimi oluşturmak her zamankinden daha önemli.
Kamera önizlemesini doğru şekilde ayarlamak, özellikle geniş ekranlı katlanabilir cihazlarda oldukça zordur.
Bu cihazlar açıldığında iç kamerası yatay, arka kamerası ise dikey olarak monte edilir.
Dolayısıyla, tüm kamera sensörlerinin dikey olarak monte edildiğini varsayarsanız uzamsal bir uyumsuzluğa yol açarsınız ve bozulmaya veya yana doğru kaymaya neden olursunuz.
CameraXViewfinder, karmaşık işlemleri tamamen sizin yerinize halledecek şekilde tasarlanmıştır. Böylece kamera önizlemenizin tüm form faktörlerinde sorunsuz çalışmasını sağlar.
Şimdi de CameraXViewfinder composable'ının nasıl kullanılacağına bakalım.
var surfaceRequest by remember {
mutableStateOf<SurfaceRequest?>(null)
}
LaunchedEffect(...) {
preview.setSurfaceProvider { surfaceRequest = it }
cameraProvider.bindToLifecycle(..., preview)
}
surfaceRequest?.let { request ->
CameraXViewfinder(
surfaceRequest = request,
contentScale = ContentScale.Fit
)
}İlk olarak, yüzey isteğini tutmak için surfaceRequest içerik değişkenini tanımlarsınız.
Özür dilerim.
İkinci olarak, LaunchedEffect içinde yüzey sağlayıcıyı, yüzey isteği nesnesini yakalayacak şekilde ayarlarsınız.
Ardından yaşam döngüsüne bağlayıp kamerayı başlatırsınız.
Son olarak, geçerli bir yüzey isteğiyle durum güncellemesi yapıldığında ve yeniden oluşturma tetiklendiğinde isteği doğrudan CameraXViewfinder olarak ayarlarsınız.
Burada, tercihinize bağlı olarak contentScale sığdırılacak veya kırpılacak şekilde ayarlayabilirsiniz.
Hepsi bu kadar. Artık hazırsınız.
CameraX 1.7'de CameraXViewfinder için birkaç yeni özellik ekledik.
Odaklamak için dokunma veya yakınlaştırmak için iki parmağı yakınlaştırma gibi yeni hareketler de buna dahildir.
Ayrıca, selfie'nizi aydınlatmak için ekranı kullanmanıza olanak tanıyan ekran flaşını da destekler.
Bu özelliği uygulamak kolaydır.
CameraXViewfinder(
surfaceRequest = viewModel.surfaceRequest,
contentScale = ContentScale.Fit,
isTapToFocusEnabled = true,
isPinchToZoomEnabled = true,
onScreenFlashReady =
{
imageCapture.screenFlash = it
imageCapture.flashMode = FLASH_MODE_SCREEN
}
)"Odaklamak için dokun" ve "Yakınlaştırmak için iki parmakla sıkıştır" özelliklerini etkinleştirmeniz yeterlidir.
Yanıp sönen ekran ışığı için ise onScreenFlashReady geri çağırma işlevinden yanıp sönen ekran ışığı örneğini alıp ImageCapture'a iletir ve flaş modunu FLASH_MODE_SCREEN olarak ayarlarsınız.
Hepsi bu kadar.
CameraX'in, tüm form faktörlerinde sorunsuz çalışan kamera önizlemesini nasıl etkinleştirdiğini gördük.
Şimdi Android XR'da kamera çekimiyle bir adım daha ileri gidelim.
Üç XR cihaz kategorisi vardır. Birincisi XR kulaklığıdır.
Bunlar, fiziksel dünyayı yakalamak için kamera kullanan ve başlığın içinde görüntüleyen, tamamen kapalı ve sürükleyici başlıklardır.
İkincisi ise kablolu XR gözlükleri.
Bugün bu kategorideki açılış konuşmasında XREAL Aura'yı duyurduk.
Konuşmalarda da gördüğünüz gibi, bunlar işlem birimine bağlı olan ve gerçek dünyadaki sanal içerik katmanını görmenizi sağlayan şeffaf gözlüklerdir.
Üçüncüsü ise sesli ve görüntülü gözlükler.
Bunlar hafif gözlükler.
Eller serbest ve göz atılabilir deneyimler için ses, kamera ve ekranı birleştirebilirler.
İlk iki kategori olan XR kulaklığı ve kablolu XR gözlükleri, normal bir telefon gibi Camera2 ve CameraX'i de destekler.
Bu nedenle bugün yalnızca sesli gözlüklere ve görüntülü gözlüklere odaklanacağız.
Bu gözlüklerde uygulamalar gözlük yerine Android telefonda (ana makine Android telefon) çalışır ancak burada hem telefon kamerasına hem de gözlük kamerasına erişim sağlanır.
Asıl soru, hangi kamerayla konuştuğunuzu nasıl anlayacağınızdır.
Yani bu çok basit.
Standart Context ile CameraX'iniz telefon kamerasına erişir.
ProjectedDeviceContext ile CameraX, gözlük kamerasına erişir.
Bu nedenle, farklı bağlamlar farklı hedef kameralara yol açar.
Kamera ve gözlük izinlerinin ayrı olduğunu unutmayın.
Telefon ve gözlük izinleri ayrı olduğundan gözlük iznini ayrı olarak istemeniz gerekir.
Diğer seçenek ise ana Android cihazlarda da çalışan ancak kullanıcı arayüzünüzün gözlüğe yansıtıldığı Planlanan Etkinlik'i kullanmaktır.
Burada kural tersine dönüyor.
Standart Context kullanıyorsanız gözlük kamerasına erişirsiniz.
Telefon kamerasına erişmek istiyorsanız HostContext'i kullanmanız gerekir.
Şimdi koda bakalım ve gözlük kamerasını kullanarak nasıl görüntü yakalayabileceğimizi görelim.
// In a coroutine
val imageCapture = ImageCapture.Builder().build()
ProjectedContext.isProjectedDeviceConnected(activity, coroutineContext)
.collectLatest { isConnected ->
if (isConnected) {
val projectedContext = ProjectedContext.createProjectedDeviceContext(activity)
val cameraConfig = CameraXConfig.Builder.fromConfig(Camera2Config.defaultConfig())
.setRepeatingStreamForced(false)
.build()
val cameraProvider = LifecycleCameraProvider.createInstance(projectedContext, cameraConfig)
cameraProvider.bindToLifecycle(activity, DEFAULT_BACK_CAMERA, imageCapture)
}
}
// Shutter button clicked
imageCapture.takePicture(...)Öncelikle, gözlüğün bağlı olup olmadığını görmek için isProjectedDeviceConnected komutunu çağırırsınız.
Ardından projectedContext almak için createProjectedDeviceContext numaralı telefonu ararsınız.
İkinci olarak, burada CameraX'i ilk kullanıma hazırlamak için ProcessCameraProvider yerine LifecycleCameraProvider'ı kullanırsınız.
Yani ProcessCameraProvider, başlatma işleminden sonra Context'i değiştiremeyeceğiniz bir singleton'dır.
LifecycleCameraProvider'ı kullanarak Context'i istediğiniz zaman değiştirebilirsiniz.
Ardından, CameraX'te ek yinelenen akışı devre dışı bırakmanız gerekir.
Günümüzdeki gözlükler yalnızca tek akışı desteklediği için bu gereklidir.
API şu anda dahili olarak kullanılıyor ancak yakında herkese açık hale getirilecek.
Hepsi bu kadar.
Buradan sonra standart CameraX'i kullanabilirsiniz. ImageCapture'ı bağlamanız yeterlidir. Artık gözlükle çekim yapabilirsiniz.
Anladım.
Şimdi de CameraX'in, birlikte çalışan özellik kombinasyonunu bulmanıza ve cihazdan en iyi şekilde yararlanmanıza nasıl yardımcı olduğunu görelim.
Modern kamera uygulamaları güçlü özelliklerle tanımlanır ve kullanıcılar bu kameranın HDR, 60 FPS ve önizleme sabitleme gibi özellikleri aynı anda desteklemesini bekler.
Ancak geliştirici olarak bu özellikleri bir araya getirmenin her zaman kolay olmadığını biliyoruz.
Özelliklerin ayrı ayrı desteklenmesi, birlikte çalışacaklarını garanti etmez.
Bu belirsizlik, geliştiricileri muhafazakar olmaya ve kullanıcıların yetenekli cihazlarda deneyimleyebileceklerini sınırlamaya zorladı.
Bu sorunu çözmek için Camera2 özellik kombinasyonu sorgu çerçevesi tarafından desteklenen Feature Group API'yi kullanıma sunduk.
Bu özelliği iki şekilde kullanabilirsiniz: İlk olarak, requiredFeatureGroup özelliğini kullanarak özellik kombinasyonunu kontrol edip desteklendiğinde etkinleştirebilirsiniz.
İkinci olarak, özellik önceliğinizi preferredFeatureGroup ile belirtebilirsiniz. Ardından CameraX, sizin için en iyi desteklenen kombinasyonu seçer.
Örneği inceleyelim.
Sağda, pardon solda, hiçbir şey etkinleştirilmemiş, normal bir telefon, normal bir kayıt var.
Solda HDR, 60 FPS ve Önizleme Sabitleme'yi birlikte etkinleştiriyoruz.
Daha parlak, daha akıcı ve sarsıntısız video ile kalitenin önemli ölçüde arttığını görebilirsiniz.
Şimdi koda göz atalım.
cameraProvider.bindToLifecycle(
lifecycleOwner,
cameraSelector,
SessionConfig(
useCases = listOf(preview, videoCapture),
// HDR_HLG10 > FPS_60 > Preview Stabilization.
preferredFeatureGroup =
listOf(HDR_HLG10, FPS_60, PREVIEW_STABILIZATION),
)
)Bu nedenle, özellik öncelik listemizi (HDR, 60 FPS ve önizleme stabilizasyonu) sağlamak için preferredFeatureGroup kullanıyoruz.
CameraX, kombinasyonu kontrol eder ve cihaz tarafından desteklenen en iyi kombinasyonları seçer.
CameraX 1.6 ve sonraki sürümlerde, 4K kayıt ve video sabitleme özelliklerini doğrudan Feature Group API'ye ekliyoruz.
// CameraX 1.6+ supports:
// 4K, video stabilization & Effect
val sessionConfig = SessionConfig(
useCases = listOf(preview, videoCapture),
requiredFeatureGroup =
setOf(UHD_RECORDING, VIDEO_STABILIZATION),
effects = listOf(overlayEffect)
)4K ve Video Sabitleme özelliklerinin bir arada kullanımı birçok premium cihazda desteklenir.
Artık Feature Group API ile bunları güvenle birlikte etkinleştirebilirsiniz.
Ayrıca, daha önce mümkün olmayan Feature Group API ile gerçek zamanlı efekt uygulama esnekliğine de sahipsiniz.
Şimdi CameraX'te nasıl yüksek kaliteli görüntü yakalayabileceğinizden bahsedelim.
CameraX artık DNG RAW çekimini destekliyor.
Profesyonel düzenleme için doğrudan kamera sensöründen işlenmemiş, sıkıştırılmamış RAW görüntülere erişmenizi sağlar.
Ayrıca, Gece Modu uzantımızı iyileştirdik.
Bu uzantı, flaş kullanmadan düşük ışıkta parlak ve net fotoğraflar çekmenizi sağlar.
Ayrıca yeni bir Gece Modu Göstergesi API'si kullanıma sunduk.
Mevcut ortamın karanlık ve gece moduna uygun olup olmadığını izler. Gece modu göstergesini göstermek için bu özelliği kullanabilirsiniz.
Ayrıca Ultra HDR artık CameraX uzantılarında destekleniyor.
Bu sayede Gece Modu'nda daha geniş bir dinamik aralık ve canlı renkler elde edilir. Ultra HDR özellikli Gece Modu şu anda birçok yeni premium cihazda desteklenmektedir.
Normal, gece ve Ultra HDR ile Gece Modu arasındaki farkı burada görebilirsiniz.
Şimdi bunu nasıl uygulayacağımızı görelim.
val cameraInfo = cameraProvider.getCameraInfo(cameraSelector,
ExtensionSessionConfig(ExtensionMode.NIGHT, extensionsManager))
val imageCapabilities = ImageCapture.getImageCaptureCapabilities(cameraInfo)
val imageCapture = ImageCapture.Builder().apply {
if (imageCapabilities.supportedOutputFormats
.contains(OUTPUT_FORMAT_JPEG_ULTRA_HDR)) {
setOutputFormat(OUTPUT_FORMAT_JPEG_ULTRA_HDR)
}
}.build()
val extensionSessionConfig = ExtensionSessionConfig(
ExtensionMode.NIGHT, extensionsManager, preview, imageCapture
)
cameraProvider.bindToLifecycle(..., extensionSessionConfig)Öncelikle Gece Modu için bir ExtensionSessionConfig oluşturup CameraInfo örneğini almak için bunu kullanırsınız.
Ardından, görüntü yakalama özelliğini almak için CameraInfo'yu kullanır ve Ultra HDR'nin desteklenip desteklenmediğini sorgularsınız.
Ardından çıkış biçimini Ultra HDR olarak ayarlayın.
Son olarak, kullanım alanlarıyla ExtensionSessionConfig öğesini tekrar oluşturup yaşam döngüsüne bağlarsınız.
Artık Ultra HDR fotoğraflarla Gece Modu'nda çekim yapmaya hazırsınız.
Ayrıca CameraX'e Hareketli Fotoğraflar desteği de ekliyoruz.
Hareketli fotoğraflar, fotoğrafın etrafındaki ses ve hareketi yakalayarak yalnızca hareketsiz bir görüntüyü değil, anı da korur.
Bu özelliği farklı telefonlar ve Android cihazlar için standartlaştırarak Hareketli Fotoğraflar'ın desteklenmesini kolaylaştırıyoruz.
Hareketli Fotoğraflar, 2027'nin ilk çeyreğinde CameraX'e eklenecek.
Özellik kullanıma sunulduğunda ImageCapture.Builder uygulamasında Hareketli Fotoğraflar modunu ayarlayarak Hareketli Fotoğraflar çekmeye başlayabilirsiniz.
val imageCapture = ImageCapture.Builder()
.setMotionPhotoMode(
ImageCapture.MOTION_PHOTO_MODE_ON,
customConfig
)
.build()
cameraProvider.bindToLifecycle(.. imageCapture)
imageCapture.takePicture(...)Şimdi CameraX'in yüksek hızlı video kaydını nasıl etkinleştirdiğini inceleyelim.
Hızlı hareket eden aksiyonu net bir şekilde kaydetmek, modern kamera uygulamalarının önemli bir özelliğidir.
Bu özellik, özellikle spor gibi hızlı tempolu senaryolarda kullanışlıdır.
Bu, 120 veya 240 fps'de yüksek hızlı çekimle elde edilir.
Bunu kullanmanın iki yolu vardır.
Öncelikle aynı kare hızında kodlama yapmanız, ardından gerçek bir yüksek kare hızlı video oluşturmanız gerekir.
Diğer seçenek ise videoyu 30 fps'de kodlayarak oynatılmaya hazır bir ağır çekim video oluşturmaktır.
Örneğin, 120 fps'de kaydedilen bir saniyelik videonun 30 fps'de oynatılması dört saniye sürer.
Bu zaman aralığı, ağır çekim efekti oluşturur.
Yüksek hızlı kayıt özelliğini uygulamak için videoCapture ile bir HighSpeedVideoSessionConfig oluşturursunuz.
val recorder = Recorder.Builder().build()
val videoCapture = VideoCapture.withOutput(recorder)
val frameRateRange = cameraInfo.getSupportedFrameRateRanges(
HighSpeedVideoSessionConfig(videoCapture, preview)).first()
val sessionConfig = HighSpeedVideoSessionConfig(
videoCapture,
preview,
frameRateRange = frameRateRange,
isSlowMotionEnabled = true
)
cameraProvider.bindToLifecycle(
lifecycleOwner, cameraSelector, sessionConfig)
// Start recording slow motion videos.
val recording = recorder.prepareRecording(context, outputOption)
.start(executor, {})Ardından, ağır çekim video oluşturmak için isSlowMotionEnabled değerini "true" olarak ayarlayarak 30 fps'de kodlayın veya yüksek hızlı kare hızına sahip bir video oluşturmak için "false" olarak ayarlayın.
Ağır çekim etkinleştirildiğinde Google Fotoğraflar bunu otomatik olarak algılar ve küçük resme ağır çekim rozeti ekler.
Şimdi de Google Fotoğraflar'da nasıl çalıştığına bakalım.
Burada ağır çekim, kediye dramatik bir etki katıyor.
Kedim ona dokunmamı hiç istemiyor.
Üzgünüz.
Son olarak, eşzamanlı API'miz olan Concurrent Camera API'deki bazı iyileştirmelere bakalım.
Eşzamanlı API, uygulamanızın ön ve arka kameradan aynı anda yayın yapmasına olanak tanır.
Bu yıl, Concurrent Camera API'de bazı iyileştirmeler yaptık.
Yaşam döngüsüne bağlandıktan ve bir kamera açtıktan sonra kamera kompozisyonunu dinamik olarak güncelleyebilirsiniz.
Yani konum, boyut ve oluşturma sırasını değiştirmek de buna dahildir.
Yuvarlak köşe, kenarlık genişliği ve kenarlık rengi gibi stiller de ekleyebilirsiniz.
Bunu yapmak için CompositionSettings kullanarak yuvarlak köşe, kenarlık genişliği ve renk gibi stilleri yapılandırın ve setZOrder kullanarak oluşturma sırasını ayarlayın.
val concurrentCamera =
cameraProvider.bindToLifecycle(list(config1, config2))
// CameraX 1.7 features: rounded corner, border width & color
val pipSettings = CompositionSettings.Builder()
.setOffset(0.2f, 0.2f)
.setScale(0.35f, 0.35f)
.setRoundedCornerRatio(0.15f)
.setBorderWidthRatio(0.02f)
.setBorderColor(Color.WHITE)
.setZOrder(1)
.build()
// CameraX 1.7 features: dynamical composition update
concurrentCamera.setCompositionSettings(
listOf(mainSettings, pipSettings))Ardından, kompozisyonu dinamik olarak güncellemek için etkin eşzamanlı kamerada setCompositionSettings yöntemini çağırırsınız.
Hepsi bu kadar.
Oluşturmayı dinamik olarak güncellemeye hazırsınız.
Anladım.
Tüm özellikleri inceledik.
Bu konuda önemli bir uyarımız var. CameraX 1.6 ve sonraki sürümlere yükseltmenizi önemle tavsiye ederiz.
Bu sayede, yeni formatı (Eclipsa Video) destekleyen yeni cihazlarda kilitlenme sorunları önlenebilir ve CameraX uzantınızın gelecekteki Pixel güncellemelerinde çalışmaya devam etmesi sağlanabilir.
Böylece ilk oturumumuzun sonuna geldik.
Profesyonel düzeyde bir kamera deneyimi oluşturmanıza yardımcı olan CameraX özelliklerini ele aldık. Şimdi de Aman'ı cihaz üzerinde yapay zeka ile ilgili bir sonraki oturumumuza davet etmek istiyorum.
Scott, CameraX özelliklerini anlattığın için teşekkürler.
Şimdi, akıllı kamera deneyimleri oluşturmak için cihaz üzerinde makine öğreniminden nasıl yararlanabileceğinize bakalım.
Cihaz üzerinde makine öğrenimi, iki ana alanda çok çeşitli kamera kullanım alanları sağlar.
İlk olarak, çekim öncesi aşaması vardır.
Burada, nesne algılama gibi işlemler için kamera önizlemenizi gerçek zamanlı olarak analiz edebilir veya önizlemenin kendisini iyileştirebilirsiniz.
İkincisi, çekim sonrasıdır.
Görüntüyü yakaladıktan sonra kalitesini iyileştirebilir veya görüntü için açıklama oluşturma gibi işlemler yapabilirsiniz.
Şimdi, kamera uygulamalarınız için sunduğumuz cihaz üzerinde makine öğrenimi çözümlerinden bazılarını inceleyelim.
Hakkında konuşacağımız ilk cihaz üzerinde ML kitaplığı, ML Kit'tir.
ML Kit, öncelikle görüntü ve doğal dil alanlarındaki yaygın sorunları (ör. metin tanıma, yüz algılama ve dil çevirisi) çözmek için geliştirilmiştir.
Geçen yıl ML Kit'i kullanıma sunduk.
ML Kit Vision API'lerine örnek olarak yüz örgüsü algılama, özne segmentasyonu ve gerçek zamanlı nesne algılama verilebilir.
Evet.
Geçen yıl üretken yapay zeka API'lerini kullanıma sunduk.
Bu API'ler, Gemini Nano'nun gücünden yararlanarak metin özetleme, görüntü açıklama ve daha birçok özellik sunar.
Prompt API'yi kullanarak resim açıklaması oluşturma örneğini aşağıda bulabilirsiniz.
Metin istemiyle birlikte resim bit eşlemini modele iletiyoruz. Sonuç açıklamasında, kaktüs benzeri bir tasarıma sahip küçük yeşil bir Android robotun siyah bir yüzeyde oturduğu yazıyor.
Tüm bunlar cihazda gerçekleşir.
Harika, değil mi?
Adobe Photoshop, uygulamasındaki kullanıcı deneyimini iyileştirmek için Prompt API'yi kullanıyor.
Kullanıcılar, öğeleri düzenlerken genellikle Photoshop uygulamasında birden fazla katmanı yönetmek zorunda kalır.
Uygulama, Prompt API'yi kullanarak düzensiz katmanları otomatik olarak yeniden adlandırabiliyor.
Uygulama, resimler için başlık ve hashtag oluşturmak amacıyla Prompt API'yi de kullanır. Bu, sosyal medyada paylaşım yapmak için oldukça kullanışlıdır.
Prompt API'yi kullanarak görüntü açıklaması için koda bakalım.
// 1. Initialize the on-device GenerativeModel client
val generativeModel = Generation.getClient()
// 2. Check whether Gemini Nano is available on the device
val status = generativeModel.checkStatus()
when (status) {
FeatureStatus.UNAVAILABLE -> {}
FeatureStatus.DOWNLOADABLE -> {}
FeatureStatus.DOWNLOADING -> {}
FeatureStatus.AVAILABLE -> {}
}Öncelikle bir generativeModel istemci nesnesine ihtiyacınız vardır. Ardından, Gemini Nano'nun cihazınızda kullanılabilir veya indirilebilir olup olmadığını kontrol edin.
Ardından, görüntünüzü ve yazılı istemi birleştirerek bir içerik isteği oluşturur. Son olarak, Gemini Nano'da çıkarım yapmak ve görüntü açıklamanızı almak için bu isteği generateContent çağrısına gönderir.
// 3. Build a multimodal request with the image and text prompt
val request = generateContentRequest(
ImagePart(bitmap),
TextPart("Describe this image in detail.")
) {}
// 4. Run inference on-device and get the description
val response = generativeModel.generateContent(request)
val description = response.candidates.first().textEvet, cihaz üzerinde ML kitaplıklarından bir diğeri MediaPipe.
MediaPipe, uygulamalarınız için çok çeşitli makine öğrenimi çözümleri sunar.
Yüz algılama, nesne tespit etme, görüntü segmentasyonu ve daha birçok farklı örneği denemek için MediaPipe web sitesini ziyaret edebilirsiniz.
Tüm bu kullanım alanları ML Kit'e çok benziyor. Peki hangi kitaplığı kullanmalısınız?
MediaPipe ve ML Kit benzer sorunları çözse de aralarında birkaç önemli fark vardır.
Birincisi platform desteğidir.
MediaPipe; Android, iOS, web ve Python'da çalışırken ML Kiti yalnızca Android ve iOS'e odaklanır.
Ayrıca MediaPipe, model özelleştirme olanağı sunarken ML Kiti, kullanıma hazır API'ler sağlar.
Son olarak, MediaPipe açık kaynaklı bir çözümken ML Kiti bir Google SDK'sıdır.
MediaPipe Vision API'leri kullanılarak yapılan hareket tanıma örneğini aşağıda bulabilirsiniz.
Bu API, kamera girişinden elle yapılan hareketleri gerçek zamanlı olarak algılar.
Örneğin, telefondan uzakta dururken basit elle yapılan hareketlerle kamera kaydını başlatmak veya durdurmak için kullanılabilir.
Koda göz atalım.
Bu nedenle, önce model yolunu, canlı yayın modunu ve sonuç işleyiciyi sağlayarak GestureRecognizerOptions nesnesini oluşturmanız gerekir.
// 1. Build GestureRecognizerOptions
val options = GestureRecognizerOptions.builder().setBaseOptions(
BaseOptions.builder().setModelAssetPath(MP_RECOGNIZER_TASK).build())
.setRunningMode(RunningMode.LIVE_STREAM)
.setResultListener { result, image -> /* Handle detected gesture */ }
.build()
// 2. Create the GestureRecognizer
val gestureRecognizer = GestureRecognizer.createFromOptions(context, options)
// 3. Convert CameraX ImageProxy to MediaPipe MPImage
val bitmap = rotateBitmap(imageProxy.toBitmap(),
imageProxy.imageInfo.rotationDegrees)
val mpImage = BitmapImageBuilder(bitmap).build()
// 4. Run gesture recognition on the image
gestureRecognizer.recognizeAsync(mpImage, frameTime)Ardından, seçeneklerden bir hareket tanıma nesnesi oluşturun.
Ardından CameraX ImageProxy nesnesini alıp bit eşleme dönüştürün ve bit eşlemi kullanarak MediaPipe mpImage nesnesi oluşturun.
Son olarak, hareketleri anlık olarak algılamak için MediaPipe mpImage nesnesini recognizeAsync çağrısına göndermeniz gerekir.
Sırada, Google Play Hizmetleri API'si aracılığıyla kullanılabilen cihaz üzerinde resim ve video iyileştirme özelliği var.
Bu model, çoğu premium cihazda ton eşleme, bulanıklık giderme ve Süper Çözünürlük gibi özellikler sunar.
Bu model kullanılarak ton eşlemesi ve ölçek büyütme işlemi uygulanmış bir resim örneğini aşağıda görebilirsiniz.
İyileştirilmiş resimde gökyüzü ve denizdeki daha zengin renkleri ve daha iyi keskinliği net bir şekilde görebilirsiniz.
Görüntü iyileştirme koduna bakalım.
// Step 1: Verify device support & install module
val enhancementClient = Enhancement.getClient(context)
suspend fun prepare(): Boolean {
if (!enhancementClient.isDeviceSupported().await()) return false
if (!enhancementClient.isModuleInstalled().await()) {
check(enhancementClient.installModule().await()) {
"Enhancement module install failed"
}
}
return true
}Öncelikle, temel cihazın bu özelliği destekleyip desteklemediğini sorgulamanız ve gerekirse geliştirme modülünü cihazınıza yüklemeniz gerekir.
Ardından, bit eşlemi ve tercih ettiğiniz geliştirmeleri belirterek EnhancementOptions nesnesini oluşturun.
// Step 2: Select Enhancement options & create session
val options = EnhancementOptions(
width = bitmap.width,
height = bitmap.height,
enhancementMode = EnhancementMode.BITMAP,
isTonemappingEnabled = true,
isDeblurAndDenoisePhotoEnabled = true,
isDeblurAndDenoiseVideoEnabled = false,
isUpscalePhotoEnabled = false,
isUpscaleVideoEnabled = false
)
val enhancementSession = enhancementClient
.createSessionAsync(options, enhancementExecutor)Ardından, Google Play Hizmetleri API'si ile bir istemci oturumu oluşturun, ardından sonuçta elde edilen bit eşleminizi işlemek için bir geri çağırma tanımlayın ve son olarak, resminizi iyileştirmek için bit eşlem ve seçeneklerle işleme işlevini çağırın.
// Step 3: Process Enhancement
val enhancedBitmap = suspendCancellableCoroutine { continuation ->
val enhancementCallback = object : EnhancementCallback {
override fun onBitmapProcessed(result: Bitmap) {
if (continuation.isActive) continuation.resume(result)
}
override fun onError(statusCode: Int) {
if (continuation.isActive) {
continuation.resumeWithException(
Exception("Bitmap processing failed: $statusCode")
)
}
}
override fun onSurfaceProcessed(timestamp: Long) {}
}
enhancementSession.process(bitmap, options, enhancementCallback)
}Kısa süre önce Video İyileştirme API'lerini Jetpack Media3'e entegre ettik.
Görsel ve video iyileştirme API'leri hakkında daha fazla bilgi edinmek için medya konuşmamızı inceleyebilirsiniz.
Ele alacağımız son cihaz üzerinde ML özelliği, Düşük Işık Geliştirme.
Düşük ışıkta çekim yapmak, akıllı telefon kullanıcılarının sık karşılaştığı bir sorundur.
Kullanıcıların loş ortamlarda fotoğraf çektiğini veya görüntülü görüşme yaptığını düşünün.
Düşük Işık Güçlendirmesi, kamera önizlemenizi gerçek zamanlı olarak aydınlatarak bu sorunu çözer.
Düşük Işık Güçlendirme'nin iki varyantı vardır: donanım ve yazılım.
Donanım sürümü, makine öğrenimini kullanmadan loş ışıklı kareleri iyileştirmek için OEM donanımını kullanır.
Yazılım sürümü ise kareleri iyileştirmek için cihaz üzerinde makine öğrenimi modeli kullanır.
CameraX'i, Google Zayıf Işık Güçlendirme olarak da bilinen Yazılımsal Zayıf Işık Güçlendirme ile nasıl entegre edebileceğimize kısaca göz atalım.
Google Zayıf Işık Güçlendirme için iki temel yüzey gerekir: İlk olarak, ham kamera kareleri için bir giriş yüzeyi ve iyileştirilmiş çıkış kareleri için bir çıkış hedef yüzeyi gerekir.
CameraX ile entegre etmek için Google Zayıf Işık Güçlendirme ardışık düzenini bir CameraEffect içine sarmalamanız yeterlidir.
CameraX, yüzey yaşam döngüsünü ve yönlendirmeyi sizin için otomatik olarak sorunsuz bir şekilde yönetir.
Son olarak, 2026'nın 4. çeyreğinde CameraX'te Düşük Işık Geliştirme efektini kullanıma sunacağız.
// Integrates SW Low Light Boost
val lowLightBoostEffect =
LowLightBoostEffect(
CameraEffect.PREVIEW or
CameraEffect.VIDEO_CAPTURE or
CameraEffect.IMAGE_CAPTURE
)
val sessionConfig = SessionConfig(
useCases = listOf(preview, imageCapture),
effects = lowLightBoostEffect
)
cameraProvider.bindToLifecycle(.. sessionConfig)Bu sayede, bir Düşük Işık Güçlendirme nesnesi oluşturup oturum yapılandırmanıza ekleyebilir, ardından oturum yapılandırmasını kamera yaşam döngünüze bağlayabilirsiniz. Bu özellik, desteklenen cihazlarda çalışır.
Böylece her iki bölümün de sonuna gelmiş bulunuyoruz.
Bugün ele aldığımız konuları kısaca özetleyelim.
Bugün, CameraX ve cihaz üzerinde makine öğrenimi ile cihazlar genelinde kamera deneyimlerinizi nasıl geliştirebileceğinizden bahsettik.
CameraXViewfinder ile kamera önizlemelerinizin farklı form faktörlerine uyum sağlamasını sağlayabilirsiniz.
Ardından, CameraX'in XR cihazlarda da çekim yapmanıza olanak tanıdığını gördük.
Ardından, Feature Group API, donanım özelliklerinin en uygun kombinasyonunu bulmanıza yardımcı olur.
Ayrıca, Görüntü Yakalama'daki yükseltmeleri inceledik ve ağır çekim videolar için Yüksek Hızlı Video Kaydı hakkında bilgi edindik.
Son olarak, eşzamanlı kamera önizlemesini dinamik olarak nasıl geliştireceğimizi öğrendik.
Ardından, akıllı görüntü deneyimleri oluşturmak için ML Kiti ve MediaPipe gibi cihaz üzerinde makine öğrenimi çözümlerinden bazılarını inceledik.
Son olarak, cihaz üzerinde görüntü ve video iyileştirme özelliğinin yanı sıra kamera önizlemenizi gerçek zamanlı olarak aydınlatmak için Düşük Işık Geliştirme özelliğini gördük.
Daha önce de belirttiğimiz gibi Camera1'i devre dışı bırakmayı planlıyoruz. Bu nedenle CameraX'e geçmenizi önemle tavsiye ederiz.
Bu geçişi desteklemek için kısa süre önce CameraX becerisini kullanıma sunduk.
Ayrıca size yol gösterecek bir geçiş rehberimiz ve kamera örnekleri depomuz da var.
Bugün ele aldığımız özelliklerle ilgili daha fazla kaynağa erişmek için bu bağlantıyı ziyaret edebilirsiniz.
Belgelere, bloga ve taşıma kaynaklarına bağlantılar tek bir yerde sunulur.
Bir saniye duraklayacağım.
Anladım.
Herkese teşekkürler.
Konuşmamızın sonuna geldik.
var surfaceRequest by remember {
mutableStateOf<SurfaceRequest?>(null)
}
LaunchedEffect(...) {
preview.setSurfaceProvider { surfaceRequest = it }
cameraProvider.bindToLifecycle(..., preview)
}
surfaceRequest?.let { request ->
CameraXViewfinder(
surfaceRequest = request,
contentScale = ContentScale.Fit
)
}CameraXViewfinder(
surfaceRequest = viewModel.surfaceRequest,
contentScale = ContentScale.Fit,
isTapToFocusEnabled = true,
isPinchToZoomEnabled = true,
onScreenFlashReady =
{
imageCapture.screenFlash = it
imageCapture.flashMode = FLASH_MODE_SCREEN
}
)// In a coroutine
val imageCapture = ImageCapture.Builder().build()
ProjectedContext.isProjectedDeviceConnected(activity, coroutineContext)
.collectLatest { isConnected ->
if (isConnected) {
val projectedContext = ProjectedContext.createProjectedDeviceContext(activity)
val cameraConfig = CameraXConfig.Builder.fromConfig(Camera2Config.defaultConfig())
.setRepeatingStreamForced(false)
.build()
val cameraProvider = LifecycleCameraProvider.createInstance(projectedContext, cameraConfig)
cameraProvider.bindToLifecycle(activity, DEFAULT_BACK_CAMERA, imageCapture)
}
}
// Shutter button clicked
imageCapture.takePicture(...)cameraProvider.bindToLifecycle(
lifecycleOwner,
cameraSelector,
SessionConfig(
useCases = listOf(preview, videoCapture),
// HDR_HLG10 > FPS_60 > Preview Stabilization.
preferredFeatureGroup =
listOf(HDR_HLG10, FPS_60, PREVIEW_STABILIZATION),
)
)// CameraX 1.6+ supports:
// 4K, video stabilization & Effect
val sessionConfig = SessionConfig(
useCases = listOf(preview, videoCapture),
requiredFeatureGroup =
setOf(UHD_RECORDING, VIDEO_STABILIZATION),
effects = listOf(overlayEffect)
)val cameraInfo = cameraProvider.getCameraInfo(cameraSelector,
ExtensionSessionConfig(ExtensionMode.NIGHT, extensionsManager))
val imageCapabilities = ImageCapture.getImageCaptureCapabilities(cameraInfo)
val imageCapture = ImageCapture.Builder().apply {
if (imageCapabilities.supportedOutputFormats
.contains(OUTPUT_FORMAT_JPEG_ULTRA_HDR)) {
setOutputFormat(OUTPUT_FORMAT_JPEG_ULTRA_HDR)
}
}.build()
val extensionSessionConfig = ExtensionSessionConfig(
ExtensionMode.NIGHT, extensionsManager, preview, imageCapture
)
cameraProvider.bindToLifecycle(..., extensionSessionConfig)val imageCapture = ImageCapture.Builder()
.setMotionPhotoMode(
ImageCapture.MOTION_PHOTO_MODE_ON,
customConfig
)
.build()
cameraProvider.bindToLifecycle(.. imageCapture)
imageCapture.takePicture(...)val recorder = Recorder.Builder().build()
val videoCapture = VideoCapture.withOutput(recorder)
val frameRateRange = cameraInfo.getSupportedFrameRateRanges(
HighSpeedVideoSessionConfig(videoCapture, preview)).first()
val sessionConfig = HighSpeedVideoSessionConfig(
videoCapture,
preview,
frameRateRange = frameRateRange,
isSlowMotionEnabled = true
)
cameraProvider.bindToLifecycle(
lifecycleOwner, cameraSelector, sessionConfig)
// Start recording slow motion videos.
val recording = recorder.prepareRecording(context, outputOption)
.start(executor, {})val concurrentCamera =
cameraProvider.bindToLifecycle(list(config1, config2))
// CameraX 1.7 features: rounded corner, border width & color
val pipSettings = CompositionSettings.Builder()
.setOffset(0.2f, 0.2f)
.setScale(0.35f, 0.35f)
.setRoundedCornerRatio(0.15f)
.setBorderWidthRatio(0.02f)
.setBorderColor(Color.WHITE)
.setZOrder(1)
.build()
// CameraX 1.7 features: dynamical composition update
concurrentCamera.setCompositionSettings(
listOf(mainSettings, pipSettings))// 1. Initialize the on-device GenerativeModel client
val generativeModel = Generation.getClient()
// 2. Check whether Gemini Nano is available on the device
val status = generativeModel.checkStatus()
when (status) {
FeatureStatus.UNAVAILABLE -> {}
FeatureStatus.DOWNLOADABLE -> {}
FeatureStatus.DOWNLOADING -> {}
FeatureStatus.AVAILABLE -> {}
}// 3. Build a multimodal request with the image and text prompt
val request = generateContentRequest(
ImagePart(bitmap),
TextPart("Describe this image in detail.")
) {}
// 4. Run inference on-device and get the description
val response = generativeModel.generateContent(request)
val description = response.candidates.first().text// 1. Build GestureRecognizerOptions
val options = GestureRecognizerOptions.builder().setBaseOptions(
BaseOptions.builder().setModelAssetPath(MP_RECOGNIZER_TASK).build())
.setRunningMode(RunningMode.LIVE_STREAM)
.setResultListener { result, image -> /* Handle detected gesture */ }
.build()
// 2. Create the GestureRecognizer
val gestureRecognizer = GestureRecognizer.createFromOptions(context, options)
// 3. Convert CameraX ImageProxy to MediaPipe MPImage
val bitmap = rotateBitmap(imageProxy.toBitmap(),
imageProxy.imageInfo.rotationDegrees)
val mpImage = BitmapImageBuilder(bitmap).build()
// 4. Run gesture recognition on the image
gestureRecognizer.recognizeAsync(mpImage, frameTime)// Step 1: Verify device support & install module
val enhancementClient = Enhancement.getClient(context)
suspend fun prepare(): Boolean {
if (!enhancementClient.isDeviceSupported().await()) return false
if (!enhancementClient.isModuleInstalled().await()) {
check(enhancementClient.installModule().await()) {
"Enhancement module install failed"
}
}
return true
}// Step 2: Select Enhancement options & create session
val options = EnhancementOptions(
width = bitmap.width,
height = bitmap.height,
enhancementMode = EnhancementMode.BITMAP,
isTonemappingEnabled = true,
isDeblurAndDenoisePhotoEnabled = true,
isDeblurAndDenoiseVideoEnabled = false,
isUpscalePhotoEnabled = false,
isUpscaleVideoEnabled = false
)
val enhancementSession = enhancementClient
.createSessionAsync(options, enhancementExecutor)// Step 3: Process Enhancement
val enhancedBitmap = suspendCancellableCoroutine { continuation ->
val enhancementCallback = object : EnhancementCallback {
override fun onBitmapProcessed(result: Bitmap) {
if (continuation.isActive) continuation.resume(result)
}
override fun onError(statusCode: Int) {
if (continuation.isActive) {
continuation.resumeWithException(
Exception("Bitmap processing failed: $statusCode")
)
}
}
override fun onSurfaceProcessed(timestamp: Long) {}
}
enhancementSession.process(bitmap, options, enhancementCallback)
}// Integrates SW Low Light Boost
val lowLightBoostEffect =
LowLightBoostEffect(
CameraEffect.PREVIEW or
CameraEffect.VIDEO_CAPTURE or
CameraEffect.IMAGE_CAPTURE
)
val sessionConfig = SessionConfig(
useCases = listOf(preview, imageCapture),
effects = lowLightBoostEffect
)
cameraProvider.bindToLifecycle(.. sessionConfig)