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

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

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

کاتلین

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

جاوا

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

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

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

موضوعات

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

مجری دوربین

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

برنامه ریز

کنترل‌کننده زمان‌بندی برای برنامه‌ریزی کارهای داخلی در فواصل زمانی ثابت، مانند باز کردن مجدد دوربین در زمانی که در دسترس نیست، استفاده می‌شود. این کنترلر کارها را اجرا نمی کند و فقط آنها را به مجری دوربین ارسال می کند. همچنین گاهی اوقات در پلتفرم های API قدیمی که به یک Handler برای پاسخگویی به تماس نیاز دارند استفاده می شود. در این موارد باز هم تماس‌های تماس مستقیماً به مجری دوربین ارسال می‌شوند. CameraX یک HandlerThread داخلی را برای انجام این کارها اختصاص داده و مدیریت می کند، اما می توانید با CameraXConfig.Builder.setSchedulerHandler() آن را لغو کنید.

ورود به سیستم

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

  • Log.DEBUG (پیش‌فرض)
  • Log.INFO
  • Log.WARN
  • Log.ERROR

برای توصیف دقیق این سطوح گزارش به مستندات Android Log مراجعه کنید. از CameraXConfig.Builder.setMinimumLoggingLevel(int) برای تنظیم سطح گزارش مناسب برای برنامه خود استفاده کنید.

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

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

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

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

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

چرخش

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

برنامه شما می تواند چرخش هدف را با استفاده از تنظیمات پیکربندی تنظیم کند. سپس می‌تواند تنظیمات چرخش را با استفاده از روش‌های استفاده از APIهای مورد استفاده (مانند 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 دارد.

Crop rect

به طور پیش فرض، crop rect بافر کامل rect است. می توانید آن را با 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 بزرگترین Crop Rect ممکن را بر اساس ویژگی های viewport و موارد استفاده پیوست شده محاسبه می کند. معمولاً برای دستیابی به افکت WYSIWYG، می‌توانید Viewport را بر اساس مورد استفاده پیش‌نمایش پیکربندی کنید. یک راه ساده برای دریافت ویوپورت استفاده از 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 و نحوه دریافت هر دو شی Camera از شی 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 بر اساس مجموعه موارد استفاده محدود شده با در نظر گرفتن سطح سخت‌افزار پشتیبانی شده دستگاه و با در نظر گرفتن واریانس خاص دستگاه (در مواردی که دستگاه از پیکربندی‌های جریان موجود فراتر می‌رود یا مطابقت ندارد)، وضوح‌ها را تعیین می‌کند. هدف این است که به برنامه اجازه دهیم در طیف گسترده ای از دستگاه ها اجرا شود و در عین حال مسیرهای کد خاص دستگاه را به حداقل برسانیم.

نسبت تصویر پیش فرض برای موارد استفاده از عکس برداری و تحلیل تصویر 4:3 است.

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

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

  • وضوح هدف 4:3 یا 16:9 را برای یک مورد استفاده مشخص کنید
  • رزولوشن سفارشی را مشخص کنید، که CameraX سعی می‌کند نزدیک‌ترین تطابق را پیدا کند
  • یک نسبت تصویر برش برای ImageCapture مشخص کنید

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

مورد استفاده وضوح سطح داخلی وضوح داده های خروجی
پیش نمایش نسبت تصویر: وضوحی که بهترین تناسب را با هدف با تنظیمات دارد. وضوح سطح داخلی ابرداده ارائه شده است تا امکان برش، مقیاس و چرخش View برای نسبت ابعاد هدف را فراهم کند.
وضوح پیش‌فرض: بالاترین وضوح پیش‌نمایش یا بالاترین وضوح ترجیحی دستگاه که با نسبت تصویر پیش‌نمایش مطابقت دارد.
حداکثر وضوح: اندازه پیش نمایش، که به بهترین اندازه مطابقت با وضوح صفحه نمایش دستگاه یا به 1080p (1920x1080) اشاره دارد که هر کدام کوچکتر باشد.
تجزیه و تحلیل تصویر نسبت تصویر: وضوحی که بهترین تناسب با هدف را با تنظیمات دارد. وضوح سطح داخلی
وضوح پیش فرض: تنظیم وضوح هدف پیش فرض 640x480 است. تنظیم وضوح هدف و نسبت تصویر متناظر منجر به بهترین وضوح پشتیبانی می شود.
حداکثر وضوح: حداکثر وضوح خروجی دستگاه دوربین با فرمت YUV_420_888 که از StreamConfigurationMap.getOutputSizes() بازیابی شده است. رزولوشن هدف به طور پیش‌فرض 640x480 تنظیم شده است، بنابراین اگر رزولوشن بزرگ‌تر از 640x480 می‌خواهید، باید از 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 در کادر مختصات بیان کنید. به عنوان مثال، دستگاهی با جهت گیری طبیعی پرتره در چرخش هدف طبیعی که درخواست تصویر پرتره می کند، می تواند 480x640 را مشخص کند و همان دستگاه، با چرخش 90 درجه و جهت گیری افقی هدف می تواند 640x480 را مشخص کند.

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

با این حال، اگر وضوحی برابر یا بزرگتر از وضوح هدف وجود نداشته باشد، نزدیکترین وضوح موجود کوچکتر از وضوح هدف انتخاب می شود. رزولوشن هایی با نسبت ابعاد یکسان با 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()

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

بزرگنمایی ضربه بزنید؛

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 که توسط هر دو API بازگردانده شده است، این گزینه را برای برنامه‌ها ارائه می‌دهد که در صورت تکمیل درخواست تکراری با مقدار بزرگنمایی مشخص شده، مطلع شوند. علاوه بر این، اگر در حالی که عملیات قبلی هنوز در حال اجرا است، مقدار بزرگنمایی جدیدی تنظیم کنید، ListenableFuture عملیات بزرگنمایی قبلی فوراً از کار می افتد.

مشعل

CameraControl.enableTorch(boolean) مشعل را فعال یا غیرفعال می کند (همچنین به عنوان چراغ قوه شناخته می شود).

CameraInfo.getTorchState() می توان برای پرس و جو از وضعیت فعلی مشعل استفاده کرد. می توانید مقدار بازگردانده شده توسط CameraInfo.hasFlashUnit() بررسی کنید تا مشخص کنید مشعل موجود است یا خیر. در غیر این صورت، فراخوانی CameraControl.enableTorch(boolean) باعث می شود که ListenableFuture برگشتی فوراً با نتیجه ناموفق کامل شود و حالت مشعل را روی TorchState.OFF تنظیم می کند.

هنگامی که مشعل فعال است، بدون در نظر گرفتن تنظیمات حالت فلش، در هنگام گرفتن عکس و فیلم روشن می ماند. flashMode در ImageCapture فقط زمانی کار می کند که مشعل غیرفعال باشد.

فوکوس و اندازه گیری

CameraControl.startFocusAndMetering() با تنظیم مناطق اندازه گیری AF/AE/AWB بر اساس FocusMeteringAction داده شده، فوکوس خودکار و نورسنجی را فعال می کند. این اغلب برای پیاده سازی ویژگی "ضربه برای فوکوس" در بسیاری از برنامه های دوربین استفاده می شود.

نقطه اندازه گیری

برای شروع، با استفاده از MeteringPointFactory.createPoint(float x, float y, float size) یک MeteringPoint ایجاد کنید. یک MeteringPoint یک نقطه روی Surface دوربین را نشان می دهد. این به شکل عادی ذخیره می شود تا بتوان آن را به راحتی به مختصات حسگر برای تعیین مناطق AF/AE/AWB تبدیل کرد.

اندازه MeteringPoint از 0 تا 1 با اندازه پیش فرض 0.15f متغیر است. هنگام فراخوانی 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 با 3 MeteringPoint در پلتفرمی که فقط 2 را پشتیبانی می کند عرضه شود، فقط از 2 MeteringPoint اول استفاده می شود. آخرین MeteringPoint توسط CameraX نادیده گرفته می شود.

جبران نوردهی

جبران نوردهی زمانی مفید است که برنامه‌ها نیاز به تنظیم دقیق مقادیر نوردهی (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