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

คุณกำหนดค่ากรณีการใช้งาน CameraX แต่ละกรณีเพื่อควบคุมการใช้งานในด้านต่างๆ ของเคสของคุณ

เช่น กำหนดสัดส่วนภาพเป้าหมายด้วย Use Case การจับภาพ และโหมดแฟลช โค้ดต่อไปนี้แสดงตัวอย่าง 1 รายการ

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 ของแพลตฟอร์มกล้องภายในทั้งหมดด้วย สำหรับ Callback จาก API เหล่านี้ CameraX จัดสรรและจัดการ Executor เพื่อดำเนินการเหล่านี้ แต่หากแอปพลิเคชันของคุณต้องการการควบคุมชุดข้อความที่เข้มงวดขึ้น ให้ใช้ CameraXConfig.Builder.setCameraExecutor()

เครื่องจัดการเครื่องจัดตารางเวลา

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

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

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

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

ความละเอียดอัตโนมัติ

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

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

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

เช่น แอปสามารถดำเนินการต่อไปนี้ได้

  • ระบุความละเอียดเป้าหมายเป็น 4:3 หรือ 16:9 สำหรับกรณีการใช้งาน
  • ระบุความละเอียดที่กำหนดเอง ซึ่ง 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();

คุณไม่สามารถตั้งค่าทั้งสัดส่วนภาพเป้าหมายและความละเอียดเป้าหมายในการใช้งานเดียวกันได้ การทำเช่นนี้จะมีการส่ง 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กำลังใช้ 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 ระบบจะใช้ MeteringPoints 2 รายการแรกเท่านั้น MeteringPointสุดท้ายคือ CameraX ไม่สนใจ

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

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

Exposure = ExposureCompensationIndex * ExposureCompensationStep

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

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

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

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

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
  • ชุมชนนักพัฒนาซอฟต์แวร์

    กลุ่มสนทนาของ Android CameraX