шаг можно перевести как: размах
Страйд относится к пространству, занимаемому каждой строкой пикселей в памяти. Как показано на рисунке ниже, для достижения выравнивания памяти (или по другим причинам) пространство, занимаемое каждой строкой пикселей в памяти, не равно ширине изображения.
Плоскости обычно имеют форму плоскости яркости и плоскости цветности. Фактически, это слой яркости и слой цветности. Как и в случае с 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.
Ниже демо-код показан общий способ написания такой функции.,Этот код не является полным,Потому что это всего лишь абстрактный алгоритм,Не до конца учтены все детали реальных требований;
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.
Эта функция требует шесть параметров:
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 байта.
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 не учитывался при сохранении. Однако приведенный выше код четко объяснил принцип.