Пропорции рисунка
В этом разделе описаны два связанных понятия, соотношение аспектов рисунка и пропорции пикселей. Затем описывается, как эти понятия выражаются в Microsoft Media Foundation с помощью типов мультимедиа.
Пропорции рисунка
Пропорции рисунка определяют форму отображаемого изображения видео. Пропорции изображения не учитываются X:Y, где X:Y — это соотношение ширины рисунка к высоте рисунка. Большинство стандартов видео используют пропорции изображения 4:3 или 16:9. Пропорции 16:9 обычно называются широкоэкранным. Фильм кино часто использует пропорции 1:85:1 или 1:66:1. Пропорции рисунка также называются пропорциями отображения (DAR).
Иногда изображение видео не имеет той же фигуры, что и область отображения. Например, видео 4:3 может отображаться на широкоэкранном телевидении (16×9). На компьютере видео видео может отображаться в окне с произвольным размером. В этом случае существует три способа размещения изображения в области отображения:
- Растяните изображение вдоль одной оси, чтобы поместить область отображения.
- Масштабируйте изображение, чтобы соответствовать области отображения, сохраняя исходное соотношение пропорций изображения.
- Обрезка изображения.
Растяжение изображения в соответствии с областью отображения почти всегда неправильно, так как оно не сохраняет правильное соотношение пропорций рисунка.
Почтовые ящики
Процесс масштабирования широкоэкранного изображения в соответствии с отображением 4:3 называется почтовым ящиком, показанным на следующей схеме. Результированные прямоугольные области в верхней и нижней части изображения обычно заполнены черным цветом, хотя другие цвета можно использовать.
Обратный регистр, масштабирование изображения 4:3 для размещения широкоэкранного дисплея, иногда называется столпboxing. Однако буквенное поле терминов также используется в общем смысле, чтобы означать масштабирование изображения видео для соответствия любой заданной области отображения.
Сдвига и сканирование
Пан-и-сканирование — это метод, в котором широкоэкранное изображение обрезается до прямоугольной области 4×3 для отображения на устройстве с дисплеем 4:3. Полученное изображение заполняет весь экран, не требуя областей черной буквы, но части исходного изображения обрезаются из рисунка. Область, которая обрезается, может перемещаться из кадра в кадр, так как область интереса сдвигается. Термин "pan" в области сдвига и сканирования относится к эффекту сдвига, которое вызвано перемещением области сдвига и сканирования.
Пропорции пикселей
Пропорции пикселей (PAR) измеряет форму пикселя.
При захвате цифрового изображения образ выполняется как по вертикали, так и по горизонтали, что приводит к прямоугольным массиву квантизованных выборок, вызываемого пикселями или pels. Форма сетки выборки определяет форму пикселей в цифровом изображении.
Ниже приведен пример, использующий небольшие числа для простоты математических вычислений. Предположим, что исходное изображение равно квадрату (т. е. пропорции рисунка равно 1:1); и предположим, что сетка выборки содержит 12 элементов, упорядоченных в сетке 4×3. Фигура каждого полученного пикселя будет выше, чем она широка. В частности, форма каждого пикселя будет составлять 3×4. Пиксели, которые не являются квадратными, называются некверными пикселями.
Пропорции пикселей также применяются к устройству отображения. Физическая форма устройства отображения и разрешение физических пикселей (по всему и внизу) определяют PAR устройства дисплея. Мониторы компьютера обычно используют квадратные пиксели. Если изображение PAR и экранный par не совпадают, изображение должно масштабироваться в одном измерении (вертикально или горизонтально) для правильного отображения. Следующая формула относится к PAR, пропорции отображения (DAR) и размер изображения в пикселях:
DAR = (ширина изображения в пикселях высоты изображения в пикселях / ) × PAR
Обратите внимание, что ширина изображения и высота изображения в этой формуле ссылаются на изображение в памяти, а не отображаемое изображение.
Ниже приведен пример реального мира: аналоговое видео NTSC-M содержит 480 строк сканирования в активной области изображения. ITU-R Rec. BT.601 указывает горизонтальную частоту выборки 704 видимых пикселей на линию, что дает цифровое изображение с 704 x 480 пикселей. Предполагаемое соотношение пропорций рисунка равно 4:3, что дает значение PAR 10:11.
- ДАР: 4:3
- Ширина в пикселях: 704
- Высота в пикселях: 480
- PAR: 10/11
4/3 = (704/480) x (10/11)
Чтобы правильно отобразить это изображение на устройстве отображения с квадратными пикселями, необходимо масштабировать ширину на 10/11 или высоту на 11/10.
Работа с пропорциями
Правильная форма кадра видео определяется пропорцией пикселей (PAR) и областью отображения.
- Par определяет форму пикселей на изображении. Квадратные пиксели имеют пропорции 1:1. Любое другое соотношение пропорций описывает некверную пиксель. Например, телевидение NTSC использует 10:11 PAR. Если вы представляете видео на мониторе компьютера, дисплей будет иметь квадратные пиксели (1:1 PAR). PAR исходного содержимого указан в атрибуте MF_MT_PIXEL_ASPECT_RATIO для типа носителя.
- Область отображения — это область изображения видео, который должен отображаться. В типе носителя могут быть указаны две соответствующие области отображения:
- Диафрагма сдвига и сканирования. Диафрагма сдвига и сканирования — это 4×3 область видео, которая должна отображаться в режиме сдвига или сканирования. Он используется для отображения содержимого на широкоэкранном экране на дисплее 4×3 без букв. Диафрагма сдвига и сканирования указана в атрибуте MF_MT_PAN_SCAN_APERTURE и должна использоваться только в том случае, если атрибут MF_MT_PAN_SCAN_ENABLED имеет значение TRUE.
- Отображение диафрагмы. Эта диафрагма определена в некоторых стандартах видео. Все, что находится за пределами диафрагмы отображения, является областью overscan и не должно отображаться. Например, телевизор NTSC составляет 720×480 пикселей с диафрагмой дисплея 704×480. Диафрагма отображения представлена в атрибуте MF_MT_MINIMUM_DISPLAY_APERTURE . Если он присутствует, его следует использовать, если режим сдвига и сканирования имеет значение FALSE.
Если режим сдвига и может иметь значение FALSE , а диафрагма отображения не определена, должен отображаться весь видеокадр. На самом деле, это дело для большинства видеоконтентов, отличных от телевидения и DVD-видео. Пропорции всего рисунка вычисляются как (высота области отображения ширины / отображения) × PAR.
Примеры кода
Поиск области отображения
В следующем коде показано, как получить область отображения из типа носителя.
MFVideoArea MakeArea(float x, float y, DWORD width, DWORD height);
HRESULT GetVideoDisplayArea(IMFMediaType *pType, MFVideoArea *pArea)
{
HRESULT hr = S_OK;
BOOL bPanScan = FALSE;
UINT32 width = 0, height = 0;
bPanScan = MFGetAttributeUINT32(pType, MF_MT_PAN_SCAN_ENABLED, FALSE);
// In pan-and-scan mode, try to get the pan-and-scan region.
if (bPanScan)
{
hr = pType->GetBlob(MF_MT_PAN_SCAN_APERTURE, (UINT8*)pArea,
sizeof(MFVideoArea), NULL);
}
// If not in pan-and-scan mode, or the pan-and-scan region is not set,
// get the minimimum display aperture.
if (!bPanScan || hr == MF_E_ATTRIBUTENOTFOUND)
{
hr = pType->GetBlob(MF_MT_MINIMUM_DISPLAY_APERTURE, (UINT8*)pArea,
sizeof(MFVideoArea), NULL);
if (hr == MF_E_ATTRIBUTENOTFOUND)
{
// Minimum display aperture is not set.
// For backward compatibility with some components,
// check for a geometric aperture.
hr = pType->GetBlob(MF_MT_GEOMETRIC_APERTURE, (UINT8*)pArea,
sizeof(MFVideoArea), NULL);
}
// Default: Use the entire video area.
if (hr == MF_E_ATTRIBUTENOTFOUND)
{
hr = MFGetAttributeSize(pType, MF_MT_FRAME_SIZE, &width, &height);
if (SUCCEEDED(hr))
{
*pArea = MakeArea(0.0, 0.0, width, height);
}
}
}
return hr;
}
MFOffset MakeOffset(float v)
{
MFOffset offset;
offset.value = short(v);
offset.fract = WORD(65536 * (v-offset.value));
return offset;
}
MFVideoArea MakeArea(float x, float y, DWORD width, DWORD height)
{
MFVideoArea area;
area.OffsetX = MakeOffset(x);
area.OffsetY = MakeOffset(y);
area.Area.cx = width;
area.Area.cy = height;
return area;
}
Преобразование между пропорциями пикселей
В следующем коде показано, как преобразовать прямоугольник из одного пропорции пикселей (PAR) в другой, сохраняя пропорции изображения.
//-----------------------------------------------------------------------------
// Converts a rectangle from one pixel aspect ratio (PAR) to another PAR.
// Returns the corrected rectangle.
//
// For example, a 720 x 486 rect with a PAR of 9:10, when converted to 1x1 PAR,
// must be stretched to 720 x 540.
//-----------------------------------------------------------------------------
RECT CorrectAspectRatio(const RECT& src, const MFRatio& srcPAR, const MFRatio& destPAR)
{
// Start with a rectangle the same size as src, but offset to (0,0).
RECT rc = {0, 0, src.right - src.left, src.bottom - src.top};
// If the source and destination have the same PAR, there is nothing to do.
// Otherwise, adjust the image size, in two steps:
// 1. Transform from source PAR to 1:1
// 2. Transform from 1:1 to destination PAR.
if ((srcPAR.Numerator != destPAR.Numerator) ||
(srcPAR.Denominator != destPAR.Denominator))
{
// Correct for the source's PAR.
if (srcPAR.Numerator > srcPAR.Denominator)
{
// The source has "wide" pixels, so stretch the width.
rc.right = MulDiv(rc.right, srcPAR.Numerator, srcPAR.Denominator);
}
else if (srcPAR.Numerator < srcPAR.Denominator)
{
// The source has "tall" pixels, so stretch the height.
rc.bottom = MulDiv(rc.bottom, srcPAR.Denominator, srcPAR.Numerator);
}
// else: PAR is 1:1, which is a no-op.
// Next, correct for the target's PAR. This is the inverse operation of
// the previous.
if (destPAR.Numerator > destPAR.Denominator)
{
// The destination has "wide" pixels, so stretch the height.
rc.bottom = MulDiv(rc.bottom, destPAR.Numerator, destPAR.Denominator);
}
else if (destPAR.Numerator < destPAR.Denominator)
{
// The destination has "tall" pixels, so stretch the width.
rc.right = MulDiv(rc.right, destPAR.Denominator, destPAR.Numerator);
}
// else: PAR is 1:1, which is a no-op.
}
return rc;
}
Вычисление области "Почтовые ящики"
Следующий код вычисляет область почтовых ящиков с учетом исходного и целевого прямоугольника. Предполагается, что оба прямоугольника имеют один и тот же PAR.
RECT LetterBoxRect(const RECT& rcSrc, const RECT& rcDst)
{
// Compute source/destination ratios.
int iSrcWidth = rcSrc.right - rcSrc.left;
int iSrcHeight = rcSrc.bottom - rcSrc.top;
int iDstWidth = rcDst.right - rcDst.left;
int iDstHeight = rcDst.bottom - rcDst.top;
int iDstLBWidth;
int iDstLBHeight;
if (MulDiv(iSrcWidth, iDstHeight, iSrcHeight) <= iDstWidth)
{
// Column letterboxing ("pillar box")
iDstLBWidth = MulDiv(iDstHeight, iSrcWidth, iSrcHeight);
iDstLBHeight = iDstHeight;
}
else
{
// Row letterboxing.
iDstLBWidth = iDstWidth;
iDstLBHeight = MulDiv(iDstWidth, iSrcHeight, iSrcWidth);
}
// Create a centered rectangle within the current destination rect
LONG left = rcDst.left + ((iDstWidth - iDstLBWidth) / 2);
LONG top = rcDst.top + ((iDstHeight - iDstLBHeight) / 2);
RECT rc;
SetRect(&rc, left, top, left + iDstLBWidth, top + iDstLBHeight);
return rc;
}
См. также