Предпросмотр камеры

Примечание. На этой странице рассматривается пакет Camera2. Если вашему приложению не требуются определенные низкоуровневые функции Camera2, рекомендуем использовать CameraX. Обе библиотеки поддерживают Android 5.0 (API уровня 21) и более поздние версии.

На устройствах Android ориентация камеры и предварительного просмотра не всегда совпадает.

Камера находится в фиксированном положении на устройстве, независимо от того, является ли устройство телефоном, планшетом или компьютером. При изменении ориентации устройства меняется и ориентация камеры.

В результате приложения камеры обычно предполагают фиксированную связь между ориентацией устройства и соотношением сторон предварительного просмотра камеры. Если телефон находится в портретной ориентации, предполагается, что высота изображения с камеры больше его ширины. Когда телефон (и камера) повернуты в горизонтальное положение, изображение в окне предварительного просмотра должно быть шире, чем выше.

Однако эти предположения не учитывают новые форм-факторы, такие как складные устройства, и режимы отображения, например многооконный и многоэкранный. Складные устройства меняют размер дисплея и соотношение сторон без изменения ориентации. В многооконном режиме приложения камеры ограничены частью экрана, а предпросмотр масштабируется независимо от ориентации устройства. Режим нескольких дисплеев позволяет использовать дополнительные дисплеи, которые могут иметь не такую ориентацию, как основной дисплей.

Ориентация камеры

В определении совместимости Android указано, что датчик изображения камеры должен быть ориентирован так, чтобы длинная сторона камеры совпадала с длинной стороной экрана. То есть, когда устройство находится в горизонтальной ориентации, камеры ДОЛЖНЫ делать снимки в горизонтальной ориентации. Это относится к устройствам как с горизонтальной, так и с вертикальной ориентацией.

Такое расположение камеры и экрана позволяет максимально увеличить область отображения видоискателя в приложении камеры. Кроме того, датчики изображения обычно выводят данные в альбомной ориентации, чаще всего с соотношением сторон 4:3.

Телефон и датчик камеры в вертикальной ориентации.
Рисунок 1. Типичное соотношение ориентации телефона и датчика камеры.

Естественная ориентация датчика камеры – горизонтальная. На рисунке 1 датчик фронтальной камеры (направленной в ту же сторону, что и экран) повернут на 270 градусов относительно телефона, чтобы соответствовать документу Android Compatibility Definition.

Чтобы приложения могли получать информацию о повороте датчика, в API camera2 включена константа SENSOR_ORIENTATION. Для большинства телефонов и планшетов устройство сообщает об ориентации датчика 270 градусов для фронтальных камер и 90 градусов (точка обзора с задней стороны устройства) для задних камер, что выравнивает длинный край датчика по длинному краю устройства. Камеры ноутбуков обычно сообщают об ориентации датчика 0 или 180 градусов.

Поскольку датчики изображения камеры выводят данные (буфер изображения) в естественной ориентации датчика (альбомной), буфер изображения должен быть повернут на количество градусов, указанное в SENSOR_ORIENTATION, чтобы предварительный просмотр камеры отображался вертикально в естественной ориентации устройства. Для фронтальных камер поворот выполняется против часовой стрелки, а для основных – по часовой.

Например, для фронтальной камеры на рисунке 1 буфер изображения, созданный датчиком камеры, выглядит следующим образом:

Датчик камеры повернут в горизонтальную ориентацию, изображение повернуто набок, верхний левый угол.
Рисунок 2. Буфер необработанных изображений с датчика фронтальной камеры в естественной альбомной ориентации.

Изображение необходимо повернуть на 270 градусов против часовой стрелки, чтобы ориентация предварительного просмотра соответствовала ориентации устройства:

Датчик камеры в вертикальной ориентации с вертикальным изображением.
Рисунок 3. Буфер изображения фронтальной камеры повернут на 270 градусов против часовой стрелки, чтобы соответствовать вертикальной ориентации устройства.

Основная камера создаст буфер изображения с той же ориентацией, что и предыдущий буфер, но значение SENSOR_ORIENTATION будет равно 90 градусам. В результате буфер поворачивается на 90 градусов по часовой стрелке.

Поворот устройства

Поворот устройства – это количество градусов, на которое устройство повернуто относительно своего естественного положения. Например, если телефон находится в горизонтальной ориентации, то угол поворота устройства составляет 90 или 270 градусов в зависимости от направления поворота.

Чтобы изображение в режиме предварительного просмотра отображалось вертикально, буфер изображений датчика камеры должен быть повернут на то же количество градусов, что и устройство (в дополнение к градусам ориентации датчика).

Расчет ориентации

Правильная ориентация предварительного просмотра камеры учитывает ориентацию датчика и поворот устройства.

Общий поворот буфера изображения датчика можно рассчитать по следующей формуле:

rotation = (sensorOrientationDegrees - deviceOrientationDegrees * sign + 360) % 360

где sign – это 1 для фронтальных камер и -1 для основных камер.

Для фронтальных камер буфер изображения поворачивается против часовой стрелки (от естественной ориентации датчика). Для основных камер буфер изображения датчика поворачивается по часовой стрелке.

Выражение deviceOrientationDegrees * sign + 360 преобразует поворот устройства против часовой стрелки в поворот по часовой стрелке для задних камер (например, преобразует 270 градусов против часовой стрелки в 90 градусов по часовой стрелке). Операция деления по модулю масштабирует результат до значения менее 360 градусов (например, масштабирует поворот на 540 градусов до 180).

Различные API по-разному сообщают о повороте устройства:

  • Display#getRotation() – поворот устройства против часовой стрелки (с точки зрения пользователя). Это значение подставляется в формулу как есть.
  • OrientationEventListener#onOrientationChanged() возвращает угол поворота устройства по часовой стрелке (с точки зрения пользователя). Отрицательное значение для использования в предыдущей формуле.

Фронтальные камеры

Предварительный просмотр камеры и датчик в горизонтальной ориентации, датчик расположен вертикально.
Рисунок 4. Окно предварительного просмотра камеры и датчик, когда телефон повернут на 90 градусов в горизонтальное положение.

Вот буфер изображения, созданный датчиком камеры на рисунке 4:

Датчик камеры в горизонтальной ориентации с вертикальным изображением.
Рисунок 5. Буфер изображения, созданный датчиком фронтальной камеры, когда телефон повернут на 90 градусов против часовой стрелки.

Буфер необходимо повернуть на 270 градусов против часовой стрелки, чтобы скорректировать ориентацию датчика (см. раздел Ориентация камеры выше):

Датчик камеры повернут в вертикальную ориентацию, изображение расположено боком, вверху справа.
Рисунок 6. Буфер изображения повернут на 270 градусов против часовой стрелки, чтобы скорректировать ориентацию датчика.

Затем буфер поворачивается ещё на 90 градусов против часовой стрелки, чтобы учесть поворот устройства. В результате получается правильная ориентация предварительного просмотра камеры, как показано на рисунке 4.

Датчик камеры повернут в горизонтальную ориентацию, изображение вертикальное.
Рисунок 7. Буфер изображения после дополнительного поворота на 90 градусов против часовой стрелки для ориентации устройства.

Вот как выглядит камера, повернутая вправо в горизонтальную ориентацию:

Предварительный просмотр и датчик камеры в горизонтальной ориентации, но датчик перевернут.
Рисунок 8. Предварительный просмотр и датчик камеры, когда телефон повернут на 270 градусов (или -90 градусов) в горизонтальную ориентацию.

Вот буфер изображения:

Датчик камеры повернут в горизонтальную ориентацию, изображение перевернуто.
Рисунок 9. Буфер изображения, созданный датчиком фронтальной камеры, когда телефон повернут на 270 градусов против часовой стрелки.

Буфер необходимо повернуть на 270 градусов против часовой стрелки, чтобы скорректировать ориентацию датчика:

Датчик камеры повернут в вертикальную ориентацию, изображение расположено боком, вверху слева.
Рисунок 10. Буфер изображения повернут на 270 градусов против часовой стрелки, чтобы скорректировать ориентацию датчика.

Затем буфер поворачивается ещё на 270 градусов против часовой стрелки, чтобы учесть поворот устройства:

Датчик камеры повернут в горизонтальную ориентацию, изображение вертикальное.
Рисунок 11. Буфер изображения после дополнительного поворота на 270 градусов против часовой стрелки для ориентации устройства.

Основные камеры

Обычно у задних камер ориентация датчика составляет 90 градусов (если смотреть с задней стороны устройства). При ориентации предварительного просмотра камеры буфер изображения датчика поворачивается по часовой стрелке на величину поворота датчика (а не против часовой стрелки, как у фронтальных камер), а затем буфер изображения поворачивается против часовой стрелки на величину поворота устройства.

Предварительный просмотр и датчик камеры в горизонтальной ориентации, но датчик перевернут.
Рисунок 12. Телефон с основной камерой в горизонтальной ориентации (повернут на 270 или -90 градусов).

На рисунке 12 показан буфер изображений от датчика камеры.

Датчик камеры повернут в горизонтальную ориентацию, изображение перевернуто.
Рисунок 13. Буфер изображения, созданный датчиком основной камеры, когда телефон находится в горизонтальной ориентации.

Буфер необходимо повернуть на 90 градусов по часовой стрелке, чтобы скорректировать ориентацию датчика:

Датчик камеры повернут в вертикальную ориентацию, изображение расположено боком, вверху слева.
Рисунок 14. Буфер изображения повернут на 90 градусов по часовой стрелке, чтобы компенсировать ориентацию датчика основной камеры.

Затем буфер поворачивается на 270 градусов против часовой стрелки, чтобы учесть поворот устройства:

Датчик камеры повернут в горизонтальную ориентацию, изображение вертикальное.
Рисунок 15. Буфер изображения после поворота на 270 градусов против часовой стрелки для ориентации устройства.

Соотношение сторон

Соотношение сторон экрана меняется при изменении ориентации устройства, а также при складывании и раскладывании складных устройств, при изменении размера окон в многооконных средах и при открытии приложений на дополнительных дисплеях.

Буфер изображений датчика камеры должен быть ориентирован и масштабирован в соответствии с ориентацией и соотношением сторон элемента интерфейса видоискателя, поскольку интерфейс динамически меняет ориентацию – с изменением ориентации устройства или без него.

Если на новых типах устройств, в многооконном режиме или при использовании нескольких экранов приложение предполагает, что ориентация предпросмотра камеры совпадает с ориентацией устройства (книжная или альбомная), то предпросмотр может отображаться неправильно, иметь неверный масштаб или и то, и другое.

Разложенное складное устройство с повернутым набок изображением с камеры в портретной ориентации.
Рисунок 16. Складное устройство переходит из портретного режима в альбомный, но датчик камеры остается в портретной ориентации.

На рисунке 16 приложение ошибочно предположило, что устройство повернуто на 90 градусов против часовой стрелки, и повернуло изображение на тот же угол.

Разложенное складное устройство с вертикальным, но сжатым из-за неправильного масштабирования изображением с камеры.
Рисунок 17. Складное устройство переходит из портретной ориентации в альбомную, при этом предпросмотр камеры масштабируется неправильно.

На рисунке 17 приложение не скорректировало соотношение сторон буфера изображения, чтобы оно соответствовало новым размерам элемента интерфейса предпросмотра камеры.

Приложения камеры с фиксированной ориентацией обычно сталкиваются с проблемами на складных устройствах и других устройствах с большим экраном, таких как ноутбуки:

Изображение с камеры на ноутбуке отображается правильно, но интерфейс приложения повернут набок.
Рисунок 18. Приложение с фиксированной вертикальной ориентацией на ноутбуке.

На рисунке 18 интерфейс приложения камеры повернут набок, поскольку ориентация приложения ограничена только портретным режимом. Изображение в видоискателе ориентировано правильно относительно датчика камеры.

Режим портретной съемки с вставкой

Приложения камеры, которые не поддерживают многооконный режим (resizeableActivity="false") и ограничивают ориентацию (screenOrientation="portrait" или screenOrientation="landscape"), можно перевести в режим портретной съемки на устройствах с большим экраном, чтобы правильно ориентировать предпросмотр камеры.

В режиме портретной съемки приложения, поддерживающие только вертикальную ориентацию, показываются в ней, даже если соотношение сторон экрана соответствует горизонтальной ориентации. Приложения, поддерживающие только горизонтальную ориентацию, показываются в ней с черными полосами по краям, даже если соотношение сторон экрана соответствует вертикальной ориентации. Изображение с камеры поворачивается, чтобы соответствовать интерфейсу приложения, обрезается в соответствии с соотношением сторон предварительного просмотра камеры, а затем масштабируется, чтобы заполнить предварительный просмотр.

Режим портретной вставки активируется, когда соотношение сторон датчика изображения камеры и соотношение сторон основного действия приложения не совпадают.

Предпросмотр камеры и интерфейс приложения в правильной портретной ориентации на ноутбуке.
            Широкое изображение масштабируется и обрезается, чтобы соответствовать вертикальной ориентации.
Рисунок 19. Приложение с фиксированной вертикальной ориентацией в режиме вставки на ноутбуке.

На рисунке 19 приложение камеры, предназначенное только для портретной ориентации, было повернуто, чтобы отобразить пользовательский интерфейс в вертикальном положении на экране ноутбука. Приложение отображается в режиме леттербокс из-за разницы в соотношении сторон между вертикальным приложением и горизонтальным экраном. Изображение в окне предварительного просмотра камеры было повернуто, чтобы компенсировать поворот интерфейса приложения (из-за встроенного режима портретной съемки), а также обрезано и масштабировано в соответствии с портретной ориентацией, что уменьшило зону обзора.

Поворот, кадрирование, масштабирование

Режим портретной вставки вызывается для приложения камеры, поддерживающего только портретную ориентацию, на экране с альбомным соотношением сторон:

Изображение с камеры на ноутбуке отображается правильно, но интерфейс приложения повернут набок.
Рисунок 20. Приложение с фиксированной вертикальной ориентацией на ноутбуке.

Приложение в вертикальной ориентации с черными полосами по краям:

Приложение повернуто в вертикальную ориентацию и кадрировано. Изображение повернуто на 90 градусов по часовой стрелке.
Рисунок 21. Приложение, поддерживающее только портретную ориентацию, повернуто и дополнено черными полосами на горизонтальном экране до поворота изображения с датчика.

Изображение с камеры поворачивается на 90 градусов, чтобы соответствовать новой ориентации приложения.

Изображение с датчика повернуто на 90 градусов, чтобы оно было вертикальным.
Рисунок 22. Изображение с камеры повернуто на 90 градусов, чтобы соответствовать интерфейсу приложения.

Изображение обрезается до соотношения сторон предварительного просмотра камеры, а затем масштабируется, чтобы заполнить область предварительного просмотра (зона обзора уменьшается):

Обрезанное изображение с камеры, масштабированное для заполнения окна предварительного просмотра.
Рисунок 23. Изображение с камеры обрезано и масштабировано, чтобы заполнить вертикальное окно предварительного просмотра.

На складных устройствах ориентация датчика камеры может быть вертикальной, а соотношение сторон экрана – горизонтальным.

Предпросмотр камеры и интерфейс приложения повернуты боком на широком разложенном экране.
Рисунок 24. Раскрытое устройство с приложением камеры, которое поддерживает только портретную ориентацию, и разными соотношениями сторон датчика камеры и экрана.

Поскольку изображение в окне предварительного просмотра поворачивается в соответствии с ориентацией датчика, в видоискателе оно отображается правильно, но приложение, поддерживающее только портретную ориентацию, повернуто набок.

В режиме портретной вставки кашетирование приложения требуется только в портретной ориентации, чтобы правильно ориентировать приложение и предварительный просмотр камеры:

Приложение в режиме Letterbox в портретной ориентации с вертикальным предпросмотром камеры на складном устройстве.
Рисунок 25. Приложение, поддерживающее только вертикальную ориентацию, в режиме каше на разложенном складном устройстве.

API

Начиная с Android 12 (уровень API 31) приложения могут явно управлять режимом вертикальной ориентации с помощью свойства SCALER_ROTATE_AND_CROP класса CaptureRequest.

Значение по умолчанию – SCALER_ROTATE_AND_CROP_AUTO. Оно позволяет системе вызывать режим портретной съемки. SCALER_ROTATE_AND_CROP_90 – это поведение в режиме портретной съемки, описанное выше.

Не все устройства поддерживают все значения SCALER_ROTATE_AND_CROP. Список поддерживаемых значений приведен в разделе CameraCharacteristics#SCALER_AVAILABLE_ROTATE_AND_CROP_MODES.

CameraX

Библиотека Jetpack CameraX позволяет легко создать видоискатель, который учитывает ориентацию датчика и поворот устройства.

Элемент макета PreviewView создает окно предварительного просмотра камеры, автоматически подстраиваясь под ориентацию датчика, поворот устройства и масштабирование. PreviewView сохраняет соотношение сторон изображения с камеры, применяя тип масштабирования FILL_CENTER, который центрирует изображение, но может обрезать его в соответствии с размерами PreviewView. Чтобы добавить черные полосы по краям изображения с камеры, задайте тип масштабирования FIT_CENTER.

Чтобы узнать, как создать предварительный просмотр с камеры с помощью PreviewView, прочитайте статью Как реализовать предварительный просмотр.

Полный пример реализации можно найти в репозитории CameraXBasic на GitHub.

CameraViewfinder

Как и в случае с предварительным просмотром, библиотека CameraViewfinder предоставляет набор инструментов, упрощающих создание предварительного просмотра камеры. Она не зависит от CameraX Core, поэтому вы можете легко интегрировать ее в существующую базу кода Camera2.

Вместо того чтобы использовать Surface напрямую, вы можете использовать виджет CameraViewfinder, чтобы показывать видеопоток с камеры для Camera2.

Для показа видеопотока с камеры CameraViewfinder использует TextureView или SurfaceView, а также применяет к ним необходимые преобразования, чтобы правильно отображать видоискатель. Это включает в себя исправление их соотношения сторон, масштаба и поворота.

Чтобы запросить поверхность у объекта CameraViewfinder, необходимо создать ViewfinderSurfaceRequest.

Этот запрос содержит требования к разрешению поверхности и информацию о камере из CameraCharacteristics.

Вызов requestSurfaceAsync() отправляет запрос поставщику поверхности, который является либо TextureView, либо SurfaceView, и получает ListenableFuture из Surface.

Вызов markSurfaceSafeToRelease() уведомляет поставщика поверхности о том, что поверхность не нужна и связанные с ней ресурсы могут быть освобождены.

fun startCamera() {
    val previewResolution = Size(width, height)
    val viewfinderSurfaceRequest =
        ViewfinderSurfaceRequest(previewResolution, characteristics)
    val surfaceListenableFuture =
        cameraViewfinder.requestSurfaceAsync(viewfinderSurfaceRequest)

    Futures.addCallback(surfaceListenableFuture, object : FutureCallback<Surface> {
        override fun onSuccess(surface: Surface) {
            /* create a CaptureSession using this surface as usual */
        }
        override fun onFailure(t: Throwable) { /* something went wrong */ }
    }, ContextCompat.getMainExecutor(context))
}

SurfaceView

SurfaceView – это простой способ создать предварительный просмотр камеры, если он не требует обработки и не анимирован.

SurfaceView автоматически поворачивает буфер изображения датчика камеры в соответствии с ориентацией экрана, учитывая как ориентацию датчика, так и поворот устройства. Однако буфер изображения масштабируется в соответствии с размерами SurfaceView без учета соотношения сторон.

Вам необходимо убедиться, что соотношение сторон буфера изображения соответствует соотношению сторон SurfaceView. Этого можно добиться, масштабируя содержимое SurfaceView в методе onMeasure() компонента:

Исходный код computeRelativeRotation() приведен в разделе Относительный поворот ниже.

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
    val width = MeasureSpec.getSize(widthMeasureSpec)
    val height = MeasureSpec.getSize(heightMeasureSpec)

    val relativeRotation = computeRelativeRotation(characteristics, surfaceRotationDegrees)

    if (previewWidth > 0f && previewHeight > 0f) {
        /* Scale factor required to scale the preview to its original size on the x-axis. */
        val scaleX =
            if (relativeRotation % 180 == 0) {
                width.toFloat() / previewWidth
            } else {
                width.toFloat() / previewHeight
            }
        /* Scale factor required to scale the preview to its original size on the y-axis. */
        val scaleY =
            if (relativeRotation % 180 == 0) {
                height.toFloat() / previewHeight
            } else {
                height.toFloat() / previewWidth
            }

        /* Scale factor required to fit the preview to the SurfaceView size. */
        val finalScale = min(scaleX, scaleY)

        setScaleX(1 / scaleX * finalScale)
        setScaleY(1 / scaleY * finalScale)
    }
    setMeasuredDimension(width, height)
}

Подробнее о том, как реализовать SurfaceView в качестве предварительного просмотра камеры, читайте в статье Ориентация камеры.

TextureView

TextureView менее эффективен, чем SurfaceView, и требует больше работы, но TextureView дает вам максимальный контроль над предварительным просмотром камеры.

TextureView поворачивает буфер изображения датчика в зависимости от ориентации датчика, но не обрабатывает поворот устройства или масштабирование предварительного просмотра.

Масштабирование и поворот можно закодировать в преобразовании Matrix. Чтобы узнать, как правильно масштабировать и поворачивать TextureView, прочитайте статью Поддержка изменяемых поверхностей в приложении камеры.

Относительное вращение

Относительный поворот датчика камеры – это величина поворота, необходимая для выравнивания выходных данных датчика камеры с ориентацией устройства.

Относительный поворот используется такими компонентами, как SurfaceView и TextureView, для определения коэффициентов масштабирования по осям X и Y для изображения предварительного просмотра. Он также используется для указания поворота буфера изображения датчика.

Классы CameraCharacteristics и Surface позволяют рассчитать относительный поворот датчика камеры:

/**
 * Computes rotation required to transform the camera sensor output orientation to the
 * device's current orientation in degrees.
 *
 * @param characteristics The CameraCharacteristics to query for the sensor orientation.
 * @param surfaceRotationDegrees The current device orientation as a Surface constant.
 * @return Relative rotation of the camera sensor output.
 */
public fun computeRelativeRotation(
    characteristics: CameraCharacteristics,
    surfaceRotationDegrees: Int
): Int {
    val sensorOrientationDegrees =
        characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION) ?: 0

    // Reverse device orientation for back-facing cameras.
    val sign = if (characteristics.get(CameraCharacteristics.LENS_FACING) ==
        CameraCharacteristics.LENS_FACING_FRONT
    ) 1 else -1

    // Calculate desired orientation relative to camera orientation to make
    // the image upright relative to the device orientation.
    return (sensorOrientationDegrees - surfaceRotationDegrees * sign + 360) % 360
}

Показатели окон

Размер экрана не должен использоваться для определения размеров видоискателя камеры. Приложение камеры может работать в части экрана, в многооконном режиме на мобильных устройствах или в режиме произвольной формы в ChromeOS.

WindowManager#getCurrentWindowMetrics() (добавлен в API уровня 30) возвращает размер окна приложения, а не размер экрана. Методы библиотеки Jetpack WindowManager WindowMetricsCalculator#computeCurrentWindowMetrics() и WindowInfoTracker#currentWindowMetrics() обеспечивают аналогичную поддержку с обратной совместимостью до уровня API 14.

Поворот на 180 градусов

Поворот устройства на 180 градусов (например, из стандартной ориентации в перевернутую) не запускает обратный вызов onConfigurationChanged(). В результате изображение с камеры может быть перевернуто.

Чтобы определить поворот на 180 градусов, реализуйте DisplayListener и проверьте поворот устройства с помощью вызова Display#getRotation() в обратном вызове onDisplayChanged().

Эксклюзивные ресурсы

До Android 10 только верхнее видимое действие в многооконном режиме находилось в состоянии RESUMED. Это сбивало пользователей с толку, поскольку система не указывала, какое действие было возобновлено.

В Android 10 (уровень API 29) появилась возможность одновременной работы нескольких приложений, когда все видимые объекты activity находятся в состоянии RESUMED. Видимые действия могут перейти в состояние PAUSED, если, например, поверх них находится прозрачное действие или они не могут быть в фокусе, как в режиме "Картинка в картинке" (см. раздел Поддержка режима "Картинка в картинке").

Приложение, использующее камеру, микрофон или любой эксклюзивный или одноэлементный ресурс на уровне API 29 или выше, должно поддерживать одновременную работу нескольких приложений. Например, если три возобновленных действия хотят использовать камеру, только одно из них сможет получить доступ к этому эксклюзивному ресурсу. Каждое действие должно реализовывать обратный вызов onDisconnected(), чтобы отслеживать упреждающий доступ к камере со стороны действия с более высоким приоритетом.

Подробнее об одновременной работе нескольких приложений…

Дополнительные ресурсы