گزینه‌های پیکربندی

هر مورد استفاده CameraX را برای کنترل جنبه‌های مختلف عملیات مورد استفاده پیکربندی می‌کنید.

برای مثال، با مورد استفاده ضبط تصویر، می‌توانید نسبت ابعادی هدف و حالت فلاش را تنظیم کنید. کد زیر یک نمونه را نشان می‌دهد:

کاتلین

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

جاوا

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 را فقط به پیام‌های خطا محدود می‌کند:

کاتلین

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

اگر برنامه‌تان لازم است پیکربندی CameraX را پس‌از تنظیم آن بداند، یک نسخه محلی از شیء CameraXConfig نگه دارید.

محدودکننده دوربین

درطول اولین فراخوانی ProcessCameraProvider.getInstance()، CameraX ویژگی‌های دوربین‌های موجود در دستگاه را فهرست و پرسمان می‌کند. چون CameraX باید با قطعات سخت‌افزاری ارتباط برقرار کند، این فرایند می‌تواند برای هر دوربین زمان قابل‌توجهی طول بکشد، به‌ویژه در دستگاه‌های رده‌پایین. اگر برنامه شما فقط از دوربین‌های خاصی در دستگاه استفاده می‌کند، مثلاً دوربین جلو پیش‌فرض، می‌توانید CameraX را طوری تنظیم کنید که دوربین‌های دیگر را نادیده بگیرد، که می‌تواند تأخیر راه‌اندازی را برای دوربین‌هایی که برنامه‌تان استفاده می‌کند کاهش دهد.

اگر CameraSelector ارسال‌شده به CameraXConfig.Builder.setAvailableCamerasLimiter() دوربینی را فیلتر کند، CameraX طوری رفتار می‌کند که گویی آن دوربین وجود ندارد. برای مثال، کد زیر برنامه را محدود می‌کند تا فقط از دوربین پشت پیش‌فرض دستگاه استفاده کند:

کاتلین

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

رشته‌ها

بسیاری از میاناهای برنامه‌سازی کاربردی پلاتفرم که CameraX براساس آن‌ها ساخته شده است، به مسدود کردن ارتباط میان پردازشی (IPC) با سخت‌افزاری نیاز دارند که گاهی اوقات ممکن است صدها میلی‌ثانیه طول بکشد تا پاسخ دهد. به همین دلیل، CameraX این میاناهای برنامه‌سازی کاربردی را فقط از رشته‌های پس‌زمینه فراخوانی می‌کند تا رشته اصلی مسدود نشود و میانای کاربر روان باقی بماند. CameraX این رشته‌های پس‌زمینه را به‌صورت داخلی مدیریت می‌کند تا این رفتار شفاف به‌نظر برسد. بااین‌حال، برخی‌از برنامه‌ها به کنترل دقیق رشته‌ها نیاز دارند. CameraXConfig به برنامه اجازه می‌دهد رشته‌های پس‌زمینه را تنظیم کند که ازطریق CameraXConfig.Builder.setCameraExecutor() و CameraXConfig.Builder.setSchedulerHandler() استفاده می‌شوند.

Camera Executor

مجری دوربین برای همه فراخوانی‌های میانای برنامه‌سازی کاربردی پلاتفرم دوربین داخلی و همچنین برای فراخوانی‌های برگشتی از این میاناهای برنامه‌سازی کاربردی استفاده می‌شود. CameraX برای انجام این تکالیف، Executor داخلی را اختصاص می‌دهد و مدیریت می‌کند. بااین‌حال، اگر برنامه شما به کنترل دقیق‌تر رشته‌ها نیاز دارد، از CameraXConfig.Builder.setCameraExecutor() استفاده کنید.

کنترل‌کننده زمان‌بندی

از گرداننده زمان‌بندی برای زمان‌بندی کردن کارهای داخلی در فواصل زمانی ثابت استفاده می‌شود، مثلاً تلاش مجدد برای باز کردن دوربین وقتی دردسترس نیست. این گرداننده کارها را اجرا نمی‌کند و فقط آن‌ها را به اجراکننده دوربین ارسال می‌کند. گاهی اوقات نیز در پلاتفرم‌های قدیمی API که به 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 براساس قابلیت دستگاه، وضوح و نسبت ابعادی را تغییر می‌دهد. این آسیب‌پذیری ممکن است به دلایل زیر رخ دهد:

  • دستگاه از وضوح درخواستی پشتیبانی نمی‌کند.
  • دستگاه مشکلات سازگاری دارد، مثلاً دستگاه‌های قدیمی که برای عملکرد صحیح به وضوح خاصی نیاز دارند.
  • در برخی‌از دستگاه‌ها، قالب‌های خاصی فقط در نسبت‌های ابعادی خاصی دردسترس هستند.
  • دستگاه برای کدبندی JPEG یا ویدیو، «نزدیک‌ترین mod16» را ترجیح می‌دهد. برای اطلاعات بیشتر، به SCALER_STREAM_CONFIGURATION_MAP مراجعه کنید.

اگرچه CameraX جلسه را ایجاد و مدیریت می‌کند، همیشه اندازه‌های تصویر برگردانده‌شده را در خروجی مورد استفاده در کد خود بررسی کنید و بر این اساس تنظیم کنید.

چرخش

به‌طور پیش‌فرض، چرخش دوربین طوری تنظیم شده است که با چرخش نمایشگر پیش‌فرض درطول ایجاد مورد استفاده مطابقت داشته باشد. در این حالت پیش‌فرض، CameraX خروجی‌هایی تولید می‌کند تا برنامه با آنچه انتظار دارید در پیش‌نمایش ببینید مطابقت داشته باشد. می‌توانید چرخش را به مقدار سفارشی تغییر دهید تا از دستگاه‌های چندنمایشگری پشتیبانی شود. برای این کار، جهت نمایش فعلی را هنگام پیکربندی اشیای مورد استفاده یا به‌صورت پویا پس‌از ایجاد آن‌ها ارسال کنید.

برنامه شما می‌تواند چرخش هدف را بااستفاده از تنظیمات پیکربندی تنظیم کند. سپس می‌تواند تنظیمات چرخش را بااستفاده از روش‌های میاناهای برنامه‌سازی کاربردی مورد استفاده (مانند ImageAnalysis.setTargetRotation()) به‌روز کند، حتی زمانی که چرخه حیات در وضعیت اجرا باشد. ممکن است زمانی از این استفاده کنید که برنامه در حالت عمودی قفل شده باشد—و بنابراین هیچ پیکربندی مجددی در چرخش رخ ندهد—اما مورد استفاده عکس یا تحلیل باید از چرخش فعلی دستگاه مطلع باشد. برای مثال، ممکن است به آگاهی از چرخش نیاز باشد تا چهره‌ها برای تشخیص چهره به‌درستی جهت‌یابی شوند، یا عکس‌ها روی افقی یا عمودی تنظیم شوند.

داده‌های تصاویر ثبت‌شده ممکن است بدون اطلاعات چرخش ذخیره شود. داده‌های Exif حاوی اطلاعات چرخش است تا برنامه‌های گالری بتوانند تصویر را پس‌از ذخیره کردن در جهت درست نشان دهند.

برای نمایش داده‌های پیش‌نمایش با جهت صحیح، می‌توانید از خروجی فراداده Preview.PreviewOutput() برای ایجاد تبدیل‌ها استفاده کنید.

نمونه کد زیر نحوه تنظیم چرخش در رویداد جهت‌یابی را نشان می‌دهد:

کاتلین

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()
}

جاوا

@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 تضمین می‌کند که مستطیل‌های برش همه موارد استفاده در گروه به همان ناحیه در حسگر دوربین اشاره می‌کنند.

تکه‌کد زیر نحوه استفاده از این دو کلاس را نشان می‌دهد:

کاتلین

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)

جاوا

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 را نشان می‌دهد:

کاتلین

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

جاوا

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

در مثال قبلی، آنچه برنامه از ImageAnalysis و ImageCapture دریافت می‌کند با آنچه کاربر نهایی در PreviewView می‌بیند مطابقت دارد، با فرض اینکه نوع مقیاس PreviewView روی پیش‌فرض، FILL_CENTER، تنظیم شده باشد. پس‌از اعمال مستطیل برش و چرخش به میان‌گیر خروجی، تصویر همه موارد استفاده یکسان است، اگرچه ممکن است وضوح متفاوتی داشته باشد. برای اطلاعات بیشتر درباره نحوه اعمال اطلاعات تبدیل، به خروجی تبدیل مراجعه کنید.

انتخاب دوربین

CameraX به‌طور خودکار بهترین دستگاه دوربین را برای الزامات و موارد استفاده برنامه‌تان انتخاب می‌کند. اگر می‌خواهید از دستگاهی غیراز دستگاهی که برایتان انتخاب شده است استفاده کنید، چند گزینه وجود دارد:

نمونه کد زیر نحوه ایجاد CameraSelector را برای تأثیرگذاری بر انتخاب دستگاه نشان می‌دهد:

کاتلین

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 برگردانده‌شده نشان می‌دهد.

کاتلین

// 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]

جاوا

// 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 وضوح‌ها را براساس مجموعه موارد استفاده محدودشده با درنظر گرفتن سطح سخت‌افزار پشتیبانی‌شده دستگاه و با درنظر گرفتن تفاوت‌های خاص دستگاه (جایی که دستگاه از پیکربندی‌های جریان موجود فراتر می‌رود یا آن‌ها را برآورده نمی‌کند) تعیین می‌کند. هدف این است که برنامه بتواند در طیف گسترده‌ای از دستگاه‌ها اجرا شود و درعین‌حال مسیرهای کد مختص دستگاه به حداقل برسد.

نسبت ابعادی پیش‌فرض برای موارد استفاده ضبط تصویر و تحلیل تصویر ۴:۳ است.

موارد استفاده دارای نسبت ابعادی قابل‌پیکربندی هستند تا به برنامه اجازه دهند نسبت ابعادی موردنظر را براساس طراحی واسط کاربر مشخص کند. خروجی CameraX به‌گونه‌ای تولید می‌شود که تا حد امکان با نسبت‌های ابعادی درخواستی که دستگاه پشتیبانی می‌کند مطابقت داشته باشد. اگر وضوح منطبق دقیقی پشتیبانی نشود، وضوحی که بیشترین شرایط را برآورده کند انتخاب می‌شود. بنابراین، برنامه تعیین می‌کند که دوربین چگونه در برنامه ظاهر شود و CameraX بهترین تنظیمات وضوح دوربین را برای برآورده کردن این نیاز در دستگاه‌های مختلف تعیین می‌کند.

برای مثال، برنامه می‌تواند هرکدام از کارهای زیر را انجام دهد:

  • وضوح هدف ۴:۳ یا ۱۶:۹ را برای مورد استفاده مشخص کنید
  • وضوح سفارشی را مشخص کنید، CameraX تلاش می‌کند نزدیک‌ترین مطابقت را پیدا کند
  • نسبت ابعادی برش را برای ImageCapture مشخص کنید

CameraX وضوح‌های سطح Camera2 داخلی را به‌طور خودکار انتخاب می‌کند. جدول زیر وضوح‌ها را نشان می‌دهد:

مورد استفاده وضوح سطح داخلی وضوح داده‌های خروجی
پیش‌نمایش نسبت ابعادی: وضوحی که بهترین تناسب را بین هدف و تنظیمات ایجاد می‌کند. وضوح سطح داخلی. فراداده برای این ارائه می‌شود که View بتواند برای نسبت ابعادی هدف برش دهد، مقیاس‌بندی کند، و بچرخاند.
وضوح پیش‌فرض: بالاترین وضوح پیش‌نمایش، یا بالاترین وضوح ترجیحی دستگاه که با نسبت ابعادی «پیش‌نمایش» مطابقت دارد.
حداکثر وضوح: اندازه پیش‌نمایش، که به بهترین اندازه مطابق با وضوح صفحه‌نمایش دستگاه، یا به ۱۰۸۰ پیکسل (۱۹۲۰×۱۰۸۰) اشاره دارد، هرکدام که کوچک‌تر باشد.
تحلیل تصویر نسبت ابعادی: وضوحی که بهترین تناسب را با هدف در تنظیمات دارد. وضوح سطح داخلی.
وضوح پیش‌فرض: تنظیم وضوح هدف پیش‌فرض ۶۴۰×۴۸۰ است. تنظیم کردن وضوح هدف و نسبت ابعادی مربوطه منجر به بهترین وضوح پشتیبانی‌شده می‌شود.
حداکثر وضوح: حداکثر وضوح خروجی دستگاه دوربین با قالب YUV_420_888 که از StreamConfigurationMap.getOutputSizes() بازیابی شده است. وضوح هدف به‌طور پیش‌فرض روی ۶۴۰x۴۸۰ تنظیم شده است، بنابراین اگر وضوحی بزرگ‌تر از ۶۴۰x۴۸۰ می‌خواهید، باید از setTargetResolution() و setTargetAspectRatio() استفاده کنید تا نزدیک‌ترین وضوح را از بین وضوح‌های پشتیبانی‌شده دریافت کنید.
ضبط کردن تصویر نسبت ابعادی: نسبت ابعادی که بهترین تناسب را با تنظیمات دارد. وضوح سطح داخلی.
وضوح پیش‌فرض: بالاترین وضوح موجود، یا بالاترین وضوح ترجیحی دستگاه که با نسبت ابعادی ImageCapture مطابقت دارد.
حداکثر وضوح: حداکثر وضوح خروجی دستگاه دوربین در قالب JPEG. از StreamConfigurationMap.getOutputSizes() برای بازیابی این مورد استفاده کنید.

وضوح را مشخص کنید

هنگام ساختن موارد استفاده بااستفاده از روش setTargetResolution(Size resolution)، می‌توانید وضوح‌های خاصی را تنظیم کنید، همان‌طور که در نمونه کد زیر نشان داده شده است:

کاتلین

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

جاوا

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

نمی‌توانید هم نسبت ابعادی هدف و هم وضوح هدف را برای یک مورد استفاده تنظیم کنید. انجام این کار باعث می‌شود هنگام ساختن شیء پیکربندی، IllegalArgumentException ایجاد شود.

وضوح Size را در قاب مختصات پس‌از چرخاندن اندازه‌های پشتیبانی‌شده با چرخش هدف بیان کنید. برای مثال، دستگاهی با جهت طبیعی عمودی در چرخش هدف طبیعی که تصویر عمودی درخواست می‌کند می‌تواند ۴۸۰×۶۴۰ را مشخص کند، و همان دستگاه، با چرخش ۹۰ درجه و هدف‌گیری جهت افقی می‌تواند ۴۸۰×۶۴۰ را مشخص کند.

وضوح هدف تلاش می‌کند حداقل حدودی را برای وضوح تصویر تعیین کند. وضوح واقعی تصویر نزدیک‌ترین وضوح موجود ازنظر اندازه است که از وضوح هدف کوچک‌تر نیست، همان‌طور که توسط پیاده‌سازی «دوربین» تعیین شده است.

بااین‌حال، اگر وضوحی برابر یا بزرگ‌تر از وضوح هدف وجود نداشته باشد، نزدیک‌ترین وضوح دردسترس که کوچک‌تر از وضوح هدف است انتخاب می‌شود. وضوح‌هایی که نسبت ابعادی یکسانی با Size ارائه‌شده دارند اولویت بالاتری نسبت به وضوح‌هایی با نسبت ابعادی متفاوت دارند.

CameraX بهترین وضوح مناسب را براساس درخواست‌ها اعمال می‌کند. اگر نیاز اصلی برآورده کردن نسبت ابعادی است، فقط setTargetAspectRatio را مشخص کنید، و CameraX وضوح خاصی را که براساس دستگاه مناسب است تعیین می‌کند. اگر نیاز اصلی برنامه مشخص کردن وضوح برای کارآمدتر کردن پردازش تصویر است (برای مثال، تصویر کوچک یا متوسط براساس قابلیت پردازش دستگاه)، از setTargetResolution(Size resolution) استفاده کنید.

اگر برنامه‌تان به وضوح دقیقی نیاز دارد، جدول موجود در createCaptureSession() را ببینید تا مشخص شود هر سطح سخت‌افزار از چه حداکثر وضوحی پشتیبانی می‌کند. برای بررسی وضوح‌های خاصی که دستگاه فعلی پشتیبانی می‌کند، به StreamConfigurationMap.getOutputSizes(int) مراجعه کنید.

اگر برنامه‌تان در Android 10 یا بالاتر اجرا می‌شود، می‌توانید از isSessionConfigurationSupported() برای درستی‌سنجی SessionConfiguration خاصی استفاده کنید.

کنترل خروجی دوربین

علاوه‌بر اینکه به شما امکان می‌دهد خروجی دوربین را درصورت نیاز برای هر مورد استفاده جداگانه پیکربندی کنید، CameraX همچنین واسط‌های زیر را برای پشتیبانی از عملیات دوربین مشترک برای همه موارد استفاده محدود پیاده‌سازی می‌کند:

  • CameraControl به شما امکان می‌دهد ویژگی‌های رایج دوربین را پیکربندی کنید.
  • CameraInfo به شما امکان می‌دهد وضعیت آن ویژگی‌های رایج دوربین را جستجو کنید.

ویژگی‌های دوربین پشتیبانی‌شده با CameraControl عبارت‌اند از:

  • بزرگ‌نمایی
  • چراغ
  • کانونی کردن و نورسنجی (کانونی کردن با تک‌ضرب)
  • جبران نوردهی

دریافت نمونه‌های CameraControl و CameraInfo

نمونه‌های CameraControl و CameraInfo را بااستفاده از شیء Camera که توسط ProcessCameraProvider.bindToLifecycle() برگردانده شده است بازیابی کنید. کد زیر نمونه‌ای را نشان می‌دهد:

کاتلین

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

جاوا

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()

برای مثال، می‌توانید پس‌از فراخوانی bindToLifecycle()، بزرگ‌نمایی و سایر عملیات CameraControl را ارسال کنید. پس‌از توقف یا ازبین بردن فعالیت استفاده‌شده برای اتصال نمونه دوربین، CameraControl دیگر نمی‌تواند عملیات را اجرا کند و ListenableFuture ناموفق برمی‌گرداند.

بزرگ‌نمایی

‫CameraControl دو روش برای تغییر سطح بزرگ‌نمایی ارائه می‌دهد:

  • setZoomRatio() بزرگ‌نمایی را براساس نسبت بزرگ‌نمایی تنظیم می‌کند.

    نسبت باید در محدوده CameraInfo.getZoomState().getValue().getMinZoomRatio() و CameraInfo.getZoomState().getValue().getMaxZoomRatio() باشد. درغیراین‌صورت، تابع ListenableFuture ناموفق برمی‌گرداند.

  • setLinearZoom() بزرگ‌نمایی فعلی را با مقدار بزرگ‌نمایی خطی از ۰ تا ۱٫۰ تنظیم می‌کند.

    مزیت بزرگ‌نمایی خطی این است که میدان دید (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 از ۰ تا ۱ است و اندازه پیش‌فرض آن ۰٫۱۵f است. هنگام فراخوانی MeteringPointFactory.createPoint(float x, float y, float size)، CameraX یک ناحیه مستطیلی با مرکز (x, y) برای size ارائه‌شده ایجاد می‌کند.

کد زیر نحوه ایجاد MeteringPoint را نشان می‌دهد:

کاتلین

// 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 تشکیل شده است. کد زیر این کاربرد را نشان می‌دهد:

کاتلین

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 در پلاتفرمی که فقط از ۲ MeteringPoint پشتیبانی می‌کند ارائه شود، فقط از ۲ MeteringPoint اول استفاده می‌شود. ‫CameraX از MeteringPoint نهایی صرف‌نظر می‌کند.

جبران نوردهی

جبران نوردهی زمانی مفید است که برنامه‌ها نیاز به تنظیم دقیق مقادیر نوردهی (EV) فراتر از نتیجه خروجی نوردهی خودکار (AE) داشته باشند. مقادیر جبران نوردهی به روش زیر ترکیب می‌شوند تا نوردهی لازم برای شرایط تصویر فعلی تعیین شود:

Exposure = ExposureCompensationIndex * ExposureCompensationStep

CameraX تابع Camera.CameraControl.setExposureCompensationIndex() را برای تنظیم جبران نوردهی به‌عنوان مقدار نمایه ارائه می‌دهد.

مقادیر شاخص مثبت تصویر را روشن‌تر می‌کند، درحالی‌که مقادیر منفی تصویر را تاریک‌تر می‌کند. برنامه‌ها می‌توانند محدوده پشتیبانی‌شده را با CameraInfo.ExposureState.exposureCompensationRange() که در بخش بعدی توضیح داده شده است جستجو کنند. اگر مقدار پشتیبانی شود، ListenableFuture برگردانده‌شده وقتی مقدار با موفقیت در درخواست ضبط فعال شود تکمیل می‌شود؛ اگر نمایه مشخص‌شده خارج از محدوده پشتیبانی‌شده باشد، setExposureCompensationIndex() باعث می‌شود ListenableFuture برگردانده‌شده فوراً با نتیجه ناموفق تکمیل شود.

CameraX فقط جدیدترین درخواست setExposureCompensationIndex() معوقه را نگه می‌دارد و فراخوانی تابع چندین بار قبل‌از اجرای درخواست قبلی منجر به لغو آن می‌شود.

قطعه کد زیر شاخص جبران نوردهی را تنظیم می‌کند و یک فراخوانی برگشتی برای زمانی که درخواست تغییر نوردهی اجرا شده است ثبت می‌کند:

کاتلین

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 مقداردهی اولیه می‌کند:

کاتلین

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