خيارات الإعداد

يمكنك ضبط كل حالة من حالات استخدام CameraX للتحكُّم في الجوانب المختلفة للاستخدام. وعمليات الحالة.

على سبيل المثال، يمكنك ضبط نسبة عرض إلى ارتفاع مستهدَفة في حالة استخدام التقاط الصور. ووضع الفلاش. يوضح الرمز التالي مثالاً واحدًا:

Kotlin

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

Java

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

بالإضافة إلى خيارات التهيئة، تعرض بعض حالات الاستخدام واجهات برمجة التطبيقات إلى تغيير الإعدادات بعد إنشاء حالة الاستخدام. للحصول على معلومات عن الخاصة بحالات الاستخدام الفردية، راجع تنفيذ معاينة، تحليل والصورة تسجيل البيانات

إعدادات CameraXConfig

للتبسيط، يستخدم تطبيق CameraX إعدادات تلقائية، مثل برامج التنفيذ الداخلية. والمعالجات المناسبة لمعظم سيناريوهات الاستخدام. ومع ذلك، إذا كان تطبيق متطلبات خاصة أو يفضل تخصيص تلك الإعدادات، CameraXConfig هي الواجهة لهذا الغرض

باستخدام CameraXConfig، يمكن لأي تطبيق تنفيذ ما يلي:

نموذج الاستخدام

يصف الإجراء التالي كيفية استخدام "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(), تلخص كاميرا X خصائص الكاميرات المتاحة على الخاص بك. ونظرًا لأن كاميرا X تحتاج إلى الاتصال بمكونات الأجهزة، فإن هذا يمكن أن تستغرق وقتًا بسيطًا لكل كاميرا، خاصةً في الأجهزة المنخفضة المستوى. فإذا كان التطبيق يستخدم كاميرات معينة فقط على الجهاز، مثل الكاميرا الأمامية الافتراضية، يمكنك ضبط CameraX على تجاهل الكاميرات الأخرى، ما يمكن أن يقلّل من وقت استجابة بدء التشغيل للكاميرات التي يستخدمها تطبيقك.

في حال اجتياز CameraSelector بنجاح إلى CameraXConfig.Builder.setAvailableCamerasLimiter() لتصفية الكاميرا، فإن كاميرا X تعمل كما لو كانت هذه الكاميرا غير موجودة. بالنسبة على سبيل المثال، الرمز التالي يقيد التطبيق بحيث لا يستخدم سوى واجهة برمجة تطبيقات الكاميرا الخلفية التلقائية:

Kotlin

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

Threads

تتطلب العديد من واجهات برمجة التطبيقات التي بني عليها CameraX النظام الأساسي حظر الاتصال البيني للعمليات (IPC) بالأجهزة والذي يمكن أن يستغرق أحيانًا مئات الأجهزة من المللي ثانية للاستجابة. لهذا السبب، يستدعي CameraX واجهات برمجة التطبيقات هذه فقط من بحيث لا يتم حظر سلسلة التعليمات الرئيسية وواجهة المستخدم ويظل سائلاً. يدير تطبيق CameraX سلاسل المحادثات هذه داخليًا في الخلفية بحيث يمكن سلوكك بشفافية. ومع ذلك، تتطلب بعض التطبيقات تحكّمًا صارمًا من سلاسل المحادثات. يتيح CameraXConfig للتطبيق ضبط سلاسل المحادثات في الخلفية. والتي يتم استخدامها من خلال CameraXConfig.Builder.setCameraExecutor() أو CameraXConfig.Builder.setSchedulerHandler()

برنامج تنفيذ الكاميرا

يُستخدَم تطبيق الكاميرا في كل طلبات البيانات من واجهة برمجة التطبيقات في النظام الأساسي للكاميرا الداخلية، بالإضافة إلى بالنسبة إلى عمليات الاستدعاء من واجهات برمجة التطبيقات هذه. يخصص تطبيق CameraX قسمًا داخليًا ويديره Executor لتنفيذ هذه المهام. ومع ذلك، إذا كان التطبيق يتطلب تحكمًا أكثر صرامة في سلاسل المحادثات، استخدم CameraXConfig.Builder.setCameraExecutor()

معالِج أداة الجدولة

يُستخدم معالج الجدولة لجدولة المهام الداخلية على فترات زمنية ثابتة، مثل إعادة محاولة فتح الكاميرا عندما لا تكون متاحة. يفعل هذا المعالج ولكنهم لا ينفذون المهام، بل يرسلونها فقط إلى المسؤول عن تشغيل الكاميرا. من المهم أيضًا يُستخدم أحيانًا على منصات واجهة برمجة التطبيقات القديمة التي تتطلب Handler لعمليات معاودة الاتصال. في هذه الحالات، لا يزال يتم إرسال طلبات معاودة الاتصال مباشرةً إلى جهة تنفيذ الكاميرا. الكاميراX ويخصص ويدير مشروعًا داخليًا HandlerThread لتنفيذ هذه المهام ولكن يمكنك إلغاؤه باستخدام CameraXConfig.Builder.setSchedulerHandler().

التسجيل

يتيح تسجيل CameraX للتطبيقات تصفية رسائل Logcat، حيث يمكن أن تكون جيدة التدريب لتجنب الرسائل المطوَّلة في رمز الإنتاج يتوافق مع CameraX. أربعة مستويات للتسجيل، من الأكثر تفصيلاً إلى الأكثر شدّة:

  • Log.DEBUG (تلقائي)
  • Log.INFO
  • Log.WARN
  • Log.ERROR

يمكنك الرجوع إلى مستندات سجلّ Android. للحصول على أوصاف تفصيلية لمستويات السجل هذه. استخدام CameraXConfig.Builder.setMinimumLoggingLevel(int) لضبط مستوى التسجيل المناسب لتطبيقك.

الاختيار التلقائي

يوفّر تطبيق CameraX تلقائيًا وظائف خاصة بالجهاز الذي الذي يعمل عليه تطبيقك على سبيل المثال، تحدد CameraX تلقائيًا أفضل حل يمكن استخدامه إذا لم تحدد درجة الدقة، أو إذا كانت التي تحددها غير معتمدة. تتم معالجة كل هذا بواسطة المكتبة، مما يحذف الحاجة إلى كتابة رمز خاص بالجهاز.

يتمثل هدف CameraX في تهيئة جلسة كاميرا بنجاح. يعني ذلك ويمثل خيار CameraX التنازل عن درجة الدقة ونسب العرض إلى الارتفاع وفقًا لإمكانيات الجهاز. يمكن أن يحدث الاختراق للأسباب التالية:

  • لا يتيح الجهاز درجة الدقة المطلوبة.
  • الجهاز به مشاكل توافق، مثل الأجهزة القديمة التي تتطلب. درجات دقة معينة لتعمل بشكل صحيح.
  • في بعض الأجهزة، لا تتوفّر تنسيقات محدّدة إلا على جوانب محدّدة. والنسب.
  • يفضّل الجهاز استخدام "أقرب mod16". لتنسيق JPEG أو للفيديو الترميز. لمزيد من المعلومات، يُرجى مراجعة SCALER_STREAM_CONFIGURATION_MAP

على الرغم من أن CameraX ينشئ الجلسة ويديرها، تحقق دائمًا من عرض أحجام الصور على مخرجات حالة الاستخدام في التعليمات البرمجية وضبطها وفقًا لذلك.

الدوران

يتم ضبط دوران الكاميرا تلقائيًا ليتطابق مع دوران شاشة العرض التلقائية. أثناء إنشاء حالة الاستخدام. في هذه الحالة الافتراضية، تنتج CameraX. للسماح للتطبيق بمطابقة ما تتوقّع رؤيته في معاينة. يمكنك تغيير التدوير إلى قيمة مخصّصة لإتاحة العرض المتعدّد. من خلال تمرير اتجاه العرض الحالي عند تهيئة حالة الاستخدام الكائنات أو ديناميكيًا بعد إنشائها.

يمكن لتطبيقك ضبط التغيير المستهدف باستخدام إعدادات الضبط. يمكنه بعد ذلك لتحديث إعدادات العرض بالتناوب باستخدام الطرق من واجهات برمجة التطبيقات لحالة الاستخدام (مثل 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()
  • تحليل الصور: يتم توفير مخرجات البيانات الوصفية كي يتم المخزن المؤقت للصور. الإحداثيات بالنسبة إلى إحداثيات العرض.
  • ImageCapture: بيانات Exif الوصفية للصورة أو المخزن المؤقت أو كل من المخزن المؤقت تغيير بيانات التعريف لملاحظة إعداد التدوير. القيمة التي تم تغييرها على تنفيذ بروتوكول HAL.

اقتصاص المستطيل

بشكل افتراضي، يكون مستطيل الاقتصاص هو المستطيل الكامل. يمكنك تخصيصها باستخدام ViewPort و UseCaseGroup حسب استخدام التجميع فالحافظات وإعداد إطار العرض، تضمن CameraX أن تكون مستطيلات الاقتصاص تشير حالات الاستخدام في المجموعة إلى المنطقة نفسها في أداة استشعار الكاميرا.

يوضِّح مقتطف الرمز التالي كيفية استخدام هاتين الفئتَين:

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. أكبر مستطيل اقتصاص ممكن بناءً على خصائص إطار العرض أي حالات استخدام مرفقة. عادة، لتحقيق تأثير 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 تلقائيًا أفضل جهاز كاميرا لتطبيق تطبيقك. متطلبات المشروع وحالات الاستخدام. إذا أردت استخدام جهاز مختلف عن الجهاز تم تحديدها لك، فهناك بعض الخيارات:

يوضح نموذج الرمز البرمجي التالي كيفية إنشاء 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، يمكنك أيضًا اختيار عدة كاميرات بشكل متزامن. على سبيل المثال، يمكنك الربط بكاميرا أمامية وكاميرا خلفية لالتقاط الصور أو التسجيل مقاطع فيديو من كلا المنظورين في وقت واحد.

عند استخدام ميزة "الكاميرا المتزامنة"، يمكن للجهاز تشغيل كاميرتين باستخدام عدسات مختلفة المواجهة في الوقت نفسه، أو تشغيل كاميراتين خلفيتين في في نفس الوقت. توضح مجموعة الرموز التالية كيفية ضبط كاميرتين عند جارٍ الاتصال بالرقم bindToLifecycle وكيفية استعادة كائنَي الكاميرا من الجهة التي تم إرجاعها كائن 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 بضبط دقة الصورة بناءً على تركيبة ما. لإمكانات الجهاز وتوافقه والمستوى، وحالة الاستخدام، ونسبة العرض إلى الارتفاع المقدمة. وبدلاً من ذلك، يمكنك تعيين نطاق الدقة المستهدفة أو نسبة عرض إلى ارتفاع محددة في حالات الاستخدام التي تتيح التكوين.

درجة الدقة التلقائية

يمكن لـ CameraX تحديد أفضل إعدادات الدقة تلقائيًا استنادًا إلى حالات الاستخدام المحدّدة في cameraProcessProvider.bindToLifecycle(). في كل مرة تحديد جميع حالات الاستخدام اللازمة للعمل بالتزامن في حملة واحدة جلسة في مكالمة bindToLifecycle() واحدة. يحدد تطبيق CameraX درجات الدقة. استنادًا إلى مجموعة حالات الاستخدام المرتبطة بمراعاة توافق الجهاز على مستوى الجهاز ومن خلال مراعاة التباين الخاص بالجهاز (حيث يكون الجهاز يتجاوز أو لا يستوفي إعدادات مصدر البيانات المتوفرة). والغرض من ذلك هو السماح بتشغيل التطبيق على مجموعة متنوعة من الأجهزة مع وخفض مسارات الرموز الخاصة بالجهاز.

إنّ نسبة العرض إلى الارتفاع التلقائية لحالات استخدام تحليل الصور والتقاطها هي 4:3.

يمكن أن تحتوي حالات الاستخدام على نسبة عرض إلى ارتفاع قابلة للضبط كي يتمكّن التطبيق من تحديد نسبة العرض إلى الارتفاع المطلوبة بناءً على تصميم واجهة المستخدم. يتم إنتاج مخرجات CameraX إلى تتطابق مع نِسب العرض إلى الارتفاع المطلوبة بأكبر قدر ممكن من توافق الجهاز إذا كان هناك لا يتم دعم حل مطابقة تامة، والخيار الذي يفي بأكبر قدر من الشروط . وبالتالي، يوضح التطبيق كيفية ظهور الكاميرا في ويحدد تطبيق CameraX أفضل إعدادات دقة الكاميرا لتلبية على أجهزة مختلفة.

على سبيل المثال، يمكن للتطبيق تنفيذ أي من الإجراءات التالية:

  • حدِّد درجة دقة مستهدَفة تبلغ 4:3 أو 16:9 لحالة استخدام.
  • تحديد درجة دقة مخصصة، يحاول تطبيق CameraX الوصول إلى أقرب درجة مطابقة مع
  • تحديد نسبة عرض إلى ارتفاع للاقتصاص في ImageCapture

تختار CameraX درجات دقة سطح الكاميرا2 الداخلية تلقائيًا. تشير رسالة الأشكال البيانية يوضح الجدول التالي درجات الدقة:

حالة الاستخدام درجة دقة السطح الداخلي دقة بيانات الإخراج
معاينة نسبة العرض إلى الارتفاع: درجة الدقة التي تناسب الهدف على أفضل نحو الإعداد. درجة دقة السطح الداخلي يتم توفير بيانات التعريف للسماح لاقتصاص العرض، وتغيير الحجم وتدويره للوصول إلى نسبة العرض إلى الارتفاع المستهدفة.
درجة الدقة التلقائية: أعلى درجة دقة معاينة أو الأعلى درجة الدقة المفضّلة للجهاز التي تتطابق مع نسبة العرض إلى الارتفاع الخاصة بالمعاينة.
الدقة القصوى: حجم المعاينة الذي يشير إلى أفضل حجم مع دقة شاشة الجهاز، أو بدقة 1080p (1920×1080)، أيهما أصغر.
تحليل الصور نسبة العرض إلى الارتفاع: درجة الدقة التي تناسب الهدف على أفضل وجه الإعداد. درجة دقة السطح الداخلي
درجة الدقة التلقائية: إعداد درجة الدقة المستهدف التلقائي هو 640 × 480. ضبط كل من درجة الدقة المستهدفة ونسبة العرض إلى الارتفاع المقابلة يؤدي إلى أفضل درجة دقة متوافقة.
الدقة القصوى: أقصى درجة دقة للإخراج من جهاز الكاميرا تبلغ تنسيق YUV_420_888 الذي تم استرداده من StreamConfigurationMap.getOutputSizes() تكون درجة الدقة المستهدفة 640×480 تلقائيًا، لذلك إذا كنت تريد درجة دقة أكبر من 640×480، يجب استخدام setTargetResolution() أو setTargetAspectRatio() للحصول على أقرب درجة من درجات الدقة المتوافقة.
التقاط صورة نسبة العرض إلى الارتفاع: نسبة العرض إلى الارتفاع التي تناسب الإعداد على أفضل وجه. درجة دقة السطح الداخلي
درجة الدقة التلقائية: أعلى درجة دقة متوفّرة أو الأعلى درجة الدقة المفضّلة للجهاز التي تتطابق مع نسبة العرض إلى الارتفاع في ImageCapture.
الدقة القصوى: الحد الأقصى لدقة الإخراج لجهاز الكاميرا بـ بتنسيق JPEG. استخدام StreamConfigurationMap.getOutputSizes() لاسترداد ذلك.

تحديد درجة الدقة

يمكنك تحديد درجات دقة محدّدة عند إنشاء حالات استخدام باستخدام 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 درجة استهداف الاتجاه الأفقي تحديد 640×480.

تحاول درجة الدقة المستهدفة وضع حد أدنى للصورة. الحل. وأن الدقة الفعلية للصورة هي أقرب درجة دقة متاحة. من حيث الحجم الذي لا يقل عن درجة الدقة المستهدفة، على النحو المحدد بواسطة استخدام الكاميرا

ومع ذلك، إذا لم يكن هناك حل يساوي أو أكبر من درجة الدقة المستهدفة، تكون أقرب درجة دقة متاحة أصغر من يتم اختيار درجة الدقة المستهدفة. درجات الدقة بنفس نسبة العرض إلى الارتفاع يتم إعطاء Size المقدمة أولوية أعلى من درجات الدقة المختلفة نِسب العرض إلى الارتفاع:

يطبق CameraX أفضل درجة دقة مناسبة بناءً على الطلبات. إذا كانت أولًا هو تلبية متطلبات نسبة العرض إلى الارتفاع، وتحديد setTargetAspectRatio فقط، وتحدد CameraX درجة دقة معينة تناسب الجهاز. فإذا كان هناك حاجة أساسية للتطبيق هو تحديد درجة دقة من أجل إنشاء صورة معالجة أكثر فاعلية (على سبيل المثال، صورة صغيرة أو متوسطة الحجم تستند إلى إمكانات معالجة الجهاز)، استخدم setTargetResolution(Size resolution).

إذا كان تطبيقك يتطلب دقة دقيقة، يُرجى الاطّلاع على الجدول الموجود داخل createCaptureSession() لتحديد الحد الأقصى لدرجات الدقة التي يدعمها كل مستوى من الأجهزة. إلى للتحقق من درجات الدقة المحددة التي يوفّرها الجهاز الحالي، والاطّلاع على StreamConfigurationMap.getOutputSizes(int)

إذا كان تطبيقك يعمل بنظام التشغيل Android 10 أو إصدار أحدث، يمكنك استخدام isSessionConfigurationSupported() لإثبات ملكية SessionConfiguration محدّد.

التحكم في إخراج الكاميرا

بالإضافة إلى السماح لك بضبط إخراج الكاميرا حسب الحاجة لكل في حالة استخدام فردي، تنفذ CameraX أيضًا الواجهات التالية لدعم عمليات الكاميرا الشائعة في جميع حالات الاستخدام المرتبطة:

  • يتيح لك 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 طريقتين لتغيير مستوى التكبير/التصغير:

  • 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 لتعديلهما بدون الحاجة إلى تنفيذ تحويل.

يوفّر ListenableFuture الذي تعرضه كلتا واجهتَي برمجة التطبيقات خيار استخدام التطبيقات. ليتم إرسال إشعار إليه عندما يتم تكرار طلب متكرر بقيمة التكبير أو التصغير المحددة مكتملة. بالإضافة إلى ذلك، إذا تم تعيين قيمة تكبير/تصغير جديدة أثناء إجراء العملية السابقة لا تزال قيد التنفيذ، تعذّر تنفيذ عملية التكبير/التصغير السابقة 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.15 و. عند استدعاء 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 واحدة أو أكثر مع وضع قياس حصة القراءة الاختياري المجموعات من 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 أخرى للإعلانات الديناميكية على شبكة البحث والإمارات العربية المتحدة فقط

يحوّل تطبيق CameraX الكاميرا إلى كاميرا 2. MeteringRectangles وتضبط الأعمدة CONTROL_AF_REGIONS / CONTROL_AE_REGIONS / CONTROL_AWB_REGIONS المعلَمات على طلب الالتقاط.

بما أنّ بعض الأجهزة لا تتوافق مع AF/AE/AWB ومناطق متعدّدة، يتم تنفيذ CameraX. FocusMeteringAction بأفضل جهد. يستخدم CameraX الحد الأقصى لعدد من MeteringPoints المعتمَدة بالترتيب الذي أُضيفت به النقاط. الكل ويتم تجاهل MeteringPoints التي تتم إضافتها بعد الحدّ الأقصى للعدد. على سبيل المثال، إذا كانت يتم تزويد "FocusMeteringAction" بثلاثة MeteringPoints على منصة متوافقة فقط 2، يتم استخدام أول نقطتين MeteringPoints فقط. آخر 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، يمكنك الرجوع إلى الموارد الإضافية التالية.

درس تطبيقي حول الترميز

  • بدء استخدام CameraX
  • نموذج التعليمات البرمجية

  • نماذج تطبيقات CameraX
  • منتدى المطوّرين

    مجموعة مناقشة Android CameraX