Taxa de proporção de imagem
Este tópico descreve dois conceitos relacionados: taxa de proporção da imagem e taxa de proporção de pixel. Em seguida, descreve como esses conceitos são expressos no Microsoft Media Foundation usando tipos de mídia.
- Taxa de proporção de imagem
- Taxa de proporção de pixel
- Trabalhando com taxas de proporção
- Exemplos de código
- Tópicos relacionados
Taxa de proporção de imagem
A taxa de proporção de imagem define a forma da imagem de vídeo exibida. A taxa de proporção de imagem tem notação X:Y, em que X:Y é a razão entre a largura e a altura da imagem. A maioria dos padrões de vídeo usa a taxa de proporção de imagem 4:3 ou 16:9. A taxa de proporção 16:9 é comumente chamada de widescreen. O cinema geralmente usa uma proporção de 1:85:1 ou 1:66:1. A taxa de proporção de imagem também é chamada de taxa de proporção do vídeo (DAR).
Às vezes, a imagem do vídeo não tem a mesma forma que a área do vídeo. Por exemplo, um vídeo 4:3 pode ser exibido em uma televisão widescreen (16×9). No vídeo do computador, ele pode ser mostrado dentro de uma janela que tem um tamanho arbitrário. Nesse caso, existem três maneiras de fazer a imagem se ajustar dentro da área de vídeo:
- Esticar a imagem ao longo de um eixo para ajustá-la à área do vídeo.
- Dimensionar a imagem para se ajustar à área de vídeo, mantendo a taxa de proporção de imagem original.
- Cortar a imagem.
Esticar a imagem para ajustá-la à área de vídeo quase sempre está errado, pois não preserva a proporção correta da imagem.
Letterboxing
O processo de redimensionar uma imagem widescreen para caber em uma tela 4:3 é chamado de letterboxing, como mostrado no próximo diagrama. As áreas retangulares resultantes na parte superior e inferior da imagem normalmente são preenchidas com a cor preta, embora outras cores também possam ser usadas.
O caso inverso, dimensionar uma imagem 4:3 para se ajustar a uma tela widescreen, às vezes é chamado de pillarboxing. No entanto, o termo letterbox também é usado em um sentido geral, para significar o dimensionamento de uma imagem de vídeo para se ajustar a qualquer área de vídeo específica.
Pan-and-scan
Pan-and-scan é uma técnica pela qual uma imagem widescreen é cortada para uma área retangular 4×3, para ser exibida em um dispositivo de vídeo 4:3. A imagem resultante preenche toda a tela sem exigir áreas pretas de letterbox, mas partes da imagem original serão cortadas. A área cortada pode passar de quadro para quadro, conforme a área de interesse muda. O termo "pan", em pan-and-scan, refere-se ao efeito de panorâmica causado pelo movimento da área de pan-and-scan.
Taxa de proporção de pixel
A proporção de pixel (PAR) mede a forma de um pixel.
Quando uma imagem digital é capturada, a imagem é amostrada tanto verticalmente quanto horizontalmente, resultando em uma matriz retangular de amostras quantizadas, chamadas de pixels ou pels. A forma da grade de amostragem determina a forma dos pixels na imagem digitalizada.
Aqui está um exemplo que usa números pequenos para facilitar a matemática. Suponha que a imagem original seja quadrada (ou seja, a taxa de proporção da imagem é 1:1); e suponha que a grade de amostragem contenha 12 elementos, organizados em uma grade de 4×3. A forma de cada pixel resultante será mais alta do que larga. Especificamente, a forma de cada pixel será 3×4. Pixels que não são quadrados são chamados de pixels não quadrados.
A taxa de proporção de pixel também se aplica ao dispositivo de vídeo. A forma física do dispositivo de vídeo e a resolução física dos pixels (horizontal e vertical) determinam a taxa de proporção de pixels (PAR) do dispositivo de vídeo. Os monitores de computador geralmente usam pixels quadrados. Se a imagem PAR e o vídeo PAR não corresponderem, o tamanho da imagem deverá ser alterado em uma das dimensões, vertical ou horizontal, para ser exibido de forma correta. A fórmula a seguir relaciona PAR, DAR (taxa de proporção de vídeo) e tamanho da imagem em pixels:
DAR = (largura da imagem em pixels / altura da imagem em pixels) × PAR
Observe que a largura e a altura da imagem nesta fórmula referem-se à imagem na memória, não à imagem exibida.
Aqui está um exemplo do mundo real: o vídeo analógico NTSC-M contém 480 linhas de varredura na área de imagem ativa. ITU-R Rec. O BT.601 especifica uma taxa de amostragem horizontal de 704 pixels visíveis por linha, resultando em uma imagem digital com 704 x 480 pixels. A taxa de proporção de imagem pretendida é 4:3, gerando uma PAR de 10:11.
- DAR: 4:3
- Largura em pixels: 704
- Altura em pixels: 480
- PAR: 10/11
4/3 = (704/480) x (10/11)
Para exibir essa imagem corretamente em um dispositivo de vídeo com pixels quadrados, você deve dimensionar a largura em 10/11 ou a altura em 11/10.
Trabalhar com taxas de proporção
A forma correta de um quadro de vídeo é definida pela taxa de proporção de pixel (PAR) e pela área de exibição.
- A PAR define a forma dos pixels em uma imagem. Os pixels quadrados têm uma proporção de 1:1. Qualquer outra taxa de proporção descreve um pixel não quadrado. Por exemplo, a televisão NTSC usa um PAR de 10:11. Supondo que você esteja apresentando o vídeo em um monitor de computador, o vídeo terá pixels quadrados (1:1 PAR). A PAR do conteúdo de origem é definida no atributo MF_MT_PIXEL_ASPECT_RATIO no tipo de mídia.
- A área de vídeo é a região da imagem do vídeo que deve ser mostrada. Há duas áreas de vídeo relevantes que podem ser especificadas no tipo de mídia:
- Abertura pan-and-scan. A abertura pan-and-scan é uma região de 4×3 do vídeo que deve ser exibida no modo pan/scan. Ela é usada para mostrar conteúdo widescreen em uma tela 4×3 sem letterboxing. A abertura pan-and-scan é definida no atributo MF_MT_PAN_SCAN_APERTURE e deve ser usada somente quando o atributo MF_MT_PAN_SCAN_ENABLED for TRUE.
- Abertura do vídeo. Essa abertura é definida em alguns padrões de vídeo. Qualquer coisa fora da abertura do vídeo é a região de overscan e não deve ser exibida. Por exemplo, a televisão NTSC tem 720×480 pixels com uma abertura de vídeo de 704×480. A abertura de vídeo é definida no atributo MF_MT_MINIMUM_DISPLAY_APERTURE. Se estiver presente, ele deverá ser usado quando o modo pan-and-scan for FALSE.
Se o modo pan-and-can for FALSE e nenhuma abertura de vídeo estiver definida, todo o quadro de vídeo deverá ser exibido. Na verdade, este é o caso da maioria do conteúdo de vídeo que não é vídeo para televisão e DVD. A taxa de proporção de toda a imagem é calculada como (largura da área do vídeo / altura da área do vídeo) × PAR.
Exemplos de código
Localizar a área de vídeo
O código a seguir mostra como obter a área de vídeo do tipo de mídia.
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;
}
Converter entre taxas de proporção de pixel
O código a seguir mostra como converter um retângulo de uma taxa de proporção de pixel (PAR) para outra, preservando a taxa de proporção de imagem.
//-----------------------------------------------------------------------------
// 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;
}
Calcular a área de letterbox
O código a seguir calcula a área de letterbox, considerando um retângulo de origem e destino. Supõe-se que ambos os retângulos tenham a mesma 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;
}
Tópicos relacionados