ผู้ใช้คาดหวังให้แอปของบุคคลที่สามจับภาพและวิดีโอที่มีความแม่นยำสูงเช่นเดียวกับกล้องที่มาพร้อมกับอุปกรณ์ ไม่ว่าจะมีสภาพแสงหรือระดับฮาร์ดแวร์ใดก็ตาม การมอบความสอดคล้องนี้ในระบบนิเวศของ Android ที่กำลังขยายตัวมาพร้อมกับการพิจารณาด้านสถาปัตยกรรมที่สำคัญ เซสชันนี้จะสาธิตวิธีสร้างไปป์ไลน์การจับภาพที่มีประสิทธิภาพและเป็นมืออาชีพ ซึ่งจะเพิ่มความสามารถของอุปกรณ์ให้สูงสุดในขณะที่ยังคงเชื่อถือได้ในทุกรูปแบบของอุปกรณ์
เราจะสำรวจความก้าวหน้าล่าสุดใน CameraX โดยแสดงวิธีผสานรวมความสามารถที่ล้ำสมัย เช่น รูปภาพเคลื่อนไหวและการปรับปรุงด้วย AI ในอุปกรณ์ผ่านบริการ Google Play ควบคู่ไปกับประสบการณ์เชิงมิติพื้นที่โดยใช้ Jetpack XR SDK นอกจากนี้ เราจะพูดถึงทักษะ CameraX ซึ่งช่วยให้เอเจนต์การเขียนโค้ดที่คุณเลือกสามารถนำแนวคิดในการพูดคุยนี้ไปใช้โดยอัตโนมัติ และอื่นๆ อีกมากมาย
CameraXViewfinder ปรับตัวอย่างภาพจากกล้องให้เหมาะกับอุปกรณ์รูปแบบต่างๆ เช่น อุปกรณ์แบบพับได้ ใน CameraX 1.7 มีการเพิ่มการควบคุมด้วยท่าทางสัมผัสและการรองรับแฟลชหน้าจอProjectedDeviceContext จะช่วยให้ 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
ง่ายๆ แค่นี้เอง
เราได้เห็นแล้วว่า 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 และตอนนี้คุณก็กำลังจับภาพผ่านแว่นตาอยู่
ตกลง
ต่อไปเรามาดูว่า 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 เพื่อรองรับการย้ายข้อมูลนี้
นอกจากนี้ เรายังมีคำแนะนำในการย้ายข้อมูลและที่เก็บตัวอย่างกล้องเพื่อเป็นแนวทางให้คุณด้วย
คุณไปที่ลิงก์นี้เพื่อเข้าถึงแหล่งข้อมูลเพิ่มเติมเกี่ยวกับฟีเจอร์ที่เราพูดถึงในวันนี้ได้
ซึ่งรวมถึงลิงก์ไปยังเอกสารประกอบ บล็อก แหล่งข้อมูลการย้ายข้อมูล ทั้งหมดในที่เดียว
ฉันจะหยุดพักสักครู่
ตกลง
ขอบคุณทุกคน
เรามาถึงช่วงสุดท้ายของการพูดคุยแล้ว
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)