Apps foundation

ยกระดับประสบการณ์การใช้งานกล้องในอุปกรณ์ต่างๆ ด้วย CameraX และระบบอัจฉริยะในอุปกรณ์

ลำโพง

เกี่ยวกับ

เกี่ยวกับการเสวนา

ผู้ใช้คาดหวังให้แอปของบุคคลที่สามจับภาพและวิดีโอที่มีความแม่นยำสูงเช่นเดียวกับกล้องที่มาพร้อมกับอุปกรณ์ ไม่ว่าจะมีสภาพแสงหรือระดับฮาร์ดแวร์ใดก็ตาม การมอบความสอดคล้องนี้ในระบบนิเวศของ Android ที่กำลังขยายตัวมาพร้อมกับการพิจารณาด้านสถาปัตยกรรมที่สำคัญ เซสชันนี้จะสาธิตวิธีสร้างไปป์ไลน์การจับภาพที่มีประสิทธิภาพและเป็นมืออาชีพ ซึ่งจะเพิ่มความสามารถของอุปกรณ์ให้สูงสุดในขณะที่ยังคงเชื่อถือได้ในทุกรูปแบบของอุปกรณ์

เราจะสำรวจความก้าวหน้าล่าสุดใน CameraX โดยแสดงวิธีผสานรวมความสามารถที่ล้ำสมัย เช่น รูปภาพเคลื่อนไหวและการปรับปรุงด้วย AI ในอุปกรณ์ผ่านบริการ Google Play ควบคู่ไปกับประสบการณ์เชิงมิติพื้นที่โดยใช้ Jetpack XR SDK นอกจากนี้ เราจะพูดถึงทักษะ CameraX ซึ่งช่วยให้เอเจนต์การเขียนโค้ดที่คุณเลือกสามารถนำแนวคิดในการพูดคุยนี้ไปใช้โดยอัตโนมัติ และอื่นๆ อีกมากมาย

สรุป

  • Jetpack CameraX เป็นไลบรารีกล้องที่แนะนำสำหรับแอป Android เนื่องจาก Camera1 เลิกใช้งานแล้ว การบังคับใช้นโยบาย Play จะเริ่มปิดใช้ Camera1 ในปีหน้าใน Android 18
  • CameraXViewfinder ปรับตัวอย่างภาพจากกล้องให้เหมาะกับอุปกรณ์รูปแบบต่างๆ เช่น อุปกรณ์แบบพับได้ ใน CameraX 1.7 มีการเพิ่มการควบคุมด้วยท่าทางสัมผัสและการรองรับแฟลชหน้าจอ
  • แว่นตาที่มีเสียงและจอแสดงผลจะเรียกใช้แอปในโทรศัพท์โฮสต์ขณะที่แสดงกล้องในอุปกรณ์ทั้ง 2 เครื่อง การส่ง ProjectedDeviceContext จะช่วยให้ CameraX ถ่ายภาพจากแว่นตาได้โดยตรง
  • Feature Group API ช่วยให้แอปเลือกชุดความสามารถของกล้องที่รองรับได้ ตั้งแต่ CameraX 1.6 เป็นต้นไป ระบบจะรองรับการรวมการบันทึก 4K เข้ากับระบบกันภาพสั่นไหวของวิดีโอ
  • แมชชีนเลิร์นนิงในอุปกรณ์จะวิเคราะห์ตัวอย่างภาพจากกล้องและสื่อที่บันทึกผ่าน ML Kit และ MediaPipe นักพัฒนาแอปสามารถเรียกใช้งานต่างๆ ได้ตั้งแต่การตรวจจับท่าทางสัมผัสแบบเรียลไทม์ไปจนถึงคำอธิบายรูปภาพจาก Generative AI

แหล่งข้อมูล

Gemini Notebook

หัวข้อ

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

ข้อความถอดเสียง

บทนำและภาพรวมของ CameraX

  • สวัสดีทุกคน

  • ยินดีต้อนรับสู่เซสชันของเรา

  • ฉันชื่อ Aman และ Scott จะเป็นผู้ดูแลคุณในวันนี้

  • วันนี้เราตื่นเต้นมากที่จะได้พูดคุยเกี่ยวกับวิธีที่คุณสามารถยกระดับประสบการณ์การใช้งานกล้องในอุปกรณ์ต่างๆ ด้วย CameraX และระบบอัจฉริยะในอุปกรณ์

  • มาเริ่มกันเลย

  • ลองนึกถึงวิธีที่คุณใช้โทรศัพท์

  • เรามักจะใช้กล้องโทรศัพท์เพื่อบันทึกช่วงเวลาต่างๆ และแชร์กับคนที่เรารัก

  • กล้องได้กลายเป็นหัวใจสำคัญของประสบการณ์การใช้งานสมาร์ทโฟน

  • อันที่จริงแล้ว กล้องที่ดีมักเป็นปัจจัยสำคัญในการซื้อสมาร์ทโฟน

  • วันนี้เราจะพูดถึง 2 ธีมกว้างๆ สำหรับการสร้างประสบการณ์การใช้งานกล้องระดับพรีเมียม

  • ก่อนอื่น เราจะสำรวจฟีเจอร์บางอย่างของ CameraX จากนั้นเราจะเรียนรู้เกี่ยวกับเทคนิคแมชชีนเลิร์นนิงในอุปกรณ์

  • มาเริ่มกันที่ CameraX

  • Jetpack CameraX ขับเคลื่อนประสบการณ์การใช้งานกล้องใน Android

  • นอกจาก CameraX แล้ว เรายังมี Camera1 และ Camera2 ซึ่งเป็นส่วนหนึ่งของเฟรมเวิร์กแพลตฟอร์ม Android ด้วย

  • คุณควรใช้ไลบรารีใด

  • Camera1 เป็น Camera API ดั้งเดิมใน Android

  • ตอนนี้เลิกใช้งานแล้ว ดังนั้นแอปใหม่จึงควรใช้ Camera2 หรือ CameraX

  • Camera2 แทนที่ Camera1

  • ดังนั้น หากคุณต้องการการควบคุมกล้องระดับต่ำสำหรับ Use Case ที่ซับซ้อน Camera2 ก็เป็นตัวเลือกที่ดี

  • อย่างไรก็ตาม คุณจะต้องจัดการการกำหนดค่าเฉพาะอุปกรณ์ด้วยตนเอง

  • และสุดท้าย Jetpack CameraX จะต่อยอดจาก Camera2

  • โดยจะมอบ API ที่สอดคล้องกันและจัดการการกำหนดค่าเฉพาะอุปกรณ์โดยอัตโนมัติ

  • ซึ่งเป็นตัวเลือกที่แนะนำสำหรับนักพัฒนาแอปส่วนใหญ่

  • เรามีเรื่องสำคัญมากที่ต้องแจ้งให้ทราบ

  • เราวางแผนที่จะปิดใช้ Camera1 และจะเริ่มด้วยการบังคับใช้นโยบาย Google Play ในปีหน้าใน Android 18

  • หากยังใช้ Camera1 API เดิมอยู่ คุณจะต้องย้ายข้อมูลไปยัง CameraX หรือ Camera2

  • แล้วทำไมคุณจึงควรใช้ CameraX

  • ประการแรก ฟีเจอร์นี้รองรับ Android 7 ขึ้นไป จึงใช้งานร่วมกับอุปกรณ์ Android ที่มีการใช้งานอยู่ได้เกือบ 99%

  • ประการที่ 2 ใช้งานง่ายและมี API ที่ไม่ซับซ้อนสำหรับ Use Case ทั่วไป เช่น การแสดงตัวอย่าง การจับภาพ และการบันทึกโดยใช้โค้ดน้อยลง

  • ประการที่ 3 คือช่วยให้ผู้ใช้ได้รับประสบการณ์การใช้งานที่สอดคล้องกันในอุปกรณ์ต่างๆ โดยลดปัญหาที่เกิดขึ้นเฉพาะในอุปกรณ์ เช่น การยืดตัวอย่าง ซึ่งพบได้บ่อยในอุปกรณ์แบบพับได้และแท็บเล็ต

  • และสุดท้ายคือช่วยให้การติดตั้งใช้งานความสามารถขั้นสูงของ OEM เช่น โหมดกลางคืนและโหมดแนวตั้ง ทำได้ง่ายขึ้น

  • ตอนนี้ฉันขอเชิญ Scott มาพูดถึงฟีเจอร์บางอย่างของ CameraX

  • ขอเชิญ Scott

  • ขอบคุณมาก Aman

  • สวัสดีทุกคน

  • ฉันชื่อ Scott

  • และวันนี้เราจะพูดถึงฟีเจอร์ CameraX หลายรายการที่จะช่วยให้คุณสร้างประสบการณ์การใช้งานกล้องระดับมืออาชีพได้

ฟีเจอร์ช่องมองภาพแบบปรับอัตโนมัติ

  • โดยเริ่มจากช่องมองภาพแบบปรับอัตโนมัติ

  • ซึ่งออกแบบมาเพื่อช่วยให้คุณจัดการตัวอย่างแฮนเดิลในอุปกรณ์รูปแบบต่างๆ และขนาดหน้าจอที่แตกต่างกันได้อย่างง่ายดาย

  • ปัจจุบันผู้ใช้มีอุปกรณ์หลากหลายประเภท เช่น โทรศัพท์แบบพับได้ โทรศัพท์ แล็ปท็อป และอุปกรณ์ XR

  • ดังนั้น การสร้างประสบการณ์การใช้งานกล้องที่ปรับให้เข้ากับรูปแบบของอุปกรณ์ใหม่ๆ จึงสำคัญยิ่งกว่าที่เคย

  • และเป็นที่ทราบกันดีว่าการแสดงตัวอย่างจากกล้องให้ถูกต้องนั้นทำได้ยาก โดยเฉพาะในอุปกรณ์แบบพับได้ที่มีหน้าจอกว้าง

  • ในอุปกรณ์เหล่านี้ เมื่อกางออก กล้องด้านในจะติดตั้งในแนวนอน ส่วนกล้องหลังจะติดตั้งในแนวตั้ง

  • ดังนั้น หากคุณคิดว่าเซ็นเซอร์ตรวจจับผ่านกล้องทั้งหมดติดตั้งในแนวตั้ง คุณจะพบกับความไม่สอดคล้องกันของพื้นที่และทำให้เกิดการบิดเบี้ยวหรือภาพด้านข้าง

  • และ CameraXViewfinder ได้รับการออกแบบมาเพื่อจัดการกับความซับซ้อนทั้งหมดให้คุณ เพื่อให้มั่นใจว่าตัวอย่างภาพจากกล้องจะทำงานได้อย่างราบรื่นในอุปกรณ์รูปแบบต่างๆ ทั้งหมด

  • และมาดูวิธีใช้ Composable 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
        )
    }
  • ก่อนอื่น ให้ประกาศตัวแปรเนื้อหา surfaceRequest เพื่อเก็บคำขอแพลตฟอร์ม

  • ขออภัย

  • และประการที่ 2 ใน LaunchedEffect คุณตั้งค่าผู้ให้บริการแพลตฟอร์มให้ตรวจจับออบเจ็กต์คำขอแพลตฟอร์ม

  • จากนั้นคุณจะเชื่อมโยงกับวงจร แล้วเริ่มใช้งานกล้อง

  • และสุดท้าย เมื่อใดก็ตามที่สถานะอัปเดตด้วยคำขอแพลตฟอร์มที่ถูกต้องและทริกเกอร์การจัดองค์ประกอบใหม่ คุณจะตั้งค่าคำขอไปยัง CameraXViewfinder โดยตรง

  • และในส่วนนี้ คุณสามารถตั้งค่าcontentScaleให้พอดีหรือครอบตัดได้ตามต้องการ

  • เพียงเท่านี้ก็เรียบร้อย

  • ใน CameraX 1.7 เราได้เพิ่มฟีเจอร์ใหม่หลายรายการลงใน CameraXViewfinder

  • ซึ่งรวมถึงท่าทางสัมผัสใหม่ๆ เช่น แตะเพื่อโฟกัสหรือบีบเพื่อซูม

  • นอกจากนี้ยังรองรับแฟลชหน้าจอ ซึ่งช่วยให้คุณใช้หน้าจอเพื่อเพิ่มความสว่างให้ภาพเซลฟีได้

  • การใช้ฟีเจอร์นี้ทำได้ง่ายๆ

    CameraXViewfinder(
        surfaceRequest = viewModel.surfaceRequest,
        contentScale = ContentScale.Fit,
        isTapToFocusEnabled = true,
        isPinchToZoomEnabled = true,
        onScreenFlashReady =
            {
               imageCapture.screenFlash = it
               imageCapture.flashMode = FLASH_MODE_SCREEN
            }
    )
  • คุณเพียงแค่เปิดใช้การแตะเพื่อโฟกัสและบีบเพื่อซูมเป็น "จริง"

  • และสำหรับแฟลชหน้าจอ คุณจะได้รับอินสแตนซ์แฟลชหน้าจอจาก Callback onScreenFlashReady แล้วส่งไปยัง ImageCapture และตั้งค่าโหมดแฟลชเป็น FLASH_MODE_SCREEN

  • ง่ายๆ แค่นี้เอง

การจับภาพด้วยกล้องใน Android XR

  • เราได้เห็นแล้วว่า CameraX ช่วยให้การแสดงตัวอย่างจากกล้องทำงานได้อย่างราบรื่นในอุปกรณ์รูปแบบต่างๆ ทั้งหมด

  • ทีนี้เรามาดูขั้นตอนต่อไปเกี่ยวกับการจับภาพด้วยกล้องใน Android XR กัน

  • อุปกรณ์ XR แบ่งออกเป็น 3 หมวดหมู่ ได้แก่ หมวดหมู่แรกคือชุดหูฟัง XR

  • ชุดหูฟังเหล่านี้เป็นชุดหูฟังแบบปิดสนิทและสมจริงซึ่งใช้กล้องเพื่อจับภาพโลกจริงและแสดงภายในชุดหูฟัง

  • และ 2 แว่นตา XR แบบใช้สาย

  • เราได้ประกาศเปิดตัว XREAL Aura ในประเด็นสำคัญในหมวดหมู่นี้ในวันนี้

  • และอย่างที่คุณเห็นในคีย์โน้ต แว่นตาเหล่านี้เป็นแว่นตาแบบมองทะลุที่เชื่อมต่อกับ Compute Puck และช่วยให้คุณดูการวางซ้อนเนื้อหาเสมือนจริงในโลกจริงได้

  • และประเภทที่ 3 คือแว่นตาที่มีระบบเสียงและจอแสดงผล

  • แว่นตาเหล่านี้มีน้ำหนักเบา

  • โดยสามารถรวมเสียง กล้อง และจอแสดงผลเพื่อประสบการณ์การใช้งานแบบแฮนด์ฟรีและดูข้อมูลได้อย่างรวดเร็ว

  • และอุปกรณ์ 2 หมวดหมู่แรก ได้แก่ ชุดหูฟัง XR และแว่นตา XR แบบมีสาย ยังรองรับ Camera2 และ CameraX เช่นเดียวกับโทรศัพท์ทั่วไปด้วย

  • ดังนั้นวันนี้เราจะโฟกัสเฉพาะแว่นตาที่มีระบบเสียงและแว่นตาที่มีจอแสดงผล

  • ในแว่นตาเหล่านี้ แอปจะทำงานบนโทรศัพท์ Android ซึ่งเป็นโทรศัพท์ Android โฮสต์ แทนที่จะเป็นแว่นตา แต่ในกรณีนี้จะเข้าถึงทั้งกล้องโทรศัพท์และกล้องแว่นตา

  • คำถามสำคัญคือคุณจะรู้ได้อย่างไรว่ากำลังพูดกับกล้องตัวใดอยู่

  • ซึ่งง่ายมาก

  • เมื่อใช้บริบทมาตรฐาน CameraX จะเข้าถึงกล้องของโทรศัพท์

  • และเมื่อใช้ ProjectedDeviceContext แล้ว CameraX จะเข้าถึงกล้องของแว่นตาได้

  • ดังนั้นบริบทที่แตกต่างกันจะนำไปสู่กล้องเป้าหมายที่แตกต่างกัน

  • และอย่าลืมว่าสิทธิ์เข้าถึงกล้องและแว่นตาแยกกัน

  • สิทธิ์ของโทรศัพท์และแว่นตาแยกกัน คุณจึงต้องขอสิทธิ์ของแว่นตาแยกต่างหาก

  • อีกตัวเลือกหนึ่งคือคุณยังใช้ Projected Activity ได้ด้วย ซึ่งจะทำงานบนอุปกรณ์ Android โฮสต์เช่นกัน แต่ UI จะแสดงบนแว่นตา

  • และกฎจะเปลี่ยนไปในกรณีนี้

  • หากใช้บริบทมาตรฐาน คุณจะเข้าถึงกล้องของแว่นตาได้

  • หากต้องการเข้าถึงกล้องของโทรศัพท์ คุณต้องใช้ HostContext

  • และมาดูโค้ดกันว่าเราจะจับภาพโดยใช้กล้องของแว่นตาได้อย่างไร

    // 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(...)
  • ก่อนอื่น คุณต้องเรียกใช้ isProjectedDeviceConnected เพื่อดูว่าแว่นตาเชื่อมต่ออยู่หรือไม่

  • จากนั้นคุณโทรหา createProjectedDeviceContext เพื่อรับ projectedContext

  • และอย่างที่ 2 คุณจะใช้ LifecycleCameraProvider เพื่อเริ่มต้น CameraX แทน ProcessCameraProvider

  • ดังนั้น ProcessCameraProvider จึงเป็น Singleton ที่คุณไม่สามารถเปลี่ยนบริบทหลังจากเริ่มต้นได้

  • ดังนั้นการใช้ LifecycleCameraProvider จะช่วยให้คุณเปลี่ยนบริบทได้ทุกเมื่อที่ต้องการ

  • และถัดไป คุณต้องปิดใช้สตรีมที่ทำซ้ำเพิ่มเติมใน CameraX

  • ซึ่งจำเป็นเนื่องจากแว่นตาในปัจจุบันรองรับสตรีมเดียวเท่านั้น

  • และปัจจุบัน API นี้เป็นแบบภายใน แต่เราจะเปิดให้ใช้งานแบบสาธารณะในเร็วๆ นี้

  • ง่ายๆ แค่นี้เอง

  • จากตรงนี้จะเป็น CameraX มาตรฐาน คุณเพียงแค่เชื่อมโยง ImageCapture และตอนนี้คุณก็กำลังจับภาพผ่านแว่นตาอยู่

ฟีเจอร์และ API ของการจับภาพ

  • ตกลง

  • ต่อไปเรามาดูว่า CameraX ช่วยคุณค้นหาชุดค่าผสมของฟีเจอร์ที่ทำงานร่วมกันและใช้ประโยชน์จากอุปกรณ์ได้อย่างไร

  • แอปกล้องสมัยใหม่มีฟีเจอร์ที่ทรงพลัง และผู้ใช้คาดหวังว่ากล้องจะรองรับฟีเจอร์ต่างๆ เช่น HDR, 60 FPS และระบบกันสั่นในตัวอย่างพร้อมกันทั้งหมด

  • แต่ในฐานะนักพัฒนาแอป เราทราบดีว่าการรวมฟีเจอร์เหล่านี้เข้าด้วยกันอาจไม่ใช่เรื่องง่ายเสมอไป

  • การตรวจสอบการรองรับฟีเจอร์การช่วยเหลือพิเศษแต่ละรายการไม่ได้รับประกันว่าฟีเจอร์เหล่านั้นจะทำงานร่วมกันได้

  • ความไม่แน่นอนนี้ทำให้นักพัฒนาแอปต้องระมัดระวังและจำกัดสิ่งที่ผู้ใช้จะได้รับประสบการณ์บนอุปกรณ์ที่มีความสามารถ

  • เราจึงได้เปิดตัว Feature Group API ซึ่งทำงานด้วยเฟรมเวิร์กการค้นหาชุดค่าผสมของฟีเจอร์ Camera2 เพื่อแก้ปัญหานี้

  • และคุณสามารถใช้ฟีเจอร์นี้ได้ 2 วิธี วิธีแรกคือใช้ requiredFeatureGroup เพื่อตรวจสอบและเปิดใช้การรวมฟีเจอร์เมื่อรองรับ

  • และ 2 คุณสามารถระบุลำดับความสำคัญของฟีเจอร์ได้โดยใช้ preferredFeatureGroup จากนั้น CameraX จะเลือกชุดค่าผสมที่รองรับที่ดีที่สุดให้คุณ

  • และนี่คือตัวอย่าง

  • ทางด้านขวา ทางด้านซ้าย ขอโทษที ไม่ได้เปิดใช้ฟีเจอร์อะไรเลย เป็นแค่โทรศัพท์ธรรมดา บันทึกเสียงธรรมดา

  • ทางด้านซ้าย เราเปิดใช้ HDR, 60 FPS และระบบกันสั่นในตัวอย่างพร้อมกัน

  • และคุณจะเห็นว่าคุณภาพวิดีโอดีขึ้นอย่างมาก โดยวิดีโอจะสว่างขึ้น ลื่นไหลขึ้น และไม่สั่นไหว

  • มาดูโค้ดกัน

    cameraProvider.bindToLifecycle(
        lifecycleOwner,
        cameraSelector,
        SessionConfig(
            useCases = listOf(preview, videoCapture),
            // HDR_HLG10 > FPS_60 > Preview Stabilization.
            preferredFeatureGroup =
               listOf(HDR_HLG10, FPS_60, PREVIEW_STABILIZATION),
        )
    )
  • ดังนั้นในที่นี้เราจะใช้ preferredFeatureGroup เพื่อระบุรายการลำดับความสำคัญของฟีเจอร์ ซึ่งก็คือ HDR, 60 FPS และระบบกันภาพสั่นไหวในตัวอย่าง

  • และ CameraX จะตรวจสอบชุดค่าผสมและเลือกชุดค่าผสมที่ดีที่สุดที่อุปกรณ์รองรับ

  • ใน CameraX 1.6 ขึ้นไป เราจะเพิ่มการบันทึก 4K และระบบกันภาพสั่นไหวของวิดีโอลงใน 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)
    )
  • อุปกรณ์พรีเมียมหลายรุ่นรองรับการใช้ทั้ง 4K และระบบกันภาพสั่นสำหรับวิดีโอร่วมกัน

  • แต่ตอนนี้ Feature Group API ช่วยให้คุณเปิดใช้ฟีเจอร์เหล่านี้ร่วมกันได้อย่างมั่นใจ

  • นอกจากนี้ คุณยังใช้เอฟเฟกต์แบบเรียลไทม์กับ Feature Group API ได้อย่างยืดหยุ่น ซึ่งก่อนหน้านี้ทำไม่ได้

  • ทีนี้เราจะมาพูดถึงวิธีจับภาพคุณภาพสูงใน CameraX กัน

  • ตอนนี้ CameraX รองรับการจับภาพไฟล์ข้อมูล RAW แบบ DNG แล้ว

  • ซึ่งช่วยให้คุณเข้าถึงรูปภาพ RAW ที่ยังไม่ได้ประมวลผลและไม่บีบอัดได้โดยตรงจากเซ็นเซอร์กล้องเพื่อการแก้ไขอย่างมืออาชีพ

  • ถัดไป เราได้ปรับปรุงส่วนขยายโหมดกลางคืน

  • ส่วนขยายนี้ช่วยให้ถ่ายภาพที่สว่างและคมชัดในที่แสงน้อยได้โดยไม่ต้องใช้แฟลช

  • และเราได้เปิดตัว Night Mode Indicator API ใหม่

  • โดยจะตรวจสอบเมื่อสภาพแวดล้อมปัจจุบันมืดและเหมาะสำหรับโหมดกลางคืน และคุณสามารถใช้เพื่อแสดงสัญญาณบอกสถานะโหมดกลางคืนได้

  • และตอนนี้ส่วนขยาย CameraX รองรับ Ultra HDR แล้ว

  • ซึ่งจะช่วยให้โหมดกลางคืนมีช่วงไดนามิกที่กว้างขึ้นและสีสันสดใส โดยปัจจุบันโหมดกลางคืนที่มี Ultra HDR รองรับในอุปกรณ์พรีเมียมรุ่นล่าสุดหลายรุ่น

  • คุณดูความแตกต่างระหว่างโหมดปกติ โหมดกลางคืน และโหมดกลางคืนที่มี Ultra HDR ได้ที่นี่

  • มาดูวิธีใช้กัน

    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)
  • ก่อนอื่น คุณต้องสร้าง ExtensionSessionConfig สำหรับโหมดกลางคืน แล้วใช้เพื่อรับอินสแตนซ์ CameraInfo

  • จากนั้นใช้ CameraInfo เพื่อรับความสามารถในการจับภาพ แล้วค้นหาว่าระบบรองรับ Ultra HDR หรือไม่

  • จากนั้นตั้งค่ารูปแบบเอาต์พุตเป็น Ultra HDR

  • และสุดท้าย คุณสร้าง ExtensionSessionConfig อีกครั้งด้วยกรณีการใช้งาน และเชื่อมโยงกับวงจร

  • ตอนนี้คุณก็พร้อมที่จะถ่ายภาพด้วยโหมดกลางคืนพร้อมรูปภาพ Ultra HDR แล้ว

  • นอกจากนี้ เรายังเพิ่มการรองรับรูปภาพเคลื่อนไหวลงใน CameraX ด้วย

  • รูปภาพเคลื่อนไหวจะบันทึกเสียงและการเคลื่อนไหวรอบๆ รูปภาพ เพื่อเก็บช่วงเวลาไว้ ไม่ใช่แค่ภาพนิ่ง

  • เรากำหนดมาตรฐานนี้ในโทรศัพท์และอุปกรณ์ Android ต่างๆ และทำให้รองรับรูปภาพเคลื่อนไหวได้ง่ายขึ้น

  • รูปภาพเคลื่อนไหวจะพร้อมใช้งานใน CameraX ในไตรมาสที่ 1 ปี 2027

  • เมื่อพร้อมใช้งานแล้ว เพียงตั้งค่าโหมดรูปภาพเคลื่อนไหวใน ImageCapture.Builder คุณก็เริ่มถ่ายรูปภาพเคลื่อนไหวได้เลย

    val imageCapture = ImageCapture.Builder()
            .setMotionPhotoMode(
                 ImageCapture.MOTION_PHOTO_MODE_ON,
                 customConfig
             )
            .build()
    
    cameraProvider.bindToLifecycle(.. imageCapture)
    imageCapture.takePicture(...)
  • ต่อไป เราจะมาดูวิธีที่ CameraX ช่วยให้บันทึกวิดีโอความเร็วสูงได้

  • การบันทึกภาพเคลื่อนไหวที่รวดเร็วอย่างชัดเจนเป็นฟีเจอร์ที่สำคัญของแอปกล้องถ่ายรูปสมัยใหม่

  • ซึ่งมีประโยชน์อย่างยิ่งสำหรับสถานการณ์ที่ดำเนินไปอย่างรวดเร็ว เช่น กีฬา

  • ซึ่งทำได้โดยการจับภาพความเร็วสูงที่ 120 หรือ 240 FPS

  • ซึ่งใช้ได้ 2 วิธีดังนี้

  • ขั้นแรก ให้เข้ารหัสที่อัตราเฟรมเดียวกัน จากนั้นคุณจะสร้างวิดีโอที่มีอัตราเฟรมสูงอย่างแท้จริงได้

  • อีกตัวเลือกหนึ่งคือการเข้ารหัสที่ 30 FPS เพื่อสร้างวิดีโอสโลว์โมชันที่พร้อมเล่น

  • เช่น วิดีโอ 1 วินาทีที่บันทึกด้วยความเร็ว 120 FPS จะใช้เวลา 4 วินาทีในการเล่นที่ความเร็ว 30 FPS

  • ดังนั้นช่วงเวลานี้จึงสร้างเอฟเฟกต์สโลว์โมชัน

  • และหากต้องการใช้การบันทึกความเร็วสูง ให้สร้าง HighSpeedVideoSessionConfig ด้วย 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, {})
  • จากนั้นตั้งค่า isSlowMotionEnabled เป็น "จริง" เพื่อเข้ารหัสที่ 30 FPS เพื่อสร้างวิดีโอสโลว์โมชัน หรือตั้งค่าเป็น "เท็จ" เพื่อสร้างวิดีโอที่มีอัตราเฟรมความเร็วสูง

  • และเมื่อเปิดใช้สโลว์โมชัน Google Photos จะระบุวิดีโอดังกล่าวโดยอัตโนมัติ และเพิ่มป้ายสโลว์โมชันลงในภาพปก

  • มาดูวิธีการทำงานใน Google Photos กัน

  • ในกรณีนี้ สโลว์โมชันจะช่วยเพิ่มความน่าทึ่งให้กับแมวตัวนั้น

  • แมวของฉันไม่เคยอยากให้ฉันแตะตัวเลย

  • ขออภัยในความไม่สะดวก

  • สุดท้าย มาดูการปรับปรุงบางอย่างใน API ที่ทำงานพร้อมกันของเรา ซึ่งก็คือ Concurrent Camera API

  • Concurrent API ช่วยให้แอปสตรีมจากกล้องหน้าและกล้องหลังพร้อมกันได้

  • ในปีนี้ เราได้ปรับปรุง Concurrent Camera API บางอย่าง

  • คุณสามารถอัปเดตองค์ประกอบของกล้องแบบไดนามิกได้หลังจากเชื่อมโยงกับวงจรและเปิดกล้อง

  • ซึ่งรวมถึงการเปลี่ยนตำแหน่ง ขนาด และลำดับการแสดงผล

  • นอกจากนี้ คุณยังเพิ่มสไตล์ เช่น มุมโค้งมน ความกว้างของขอบ และสีขอบได้ด้วย

  • วิธีดำเนินการคือใช้ CompositionSettings เพื่อกำหนดค่าการจัดรูปแบบ เช่น มุมโค้ง ความกว้างของขอบ และสี และใช้ setZOrder เพื่อปรับลำดับการแสดงผล

    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))
  • จากนั้น คุณเพียงแค่เรียกใช้ setCompositionSettings ในกล้องที่ทำงานพร้อมกันอยู่เพื่ออัปเดตองค์ประกอบแบบไดนามิก

  • ง่ายๆ แค่นี้เอง

  • คุณสามารถอัปเดตองค์ประกอบแบบไดนามิกได้

  • ตกลง

  • ตอนนี้เราได้พูดถึงฟีเจอร์ทั้งหมดแล้ว

  • เรามีคำแนะนำที่สำคัญเกี่ยวกับเรื่องนี้ ดังนั้นเราขอแนะนำอย่างยิ่งให้คุณอัปเกรดเป็น CameraX 1.6 ขึ้นไป

  • ซึ่งจะช่วยป้องกันไม่ให้แอปขัดข้องในอุปกรณ์ที่กำลังจะเปิดตัวซึ่งรองรับรูปแบบใหม่ที่เรียกว่า Eclipsa Video และยังช่วยให้ส่วนขยาย CameraX ทำงานต่อไปได้ในการอัปเดต Pixel ในอนาคต

  • และนี่คือทั้งหมดของเซสชันแรก

  • เราได้พูดถึงฟีเจอร์ CameraX ที่ช่วยคุณสร้างประสบการณ์การใช้งานกล้องระดับมืออาชีพไปแล้ว และตอนนี้ผมขอเชิญ Aman มาพูดถึงเซสชันถัดไปเกี่ยวกับ AI ในอุปกรณ์

แมชชีนเลิร์นนิงในอุปกรณ์

  • ขอบคุณ Scott ที่อธิบายฟีเจอร์ของ CameraX ให้เราฟัง

  • ทีนี้มาดูวิธีใช้ประโยชน์จากแมชชีนเลิร์นนิงในอุปกรณ์เพื่อสร้างประสบการณ์การใช้งานกล้องอัจฉริยะกัน

  • แมชชีนเลิร์นนิงในอุปกรณ์ช่วยให้กล้องสามารถใช้งานได้หลากหลายใน 2 ด้านหลักๆ

  • ขั้นแรกคือการเตรียมความพร้อมก่อนการจับภาพ

  • ในส่วนนี้ คุณสามารถวิเคราะห์ตัวอย่างภาพจากกล้องแบบเรียลไทม์เพื่อทำสิ่งต่างๆ เช่น การตรวจจับออบเจ็กต์ หรือจะปรับปรุงตัวอย่างภาพก็ได้

  • อย่างที่ 2 คือหลังการจับภาพ

  • เมื่อจับภาพแล้ว คุณสามารถปรับปรุงคุณภาพหรือทำสิ่งต่างๆ เช่น สร้างคำอธิบายสำหรับรูปภาพ

  • ตอนนี้เรามาดูโซลูชันแมชชีนเลิร์นนิงในอุปกรณ์ที่เรามีให้สำหรับแอปกล้องกัน

  • ไลบรารี ML ในอุปกรณ์รายการแรกที่เราจะพูดถึงคือ ML Kit

  • ML Kit สร้างขึ้นเพื่อแก้ปัญหาที่พบได้ทั่วไปในโดเมนการมองเห็นและภาษาธรรมชาติเป็นหลัก เช่น การจดจำข้อความ การตรวจจับใบหน้า และการแปลภาษา

  • เมื่อปีที่แล้ว เราได้เปิดตัว ML Kit

  • ตัวอย่าง API ของ ML Kit Vision ได้แก่ การตรวจจับเมชใบหน้า การแบ่งกลุ่มวัตถุ และการตรวจจับออบเจ็กต์แบบเรียลไทม์

  • ได้

  • ปีที่แล้วเราได้เปิดตัว GenAI API

  • API เหล่านี้ใช้ประโยชน์จากความสามารถของ Gemini Nano เพื่อเปิดใช้ความสามารถต่างๆ เช่น การสรุปข้อความ คำอธิบายรูปภาพ และอื่นๆ อีกมากมาย

  • ต่อไปนี้คือตัวอย่างคำอธิบายรูปภาพโดยใช้ Prompt API

  • เราส่งบิตแมปรูปภาพพร้อมพรอมต์ข้อความไปยังโมเดล และคำอธิบายผลลัพธ์จะอ่านได้ว่าหุ่นยนต์ Android สีเขียวขนาดเล็กที่มีดีไซน์คล้ายกระบองเพชรนั่งอยู่บนพื้นผิวสีดำ

  • และทั้งหมดนี้จะเกิดขึ้นในอุปกรณ์

  • เจ๋งใช่ไหมล่ะ

  • Adobe Photoshop ใช้ Prompt API เพื่อปรับปรุงประสบการณ์ของผู้ใช้ในแอป

  • ขณะแก้ไขชิ้นงาน ผู้ใช้มักจะต้องจัดการเลเยอร์หลายเลเยอร์ในแอป Photoshop

  • เมื่อใช้ Prompt API ตอนนี้แอปจะเปลี่ยนชื่อเลเยอร์ที่ไม่ได้จัดระเบียบได้โดยอัตโนมัติ

  • นอกจากนี้ แอปยังใช้ Prompt API เพื่อสร้างคำบรรยายภาพและแฮชแท็กสำหรับรูปภาพ ซึ่งมีประโยชน์มากสำหรับการแชร์บนโซเชียลมีเดีย

  • มาดูโค้ดสำหรับคำอธิบายรูปภาพโดยใช้ 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 -> {}
    }
  • ก่อนอื่น คุณต้องมีออบเจ็กต์ไคลเอ็นต์ generativeModel จากนั้นตรวจสอบว่า Gemini Nano พร้อมใช้งานหรือดาวน์โหลดได้ในอุปกรณ์ของคุณหรือไม่

  • ถัดไป ให้สร้างคำขอเนื้อหาโดยรวมรูปภาพและพรอมต์ข้อความเข้าด้วยกัน และสุดท้ายให้ส่งคำขอนี้ไปยังการเรียก generateContent เพื่อเรียกใช้การอนุมานใน Gemini Nano และรับคำอธิบายรูปภาพ

    // 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
  • ใช่ ไลบรารี ML ในอุปกรณ์รายการถัดไปที่เรามีคือ MediaPipe

  • MediaPipe มีโซลูชันแมชชีนเลิร์นนิงที่หลากหลายสำหรับแอปพลิเคชันของคุณ

  • คุณสามารถไปที่เว็บไซต์ MediaPipe เพื่อลองใช้ตัวอย่างต่างๆ เช่น การตรวจจับใบหน้า การตรวจจับออบเจ็กต์ การแบ่งกลุ่มรูปภาพ และอื่นๆ อีกมากมายได้อย่างรวดเร็ว

  • กรณีการใช้งานทั้งหมดนี้ฟังดูคล้ายกับ ML Kit มาก แล้วคุณควรใช้ไลบรารีใด

  • แม้ว่า MediaPipe และ ML Kit จะแก้ปัญหาที่คล้ายกัน แต่ก็มีความแตกต่างที่สำคัญอยู่ 2-3 ประการ

  • ข้อแรกคือการสนับสนุนแพลตฟอร์ม

  • MediaPipe ทำงานได้ทั้งบน Android, iOS, เว็บ และ Python ส่วน ML Kit จะเน้นเฉพาะ Android และ iOS เท่านั้น

  • ถัดไป MediaPipe มีการปรับแต่งโมเดล ส่วน ML Kit มี API ที่พร้อมใช้งาน

  • และสุดท้าย แม้ว่า MediaPipe จะเป็นโอเพนซอร์ส แต่ ML Kit เป็น SDK ของ Google

  • ต่อไปนี้คือตัวอย่างการจดจำท่าทางสัมผัสโดยใช้ MediaPipe Vision API

  • API นี้จะตรวจจับท่าทางของมือแบบเรียลไทม์จากข้อมูลจากกล้อง

  • ตัวอย่างเช่น คุณสามารถใช้ฟีเจอร์นี้เพื่อเริ่มหรือหยุดการบันทึกของกล้องโดยใช้ท่าทางของมือง่ายๆ ขณะยืนห่างจากโทรศัพท์

  • มาดูโค้ดกัน

  • ก่อนอื่น คุณต้องสร้างออบเจ็กต์ GestureRecognizerOptions โดยระบุเส้นทางโมเดล โหมดไลฟ์สด และ Listener ผลลัพธ์

    // 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)
  • จากนั้นสร้างออบเจ็กต์เครื่องมือจดจำท่าทางสัมผัสจากตัวเลือก

  • ถัดไป ให้รับ ImageProxy ของ CameraX และแปลงเป็นบิตแมป แล้วใช้บิตแมปเพื่อสร้างออบเจ็กต์ mpImage ของ MediaPipe

  • สุดท้าย คุณต้องระบุออบเจ็กต์ MediaPipe mpImage ไปยังการเรียก recognizeAsync เพื่อตรวจจับท่าทางสัมผัสแบบเรียลไทม์

การปรับปรุงรูปภาพและเพิ่มประสิทธิภาพวิดีโอ

  • ถัดไป เรามีการปรับปรุงรูปภาพและวิดีโอในอุปกรณ์ที่พร้อมใช้งานผ่าน Google Play Services API

  • โมเดลนี้มีความสามารถต่างๆ เช่น การแมปโทน การปรับให้คมชัด และความละเอียดสูงในอุปกรณ์ระดับพรีเมียมส่วนใหญ่

  • ต่อไปนี้คือตัวอย่างรูปภาพที่ใช้การแมปโทนสีและเพิ่มสเกลโดยใช้โมเดลนี้

  • คุณจะเห็นสีสันที่สดใสยิ่งขึ้นบนท้องฟ้าและทะเล รวมถึงความคมชัดที่เพิ่มขึ้นในรูปภาพที่ปรับปรุงแล้วได้อย่างชัดเจน

  • มาดูโค้ดสำหรับการปรับปรุงรูปภาพกัน

    // 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
    }
  • ก่อนอื่น คุณต้องค้นหาว่าอุปกรณ์ที่ใช้รองรับหรือไม่ และหากจำเป็น คุณต้องติดตั้งโมดูลการเพิ่มประสิทธิภาพในอุปกรณ์

  • จากนั้นสร้างออบเจ็กต์ EnhancementOptions โดยระบุบิตแมปและการเพิ่มประสิทธิภาพที่ต้องการเลือกใช้

    // 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)
  • ถัดไป ให้สร้างเซสชันไคลเอ็นต์ด้วย Google Play Services API จากนั้นกำหนด Callback เพื่อจัดการบิตแมปผลลัพธ์ และสุดท้ายให้เรียกใช้ฟังก์ชันกระบวนการด้วยบิตแมปและตัวเลือกเพื่อปรับปรุงรูปภาพ

    // 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)
    }
  • เมื่อไม่นานมานี้ เราได้ผสานรวม Video Enhancement API เข้ากับ Jetpack Media3

  • คุณสามารถดูการพูดคุยเกี่ยวกับสื่อเพื่อดูข้อมูลเพิ่มเติมเกี่ยวกับ Image and Video Enhancement API

  • ฟีเจอร์ ML ในอุปกรณ์ฟีเจอร์สุดท้ายที่เราจะพูดถึงคือการเพิ่มแสงในสภาวะแสงน้อย

  • การถ่ายภาพในที่แสงน้อยเป็นปัญหาที่พบบ่อยสำหรับผู้ใช้สมาร์ทโฟน

  • ลองนึกถึงผู้ใช้ที่จับภาพหรือวิดีโอคอลในสภาพแวดล้อมที่มีแสงสลัว

  • ฟีเจอร์เพิ่มความสว่างในที่แสงน้อยจะช่วยแก้ปัญหานี้ด้วยการเพิ่มความสว่างของตัวอย่างภาพจากกล้องแบบเรียลไทม์

  • การเพิ่มแสงในสภาวะแสงน้อยมี 2 รูปแบบ ได้แก่ ฮาร์ดแวร์และซอฟต์แวร์

  • เวอร์ชันฮาร์ดแวร์จะใช้ฮาร์ดแวร์ OEM เพื่อปรับปรุงเฟรมที่มีแสงสลัวโดยไม่ต้องใช้แมชชีนเลิร์นนิง

  • ในทางตรงกันข้าม เวอร์ชันของซอฟต์แวร์จะใช้โมเดล ML ในอุปกรณ์เพื่อปรับปรุงเฟรม

  • มาดูวิธีผสานรวม CameraX กับฟีเจอร์เพิ่มแสงในสภาวะแสงน้อยด้วยซอฟต์แวร์ หรือที่เรียกว่าฟีเจอร์เพิ่มแสงในสภาวะแสงน้อยของ Google กันอย่างรวดเร็ว

  • ฟีเจอร์เพิ่มคุณภาพในที่แสงน้อยของ Google ต้องใช้แพลตฟอร์มหลัก 2 รายการ ได้แก่ แพลตฟอร์มอินพุตสำหรับเฟรมกล้องดิบ และแพลตฟอร์มเป้าหมายเอาต์พุตสำหรับเฟรมเอาต์พุตที่ปรับปรุงแล้ว

  • หากต้องการผสานรวมกับ CameraX เพียงรวมไปป์ไลน์การเพิ่มประสิทธิภาพในที่แสงน้อยของ Google ไว้ใน CameraEffect

  • CameraX จะจัดการวงจรของ Surface และการกำหนดเส้นทางให้คุณโดยอัตโนมัติอย่างราบรื่น

  • สุดท้าย เราจะเปิดตัวเอฟเฟกต์เพิ่มแสงในสภาวะแสงน้อยใน CameraX ในไตรมาสที่ 4 ของปี 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)
  • ซึ่งจะช่วยให้คุณสร้างออบเจ็กต์การเพิ่มคุณภาพแสงน้อยและเพิ่มลงในการกำหนดค่าเซสชัน จากนั้นเชื่อมโยงการกำหนดค่าเซสชันกับวงจรของกล้องได้ และจะทำงานในอุปกรณ์ที่รองรับ

สรุปและการย้ายข้อมูล

  • เรามาถึงช่วงสุดท้ายของทั้ง 2 ส่วนแล้ว

  • มาสรุปสิ่งที่เราได้พูดถึงในวันนี้กันอย่างรวดเร็ว

  • วันนี้เราได้พูดคุยเกี่ยวกับวิธีที่คุณสามารถยกระดับประสบการณ์การใช้งานกล้องในอุปกรณ์ต่างๆ ด้วย CameraX และแมชชีนเลิร์นนิงในอุปกรณ์

  • ประการแรก CameraXViewfinder ช่วยให้คุณเปิดใช้ตัวอย่างกล้องเพื่อปรับให้เข้ากับรูปแบบต่างๆ ได้

  • ต่อไป เราได้เห็นว่า CameraX ช่วยให้คุณจับภาพในอุปกรณ์ XR ได้ด้วย

  • จากนั้น Feature Group API จะช่วยคุณค้นหาชุดฟีเจอร์ฮาร์ดแวร์ที่เหมาะสมที่สุด

  • นอกจากนี้ เรายังได้สำรวจการอัปเกรดฟีเจอร์ Image Capture และเรียนรู้เกี่ยวกับการบันทึกวิดีโอความเร็วสูงสำหรับวิดีโอสโลว์โมชันด้วย

  • สุดท้าย เราได้เรียนรู้วิธีปรับปรุงตัวอย่างกล้องที่ทำงานพร้อมกันแบบไดนามิก

  • ถัดไป เราได้ดูโซลูชันแมชชีนเลิร์นนิงในอุปกรณ์บางอย่าง เช่น ML Kit และ MediaPipe เพื่อสร้างประสบการณ์การมองเห็นอัจฉริยะ

  • สุดท้าย เราได้เห็นการปรับปรุงรูปภาพและการเพิ่มประสิทธิภาพวิดีโอในอุปกรณ์ รวมถึงการเพิ่มแสงในสภาวะแสงน้อยเพื่อเพิ่มความสว่างให้ตัวอย่างภาพจากกล้องแบบเรียลไทม์

  • ตามที่กล่าวไว้ก่อนหน้านี้ เราวางแผนที่จะปิดใช้ Camera1 ดังนั้นเราขอแนะนำอย่างยิ่งให้คุณย้ายข้อมูลไปยัง CameraX

  • เราเพิ่งเปิดตัวทักษะ CameraX เพื่อรองรับการย้ายข้อมูลนี้

  • นอกจากนี้ เรายังมีคำแนะนำในการย้ายข้อมูลและที่เก็บตัวอย่างกล้องเพื่อเป็นแนวทางให้คุณด้วย

  • คุณไปที่ลิงก์นี้เพื่อเข้าถึงแหล่งข้อมูลเพิ่มเติมเกี่ยวกับฟีเจอร์ที่เราพูดถึงในวันนี้ได้

  • ซึ่งรวมถึงลิงก์ไปยังเอกสารประกอบ บล็อก แหล่งข้อมูลการย้ายข้อมูล ทั้งหมดในที่เดียว

  • ฉันจะหยุดพักสักครู่

  • ตกลง

  • ขอบคุณทุกคน

  • เรามาถึงช่วงสุดท้ายของการพูดคุยแล้ว

รหัส

ข้อมูลโค้ด

ข้อมูลโค้ด Kotlin ที่ 04:18 ใน "ฟีเจอร์ช่องมองภาพแบบปรับอัตโนมัติ"
var surfaceRequest by remember {
    mutableStateOf<SurfaceRequest?>(null)
}

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

surfaceRequest?.let { request ->
    CameraXViewfinder(
        surfaceRequest = request,
        contentScale = ContentScale.Fit
    )
}
ข้อมูลโค้ด Kotlin ที่ 05:14 ใน "ฟีเจอร์ช่องมองภาพแบบปรับอัตโนมัติ"
CameraXViewfinder(
    surfaceRequest = viewModel.surfaceRequest,
    contentScale = ContentScale.Fit,
    isTapToFocusEnabled = true,
    isPinchToZoomEnabled = true,
    onScreenFlashReady =
        {
           imageCapture.screenFlash = it
           imageCapture.flashMode = FLASH_MODE_SCREEN
        }
)
ข้อมูลโค้ด Kotlin ที่นาที 07:30 ใน "การจับภาพด้วยกล้องใน 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(...)
ข้อมูลโค้ด Kotlin ที่ 09:42 ใน "ฟีเจอร์และ API ของการจับภาพ"
cameraProvider.bindToLifecycle(
    lifecycleOwner,
    cameraSelector,
    SessionConfig(
        useCases = listOf(preview, videoCapture),
        // HDR_HLG10 > FPS_60 > Preview Stabilization.
        preferredFeatureGroup =
           listOf(HDR_HLG10, FPS_60, PREVIEW_STABILIZATION),
    )
)
ข้อมูลโค้ด Kotlin ที่นาที 09:58 ใน "ฟีเจอร์และ 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)
)
ข้อมูลโค้ด Kotlin ที่ 11:20 ใน "ฟีเจอร์และ API ของการจับภาพ"
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)
ข้อมูลโค้ด Kotlin ที่นาที 12:11 ใน "ฟีเจอร์และ API ของการจับภาพ"
val imageCapture = ImageCapture.Builder()
        .setMotionPhotoMode(
             ImageCapture.MOTION_PHOTO_MODE_ON,
             customConfig
         )
        .build()

cameraProvider.bindToLifecycle(.. imageCapture)
imageCapture.takePicture(...)
ข้อมูลโค้ด Kotlin ที่นาที 13:06 ใน "ฟีเจอร์และ API ของการจับภาพ"
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, {})
ข้อมูลโค้ด Kotlin ที่ 14:18 ใน "ฟีเจอร์และ API ของการจับภาพ"
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))
ข้อมูลโค้ด Kotlin ที่นาที 17:51 ใน "แมชชีนเลิร์นนิงในอุปกรณ์"
// 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 -> {}
}
ข้อมูลโค้ด Kotlin ที่นาที 18:06 ใน "แมชชีนเลิร์นนิงในอุปกรณ์"
// 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
ข้อมูลโค้ด Kotlin ที่ 19:38 ใน "แมชชีนเลิร์นนิงในอุปกรณ์"
// 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)
ข้อมูลโค้ด Kotlin ที่ 20:44 ใน "การปรับปรุงรูปภาพและวิดีโอ"
// 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
}
ข้อมูลโค้ด Kotlin ที่ 20:57 ใน "การเพิ่มประสิทธิภาพรูปภาพและวิดีโอ"
// 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)
ข้อมูลโค้ด Kotlin ที่นาที 21:05 ใน "การเพิ่มประสิทธิภาพวิดีโอ"
// 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)
}
ข้อมูลโค้ด Kotlin ที่ 22:51 ใน "การเพิ่มประสิทธิภาพรูปภาพและวิดีโอ"
// 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)