تحليل الصور

توفِّر حالة الاستخدام تحليل الصورة لتطبيقك صورة يمكن الوصول إليها من خلال وحدة المعالجة المركزية (CPU) حيث يمكنك من خلالها إجراء معالجة الصور أو الرؤية الحاسوبية أو استنتاج تعلُّم الآلة. ينفِّذ التطبيق طريقة analyze() يتم تشغيلها على كل إطار.

للتعرّف على كيفية دمج حزمة تعلُّم الآلة من Google مع تطبيق CameraX، راجِع أداة تحليل تعلّم الآلة.

أوضاع التشغيل

عندما يتعذّر على مسار تحليل التطبيق مواكبة متطلبات عدد اللقطات في الثانية في CameraX، يمكن ضبط CameraX بهدف إسقاط الإطارات بإحدى الطرق التالية:

  • غير الحظر (تلقائيًا): في هذا الوضع، يخزّن مسؤول التنفيذ دائمًا أحدث صورة في مخزن مؤقت للصور (على غرار قائمة الانتظار بعمق واحد) بينما يحلل التطبيق الصورة السابقة. إذا تلقت CameraX صورة جديدة قبل انتهاء معالجة التطبيق، سيتم حفظ الصورة الجديدة في المخزن المؤقت نفسه، وستحل الصورة السابقة محل الصورة السابقة. يُرجى العلم أنّ السمة ImageAnalysis.Builder.setImageQueueDepth() ليس لها أي تأثير في هذا السيناريو، ويتم دائمًا استبدال محتوى المخزن المؤقت. يمكنك تفعيل وضع عدم الحظر هذا عن طريق استدعاء setBackpressureStrategy() باستخدام STRATEGY_KEEP_ONLY_LATEST. لمزيد من المعلومات حول الآثار المترتبة على منفّذي الطلبات، يمكنك الاطّلاع على المستندات المرجعية الخاصة بـ STRATEGY_KEEP_ONLY_LATEST.

  • الحظر: في هذا الوضع، يمكن للمسؤول التنفيذي الداخلي إضافة عدة صور إلى قائمة انتظار الصور الداخلية ويبدأ في تجاهل الإطارات فقط عندما تكون قائمة الانتظار ممتلئة. يحدث الحظر على مستوى نطاق الكاميرا بالكامل: إذا كان لجهاز الكاميرا عدة حالات استخدام مرتبطة، سيتم حظر جميع حالات الاستخدام هذه أثناء معالجة CameraX لهذه الصور. على سبيل المثال، عند ربط كل من المعاينة وتحليل الصور بجهاز كاميرا، سيتم حظر المعاينة أيضًا أثناء معالجة CameraX للصور. يمكنك تفعيل وضع الحظر عن طريق تمرير STRATEGY_BLOCK_PRODUCER إلى setBackpressureStrategy(). يمكنك أيضًا ضبط عمق قائمة انتظار الصور باستخدام ImageAnalysis.Builder.setImageQueueDepth().

باستخدام وقت الاستجابة المنخفض وأدوات التحليل العالية الأداء التي يكون فيها الوقت الإجمالي لتحليل الصورة أقل من مدة إطار كاميرا CameraX (على سبيل المثال، 16 ملي ثانية و60 لقطة في الثانية)، فإن أي من وضعَي التشغيل يوفران تجربة شاملة سلسة. قد يظل وضع الحظر مفيدًا في بعض السيناريوهات، مثل التعامل مع اضطرابات قصيرة جدًا في النظام.

مع وقت الاستجابة الطويل وأدوات تحليل الأداء العالي، من الضروري استخدام وضع الحظر مع قائمة انتظار أطول لتعويض وقت الاستجابة. لاحظ، مع ذلك، أن التطبيق لا يزال بإمكانه معالجة جميع الإطارات.

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

التنفيذ

لاستخدام تحليل الصور في تطبيقك، اتّبِع الخطوات التالية:

بعد الربط مباشرةً، ترسل CameraX الصور إلى أداة التحليل المسجَّل. بعد الانتهاء من التحليل، يمكنك استدعاء الدالة ImageAnalysis.clearAnalyzer() أو إلغاء ربط حالة استخدام ImageAnalysis لإيقاف التحليل.

إنشاء حالة استخدام أداة "تحليل الصور"

يربط ImageAnalysis أداة التحليل (مستهلك الصور) بكاميرا CameraX، وهي منتج صور. يمكن أن تستخدم التطبيقات ImageAnalysis.Builder لإنشاء كائن ImageAnalysis. باستخدام ImageAnalysis.Builder، يمكن للتطبيق ضبط ما يلي:

ويمكن للتطبيقات ضبط إما درجة الدقة أو نسبة العرض إلى الارتفاع، ولكن لا يمكنها ضبط الاثنين معًا. وتعتمد درجة دقة الإخراج الدقيقة على الحجم المطلوب للتطبيق (أو نسبة العرض إلى الارتفاع) وقد تختلف عن الحجم أو النسبة المطلوبة. للحصول على معلومات حول خوارزمية مطابقة درجة الدقة، يُرجى الاطّلاع على مستندات setTargetResolution()

يمكن لأحد التطبيقات ضبط وحدات بكسل الإخراج للصورة لتكون YUV (الخيار التلقائي) أو مساحات ألوان RGBA. عند ضبط تنسيق إخراج RGBA، تعمل CameraX داخليًا على تحويل الصور من YUV إلى مساحة اللون RGBA وتحزم وحدات بت الصورة في ByteBuffer المستوى الأول لـ ImageProxy (لا يتم استخدام المستوىين الأخريين) بالتسلسل التالي:

ImageProxy.getPlanes()[0].buffer[0]: alpha
ImageProxy.getPlanes()[0].buffer[1]: red
ImageProxy.getPlanes()[0].buffer[2]: green
ImageProxy.getPlanes()[0].buffer[3]: blue
...

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

إنشاء أداة التحليل

يمكن للتطبيقات إنشاء أدوات تحليل من خلال تنفيذ واجهة ImageAnalysis.Analyzer وتجاوز analyze(ImageProxy image). في كل أداة تحليل، تتلقى التطبيقات ImageProxy، وهو برنامج تضمين للرمز Media.Image. يمكن الاستعلام عن تنسيق الصورة باستخدام ImageProxy.getFormat(). يُعد التنسيق إحدى القيم التالية التي يوفرها التطبيق مع ImageAnalysis.Builder:

  • ImageFormat.RGBA_8888 إذا طلب التطبيق الحصول على مبلغ OUTPUT_IMAGE_FORMAT_RGBA_8888.
  • ImageFormat.YUV_420_888 إذا طلب التطبيق الحصول على مبلغ OUTPUT_IMAGE_FORMAT_YUV_420_888.

اطّلع على حالة استخدام أداة "تحليل الصورة لإنشاء" لتكوينات مساحة اللون وأين يمكن استرداد وحدات بايت البكسل.

داخل أداة التحليل، يجب أن يقوم التطبيق بما يلي:

  1. حلِّل إطارًا معيّنًا بأسرع ما يمكن، ويفضَّل أن يكون ضمن الحدّ الزمني المحدّد لعدد اللقطات في الثانية (على سبيل المثال، أقل من 32 ملي ثانية للحالات التي تتضمّن 30 لقطة في الثانية). إذا لم يتمكن التطبيق من تحليل إطار بسرعة كافية، يمكنك استخدام إحدى آليات إزالة الإطار المتوافقة.
  2. ارفع ImageProxy إلى CameraX عن طريق الاتصال بـ ImageProxy.close(). تجدر الإشارة إلى أنّه يجب عدم استدعاء دالة الإغلاق Media.Image الملفوفة (Media.Image.close()).

ويمكن للتطبيقات استخدام Media.Image الالتفافية داخل ImageProxy مباشرةً. ما عليك سوى عدم استدعاء Media.Image.close() على الصورة الملتفة، لأنّ ذلك قد يوقف آلية مشاركة الصور داخل CameraX، بل استخدِم ImageProxy.close() لفتح Media.Image الأساسي إلى CameraX.

إعداد أداة التحليل لاستخدام ميزة "تحليل الصور"

بعد إنشاء أداة تحليل، استخدِم ImageAnalysis.setAnalyzer() لتسجيلها لبدء التحليل. بمجرد الانتهاء من التحليل، استخدِم ImageAnalysis.clearAnalyzer() لإزالة أداة التحليل المسجَّلة.

يمكن ضبط أداة تحليل نشطة واحدة فقط لتحليل الصور. يؤدي استدعاء ImageAnalysis.setAnalyzer() إلى استبدال أداة التحليل المسجَّلة إذا كانت متوفّرة من قبل. يمكن للتطبيقات تعيين أداة تحليل جديدة في أي وقت، قبل أو بعد ربط حالة الاستخدام.

ربط تحليل الصور بدورة حياة

ننصحك بشدة بربط ImageAnalysis بمسار نشاط AndroidX الحالي باستخدام الدالة ProcessCameraProvider.bindToLifecycle(). تجدر الإشارة إلى أنّ الدالة bindToLifecycle() تعرض جهاز Camera المحدّد، والذي يمكن استخدامه لضبط الإعدادات المتقدّمة، مثل التعرّض للضوء وغير ذلك. يمكنك الاطّلاع على هذا الدليل للحصول على مزيد من المعلومات حول التحكّم في إخراج الكاميرا.

يجمع المثال التالي بين كل شيء بدءًا من الخطوات السابقة، وربط حالات استخدام CameraX ImageAnalysis وPreview بمالك lifeCycle:

Kotlin

val imageAnalysis = ImageAnalysis.Builder()
    // enable the following line if RGBA output is needed.
    // .setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888)
    .setTargetResolution(Size(1280, 720))
    .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
    .build()
imageAnalysis.setAnalyzer(executor, ImageAnalysis.Analyzer { imageProxy ->
    val rotationDegrees = imageProxy.imageInfo.rotationDegrees
    // insert your code here.
    ...
    // after done, release the ImageProxy object
    imageProxy.close()
})

cameraProvider.bindToLifecycle(this as LifecycleOwner, cameraSelector, imageAnalysis, preview)

Java

ImageAnalysis imageAnalysis =
    new ImageAnalysis.Builder()
        // enable the following line if RGBA output is needed.
        //.setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888)
        .setTargetResolution(new Size(1280, 720))
        .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
        .build();

imageAnalysis.setAnalyzer(executor, new ImageAnalysis.Analyzer() {
    @Override
    public void analyze(@NonNull ImageProxy imageProxy) {
        int rotationDegrees = imageProxy.getImageInfo().getRotationDegrees();
            // insert your code here.
            ...
            // after done, release the ImageProxy object
            imageProxy.close();
        }
    });

cameraProvider.bindToLifecycle((LifecycleOwner) this, cameraSelector, imageAnalysis, preview);

مراجع إضافية

لمزيد من المعلومات حول CameraX، اطّلع على الموارد الإضافية التالية.

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

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

  • نماذج تطبيقات من CameraX