Nền tảng ứng dụng

Nâng cao trải nghiệm camera trên các thiết bị bằng CameraX và trí tuệ nhân tạo trên thiết bị

Loa

Giới thiệu

Giới thiệu về bài thuyết trình

Người dùng mong đợi các ứng dụng bên thứ ba chụp ảnh và quay video với độ chân thực cao như camera gốc của thiết bị, bất kể điều kiện ánh sáng hay cấp phần cứng. Để mang lại sự nhất quán này trên hệ sinh thái Android đang mở rộng, bạn cần cân nhắc một số yếu tố quan trọng về cấu trúc. Phiên này trình bày cách xây dựng quy trình ghi hình mạnh mẽ, chuyên nghiệp, giúp tối đa hoá khả năng của thiết bị trong khi vẫn đảm bảo độ tin cậy trên mọi kiểu dáng.

Chúng ta sẽ khám phá những điểm cải tiến mới nhất trong CameraX, hướng dẫn bạn cách tích hợp các khả năng tiên tiến như Ảnh chuyển động và tính năng Làm đẹp bằng AI trên thiết bị thông qua Dịch vụ Google Play, cùng với trải nghiệm không gian bằng SDK Jetpack XR. Chúng ta cũng sẽ xem xét kỹ năng CameraX, cho phép tác nhân lập trình mà bạn chọn tự động triển khai các khái niệm trong bài nói chuyện này và hơn thế nữa!

Tóm tắt

  • Jetpack CameraX là thư viện máy ảnh được đề xuất cho các ứng dụng Android vì Camera1 không còn được dùng nữa. Các biện pháp thực thi chính sách của Play sẽ bắt đầu vô hiệu hoá Camera1 vào năm tới trong Android 18.
  • CameraXViewfinder điều chỉnh bản xem trước của máy ảnh cho phù hợp với nhiều kiểu dáng, chẳng hạn như thiết bị có thể gập lại. Trong CameraX 1.7, thư viện này bổ sung các chế độ điều khiển bằng cử chỉ và hỗ trợ Đèn flash màn hình.
  • Kính âm thanh và hiển thị chạy các ứng dụng trên điện thoại lưu trữ, đồng thời hiển thị camera trên cả hai thiết bị. Việc truyền ProjectedDeviceContext cho phép CameraX chụp ảnh trực tiếp từ mắt kính.
  • Feature Group API giúp các ứng dụng chọn tổ hợp tính năng máy ảnh được hỗ trợ. Kể từ CameraX 1.6, thư viện này hỗ trợ kết hợp tính năng quay video 4K với tính năng Ổn định video.
  • Công nghệ học máy trên thiết bị phân tích bản xem trước của camera và nội dung nghe nhìn đã chụp thông qua Bộ công cụ học máy và MediaPipe. Nhà phát triển có thể chạy các tác vụ từ phát hiện cử chỉ theo thời gian thực đến mô tả hình ảnh tạo sinh.

Tài nguyên

Gemini Notebook

Chủ đề

  • camerax
  • android-camera
  • on-device-ml
  • gemini-nano
  • mediapipe
  • ml-kit
  • android-xr

Bản chép lời

Giới thiệu và tổng quan về CameraX

  • Chào các bạn!

  • Chào mừng bạn đến với phiên đào tạo của chúng tôi.

  • Tôi là Aman, và cùng tôi là Scott.

  • Hôm nay, chúng tôi rất vui được chia sẻ về cách bạn có thể nâng cao trải nghiệm camera trên các thiết bị bằng CameraX và trí tuệ nhân tạo trên thiết bị.

  • Hãy cùng bắt đầu nào.

  • Hãy nghĩ về cách bạn sử dụng điện thoại.

  • Chúng ta thường dùng camera điện thoại để ghi lại những khoảnh khắc và chia sẻ với những người thân yêu.

  • Máy ảnh đã trở thành yếu tố cốt lõi trong trải nghiệm dùng điện thoại thông minh.

  • Trên thực tế, camera tốt thường là yếu tố then chốt khi mua điện thoại thông minh.

  • Hôm nay, chúng ta sẽ đề cập đến hai chủ đề lớn để xây dựng trải nghiệm camera cao cấp.

  • Trước tiên, chúng ta sẽ tìm hiểu một số tính năng của CameraX, sau đó tìm hiểu một số kỹ thuật học máy trên thiết bị.

  • Hãy bắt đầu với CameraX.

  • Jetpack CameraX hỗ trợ trải nghiệm camera trên Android.

  • Ngoài CameraX, chúng tôi còn có Camera1 và Camera2, là một phần của khung nền tảng Android.

  • Vậy bạn nên sử dụng thư viện nào?

  • Camera1 là API máy ảnh ban đầu trên Android.

  • API này hiện không còn được dùng nữa, vì vậy, các ứng dụng mới nên sử dụng Camera2 hoặc CameraX.

  • Camera2 kế thừa Camera1.

  • Vì vậy, nếu bạn cần quyền kiểm soát máy ảnh cấp thấp cho các trường hợp sử dụng phức tạp, thì Camera2 là một lựa chọn phù hợp.

  • Tuy nhiên, bạn phải tự xử lý các cấu hình dành riêng cho thiết bị.

  • Cuối cùng, Jetpack CameraX được xây dựng dựa trên Camera2.

  • Thư viện này cung cấp một API nhất quán và tự động xử lý các cấu hình dành riêng cho thiết bị.

  • Đây là lựa chọn nên dùng cho hầu hết các nhà phát triển.

  • Chúng tôi có một lưu ý rất quan trọng.

  • Chúng tôi dự định tắt Camera1 và việc này sẽ bắt đầu bằng việc thực thi chính sách của Play vào năm tới trong Android 18.

  • Nếu vẫn đang sử dụng API Camera1 cũ, bạn sẽ cần di chuyển sang CameraX hoặc Camera2.

  • Vậy tại sao bạn nên sử dụng CameraX?

  • Thứ nhất, thư viện này hỗ trợ Android 7 trở lên, do đó tương thích với gần 99% thiết bị Android đang hoạt động.

  • Thứ hai, thư viện này dễ sử dụng và cung cấp các API đơn giản cho các trường hợp sử dụng phổ biến như xem trước, chụp và quay bằng ít mã hơn.

  • Thứ ba, thư viện này mang lại trải nghiệm nhất quán trên các thiết bị bằng cách giảm thiểu các vấn đề dành riêng cho thiết bị, chẳng hạn như kéo giãn bản xem trước, vốn khá phổ biến trên thiết bị có thể gập lại và máy tính bảng.

  • Cuối cùng, thư viện này giúp đơn giản hoá việc triển khai các tính năng nâng cao của OEM, chẳng hạn như chế độ ban đêm và chế độ chân dung.

  • Bây giờ, tôi xin mời Scott nói về một số tính năng của CameraX.

  • Xin mời Scott.

  • Cảm ơn Aman.

  • Chào các bạn!

  • Tôi là Scott.

  • Hôm nay, chúng ta sẽ tìm hiểu một số tính năng của CameraX để giúp bạn xây dựng trải nghiệm camera chuyên nghiệp.

Các tính năng của Kính ngắm thích ứng

  • Đầu tiên là tính năng Khung ngắm thích ứng.

  • Thư viện này được thiết kế để loại bỏ hoàn toàn những khó khăn khi xử lý bản xem trước trên nhiều kiểu dáng và kích thước màn hình.

  • Người dùng hiện có nhiều loại thiết bị, bao gồm cả thiết bị gập, điện thoại, máy tính xách tay và thiết bị XR.

  • Vì vậy, việc xây dựng trải nghiệm camera phù hợp với các kiểu dáng mới là điều quan trọng hơn bao giờ hết.

  • Và bản xem trước của máy ảnh nổi tiếng là khó thực hiện đúng, đặc biệt là trên màn hình rộng có thể gập lại.

  • Trên các thiết bị này, khi mở ra, camera bên trong được gắn theo chiều ngang, còn camera sau được gắn theo chiều dọc.

  • Vì vậy, nếu giả định rằng tất cả cảm biến máy ảnh đều được gắn theo chiều dọc, thì bạn sẽ gặp phải tình trạng không khớp về không gian và gây ra hiện tượng méo hình hoặc lệch sang một bên.

  • Và CameraXViewfinder được thiết kế để xử lý hoàn toàn sự phức tạp cho bạn, nhờ đó đảm bảo bản xem trước của camera hoạt động liền mạch trên mọi kiểu dáng.

  • Hãy xem cách sử dụng thành phần kết hợp CameraXViewfinder.

    var surfaceRequest by remember {
        mutableStateOf<SurfaceRequest?>(null)
    }
    
    LaunchedEffect(...) {
        preview.setSurfaceProvider { surfaceRequest = it }
        cameraProvider.bindToLifecycle(..., preview)
    }
    
    surfaceRequest?.let { request ->
        CameraXViewfinder(
            surfaceRequest = request,
            contentScale = ContentScale.Fit
        )
    }
  • Trước tiên, bạn khai báo biến nội dung surfaceRequest để lưu giữ yêu cầu về giao diện.

  • Rất tiếc.

  • Và thứ hai, trong LaunchedEffect, bạn đặt trình cung cấp nền tảng để nhận đối tượng yêu cầu nền tảng đó.

  • Sau đó, bạn liên kết với vòng đời rồi khởi động camera.

  • Cuối cùng, bất cứ khi nào trạng thái cập nhật bằng một yêu cầu về nền tảng hợp lệ và kích hoạt quá trình kết hợp lại, bạn sẽ đặt yêu cầu trực tiếp vào CameraXViewfinder.

  • Tại đây, bạn có thể đặt contentScale thành vừa vặn hoặc cắt, tuỳ theo lựa chọn ưu tiên của bạn.

  • Vậy là xong, bạn đã hoàn tất.

  • Trong CameraX 1.7, chúng tôi đã thêm một số tính năng mới vào CameraXViewfinder.

  • Điều này bao gồm cả cử chỉ mới như nhấn để lấy nét hoặc chụm để thu phóng.

  • Tính năng này cũng hỗ trợ Đèn flash màn hình, cho phép bạn dùng màn hình để làm sáng ảnh chân dung tự chụp.

  • Việc triển khai tính năng này rất dễ dàng.

    CameraXViewfinder(
        surfaceRequest = viewModel.surfaceRequest,
        contentScale = ContentScale.Fit,
        isTapToFocusEnabled = true,
        isPinchToZoomEnabled = true,
        onScreenFlashReady =
            {
               imageCapture.screenFlash = it
               imageCapture.flashMode = FLASH_MODE_SCREEN
            }
    )
  • Bạn chỉ cần bật tính năng nhấn để lấy nét và chụm để thu phóng thành true.

  • Đối với Đèn flash của màn hình, bạn sẽ nhận được thực thể Đèn flash của màn hình từ lệnh gọi lại onScreenFlashReady, sau đó truyền đến ImageCapture và đặt chế độ đèn flash thành FLASH_MODE_SCREEN.

  • Chỉ vậy thôi.

Chụp ảnh bằng camera trên Android XR

  • Chúng ta đã thấy cách CameraX hỗ trợ tính năng Xem trước của camera hoạt động liền mạch trên mọi kiểu dáng.

  • Giờ hãy tiến thêm một bước với tính năng chụp ảnh bằng camera trên Android XR.

  • Có 3 loại thiết bị XR: đầu tiên là kính XR.

  • Đây là những chiếc kính thực tế ảo hoàn toàn khép kín và sống động, sử dụng camera để ghi lại thế giới thực và hiển thị bên trong kính.

  • Và thứ hai là Kính thông minh XR có dây.

  • Hôm nay, chúng tôi đã công bố XREAL Aura trong bài phát biểu chính về danh mục này.

  • Như bạn có thể thấy trong bài phát biểu chính, đây là kính nhìn xuyên thấu được kết nối với thiết bị điện toán và cho phép bạn xem nội dung ảo phủ lên thế giới thực.

  • Và thứ ba là Kính phát âm thanh và Kính có màn hình.

  • Đây là kính nhẹ.

  • Các thiết bị này có thể kết hợp âm thanh, camera và màn hình để mang đến trải nghiệm rảnh tay và dễ quan sát.

  • Hai danh mục đầu tiên là thiết bị đeo đầu XR và kính thông minh XR có dây cũng hỗ trợ Camera2 và CameraX, giống như điện thoại thông thường.

  • Vì vậy, hôm nay chúng ta sẽ chỉ tập trung vào kính phát âm thanh và kính có màn hình.

  • Trên chiếc kính này, các ứng dụng chạy trên điện thoại Android, điện thoại Android lưu trữ, thay vì kính, nhưng ở đây có quyền truy cập vào cả camera của điện thoại và camera của kính.

  • Câu hỏi then chốt là làm thế nào để bạn biết mình đang nói chuyện với camera nào?

  • Thật đơn giản.

  • Với Context tiêu chuẩn, CameraX sẽ truy cập vào camera của điện thoại.

  • Và với ProjectedDeviceContext, CameraX sẽ truy cập vào camera của kính.

  • Vì vậy, Context khác nhau sẽ dẫn đến camera mục tiêu khác nhau.

  • Và hãy nhớ rằng quyền sử dụng camera và quyền sử dụng kính là riêng biệt.

  • Quyền truy cập vào điện thoại và kính là riêng biệt, vì vậy, bạn cần yêu cầu quyền truy cập vào kính riêng.

  • Lựa chọn khác là bạn cũng có thể sử dụng Hoạt động được chiếu, cũng chạy trên thiết bị Android lưu trữ, nhưng giao diện người dùng của bạn được chiếu lên kính.

  • Và đây là lúc quy tắc thay đổi.

  • Nếu đang dùng Context tiêu chuẩn, bạn sẽ truy cập vào camera của kính.

  • Nếu muốn truy cập vào camera của điện thoại, bạn cần sử dụng HostContext.

  • Hãy cùng xem mã để biết cách chụp ảnh bằng camera của kính.

    // 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(...)
  • Trước tiên, bạn gọi isProjectedDeviceConnected để xem kính có được kết nối hay không.

  • Sau đó, bạn gọi createProjectedDeviceContext để nhận projectedContext.

  • Thứ hai, tại đây, bạn sử dụng LifecycleCameraProvider để khởi chạy CameraX thay vì ProcessCameraProvider.

  • Vì vậy, ProcessCameraProvider là một singleton mà bạn không thể thay đổi Context sau khi khởi chạy.

  • Vì vậy, việc sử dụng LifecycleCameraProvider cho phép bạn thay đổi Context bất cứ khi nào bạn muốn.

  • Tiếp theo, bạn cần tắt luồng lặp lại bổ sung trong CameraX.

  • Điều này là cần thiết vì kính hiện nay chỉ hỗ trợ một luồng.

  • API này hiện là API nội bộ, nhưng chúng tôi sẽ sớm công khai.

  • Chỉ vậy thôi.

  • Từ đây, bạn có thể dùng CameraX tiêu chuẩn, chỉ cần liên kết ImageCapture là bạn có thể chụp ảnh qua kính.

Tính năng và API chụp ảnh/quay video

  • Được rồi.

  • Tiếp theo, hãy xem cách CameraX giúp bạn tìm thấy tổ hợp tính năng hoạt động cùng nhau và khai thác tối đa thiết bị.

  • Các ứng dụng máy ảnh hiện đại được xác định bằng các tính năng mạnh mẽ và người dùng mong đợi máy ảnh đó hỗ trợ các tính năng như HDR, 60 khung hình/giây và Ổn định bản xem trước, tất cả cùng một lúc.

  • Tuy nhiên, với tư cách là nhà phát triển, chúng tôi biết rằng việc kết hợp các tính năng này không phải lúc nào cũng dễ dàng.

  • Việc kiểm tra khả năng hỗ trợ của từng tính năng không đảm bảo rằng các tính năng đó sẽ hoạt động cùng nhau.

  • Và sự không chắc chắn này đã buộc nhà phát triển phải thận trọng và hạn chế những gì người dùng có thể trải nghiệm trên các thiết bị có khả năng.

  • Để giải quyết vấn đề này, chúng tôi đã ra mắt Feature Group API, được hỗ trợ bởi khung truy vấn kết hợp tính năng Camera2.

  • Có hai cách để sử dụng: thứ nhất, dùng requiredFeatureGroup để kiểm tra và bật tổ hợp tính năng khi được hỗ trợ.

  • Thứ hai, bạn có thể cung cấp mức độ ưu tiên của tính năng theo preferredFeatureGroup, sau đó CameraX sẽ chọn tổ hợp được hỗ trợ tốt nhất cho bạn.

  • Sau đây là ví dụ.

  • Ở bên phải, bên trái, xin lỗi, không bật tính năng nào, chỉ là một chiếc điện thoại thông thường, ghi âm thông thường.

  • Ở bên trái, chúng tôi bật đồng thời HDR, 60 khung hình/giây và tính năng Ổn định bản xem trước.

  • Và bạn có thể thấy chất lượng video được cải thiện đáng kể, sáng hơn, mượt mà hơn và không bị rung.

  • Hãy cùng xem mã.

    cameraProvider.bindToLifecycle(
        lifecycleOwner,
        cameraSelector,
        SessionConfig(
            useCases = listOf(preview, videoCapture),
            // HDR_HLG10 > FPS_60 > Preview Stabilization.
            preferredFeatureGroup =
               listOf(HDR_HLG10, FPS_60, PREVIEW_STABILIZATION),
        )
    )
  • Vì vậy, ở đây chúng ta sử dụng preferredFeatureGroup để cung cấp danh sách ưu tiên về tính năng, đó là HDR, sau đó là 60 khung hình/giây, rồi đến tính năng Ổn định bản xem trước.

  • CameraX sẽ kiểm tra tổ hợp và chọn ra tổ hợp phù hợp nhất mà thiết bị hỗ trợ.

  • Với CameraX 1.6 trở lên, chúng tôi sẽ thêm tính năng Quay video 4K và Ổn định video ngay vào Feature Group API.

    // CameraX 1.6+ supports:
    // 4K, video stabilization & Effect
    val sessionConfig = SessionConfig(
       useCases = listOf(preview, videoCapture),
       requiredFeatureGroup =
         setOf(UHD_RECORDING, VIDEO_STABILIZATION),
       effects = listOf(overlayEffect)
    )
  • Nhiều thiết bị cao cấp hỗ trợ kết hợp độ phân giải 4K và tính năng Ổn định video.

  • Giờ đây, nhờ Feature Group API, bạn có thể tự tin bật các tính năng này cùng nhau.

  • Ngoài ra, giờ đây, bạn có thể linh hoạt áp dụng hiệu ứng theo thời gian thực bằng Feature Group API, điều mà trước đây không thể thực hiện được.

  • Bây giờ, hãy cùng tìm hiểu cách chụp ảnh chất lượng cao trong CameraX.

  • CameraX hiện hỗ trợ chụp ảnh RAW DNG.

  • Tính năng này cho phép bạn truy cập vào ảnh RAW chưa qua xử lý, chưa nén trực tiếp từ cảm biến máy ảnh để chỉnh sửa chuyên nghiệp.

  • Tiếp theo, chúng tôi đã cải thiện tiện ích Chế độ ban đêm.

  • Tiện ích này cho phép chụp ảnh sáng và rõ nét trong điều kiện ánh sáng yếu mà không cần dùng đèn flash.

  • Chúng tôi cũng đã ra mắt API chỉ báo chế độ ban đêm mới.

  • API này sẽ theo dõi thời điểm môi trường hiện tại tối và phù hợp với Chế độ ban đêm, đồng thời bạn có thể sử dụng API này để hiển thị chỉ báo Chế độ ban đêm.

  • Giờ đây, các tiện ích CameraX cũng hỗ trợ Ultra HDR.

  • Điều này mang lại dải động rộng hơn và màu sắc rực rỡ hơn cho Chế độ ban đêm. Chế độ ban đêm có Ultra HDR hiện được hỗ trợ trên nhiều thiết bị cao cấp gần đây.

  • Bạn có thể thấy sự khác biệt giữa ảnh chụp ở chế độ thường, chế độ ban đêm và Chế độ ban đêm có Ultra HDR.

  • Hãy xem cách triển khai tính năng này.

    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)
  • Trước tiên, bạn tạo một ExtensionSessionConfig cho Chế độ ban đêm và sử dụng chế độ này để lấy thực thể CameraInfo.

  • Tiếp theo, bạn sử dụng CameraInfo để lấy chức năng chụp ảnh, sau đó truy vấn xem Ultra HDR có được hỗ trợ hay không.

  • Sau đó, bạn đặt định dạng đầu ra thành Ultra HDR.

  • Cuối cùng, bạn tạo lại ExtensionSessionConfig bằng các trường hợp sử dụng và liên kết với vòng đời.

  • Giờ đây, bạn đã sẵn sàng chụp ảnh Ultra HDR ở Chế độ ban đêm.

  • Chúng tôi cũng hỗ trợ Ảnh chuyển động cho CameraX.

  • Ảnh chuyển động ghi lại âm thanh và chuyển động xung quanh ảnh, lưu giữ khoảnh khắc chứ không chỉ là một hình ảnh tĩnh.

  • Chúng tôi chuẩn hoá định dạng này trên nhiều loại điện thoại và thiết bị Android, đồng thời giúp việc hỗ trợ Ảnh chuyển động trở nên dễ dàng hơn.

  • Tính năng Ảnh chuyển động sẽ có trong CameraX vào quý 1 năm 2027.

  • Sau khi tính năng này được cung cấp, bạn chỉ cần đặt chế độ Ảnh chuyển động trong ImageCapture.Builder là có thể bắt đầu chụp Ảnh chuyển động.

    val imageCapture = ImageCapture.Builder()
            .setMotionPhotoMode(
                 ImageCapture.MOTION_PHOTO_MODE_ON,
                 customConfig
             )
            .build()
    
    cameraProvider.bindToLifecycle(.. imageCapture)
    imageCapture.takePicture(...)
  • Tiếp theo, hãy cùng tìm hiểu cách CameraX hỗ trợ quay video tốc độ cao.

  • Ghi lại hành động chuyển động nhanh một cách rõ ràng là một tính năng thiết yếu của các ứng dụng camera hiện đại.

  • Tính năng này đặc biệt hữu ích cho các tình huống có nhịp độ nhanh như thể thao.

  • Để làm được điều này, bạn cần quay ở tốc độ cao, 120 hoặc 240 khung hình/giây.

  • Có hai cách để sử dụng công cụ này.

  • Trước tiên, hãy mã hoá ở cùng tốc độ khung hình, sau đó bạn sẽ tạo được một video có tốc độ khung hình cao thực sự.

  • Lựa chọn khác là mã hoá video ở tốc độ 30 khung hình/giây để tạo video chuyển động chậm sẵn sàng phát.

  • Ví dụ: một giây được ghi ở tốc độ 120 khung hình/giây sẽ mất bốn giây để phát ở tốc độ 30 khung hình/giây.

  • Vì vậy, khoảng thời gian này tạo ra hiệu ứng chuyển động chậm.

  • Để triển khai tính năng ghi hình tốc độ cao, bạn cần tạo một HighSpeedVideoSessionConfig bằng videoCapture.

    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, {})
  • Sau đó, bạn đặt isSlowMotionEnabled thành true để mã hoá video ở tốc độ 30 khung hình/giây nhằm tạo video chuyển động chậm hoặc đặt thành false để tạo video có tốc độ khung hình cao.

  • Khi bạn bật chế độ quay chậm, Google Photos sẽ tự động nhận dạng và thêm huy hiệu quay chậm vào hình thu nhỏ.

  • Hãy cùng xem cách hoạt động của tính năng này trong Google Photos.

  • Ở đây, hiệu ứng chuyển động chậm tạo ra hiệu ứng ấn tượng cho chú mèo.

  • Con mèo của tôi không bao giờ muốn tôi chạm vào nó.

  • Rất tiếc.

  • Cuối cùng, hãy cùng tìm hiểu một số điểm cải tiến trong API đồng thời của chúng tôi, API Máy ảnh đồng thời.

  • API đồng thời cho phép ứng dụng của bạn truyền phát đồng thời từ camera trước và sau.

  • Năm nay, chúng tôi đã cải tiến một số điểm cho Concurrent Camera API.

  • Bạn có thể cập nhật linh động bố cục camera sau khi liên kết với vòng đời và mở camera.

  • Vì vậy, việc này bao gồm cả việc thay đổi vị trí, kích thước và thứ tự kết xuất.

  • Bạn cũng có thể thêm các kiểu như góc bo tròn, độ rộng đường viền và màu đường viền.

  • Và đây là cách thực hiện: chỉ cần sử dụng CompositionSettings để định cấu hình kiểu như góc bo tròn, độ rộng đường viền và màu sắc, đồng thời sử dụng setZOrder để điều chỉnh thứ tự hiển thị.

    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))
  • Tiếp theo, bạn chỉ cần gọi setCompositionSettings trên camera đồng thời đang hoạt động để cập nhật thành phần một cách linh động.

  • Chỉ vậy thôi.

  • Bạn có thể cập nhật cấu trúc một cách linh động.

  • Được rồi.

  • Giờ thì chúng ta đã tìm hiểu xong tất cả các tính năng.

  • Chúng tôi có một lưu ý quan trọng ở đây, vì vậy, bạn nên nâng cấp lên CameraX 1.6 trở lên.

  • Những thay đổi này có thể tránh được sự cố trên các thiết bị sắp ra mắt hỗ trợ định dạng mới, Eclipsa Video, đồng thời đảm bảo tiện ích CameraX của bạn tiếp tục hoạt động trong bản cập nhật Pixel trong tương lai.

  • Như vậy là chúng ta đã hoàn thành buổi đầu tiên.

  • Chúng tôi đã giới thiệu các tính năng của CameraX giúp bạn xây dựng trải nghiệm máy ảnh chuyên nghiệp. Giờ đây, tôi muốn mời Aman trình bày phiên tiếp theo về AI trên thiết bị.

Công nghệ học máy trên thiết bị

  • Cảm ơn Scott đã hướng dẫn chúng tôi về các tính năng của CameraX.

  • Bây giờ, hãy cùng tìm hiểu cách bạn có thể tận dụng công nghệ Học máy trên thiết bị để xây dựng trải nghiệm camera thông minh.

  • Công nghệ học máy trên thiết bị hỗ trợ nhiều trường hợp sử dụng camera trong hai lĩnh vực chính.

  • Đầu tiên là giai đoạn trước khi chụp.

  • Tại đây, bạn có thể phân tích bản xem trước của camera theo thời gian thực để thực hiện những việc như phát hiện đối tượng hoặc bạn có thể cải thiện chính bản xem trước đó.

  • Thứ hai là sau khi chụp.

  • Sau khi chụp ảnh, bạn có thể nâng cao chất lượng ảnh hoặc làm những việc như tạo nội dung mô tả cho ảnh.

  • Bây giờ, hãy cùng tìm hiểu một số giải pháp học máy trên thiết bị mà chúng tôi cung cấp cho ứng dụng máy ảnh của bạn.

  • Thư viện học máy trên thiết bị đầu tiên mà chúng ta sẽ nói đến là Bộ công cụ học máy.

  • Bộ công cụ học máy chủ yếu được xây dựng để giải quyết các vấn đề thường gặp trong lĩnh vực thị giác và ngôn ngữ tự nhiên, chẳng hạn như nhận dạng văn bản, phát hiện khuôn mặt và dịch ngôn ngữ.

  • Năm ngoái, chúng tôi đã giới thiệu Bộ công cụ học máy.

  • Sau đây là một số ví dụ về API thị giác của Bộ công cụ học máy, chẳng hạn như phát hiện lưới khuôn mặt, phân đoạn chủ thể và phát hiện đối tượng theo thời gian thực.

  • Có.

  • Năm ngoái, chúng tôi đã ra mắt các API AI tạo sinh.

  • Các API này khai thác sức mạnh của Gemini Nano để hỗ trợ các tính năng như tóm tắt văn bản, mô tả hình ảnh và nhiều tính năng khác.

  • Dưới đây là ví dụ về nội dung mô tả hình ảnh bằng Prompt API.

  • Chúng tôi truyền bitmap hình ảnh cùng với câu lệnh văn bản đến mô hình và nội dung mô tả kết quả là một rô-bốt Android nhỏ màu xanh lục có thiết kế giống cây xương rồng đang ngồi trên một bề mặt màu đen.

  • Và tất cả những điều này đều diễn ra trên thiết bị.

  • Thật tuyệt phải không?

  • Adobe Photoshop đã và đang sử dụng Prompt API để cải thiện trải nghiệm người dùng trong ứng dụng của họ.

  • Khi chỉnh sửa thành phần, người dùng thường phải quản lý nhiều lớp trong ứng dụng Photoshop.

  • Nhờ sử dụng Prompt API, giờ đây, ứng dụng có thể tự động đổi tên các lớp chưa được sắp xếp.

  • Ứng dụng này cũng sử dụng Prompt API để tạo chú thích và hashtag cho hình ảnh, một tính năng rất hữu ích khi chia sẻ trên mạng xã hội.

  • Hãy xem mã mô tả hình ảnh bằng Prompt API.

    // 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 -> {}
    }
  • Trước tiên, bạn cần có một đối tượng ứng dụng generativeModel, sau đó kiểm tra xem Gemini Nano có sẵn hoặc có thể tải xuống trên thiết bị của bạn hay không.

  • Tiếp theo, hãy tạo một yêu cầu nội dung bằng cách kết hợp hình ảnh và câu lệnh văn bản, rồi cuối cùng cung cấp yêu cầu này cho lệnh gọi generateContent để chạy suy luận trên Gemini Nano và nhận nội dung mô tả hình ảnh.

    // 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
  • Đúng vậy, thư viện học máy trên thiết bị tiếp theo mà chúng ta có là MediaPipe.

  • MediaPipe cung cấp nhiều giải pháp học máy cho các ứng dụng của bạn.

  • Bạn có thể nhanh chóng truy cập vào trang web MediaPipe để thử nhiều mẫu khác nhau như phát hiện khuôn mặt, phát hiện đối tượng, phân đoạn hình ảnh, v.v.

  • Tất cả các trường hợp sử dụng này đều rất giống với Bộ công cụ học máy, vậy bạn nên sử dụng thư viện nào?

  • Mặc dù MediaPipe và Bộ công cụ học máy giải quyết các vấn đề tương tự nhau, nhưng có một số điểm khác biệt chính.

  • Đầu tiên là khả năng hỗ trợ nền tảng.

  • MediaPipe hoạt động trên Android, iOS, Web và Python, trong khi Bộ công cụ học máy chỉ tập trung vào Android và iOS.

  • Tiếp theo, MediaPipe cung cấp tính năng tuỳ chỉnh mô hình, trong khi Bộ công cụ học máy cung cấp các API có thể sử dụng ngay.

  • Cuối cùng, mặc dù MediaPipe là nguồn mở, nhưng Bộ công cụ học máy là một SDK của Google.

  • Dưới đây là ví dụ về tính năng nhận dạng cử chỉ bằng API MediaPipe Vision.

  • API này phát hiện cử chỉ tay theo thời gian thực từ dữ liệu đầu vào của camera.

  • Ví dụ: bạn có thể dùng tính năng này để bắt đầu hoặc dừng quay video bằng camera thông qua các cử chỉ tay đơn giản khi đứng cách xa điện thoại.

  • Hãy xem mã.

  • Vì vậy, trước tiên, bạn cần tạo đối tượng GestureRecognizerOptions, cung cấp đường dẫn mô hình, chế độ phát trực tiếp và trình nghe kết quả.

    // 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)
  • Sau đó, hãy tạo một đối tượng nhận dạng cử chỉ từ các tuỳ chọn.

  • Tiếp theo, hãy lấy ImageProxy của CameraX và chuyển đổi thành bitmap, sau đó sử dụng bitmap để tạo đối tượng mpImage của MediaPipe.

  • Cuối cùng, bạn cần cung cấp đối tượng MediaPipe mpImage cho lệnh gọi recognizeAsync để phát hiện cử chỉ theo thời gian thực.

Cải tiến hình ảnh và video

  • Tiếp theo, chúng ta có tính năng Nâng cao hình ảnh và video trên thiết bị thông qua API Dịch vụ Google Play.

  • Mô hình này cung cấp các khả năng như ánh xạ tông màu, xoá mờ và Siêu phân giải trên hầu hết các thiết bị cao cấp.

  • Dưới đây là ví dụ về một hình ảnh được ánh xạ tông màu và nâng cấp bằng mô hình này.

  • Bạn có thể thấy rõ màu sắc phong phú hơn trên bầu trời và biển, cũng như độ sắc nét được cải thiện trong hình ảnh đã nâng cao.

  • Hãy xem mã cho tính năng Cải thiện hình ảnh.

    // 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
    }
  • Trước tiên, bạn cần truy vấn xem thiết bị cơ bản có hỗ trợ tính năng này hay không và nếu cần, bạn phải cài đặt mô-đun nâng cao trên thiết bị.

  • Tiếp theo, hãy tạo đối tượng EnhancementOptions bằng cách chỉ định bitmap và các tính năng nâng cao mà bạn muốn chọn.

    // 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)
  • Tiếp theo, hãy tạo một phiên máy khách bằng API Dịch vụ Google Play, sau đó xác định một lệnh gọi lại để xử lý bitmap thu được, cuối cùng là gọi hàm xử lý bằng bitmap và các tuỳ chọn để nâng cao hình ảnh.

    // 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)
    }
  • Gần đây, chúng tôi đã tích hợp các API Cải tiến video vào Jetpack Media3.

  • Bạn có thể xem bài nói chuyện của chúng tôi về nội dung nghe nhìn để tìm hiểu thêm về API Cải thiện hình ảnh và video.

  • Tính năng cuối cùng về công nghệ học máy trên thiết bị mà chúng ta sẽ tìm hiểu là tính năng Cải thiện ánh sáng yếu.

  • Chụp ảnh trong điều kiện thiếu sáng là một vấn đề thường gặp đối với người dùng điện thoại thông minh.

  • Hãy nghĩ đến trường hợp người dùng chụp ảnh hoặc gọi video trong môi trường thiếu sáng.

  • Tính năng Tăng cường ánh sáng yếu giải quyết vấn đề này bằng cách làm sáng bản xem trước của camera theo thời gian thực.

  • Tính năng Cải thiện ánh sáng yếu có hai biến thể: phần cứng và phần mềm.

  • Phiên bản phần cứng sử dụng phần cứng của nhà sản xuất thiết bị gốc (OEM) để cải thiện các khung hình thiếu sáng mà không cần dùng công nghệ học máy.

  • Ngược lại, phiên bản phần mềm sử dụng mô hình Học máy trên thiết bị để cải thiện khung hình.

  • Hãy cùng tìm hiểu nhanh cách tích hợp CameraX với tính năng Cải thiện ánh sáng yếu bằng phần mềm (còn gọi là tính năng Cải thiện ánh sáng yếu của Google).

  • Tính năng Tăng cường ánh sáng yếu của Google cần có hai nền tảng chính: trước tiên, bạn cần có một nền tảng đầu vào cho các khung hình thô của camera và một nền tảng đầu ra cho các khung hình đầu ra được tăng cường.

  • Để tích hợp với CameraX, bạn chỉ cần gói quy trình Tăng cường ánh sáng yếu của Google vào một CameraEffect.

  • CameraX tự động xử lý vòng đời của nền tảng và định tuyến một cách liền mạch cho bạn.

  • Cuối cùng, chúng tôi sẽ ra mắt Hiệu ứng cải thiện ánh sáng yếu trong CameraX vào quý 4 năm 2026.

    // 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)
  • Nhờ đó, bạn có thể tạo một đối tượng Tăng cường ánh sáng yếu và thêm đối tượng đó vào cấu hình phiên, sau đó liên kết cấu hình phiên với vòng đời của camera. Tính năng này sẽ hoạt động trên các thiết bị được hỗ trợ.

Tóm tắt và di chuyển

  • Đến đây là kết thúc cả hai phần.

  • Hãy cùng tóm tắt nhanh tất cả những nội dung chúng ta đã tìm hiểu hôm nay.

  • Hôm nay, chúng ta đã thảo luận về cách bạn có thể nâng cao trải nghiệm camera trên các thiết bị bằng CameraX và công nghệ học máy trên thiết bị.

  • Trước tiên, với CameraXViewfinder, bạn có thể bật bản xem trước của camera để điều chỉnh cho phù hợp với nhiều kiểu dáng.

  • Tiếp theo, chúng ta thấy rằng CameraX cũng cho phép bạn chụp ảnh trên thiết bị XR.

  • Sau đó, Feature Group API sẽ giúp bạn tìm ra cách kết hợp tối ưu các tính năng phần cứng.

  • Chúng ta cũng đã tìm hiểu về các bản nâng cấp cho tính năng Chụp ảnh và tìm hiểu về tính năng Quay video tốc độ cao cho video chuyển động chậm.

  • Cuối cùng, chúng ta đã tìm hiểu cách cải thiện bản xem trước của Camera đồng thời một cách linh hoạt.

  • Tiếp theo, chúng ta đã tìm hiểu một số giải pháp học máy trên thiết bị như Bộ công cụ học máy và MediaPipe để xây dựng trải nghiệm thị giác thông minh.

  • Cuối cùng, chúng ta đã thấy tính năng Cải thiện hình ảnh và cải tiến video trên thiết bị cùng với tính năng Tăng cường ánh sáng yếu để làm sáng bản xem trước của camera theo thời gian thực.

  • Như đã đề cập trước đó, chúng tôi dự định tắt Camera1, vì vậy, bạn nên chuyển sang CameraX.

  • Để hỗ trợ quá trình di chuyển này, gần đây chúng tôi đã ra mắt kỹ năng CameraX.

  • Chúng tôi cũng có hướng dẫn di chuyển và kho lưu trữ mẫu máy ảnh để hướng dẫn bạn.

  • Bạn có thể truy cập vào đường liên kết này để xem thêm tài nguyên về các tính năng mà chúng ta đã thảo luận hôm nay.

  • Trang này có chứa đường liên kết đến tài liệu, blog, tài nguyên di chuyển, tất cả ở cùng một nơi.

  • Tôi sẽ tạm dừng một chút.

  • Được rồi.

  • Cảm ơn các bạn.

  • Đến đây là kết thúc buổi trò chuyện của chúng ta.

Mã

Đoạn mã

Đoạn mã Kotlin ở phút 04:18 trong phần "Tính năng của kính ngắm thích ứng"
var surfaceRequest by remember {
    mutableStateOf<SurfaceRequest?>(null)
}

LaunchedEffect(...) {
    preview.setSurfaceProvider { surfaceRequest = it }
    cameraProvider.bindToLifecycle(..., preview)
}

surfaceRequest?.let { request ->
    CameraXViewfinder(
        surfaceRequest = request,
        contentScale = ContentScale.Fit
    )
}
Đoạn mã Kotlin ở phút 05:14 trong video "Các tính năng của kính ngắm thích ứng"
CameraXViewfinder(
    surfaceRequest = viewModel.surfaceRequest,
    contentScale = ContentScale.Fit,
    isTapToFocusEnabled = true,
    isPinchToZoomEnabled = true,
    onScreenFlashReady =
        {
           imageCapture.screenFlash = it
           imageCapture.flashMode = FLASH_MODE_SCREEN
        }
)
Đoạn mã Kotlin ở phút 07:30 trong video "Chụp ảnh bằng camera trên Android XR"
// 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(...)
Đoạn mã Kotlin ở phút 09:42 trong phần "Capture features and APIs" (Tính năng và API chụp ảnh)
cameraProvider.bindToLifecycle(
    lifecycleOwner,
    cameraSelector,
    SessionConfig(
        useCases = listOf(preview, videoCapture),
        // HDR_HLG10 > FPS_60 > Preview Stabilization.
        preferredFeatureGroup =
           listOf(HDR_HLG10, FPS_60, PREVIEW_STABILIZATION),
    )
)
Đoạn mã Kotlin ở phút 09:58 trong phần "Capture features and APIs" (Tính năng và API chụp ảnh)
// CameraX 1.6+ supports:
// 4K, video stabilization & Effect
val sessionConfig = SessionConfig(
   useCases = listOf(preview, videoCapture),
   requiredFeatureGroup =
     setOf(UHD_RECORDING, VIDEO_STABILIZATION),
   effects = listOf(overlayEffect)
)
Đoạn mã Kotlin ở phút 11:20 trong phần "Tính năng và API chụp ảnh"
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)
Đoạn mã Kotlin ở phút 12:11 trong video "Capture features and APIs" (Tính năng và API chụp ảnh)
val imageCapture = ImageCapture.Builder()
        .setMotionPhotoMode(
             ImageCapture.MOTION_PHOTO_MODE_ON,
             customConfig
         )
        .build()

cameraProvider.bindToLifecycle(.. imageCapture)
imageCapture.takePicture(...)
Đoạn mã Kotlin ở phút 13:06 trong video "Capture features and APIs" (Các tính năng và API chụp ảnh)
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, {})
Đoạn mã Kotlin ở phút 14:18 trong video "Capture features and APIs" (Tính năng và API chụp ảnh)
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))
Đoạn mã Kotlin ở phút 17:51 trong video "Học máy trên thiết bị"
// 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 -> {}
}
Đoạn mã Kotlin ở phút 18:06 trong video "Học máy trên thiết bị"
// 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
Đoạn mã Kotlin ở phút 19:38 trong video "Học máy trên thiết bị"
// 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)
Đoạn mã Kotlin ở phút 20:44 trong video "Cải thiện hình ảnh và video"
// 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
}
Đoạn mã Kotlin ở phút 20:57 trong video "Cải thiện hình ảnh và video"
// 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)
Đoạn mã Kotlin ở phút 21:05 trong "Cải tiến video và hình ảnh"
// 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)
}
Đoạn mã Kotlin ở phút 22:51 trong video "Cải thiện hình ảnh và video"
// 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)