يمكنك ضبط كل حالة استخدام من حالات استخدام CameraX للتحكّم في جوانب مختلفة من عمليات حالة الاستخدام.
على سبيل المثال، في حالة استخدام التقاط الصور، يمكنك ضبط نسبة عرض إلى ارتفاع مستهدفة ووضع الفلاش. يوضح الرمز التالي مثالاً واحدًا:
Kotlin
val imageCapture = ImageCapture.Builder() .setFlashMode(...) .setTargetAspectRatio(...) .build()
Java
ImageCapture imageCapture = new ImageCapture.Builder() .setFlashMode(...) .setTargetAspectRatio(...) .build();
بالإضافة إلى خيارات الضبط، توفّر بعض حالات الاستخدام واجهات برمجة تطبيقات لتغيير الإعدادات ديناميكيًا بعد إنشاء حالة الاستخدام. للحصول على معلومات عن الإعدادات الخاصة بحالات الاستخدام الفردية، يُرجى الاطّلاع على تنفيذ معاينة وتحليل الصور والتقاط الصور.
إعدادات CameraXConfig
للتبسيط، تتضمّن CameraX إعدادات تلقائية، مثل مشغّلات داخلية
ومعالجات مناسبة لمعظم سيناريوهات الاستخدام. ومع ذلك، إذا كان
تطبيق متطلبات خاصة أو يفضل تخصيص تلك
الإعدادات، CameraXConfig
هي الواجهة لهذا الغرض
باستخدام CameraXConfig
، يمكن لأي تطبيق تنفيذ ما يلي:
- تحسين وقت استجابة بدء التشغيل باستخدام
setAvailableCameraLimiter()
- قدِّم مشغّل التطبيق إلى CameraX باستخدام
setCameraExecutor()
. - استبدال معالج الجدولة التلقائي بـ
setSchedulerHandler()
- تغيير مستوى التسجيل باستخدام
setMinimumLoggingLevel()
نموذج الاستخدام
توضّح الخطوات التالية كيفية استخدام CameraXConfig
:
- أنشئ عنصر
CameraXConfig
باستخدام الإعدادات المخصّصة. - نفِّذ واجهة
CameraXConfig.Provider
فيApplication
، وأرِد عنصرCameraXConfig
فيgetCameraXConfig()
. - أضِف صف
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() } }
Threads
تتطلّب العديد من واجهات برمجة التطبيقات الخاصة بالنظام الأساسي التي تم إنشاء CameraX استنادًا إليها حظر
التواصل بين العمليات (IPC) مع الأجهزة التي يمكن أن تستغرق أحيانًا مئات
المللي ثانية للردّ. لهذا السبب، يستدعي CameraX واجهات برمجة التطبيقات هذه فقط من
بحيث لا يتم حظر سلسلة التعليمات الرئيسية وواجهة المستخدم
ويظل سائلاً. تدير CameraX هذه المواضيع في الخلفية داخليًا لكي يبدو هذا
السلوك شفافيًا. ومع ذلك، تتطلب بعض التطبيقات تحكّمًا صارمًا
من سلاسل المحادثات. يتيح CameraXConfig
للتطبيق ضبط سلاسل المهام التي تعمل في الخلفية
التي يتم استخدامها من خلال
CameraXConfig.Builder.setCameraExecutor()
و
CameraXConfig.Builder.setSchedulerHandler()
.
منفّذ الكاميرا
يتم استخدام أداة تنفيذ الكاميرا لجميع طلبات البيانات الداخلية من Camera platform API، بالإضافة
إلى طلبات البيانات المرسَلة من هذه واجهات برمجة التطبيقات. يخصص تطبيق CameraX قسمًا داخليًا ويديره
Executor
لتنفيذ هذه المهام.
ومع ذلك، إذا كان التطبيق يتطلب تحكمًا أكثر صرامة في سلاسل المحادثات، استخدم
CameraXConfig.Builder.setCameraExecutor()
معالج المخطِّط
يُستخدم معالج الجدولة لجدولة المهام الداخلية على فترات زمنية ثابتة،
مثل إعادة محاولة فتح الكاميرا عندما لا تكون متاحة. يفعل هذا المعالج
ولكنهم لا ينفذون المهام، بل يرسلونها فقط إلى المسؤول عن تشغيل الكاميرا. من المهم أيضًا
يُستخدم أحيانًا على منصات واجهة برمجة التطبيقات القديمة التي تتطلب
Handler
لعمليات معاودة الاتصال. في هذه الحالات،
لا يزال يتم إرسال طلبات معاودة الاتصال مباشرةً إلى مسؤول تنفيذ الكاميرا. تحدِّد CameraX
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.DEFAULT_FRONT_CAMERA
- طلب استخدام الكاميرا الخلفية التلقائية من خلال
CameraSelector.DEFAULT_BACK_CAMERA
- فلتِر قائمة الأجهزة المتاحة حسب
CameraCharacteristics
باستخدامCameraSelector.Builder.addCameraFilter()
.
يوضح نموذج الرمز البرمجي التالي كيفية إنشاء 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)
اختيار عدة كاميرات بشكل متزامن
بدءًا من الإصدار 1.3 من CameraX، يمكنك أيضًا اختيار كاميرات متعددة في الوقت نفسه. على سبيل المثال، يمكنك الربط بكاميرا أمامية وكاميرا خلفية لالتقاط الصور أو التسجيل مقاطع فيديو من كلا المنظورين في وقت واحد.
عند استخدام ميزة "الكاميرا المتزامنة"، يمكن للجهاز تشغيل كاميرتَين
بعدسات ذات اتجاهَين مختلفَين في الوقت نفسه، أو تشغيل كاميرتَين خلفيتَين في
الوقت نفسه. توضح مجموعة الرموز التالية كيفية ضبط كاميرتين عند
جارٍ الاتصال بالرقم 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 (1920x1080)، أيهما أصغر. | ||
تحليل الصور | نسبة العرض إلى الارتفاع: درجة الدقة التي تناسب الهدف على أفضل وجه الإعداد. | درجة دقة السطح الداخلي |
درجة الدقة التلقائية: الإعداد التلقائي لدرجة الدقة المستهدَفة هو 640×480. يؤدي تعديل كلّ من درجة الدقة المستهدَفة ونسبة العرض إلى الارتفاع المقابلة إلى الحصول على أفضل درجة دقة متوافقة. | ||
الدقة القصوى: أقصى درجة دقة للإخراج من جهاز الكاميرا تبلغ
تنسيق YUV_420_888 الذي تم استرداده من
StreamConfigurationMap.getOutputSizes()
يتم ضبط درجة الدقة المستهدَفة على 640x480 تلقائيًا، لذا إذا أردت درجة دقة أكبر من 640x480، عليك استخدام
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
في إطار
الإحداثيات بعد تدوير الأحجام المتوافقة حسب درجة التدوير المستهدَفة. على سبيل المثال، يمكن لجهاز
باتجاه طبيعي عمودي في دوران الاستهداف الطبيعي الذي يطلب
صورة عمودية تحديد 480×640، ويمكن للجهاز نفسه الذي تم تدويره 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
للبدء، أنشئ
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
واحد أو أكثر مع مجموعات وضع القياس الاختياري من 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 هذا الطلب إلى Camera2
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، يمكنك الرجوع إلى الموارد الإضافية التالية.
درس تطبيقي حول الترميز
نموذج التعليمات البرمجية