Объяснение шага и плоскости на изображениях YUV
Объяснение шага и плоскости на изображениях YUV

Image Stride (размер строки изображения в памяти)

шаг можно перевести как: размах

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

Плоскости обычно имеют форму плоскости яркости и плоскости цветности. Фактически, это слой яркости и слой цветности. Как и в случае с RGB, для их хранения используются три плоскости.

Недавно я работаю над проектом HI5321.,столкнулся с ключевой технической проблемой,Наша обработка изображенийпрограмма需 Мне нужен файл изображения в формате rgb888, а видеопоток, который я получил от hi3521, — это кадр изображения в формате yuv420sp. Проблема в том, что теперь мне нужно преобразовать кадр в формат yuv420sp. Преобразуйте изображение в изображение в формате rgb888. На самом деле моя цель — получить данные изображения rgb888. Способ хранения компонента yuv yuv420sp в памяти заключается в том, что компонент y хранится отдельно, а компонент uv чередуется. Хранение вилок. Хорошо, я могу это сделать, но когда я распечатал информацию о кадре yuv420sp, я обнаружил, что шаг (то есть размах) этого кадра размером 720*576 на самом деле равен 768. Я был озадачен. Я знаю, что даже если я успешно конвертировал кадр yuv420sp в растровое изображение bmp, я все равно не понимаю, что такое лишние 768-720=48 байт. Без учета размаха Далее я прочитал компонент прямо по адресу yuv-компонента, а затем получил данные rgb и сохранил их как растровое изображение bmp, но bmp был полностью перепутан, что-то пошло не так. Это должен быть пролет, пролет: он должен быть больше или равен ширине рамы. Степени также кратны 4. Между 720 и 768 существует множество чисел, кратных 4. Почему это 768? Все в порядке! Поскольку в конце строки необходимо добавить 0, когда она меньше кратного 4, то я предполагаю, что эти 48 байт конец каждой строки. Тогда адрес должен быть смещен при чтении компонента yuv. Попробуйте, и bmp действительно успешно сохраняется, как и захваченная картинка. Технические подробности конвертации в yuv, конечно, все знают. Я знаю не менее 3 формул для RGB.

Цель написания этой записи — рассказать об этой проблеме шага, поэтому при преобразовании видеокадров yuv420p, yuv420sp и т. д. необходимо обращать внимание на параметр шага.

When a video image is stored in memory, the memory buffer might contain extra padding bytes after each row of pixels. The padding bytes affect how the image is store in memory, but do not affect how the image is displayed.

Когда видеоизображение хранится в памяти, конец каждой строки изображения может содержать некоторое расширенное содержимое. Это расширенное содержимое влияет только на то, как изображение хранится в памяти, но не влияет на то, как оно отображается;

The stride is the number of bytes from one row of pixels in memory to the next row of pixels in memory. Stride is also called pitch. If padding bytes are present, the stride is wider than the width of the image, as shown in the following illustration.

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

Two buffers that contain video frames with equal dimensions can have two different strides. If you process a video image, you must take into the stride into account.

Два буфера содержат видеокадры одинакового размера (ширины и высоты), но не обязательно имеют одинаковое значение Stride. Если вы обрабатываете видеокадр, вы должны учитывать Stride при расчете;

In addition, there are two ways that an image can be arranged in memory. In a top-down image, the top row of pixels in the image appears first in memory. In a bottom-up image, the last row of pixels appears first in memory. The following illustration shows the difference between a top-down image and a bottom-up image.

Кроме того, изображение имеет две разные последовательности хранения (упорядоченные) в памяти. Для изображения, хранящегося сверху вниз (сверху вниз), пиксели в верхнем ряду сохраняются в начале памяти. снизу вверх (Bottom-Up), а пиксели последней строки сохраняются в начальной части памяти. На следующем рисунке показаны эти две ситуации:

A bottom-up image has a negative stride, because stride is defined as the number of bytes need to move down a row of pixels, relative to the displayed image. YUV images should always be top-down, and any image that is contained in a Direct3D surface must be top-down. RGB images in system memory are usually bottom-up.

Изображение снизу вверх имеет отрицательное значение Stride, поскольку Stride определяется как количество пикселей, которые необходимо пересечь для перехода от одного ряда пикселей к другому, относительно только отображаемого изображения, а изображения YUV всегда представляются из; сверху вниз, и любое изображение, содержащееся в поверхности Direct3D, должно быть представлено сверху вниз. Изображения RGB обычно хранятся в системной памяти снизу вверх;

Video transforms in particular need to handle buffers with mismatched strides, because the input buffer might not match the output buffer. For example, suppose that you want to convert a source image and write the result to a destination image. Assume that both images have the same width and height, but might not have the same pixel format or the same image stride.

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

The following example code shows a generalized approach for writing this kind of function. This is not a complete working example, because it abstracts many of the specific details.

демо-код

Ниже демо-код показан общий способ написания такой функции.,Этот код не является полным,Потому что это всего лишь абстрактный алгоритм,Не до конца учтены все детали реальных требований;

Язык кода:javascript
копировать
void ProcessVideoImage(
    BYTE*       pDestScanLine0,    
    LONG        lDestStride,       
    const BYTE* pSrcScanLine0,     
    LONG        lSrcStride,        
    DWORD       dwWidthInPixels,    
    DWORD       dwHeightInPixels
    )
{
    for (DWORD y = 0; y < dwHeightInPixels; y++)
    {
        SOURCE_PIXEL_TYPE *pSrcPixel = (SOURCE_PIXEL_TYPE*)pDestScanLine0;
        DEST_PIXEL_TYPE *pDestPixel = (DEST_PIXEL_TYPE*)pSrcScanLine0;

        for (DWORD x = 0; x < dwWidthInPixels; x +=2)
        {
            pDestPixel[x] = TransformPixelValue(pSrcPixel[x]);
        }
        pDestScanLine0 += lDestStride;
        pSrcScanLine0 += lSrcStride;
    }
}

This function takes six parameters:

A pointer to the start of scan line 0 in the destination image.

The stride of the destination image.

A pointer to the start of scan line 0 in the source image.

The stride of the source image.

The width of the image in pixels.

The height of the image in pixels.

Эта функция требует шесть параметров:

  1. Указатель памяти на начальную строку сканирования целевого изображения
  2. Значение шага целевого изображения
  3. Указатель памяти на начальную строку развертки исходного изображения
  4. Значение шага исходного изображения
  5. Значение ширины изображения в пикселях
  6. Значение высоты изображения в пикселях

The general idea is to process one row at a time, iterating over each pixel in the row. Assume that SOURCE_PIXEL_TYPE and DEST_PIXEL_TYPE are structures representing the pixel layout for the source and destination images, respectively. (For example, 32-bit RGB uses the RGBQUAD structure. Not every pixel format has a pre-defined structure.) Casting the array pointer to the structure type enables you to access the RGB or YUV components of each pixel. At the start of each row, the function stores a pointer to the row. At the end of the row, it increments the pointer by the width of the image stride, which advances the pointer to the next row.

Ключевым моментом здесь является то, как обрабатывать одну строку пикселей за раз, проходя каждый пиксель в строке, предполагая, что тип исходного пикселя и тип целевого пикселя структурированы на уровне пикселей для представления пикселей исходного изображения. и целевое изображение (например, 32-битные пиксели RGB используют структуру RGBQUAD. Не каждый тип пикселя имеет предопределенную структуру.) Привязка указателя массива к такому указателю структуры позволяет напрямую читать и записывать RGB или YUV каждый пиксель. В начале каждой строки эта функция сохраняет указатель на пиксели этой строки. Последняя строка функции напрямую перемещает указатель на начальную точку следующей строки пикселей изображения через значение Stride. изображение;

This example calls a hypothetical function named TransformPixelValue for each pixel. This could be any function that calculates a target pixel from a source pixel. Of course, the exact details will depend on the particular task. For example, if you have a planar YUV format, you must access the chroma planes independently from the luma plane; with interlaced video, you might need to process the fields separately; and so forth.

To give a more concrete example, the following code converts a 32-bit RGB image into an AYUV image. The RGB pixels are accessed using an RGBQUAD structure, and the AYUV pixels are accessed using aDXVA2_AYUVSample8 Structure structure.

Ниже приведен пример преобразования, в котором можно хорошо разобраться с помощью него.

Недавно я получил ЖК-экран, который использует чересстрочную развертку NTSC для вывода изображений. Используемый цветовой формат — это формат UYVY YUV4:2:2, но цветовой формат, выводимый определенным видеодекодером, — это формат I420 YUV4:2: 0. Затем необходимо выполнить преобразование между ними, где I420 хранится в формате планировщика, а UYVY хранится в сжатом (пакетном) формате. Этот процесс преобразования не сложен, его принцип показан на рисунке 1.

Каждый компонент цвета на рисунке 2 представлен одним байтом. Последовательность хранения, такая как U0Y0V0Y1, фактически представляет два пикселя, для представления которых требуется всего 4 байта. Следовательно, среднее пространство, занимаемое каждым пикселем, составляет 2 байта. Теоретической основой цветового формата YUV является то, что HVS (зрительная система человека) чувствительна к яркости и менее чувствительна к цветности. Таким образом, необходимое пространство для хранения уменьшается за счет субдискретизации компонента цветового различия каждой строки пикселей. Объем памяти, занимаемый цветами в сжатом формате YUV4:2:2, составляет 2/3 объема памяти, занимаемого форматом YUV4:4:4. Например, если используется формат YUV4:4:4, каждый пиксель должен быть представлен тремя компонентами, то есть для представления пикселя необходимо 3 байта.

Реализация кода

Язык кода:javascript
копировать
void rv_csp_i420_uyvy(
    uint8_t *y_plane,   // Y plane of I420
    uint8_t *u_plane,   // U plane of I420
    uint8_t *v_plane,   // V plane of I420
    int y_stride,       // Y stride of I420, in pixel
    int uv_stride,      // U and V stride of I420, in pixel
    uint8_t *image,     // output UYVY image
    int width,          // image width
    int height)         // image height
{
    int row;
    int col;
    uint8_t *pImg = image;

    for (row = 0; row < height; row = row+1) 
    {
        for (col = 0; col < width; col = col+2) 
        {
            pImg[0] = u_plane[row/2 * uv_stride + col/2];
            pImg[1] = y_plane[row * y_stride + col];
            pImg[2] = v_plane[row/2 * uv_stride + col/2];
            pImg[3] = y_plane[row * y_stride + col + 1];
            pImg += 4;
        }
    }
}

Кажется, что-то не так с кодом. Шаг YUV4:2:2 не учитывался при сохранении. Однако приведенный выше код четко объяснил принцип.

boy illustration
Углубленный анализ переполнения памяти CUDA: OutOfMemoryError: CUDA не хватает памяти. Попыталась выделить 3,21 Ги Б (GPU 0; всего 8,00 Ги Б).
boy illustration
[Решено] ошибка установки conda. Среда решения: не удалось выполнить первоначальное зависание. Повторная попытка с помощью файла (графическое руководство).
boy illustration
Прочитайте нейросетевую модель Трансформера в одной статье
boy illustration
.ART Теплые зимние предложения уже открыты
boy illustration
Сравнительная таблица описания кодов ошибок Amap
boy illustration
Уведомление о последних правилах Points Mall в декабре 2022 года.
boy illustration
Даже новички могут быстро приступить к работе с легким сервером приложений.
boy illustration
Взгляд на RSAC 2024|Защита конфиденциальности в эпоху больших моделей
boy illustration
Вы используете ИИ каждый день и до сих пор не знаете, как ИИ дает обратную связь? Одна статья для понимания реализации в коде Python общих функций потерь генеративных моделей + анализ принципов расчета.
boy illustration
Используйте (внутренний) почтовый ящик для образовательных учреждений, чтобы использовать Microsoft Family Bucket (1T дискового пространства на одном диске и версию Office 365 для образовательных учреждений)
boy illustration
Руководство по началу работы с оперативным проектом (7) Практическое сочетание оперативного письма — оперативного письма на основе интеллектуальной системы вопросов и ответов службы поддержки клиентов
boy illustration
[docker] Версия сервера «Чтение 3» — создайте свою собственную программу чтения веб-текста
boy illustration
Обзор Cloud-init и этапы создания в рамках PVE
boy illustration
Корпоративные пользователи используют пакет регистрационных ресурсов для регистрации ICP для веб-сайта и активации оплаты WeChat H5 (с кодом платежного узла версии API V3)
boy illustration
Подробное объяснение таких показателей производительности с высоким уровнем параллелизма, как QPS, TPS, RT и пропускная способность.
boy illustration
Удачи в конкурсе Python Essay Challenge, станьте первым, кто испытает новую функцию сообщества [Запускать блоки кода онлайн] и выиграйте множество изысканных подарков!
boy illustration
[Техническая посадка травы] Кровавая рвота и отделка позволяют вам необычным образом ощипывать гусиные перья! Не распространяйте информацию! ! !
boy illustration
[Официальное ограниченное по времени мероприятие] Сейчас ноябрь, напишите и получите приз
boy illustration
Прочтите это в одной статье: Учебник для няни по созданию сервера Huanshou Parlu на базе CVM-сервера.
boy illustration
Cloud Native | Что такое CRD (настраиваемые определения ресурсов) в K8s?
boy illustration
Как использовать Cloudflare CDN для настройки узла (CF самостоятельно выбирает IP) Гонконг, Китай/Азия узел/сводка и рекомендации внутреннего высокоскоростного IP-сегмента
boy illustration
Дополнительные правила вознаграждения амбассадоров акции в марте 2023 г.
boy illustration
Можно ли открыть частный сервер Phantom Beast Palu одним щелчком мыши? Супер простой урок для начинающих! (Прилагается метод обновления сервера)
boy illustration
[Играйте с Phantom Beast Palu] Обновите игровой сервер Phantom Beast Pallu одним щелчком мыши
boy illustration
Maotouhu делится: последний доступный внутри страны адрес склада исходного образа Docker 2024 года (обновлено 1 декабря)
boy illustration
Кодирование Base64 в MultipartFile
boy illustration
5 точек расширения SpringBoot, супер практично!
boy illustration
Глубокое понимание сопоставления индексов Elasticsearch.
boy illustration
15 рекомендуемых платформ разработки с нулевым кодом корпоративного уровня. Всегда найдется та, которая вам понравится.
boy illustration
Аннотация EasyExcel позволяет экспортировать с сохранением двух десятичных знаков.