ตัวเลือกการกำหนดค่า

คุณกําหนดค่า Use Case ของ CameraX แต่ละรายการเพื่อควบคุมแง่มุมต่างๆ ของการดำเนินการของ Use Case ได้

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

Kotlin

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

Java

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

นอกจากตัวเลือกการกำหนดค่าแล้ว กรณีการใช้งานบางกรณียังเผยแพร่ API ในแบบไดนามิก แก้ไขการตั้งค่าหลังจากที่สร้าง Use Case แล้ว สำหรับข้อมูลเกี่ยวกับ เฉพาะของแต่ละกรณีการใช้งาน โปรดดูที่ใช้ แสดงตัวอย่าง, วิเคราะห์ รูปภาพและรูปภาพ ภาพ

CameraXConfig

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

แอปพลิเคชัน CameraXConfig สามารถทำสิ่งต่อไปนี้ได้

  • เพิ่มประสิทธิภาพเวลาในการตอบสนองของการเปิดใช้งานด้วย setAvailableCameraLimiter()
  • ให้ผู้ดำเนินการของแอปพลิเคชันไปยัง CameraX ด้วย setCameraExecutor()
  • แทนที่เครื่องจัดการเครื่องจัดตารางเวลาเริ่มต้นด้วย setSchedulerHandler()
  • เปลี่ยนระดับการบันทึกด้วย setMinimumLoggingLevel()

โมเดลการใช้งาน

ขั้นตอนต่อไปนี้จะอธิบายวิธีใช้ CameraXConfig

  1. สร้างออบเจ็กต์ CameraXConfig ด้วยการกำหนดค่าที่คุณกำหนดเอง
  2. ใช้อินเตอร์เฟซ CameraXConfig.Provider ใน Application และแสดงผลออบเจ็กต์ CameraXConfig ใน getCameraXConfig()
  3. เพิ่มชั้นเรียน Application ลงในไฟล์ AndroidManifest.xml เป็น ตามที่อธิบายไว้ที่นี่

ตัวอย่างเช่น ตัวอย่างโค้ดต่อไปนี้จะจำกัดการบันทึกของ CameraX ไว้เฉพาะข้อความแสดงข้อผิดพลาดเท่านั้น

Kotlin

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

เก็บสำเนาของออบเจ็กต์ CameraXConfig ไว้ในเครื่องหากแอปพลิเคชันของคุณจำเป็นต้องทราบการกำหนดค่า CameraX หลังจากตั้งค่า

ตัวจำกัดกล้อง

ในระหว่างการเรียกใช้ ProcessCameraProvider.getInstance() ครั้งแรก CameraX จะแสดงรายการและค้นหาลักษณะของกล้องที่ใช้ได้ในอุปกรณ์ เนื่องจาก CameraX ต้องสื่อสารกับส่วนประกอบของฮาร์ดแวร์ อาจใช้เวลาเพียงเล็กน้อยสำหรับกล้องแต่ละตัว โดยเฉพาะเมื่อ อุปกรณ์โลว์เอนด์ หากแอปพลิเคชันของคุณใช้เฉพาะกล้องบางตัวบนอุปกรณ์ เช่น กล้องหน้าเริ่มต้น คุณสามารถตั้งค่า CameraX ให้ละเว้นกล้องอื่นๆ ซึ่งสามารถลดเวลาในการตอบสนองเริ่มต้นสำหรับกล้องที่แอปพลิเคชันใช้

หากCameraSelectorผ่าน ถึง CameraXConfig.Builder.setAvailableCamerasLimiter() กรองกล้องออก CameraX จะทำงานเสมือนว่าไม่มีกล้องอยู่ ตัวอย่างเช่น โค้ดต่อไปนี้จะจํากัดแอปพลิเคชันให้ใช้ได้เฉพาะกล้องหลังเริ่มต้นของอุปกรณ์

Kotlin

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

ชุดข้อความ

API ของแพลตฟอร์มหลายรายการที่ CameraX สร้างขึ้นต้องบล็อกการสื่อสารระหว่างกระบวนการ (IPC) กับฮาร์ดแวร์ ซึ่งบางครั้งอาจใช้เวลาหลายร้อยมิลลิวินาทีในการตอบสนอง ด้วยเหตุนี้ CameraX จึงเรียกใช้ API เหล่านี้จากเธรดเบื้องหลังเท่านั้น เพื่อไม่ให้เธรดหลักถูกบล็อกและ UI ยังคงทำงานได้อย่างราบรื่น CameraX จะจัดการเธรดเบื้องหลังเหล่านี้ภายในเพื่อให้ลักษณะการทำงานนี้ดูโปร่งใส อย่างไรก็ตาม แอปพลิเคชันบางอย่างอาจต้องมีการควบคุมที่เข้มงวด ทั้งหมด CameraXConfig อนุญาตให้แอปพลิเคชันตั้งค่าชุดข้อความในเบื้องหลัง ที่ใช้ผ่าน CameraXConfig.Builder.setCameraExecutor() และ CameraXConfig.Builder.setSchedulerHandler()

โปรแกรมดำเนินการกล้องถ่ายรูป

ตัวดำเนินการของกล้องใช้สำหรับการเรียก API ของแพลตฟอร์มกล้องภายในทั้งหมด รวมถึงสำหรับการเรียกกลับจาก API เหล่านี้ CameraX จัดสรรและจัดการ Executor เพื่อดำเนินการเหล่านี้ อย่างไรก็ตาม หากแอปพลิเคชันของคุณต้องใช้การควบคุมเธรดอย่างเข้มงวดมากขึ้น ให้ใช้ CameraXConfig.Builder.setCameraExecutor()

ตัวแฮนเดิลเครื่องจัดตารางเวลา

แฮนเดิลตัวจัดตารางเวลาใช้เพื่อกำหนดเวลางานภายในเป็นระยะๆ ที่แน่นอน เช่น พยายามเปิดกล้องอีกครั้งเมื่อกล้องไม่พร้อมใช้งาน เครื่องจัดการนี้ ไม่เรียกใช้งาน และจ่ายให้กับผู้ดำเนินการของกล้องเท่านั้น และยัง บางครั้งใช้บนแพลตฟอร์ม API เดิมซึ่งต้องใช้ Handler สำหรับ Callback ในกรณีเหล่านี้ พารามิเตอร์ ระบบจะยังคงส่ง Callback ไปยังผู้ดำเนินการของกล้องโดยตรงเท่านั้น CameraX จะจัดสรรและจัดการ HandlerThread ภายในเพื่อทำงานเหล่านี้ แต่คุณลบล้างได้ด้วย CameraXConfig.Builder.setSchedulerHandler()

การบันทึก

การบันทึกของ CameraX ช่วยให้แอปพลิเคชันกรองข้อความ Logcat ได้ตามต้องการ เพื่อหลีกเลี่ยงข้อความแบบละเอียดในโค้ดการผลิต CameraX รองรับการบันทึกในระดับต่างๆ 4 ระดับ ตั้งแต่การบันทึกแบบละเอียดที่สุดไปจนถึงการบันทึกแบบละเอียดน้อยที่สุด ดังนี้

  • Log.DEBUG (ค่าเริ่มต้น)
  • Log.INFO
  • Log.WARN
  • Log.ERROR

โปรดดูเอกสารประกอบเกี่ยวกับบันทึกของ Android สำหรับคำอธิบายโดยละเอียดของระดับการบันทึกเหล่านี้ ใช้ CameraXConfig.Builder.setMinimumLoggingLevel(int) เพื่อตั้งค่าระดับการบันทึกที่เหมาะสมสําหรับแอปพลิเคชัน

การเลือกอัตโนมัติ

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

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

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

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

การหมุน

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

แอปของคุณตั้งค่าการหมุนเวียนเป้าหมายได้โดยใช้การตั้งค่าการกําหนดค่า จากนั้นจะทำสิ่งต่อไปนี้ได้ อัปเดตการตั้งค่าการหมุนเวียนโดยใช้เมธอดจาก API ของ Use Case (เช่น ImageAnalysis.setTargetRotation()), แม้ว่าวงจรจะอยู่ในสถานะทำงานอยู่ คุณอาจใช้เมื่อแอป จะล็อกเป็นโหมดแนวตั้ง จึงไม่มีการสร้างการกำหนดค่าใหม่ การหมุน แต่รูปภาพหรือกรณีการใช้งานการวิเคราะห์ต้องระวัง การหมุนปัจจุบันของอุปกรณ์ เช่น จำเป็นต้องมีการรับรู้การหมุนเพื่อให้ใบหน้าอยู่ในแนวที่ถูกต้องสำหรับการจับภาพใบหน้า หรือตั้งค่ารูปภาพเป็นแนวนอนหรือแนวตั้ง

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

หากต้องการแสดงตัวอย่างข้อมูลที่มีการวางแนวที่ถูกต้อง คุณสามารถใช้ข้อมูลเมตา เอาต์พุตจาก Preview.PreviewOutput() เพื่อสร้างการเปลี่ยนรูปแบบ

ตัวอย่างโค้ดต่อไปนี้แสดงวิธีตั้งค่าการหมุนในเหตุการณ์การวางแนว

Kotlin

override fun onCreate() {
    val imageCapture = ImageCapture.Builder().build()

    val orientationEventListener = object : OrientationEventListener(this as Context) {
        override fun onOrientationChanged(orientation : Int) {
            // Monitors orientation values to determine the target rotation value
            val rotation : Int = when (orientation) {
                in 45..134 -> Surface.ROTATION_270
                in 135..224 -> Surface.ROTATION_180
                in 225..314 -> Surface.ROTATION_90
                else -> Surface.ROTATION_0
            }

            imageCapture.targetRotation = rotation
        }
    }
    orientationEventListener.enable()
}

Java

@Override
public void onCreate() {
    ImageCapture imageCapture = new ImageCapture.Builder().build();

    OrientationEventListener orientationEventListener = new OrientationEventListener((Context)this) {
       @Override
       public void onOrientationChanged(int orientation) {
           int rotation;

           // Monitors orientation values to determine the target rotation value
           if (orientation >= 45 && orientation < 135) {
               rotation = Surface.ROTATION_270;
           } else if (orientation >= 135 && orientation < 225) {
               rotation = Surface.ROTATION_180;
           } else if (orientation >= 225 && orientation < 315) {
               rotation = Surface.ROTATION_90;
           } else {
               rotation = Surface.ROTATION_0;
           }

           imageCapture.setTargetRotation(rotation);
       }
    };

    orientationEventListener.enable();
}

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

  • แสดงตัวอย่าง: แสดงเอาต์พุตข้อมูลเมตาเพื่อให้ทราบการหมุนของความละเอียดเป้าหมายโดยใช้ Preview.getTargetRotation()
  • ImageAnalysis: แสดงผลข้อมูลเมตาเพื่อให้ทราบพิกัดของบัฟเฟอร์รูปภาพซึ่งสัมพันธ์กับพิกัดของจอแสดงผล
  • ImageCapture: ระบบจะแก้ไขข้อมูลเมตา Exif ของรูปภาพ บัฟเฟอร์ หรือทั้งบัฟเฟอร์และข้อมูลเมตาเพื่อบันทึกการตั้งค่าการหมุน ค่ามีการเปลี่ยนแปลง ขึ้นอยู่กับการใช้งาน HAL

สี่เหลี่ยมผืนผ้าครอบตัด

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

ข้อมูลโค้ดต่อไปนี้แสดงวิธีใช้คลาสทั้ง 2 คลาสนี้

Kotlin

val viewPort =  ViewPort.Builder(Rational(width, height), display.rotation).build()
val useCaseGroup = UseCaseGroup.Builder()
    .addUseCase(preview)
    .addUseCase(imageAnalysis)
    .addUseCase(imageCapture)
    .setViewPort(viewPort)
    .build()
cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, useCaseGroup)

Java

ViewPort viewPort = new ViewPort.Builder(
         new Rational(width, height),
         getDisplay().getRotation()).build();
UseCaseGroup useCaseGroup = new UseCaseGroup.Builder()
    .addUseCase(preview)
    .addUseCase(imageAnalysis)
    .addUseCase(imageCapture)
    .setViewPort(viewPort)
    .build();
cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, useCaseGroup);

ViewPort กําหนดสี่เหลี่ยมผืนผ้าบัฟเฟอร์ที่ผู้ใช้ปลายทางมองเห็น จากนั้น CameraX จะคํานวณสี่เหลี่ยมผืนผ้าครอบตัดที่ใหญ่ที่สุดที่เป็นไปได้ตามพร็อพเพอร์ตี้ของวิวพอร์ตและ Use Case ที่แนบมา โดยปกติแล้ว หากต้องการใช้ผลลัพธ์ WYSIWYG คุณสามารถกําหนดค่าวิวพอร์ตตาม Use Case ของตัวอย่างได้ วิธีง่ายๆ ในการรับวิวพอร์ตคือใช้ PreviewView

ข้อมูลโค้ดต่อไปนี้แสดงวิธีรับออบเจ็กต์ ViewPort

Kotlin

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

Java

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

ในตัวอย่างก่อนหน้านี้ สิ่งที่แอปได้รับจาก ImageAnalysis และ ImageCapture จะตรงกับสิ่งที่ผู้ใช้ปลายทางเห็นใน PreviewView โดยสมมติว่า ประเภทสเกลของ PreviewView ตั้งเป็นค่าเริ่มต้น FILL_CENTER หลังจากใช้สี่เหลี่ยมผืนผ้าครอบตัดและการหมุนกับบัฟเฟอร์เอาต์พุตแล้ว รูปภาพจาก Use Case ทั้งหมดจะเหมือนกัน แม้ว่าอาจมีความละเอียดต่างกัน ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีใช้ข้อมูลการเปลี่ยนรูปแบบได้ที่ transform output

การเลือกกล้อง

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

ตัวอย่างโค้ดต่อไปนี้แสดงวิธีสร้าง CameraSelector เพื่อส่งผลต่อการเลือกอุปกรณ์

Kotlin

fun selectExternalOrBestCamera(provider: ProcessCameraProvider):CameraSelector? {
   val cam2Infos = provider.availableCameraInfos.map {
       Camera2CameraInfo.from(it)
   }.sortedByDescending {
       // HARDWARE_LEVEL is Int type, with the order of:
       // LEGACY < LIMITED < FULL < LEVEL_3 < EXTERNAL
       it.getCameraCharacteristic(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL)
   }

   return when {
       cam2Infos.isNotEmpty() -> {
           CameraSelector.Builder()
               .addCameraFilter {
                   it.filter { camInfo ->
                       // cam2Infos[0] is either EXTERNAL or best built-in camera
                       val thisCamId = Camera2CameraInfo.from(camInfo).cameraId
                       thisCamId == cam2Infos[0].cameraId
                   }
               }.build()
       }
       else -> null
    }
}

// create a CameraSelector for the USB camera (or highest level internal camera)
val selector = selectExternalOrBestCamera(processCameraProvider)
processCameraProvider.bindToLifecycle(this, selector, preview, analysis)

เลือกกล้องหลายตัวพร้อมกัน

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

เมื่อใช้ฟีเจอร์กล้องพร้อมกัน อุปกรณ์จะใช้งานกล้อง 2 ตัวที่มีเลนส์หันหน้าต่างกันได้พร้อมกัน หรือใช้งานกล้องหลัง 2 ตัวพร้อมกันได้ บล็อกโค้ดต่อไปนี้แสดงวิธีตั้งค่ากล้อง 2 ตัวเมื่อเรียกใช้ bindToLifecycle และวิธีรับออบเจ็กต์ Camera ทั้ง 2 รายการจากออบเจ็กต์ ConcurrentCamera ที่แสดงผล

Kotlin

// Build ConcurrentCameraConfig
val primary = ConcurrentCamera.SingleCameraConfig(
    primaryCameraSelector,
    useCaseGroup,
    lifecycleOwner
)

val secondary = ConcurrentCamera.SingleCameraConfig(
    secondaryCameraSelector,
    useCaseGroup,
    lifecycleOwner
)

val concurrentCamera = cameraProvider.bindToLifecycle(
    listOf(primary, secondary)
)

val primaryCamera = concurrentCamera.cameras[0]
val secondaryCamera = concurrentCamera.cameras[1]

Java

// Build ConcurrentCameraConfig
SingleCameraConfig primary = new SingleCameraConfig(
    primaryCameraSelector,
    useCaseGroup,
    lifecycleOwner
);

SingleCameraConfig secondary = new SingleCameraConfig(
    primaryCameraSelector,
    useCaseGroup,
    lifecycleOwner
);

ConcurrentCamera concurrentCamera =  
    mCameraProvider.bindToLifecycle(Arrays.asList(primary, secondary));

Camera primaryCamera = concurrentCamera.getCameras().get(0);
Camera secondaryCamera = concurrentCamera.getCameras().get(1);

ความละเอียดของกล้อง

คุณสามารถเลือกให้ CameraX ตั้งค่าความละเอียดของรูปภาพตามชุดค่าผสม ความสามารถของอุปกรณ์ ฮาร์ดแวร์ที่รองรับของอุปกรณ์ ระดับ Use Case และสัดส่วนการแสดงผลที่ให้ไว้ หรือจะกำหนดความละเอียดเป้าหมายหรือสัดส่วนภาพที่เจาะจงใน Use Case ที่รองรับการกำหนดค่าดังกล่าวก็ได้

การแก้ปัญหาอัตโนมัติ

CameraX สามารถกำหนดการตั้งค่าความละเอียดที่ดีที่สุดโดยอัตโนมัติตามกรณีการใช้งานที่ระบุไว้ใน cameraProcessProvider.bindToLifecycle() ระบุ Use Case ทั้งหมดที่จําเป็นต้องทํางานพร้อมกันในเซสชันเดียวในbindToLifecycle()การเรียกใช้ครั้งเดียวทุกครั้งที่เป็นไปได้ CameraX จะกำหนดความละเอียดโดยอิงตามชุดกรณีการใช้งานที่พิจารณาจากระดับฮาร์ดแวร์ที่รองรับของอุปกรณ์และพิจารณาความแปรปรวนเฉพาะอุปกรณ์ (ในกรณีที่อุปกรณ์มีความละเอียดสูงกว่าหรือต่ำกว่าการกำหนดค่าสตรีมที่ใช้ได้) โดยมีจุดประสงค์เพื่อให้แอปพลิเคชันทำงานได้ในอุปกรณ์ที่หลากหลายขณะที่ลดเส้นทางโค้ดเฉพาะอุปกรณ์

สัดส่วนภาพเริ่มต้นสําหรับ Use Case การจับภาพและการวิเคราะห์รูปภาพคือ 4:3

Use Case มีอัตราส่วนภาพที่กําหนดค่าได้เพื่อให้แอปพลิเคชันระบุอัตราส่วนที่ต้องการตามการออกแบบ UI ระบบจะสร้างเอาต์พุต CameraX ให้ตรงกับสัดส่วนภาพที่ขอมากที่สุดเท่าที่อุปกรณ์รองรับ หากมี ไม่สนับสนุนความละเอียดของการจับคู่แบบตรงทั้งหมด เป็นค่าที่ตรงตามเงื่อนไขมากที่สุด ไว้ ดังนั้น แอปพลิเคชันจะกำหนดลักษณะที่กล้องปรากฏในแอป และ CameraX จะกำหนดการตั้งค่าความละเอียดของกล้องที่ดีที่สุดเพื่อตอบสนองความต้องการนั้นในอุปกรณ์ต่างๆ

เช่น แอปอาจดำเนินการอย่างใดอย่างหนึ่งต่อไปนี้

  • ระบุความละเอียดเป้าหมาย 4:3 หรือ 16:9 สำหรับ Use Case
  • ระบุความละเอียดที่กำหนดเอง ซึ่ง CameraX จะพยายามค้นหาความละเอียดที่ใกล้เคียงที่สุด จับคู่กับ
  • ระบุสัดส่วนภาพสำหรับการครอบตัดของ ImageCapture

CameraX จะเลือกความละเอียดของพื้นผิว Camera2 ภายในโดยอัตโนมัติ ตารางต่อไปนี้จะแสดงความละเอียด

กรณีการใช้งาน ความละเอียดของพื้นผิวภายใน ความละเอียดของข้อมูลเอาต์พุต
แสดงตัวอย่าง สัดส่วนภาพ: ความละเอียดที่เหมาะกับเป้าหมายในการตั้งค่ามากที่สุด ความละเอียดพื้นผิวภายใน มีการจัดเตรียมข้อมูลเมตาเพื่อให้มุมมองครอบตัด ปรับขนาด และบิดสัดส่วนภาพตามสัดส่วนภาพเป้าหมาย
ความละเอียดเริ่มต้น: ความละเอียดสูงสุดของตัวอย่างหรือสูงสุด ความละเอียดที่อุปกรณ์กำหนดซึ่งตรงตามสัดส่วนภาพของตัวอย่าง
ความละเอียดสูงสุด: ขนาดตัวอย่าง ซึ่งหมายถึงขนาดที่ดีที่สุด ตรงกับความละเอียดหน้าจอของอุปกรณ์ หรือถึง 1080p (1920x1080) แล้วแต่ว่าขนาดใดจะน้อยกว่า
การวิเคราะห์รูปภาพ สัดส่วนภาพ: ความละเอียดที่เหมาะกับเป้าหมายมากที่สุดกับ การตั้งค่า ความละเอียดของพื้นผิวภายใน
ความละเอียดเริ่มต้น: การตั้งค่าความละเอียดเป้าหมายเริ่มต้นคือ 640x480 การปรับทั้งความละเอียดเป้าหมายและสัดส่วนภาพที่สอดคล้องกันจะให้ความละเอียดที่รองรับได้ดีที่สุด
ความละเอียดสูงสุด: ความละเอียดเอาต์พุตสูงสุดของอุปกรณ์กล้องในรูปแบบ YUV_420_888 ซึ่งดึงมาจาก StreamConfigurationMap.getOutputSizes() ระบบจะตั้งค่าความละเอียดเป้าหมายเป็น 640x480 โดยค่าเริ่มต้น ดังนั้นหากต้องการความละเอียดที่มากกว่า 640x480 คุณต้องใส่ค่า setTargetResolution() และ setTargetAspectRatio() เพื่อรับความละเอียดที่ใกล้เคียงที่สุดจากความละเอียดที่รองรับ
การจับภาพ สัดส่วนภาพ: สัดส่วนภาพที่เหมาะกับการตั้งค่ามากที่สุด ความละเอียดพื้นผิวภายใน
ความละเอียดเริ่มต้น: ความละเอียดสูงสุดที่ใช้ได้ หรือความละเอียดสูงสุดที่อุปกรณ์ต้องการซึ่งตรงกับสัดส่วนภาพของ ImageCapture
ความละเอียดสูงสุด: ความละเอียดเอาต์พุตสูงสุดของอุปกรณ์กล้องในรูปแบบ JPEG ใช้ StreamConfigurationMap.getOutputSizes() เพื่อเรียกข้อมูลนี้

ระบุความละเอียด

คุณสามารถตั้งความละเอียดที่เฉพาะเจาะจงเมื่อสร้าง Use Case ได้โดยใช้ setTargetResolution(Size resolution) ดังที่แสดงในโค้ดต่อไปนี้ ตัวอย่าง:

Kotlin

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

Java

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

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

แสดงความละเอียด Size ในพิกัด หลังจากหมุนขนาดที่รองรับตามการหมุนเป้าหมาย ตัวอย่างเช่น ที่มีการวางแนวตั้งตามธรรมชาติในแนวตั้งในการหมุนเป้าหมายตามปกติ รูปภาพแนวตั้งสามารถระบุเป็น 480x640 และอุปกรณ์เดียวกันหมุน 90 องศา การกำหนดเป้าหมายแนวนอนสามารถระบุเป็น 640x480

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

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

CameraX ใช้ความละเอียดที่เหมาะสมที่สุดโดยอิงตามคำขอ หาก ความต้องการหลักคือการปฏิบัติตามสัดส่วนภาพ ระบุเฉพาะ setTargetAspectRatio และ CameraX จะพิจารณาความละเอียด ที่เหมาะสมตามอุปกรณ์ หากความต้องการหลักของแอปคือการระบุความละเอียดเพื่อให้การประมวลผลรูปภาพมีประสิทธิภาพมากขึ้น (เช่น รูปภาพขนาดเล็กหรือขนาดกลางตามความสามารถในการประมวลผลของอุปกรณ์) ให้ใช้ setTargetResolution(Size resolution)

หากแอปของคุณต้องการความละเอียดที่แน่นอน โปรดดูตารางภายใน createCaptureSession() เพื่อดูว่าฮาร์ดแวร์แต่ละระดับรองรับความละเอียดสูงสุดเท่าใด ถึง ตรวจสอบความละเอียดที่อุปกรณ์ปัจจุบันรองรับ โปรดดู StreamConfigurationMap.getOutputSizes(int)

หากแอปทำงานบน Android 10 ขึ้นไป คุณจะใช้ isSessionConfigurationSupported() เพื่อยืนยัน SessionConfiguration ที่เฉพาะเจาะจงได้

ควบคุมเอาต์พุตของกล้อง

นอกจากจะช่วยให้คุณกําหนดค่าเอาต์พุตของกล้องได้ตามต้องการสําหรับแต่ละกรณีการใช้งานแล้ว CameraX ยังใช้อินเทอร์เฟซต่อไปนี้เพื่อรองรับการดําเนินการของกล้องที่ใช้ร่วมกันใน Use Case ที่เชื่อมโยงทั้งหมดด้วย

  • CameraControl ช่วยให้คุณกำหนดค่าฟีเจอร์ทั่วไปของกล้องได้
  • CameraInfo ช่วยให้คุณค้นหาสถานะของฟีเจอร์กล้องทั่วไปเหล่านั้นได้

ฟีเจอร์กล้องที่ CameraControl รองรับมีดังนี้

  • Zoom
  • คบเพลิง
  • โฟกัสและการวัด (แตะเพื่อโฟกัส)
  • ชดเชยการรับแสง

รับอินสแตนซ์ของ CameraControl และ CameraInfo

ดึงข้อมูลอินสแตนซ์ของ CameraControl และ CameraInfo โดยใช้ออบเจ็กต์ Camera ที่ ProcessCameraProvider.bindToLifecycle() แสดงผล โค้ดต่อไปนี้แสดงตัวอย่าง

Kotlin

val camera = processCameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview)

// For performing operations that affect all outputs.
val cameraControl = camera.cameraControl
// For querying information and states.
val cameraInfo = camera.cameraInfo

Java

Camera camera = processCameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview)

// For performing operations that affect all outputs.
CameraControl cameraControl = camera.getCameraControl()
// For querying information and states.
CameraInfo cameraInfo = camera.getCameraInfo()

เช่น คุณสามารถส่งการซูมและการดำเนินการอื่นๆ ของ CameraControl หลังจาก กำลังโทรหา bindToLifecycle() หลังจากหยุดหรือทำลายกิจกรรมที่ใช้เพื่อเชื่อมโยงอินสแตนซ์กล้องแล้ว CameraControl จะดำเนินการไม่ได้อีกต่อไปและแสดงผล ListenableFuture ที่ดำเนินการไม่สำเร็จ

Zoom

CameraControl มีวิธีการเปลี่ยนระดับการซูม 2 วิธี ได้แก่

  • setZoomRatio() ตั้งค่าการซูมตามอัตราส่วนการซูม

    อัตราส่วนต้องอยู่ในช่วงของ CameraInfo.getZoomState().getValue().getMinZoomRatio() และ CameraInfo.getZoomState().getValue().getMaxZoomRatio() ไม่เช่นนั้น ฟังก์ชันจะแสดงผล ListenableFuture ที่ดำเนินการไม่สำเร็จ

  • setLinearZoom() ตั้งค่าการซูมปัจจุบันด้วยค่าการซูมเชิงเส้นตั้งแต่ 0 ถึง 1.0

    ข้อดีของการซูมแบบเส้นตรงคือทำให้มุมมอง (FOV) ปรับขนาดตามการเปลี่ยนแปลงการซูม จึงเหมาะสำหรับใช้กับ Slider มุมมอง

CameraInfo.getZoomState() แสดงผล LiveData ของสถานะการซูมปัจจุบัน ค่าจะเปลี่ยนแปลงเมื่อเริ่มต้นกล้องหรือหากตั้งค่าระดับการซูมโดยใช้ setZoomRatio() หรือ setLinearZoom() การเรียกใช้เมธอดใดเมธอดหนึ่งจะตั้งค่าที่รองรับ ZoomState.getZoomRatio() และ ZoomState.getLinearZoom() ซึ่งจะเป็นประโยชน์หากคุณต้องการแสดงข้อความอัตราส่วนการซูมควบคู่ไปกับแถบเลื่อน เพียงสังเกต ZoomState LiveData เพื่ออัปเดตทั้ง 2 รายการโดยไม่ต้องดำเนินการใดๆ Conversion

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

คบเพลิง

CameraControl.enableTorch(boolean) เปิดหรือปิดไฟฉาย (หรือที่เรียกว่าไฟฉาย)

CameraInfo.getTorchState() ใช้เพื่อค้นหาสถานะไฟฉายปัจจุบันได้ คุณสามารถตรวจสอบค่าที่ส่งคืนได้ โดย CameraInfo.hasFlashUnit() เพื่อดูว่าไฟฉายพร้อมใช้งานหรือไม่ หากไม่ การเรียกใช้ CameraControl.enableTorch(boolean) จะทําให้ ListenableFuture ที่แสดงผลเสร็จสมบูรณ์ทันทีพร้อมผลลัพธ์ที่ไม่สําเร็จ และตั้งค่าสถานะไฟฉายเป็น TorchState.OFF

เมื่อเปิดใช้ไฟฉาย ไฟฉายจะยังคงเปิดอยู่ขณะถ่ายภาพและบันทึกวิดีโอ ไม่ว่าจะตั้งค่า flashMode เป็นค่าใดก็ตาม flashMode ใน ImageCapture จะทำงานเมื่อปิดไฟฉายเท่านั้น

การโฟกัสและการวัด

CameraControl.startFocusAndMetering() เรียกใช้โฟกัสอัตโนมัติและการวัดแสงโดยการตั้งค่าพื้นที่การวัด AF/AE/AWB ตาม FocusMeteringAction ที่ระบุ ซึ่งมักใช้เพื่อใช้ฟีเจอร์ "แตะเพื่อโฟกัส" ในแอปพลิเคชันกล้องหลายแอป

MeteringPoint

ในการเริ่มต้น ให้สร้าง MeteringPointกำลังใช้ MeteringPointFactory.createPoint(float x, float y, float size) MeteringPoint แสดงจุดเดียวบนกล้อง Surface โดยจัดเก็บในรูปแบบมาตรฐานเพื่อให้แปลงเป็นพิกัดเซ็นเซอร์สำหรับการระบุภูมิภาค AF/AE/AWB ได้โดยง่าย

ขนาดของ MeteringPoint อยู่ในช่วง 0 ถึง 1 โดยมีขนาดเริ่มต้นเป็น 0.15f เมื่อเรียกใช้ MeteringPointFactory.createPoint(float x, float y, float size) CameraX จะสร้างพื้นที่สี่เหลี่ยมผืนผ้าซึ่งมีศูนย์กลางอยู่ที่ (x, y) สำหรับ size

โค้ดต่อไปนี้แสดงวิธีสร้าง MeteringPoint

Kotlin

// Use PreviewView.getMeteringPointFactory if PreviewView is used for preview.
previewView.setOnTouchListener((view, motionEvent) ->  {
val meteringPoint = previewView.meteringPointFactory
    .createPoint(motionEvent.x, motionEvent.y)

}

// Use DisplayOrientedMeteringPointFactory if SurfaceView / TextureView is used for
// preview. Please note that if the preview is scaled or cropped in the View,
// it’s the application's responsibility to transform the coordinates properly
// so that the width and height of this factory represents the full Preview FOV.
// And the (x,y) passed to create MeteringPoint might need to be adjusted with
// the offsets.
val meteringPointFactory = DisplayOrientedMeteringPointFactory(
     surfaceView.display,
     camera.cameraInfo,
     surfaceView.width,
     surfaceView.height
)

// Use SurfaceOrientedMeteringPointFactory if the point is specified in
// ImageAnalysis ImageProxy.
val meteringPointFactory = SurfaceOrientedMeteringPointFactory(
     imageWidth,
     imageHeight,
     imageAnalysis)

startFocusAndMetering และ FocusMeteringAction

หากต้องการเรียกใช้ startFocusAndMetering() แอปพลิเคชันต้องสร้าง FocusMeteringAction ซึ่งประกอบด้วย MeteringPoints อย่างน้อย 1 รายการที่มีโหมดการวัดผล (ไม่บังคับ) ผสมผสานกันจาก FLAG_AF, FLAG_AE และ FLAG_AWB ติดตามโค้ดแสดงการใช้งานนี้:

Kotlin

val meteringPoint1 = meteringPointFactory.createPoint(x1, x1)
val meteringPoint2 = meteringPointFactory.createPoint(x2, y2)
val action = FocusMeteringAction.Builder(meteringPoint1) // default AF|AE|AWB
      // Optionally add meteringPoint2 for AF/AE.
      .addPoint(meteringPoint2, FLAG_AF | FLAG_AE)
      // The action is canceled in 3 seconds (if not set, default is 5s).
      .setAutoCancelDuration(3, TimeUnit.SECONDS)
      .build()

val result = cameraControl.startFocusAndMetering(action)
// Adds listener to the ListenableFuture if you need to know the focusMetering result.
result.addListener({
   // result.get().isFocusSuccessful returns if the auto focus is successful or not.
}, ContextCompat.getMainExecutor(this)

ตามที่แสดงในโค้ดก่อนหน้านี้ startFocusAndMetering() รับ FocusMeteringAction ที่มี MeteringPoint สำหรับ AF/AE/AWB ภูมิภาคการวัด และ MeteringPoint อีกจุดหนึ่งสำหรับ AF และ AE เท่านั้น

ภายใน CameraX จะแปลงเป็น Camera2 MeteringRectangles และตั้งค่าพารามิเตอร์ที่เกี่ยวข้อง CONTROL_AF_REGIONS / CONTROL_AE_REGIONS / CONTROL_AWB_REGIONS ในคำขอจับภาพ

เนื่องจากอุปกรณ์บางเครื่องไม่รองรับ AF/AE/AWB และรองรับหลายภูมิภาค CameraX จะดำเนินการ FocusMeteringAction อย่างสุดความสามารถ CameraX ใช้จำนวนสูงสุด รองรับ MeteringPoints ตามลำดับการเพิ่มคะแนน ทั้งหมด MeteringPoints ที่เพิ่มหลังจากจำนวนสูงสุดจะถูกละเว้น เช่น หากFocusMeteringActionมี MeteringPoint 3 รายการในแพลตฟอร์มที่รองรับเพียง 2 รายการ ระบบจะใช้เฉพาะ MeteringPoint 2 รายการแรก MeteringPointสุดท้ายคือ CameraX ไม่สนใจ

ชดเชยการรับแสง

การชดเชยแสงมีประโยชน์เมื่อแอปพลิเคชันต้องปรับค่าการรับแสง (EV) ให้ละเอียดยิ่งขึ้นนอกเหนือจากผลลัพธ์เอาต์พุตของการปรับการรับแสงอัตโนมัติ (AE) ชดเชยการรับแสง ค่าต่างๆ จะรวมกันด้วยวิธีต่อไปนี้เพื่อระบุการรับแสงที่จำเป็นสำหรับ สภาพรูปภาพปัจจุบัน:

Exposure = ExposureCompensationIndex * ExposureCompensationStep

CameraX มีฟังก์ชัน Camera.CameraControl.setExposureCompensationIndex() สำหรับการตั้งค่าการชดเชยแสงเป็นค่าดัชนี

ค่าดัชนีที่เป็นบวกจะทำให้รูปภาพสว่างขึ้น ส่วนค่าลบจะลดความสว่าง รูปภาพ แอปพลิเคชันจะค้นหาช่วงที่ได้รับการรองรับได้โดยใช้ CameraInfo.ExposureState.exposureCompensationRange() ที่อธิบายไว้ในส่วนถัดไป หากระบบรองรับค่า ListenableFuture ที่แสดงผลจะเสร็จสมบูรณ์เมื่อเปิดใช้ค่าดังกล่าวในคำขอบันทึกเรียบร้อยแล้ว หากอินเด็กซ์ที่ระบุอยู่นอกช่วงที่รองรับ setExposureCompensationIndex() จะทําให้ ListenableFuture ที่แสดงผลเสร็จสมบูรณ์ทันทีพร้อมผลลัพธ์ที่ไม่สําเร็จ

CameraX จะเก็บเฉพาะ setExposureCompensationIndex() ล่าสุดที่โดดเด่น และการเรียกใช้ฟังก์ชันหลายครั้งก่อนหน้าคำขอก่อนหน้า จะถูกเรียกใช้ ผลในการยกเลิก

ข้อมูลโค้ดต่อไปนี้จะตั้งค่าดัชนีการชดเชยแสงและลงทะเบียนการเรียกกลับเมื่อดำเนินการตามคำขอเปลี่ยนการเปิดรับแสง

Kotlin

camera.cameraControl.setExposureCompensationIndex(exposureCompensationIndex)
   .addListener({
      // Get the current exposure compensation index, it might be
      // different from the asked value in case this request was
      // canceled by a newer setting request.
      val currentExposureIndex = camera.cameraInfo.exposureState.exposureCompensationIndex
      
   }, mainExecutor)
  • Camera.CameraInfo.getExposureState() ดึงข้อมูลปัจจุบันจากExposureState ซึ่งรวมถึง

    • การรองรับการควบคุมการชดเชยการรับแสง
    • ดัชนีชดเชยการรับแสงปัจจุบัน
    • ช่วงดัชนีชดเชยการรับแสง
    • ขั้นตอนการปรับสมดุลแสงที่ใช้ในการคำนวณค่าการปรับสมดุลแสง

ตัวอย่างเช่น โค้ดต่อไปนี้จะเริ่มต้นการตั้งค่าสำหรับจำนวนผู้ที่เห็น SeekBar ด้วย ExposureState ปัจจุบัน มีดังนี้

Kotlin

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

แหล่งข้อมูลเพิ่มเติม

ดูข้อมูลเพิ่มเติมเกี่ยวกับ CameraX ได้ในแหล่งข้อมูลเพิ่มเติมต่อไปนี้

Codelab

  • เริ่มต้นใช้งาน CameraX
  • ตัวอย่างโค้ด

  • ตัวอย่างแอป CameraX
  • ชุมชนนักพัฒนาแอป

    กลุ่มสนทนาเกี่ยวกับ CameraX ของ Android