Proporzioni immagine

Questo argomento descrive due concetti correlati, le proporzioni dell'immagine e le proporzioni dei pixel. Descrive quindi come questi concetti vengono espressi in Microsoft Media Foundation usando i tipi di supporto.

Proporzioni immagine

Le proporzioni dell'immagine definiscono la forma dell'immagine video visualizzata. Le proporzioni dell'immagine vengono notate X:Y, dove X:Y è il rapporto tra la larghezza dell'immagine e l'altezza dell'immagine. La maggior parte degli standard video usa proporzioni immagine 4:3 o 16:9. Le proporzioni 16:9 sono comunemente denominate widescreen. Il cinema usa spesso proporzioni 1:85:1 o 1:66:1. Le proporzioni dell'immagine sono dette anche proporzioni di visualizzazione (DAR).

diagram showing 4:3 and 16:9 aspect ratios

A volte l'immagine video non ha la stessa forma dell'area di visualizzazione. Ad esempio, un video 4:3 potrebbe essere visualizzato in un televisore widescreen (16×9). Nel video del computer, il video potrebbe essere visualizzato all'interno di una finestra con dimensioni arbitrarie. In tal caso, è possibile creare tre modi per adattare l'immagine all'interno dell'area di visualizzazione:

  • Estendere l'immagine lungo un asse per adattarsi all'area di visualizzazione.
  • Ridimensionare l'immagine per adattarsi all'area di visualizzazione mantenendo le proporzioni dell'immagine originale.
  • Ritagliare l'immagine.

L'estensione dell'immagine per adattarsi all'area di visualizzazione è quasi sempre errata, perché non mantiene le proporzioni corrette dell'immagine.

Letterboxing

Il processo di ridimensionamento di un'immagine widescreen per adattarsi a uno schermo 4:3 è denominato letterboxing, illustrato nel diagramma successivo. Le aree rettangolari risultanti nella parte superiore e inferiore dell'immagine sono in genere riempite di nero, anche se è possibile usare altri colori.

diagram showing the correct way to letterbox

Il caso inverso, il ridimensionamento di un'immagine 4:3 per adattarsi a uno schermo widescreen, è talvolta detto pillarboxing. Tuttavia, il termine letterbox viene usato anche in senso generale, per indicare il ridimensionamento di un'immagine video per adattarsi a qualsiasi area di visualizzazione specificata.

diagram showing pillarboxing

Panoramica e analisi

La panoramica e l'analisi sono una tecnica in cui un'immagine widescreen viene ritagliata in un'area rettangolare 4×3, per la visualizzazione su un dispositivo di visualizzazione 4:3. L'immagine risultante riempie l'intero display, senza richiedere aree casella di lettere nere, ma parti dell'immagine originale vengono ritagliate dall'immagine. L'area ritagliata può spostarsi da frame a frame, in quanto l'area di interesse cambia. Il termine "pan" in pan-and-scan si riferisce all'effetto di panoramica causato dallo spostamento dell'area di panoramica e analisi.

diagram showing pan-and-scan

Proporzioni pixel

Le proporzioni dei pixel (PAR) misurano la forma di un pixel.

Quando viene acquisita un'immagine digitale, l'immagine viene campionata sia verticalmente che orizzontalmente, generando una matrice rettangolare di campioni quantizzati, denominati pixel o pels. La forma della griglia di campionamento determina la forma dei pixel nell'immagine digitalizzata.

Di seguito è riportato un esempio che usa numeri piccoli per semplificare la matematica. Si supponga che l'immagine originale sia quadrata (ovvero, le proporzioni dell'immagine sono 1:1); si supponga che la griglia di campionamento contenga 12 elementi, disposti in una griglia 4×3. La forma di ogni pixel risultante sarà più alta di quanto sia ampia. In particolare, la forma di ogni pixel sarà 3×4. I pixel che non sono quadrati sono denominati pixel non quadrati.

diagram showing a non-square sampling grid

Le proporzioni dei pixel si applicano anche al dispositivo di visualizzazione. La forma fisica del dispositivo di visualizzazione e la risoluzione dei pixel fisici (attraverso e giù) determinano la PAR del dispositivo di visualizzazione. I monitor computer usano in genere pixel quadrati. Se l'immagine PAR e la visualizzazione PAR non corrispondono, l'immagine deve essere ridimensionata in una dimensione, verticalmente o orizzontalmente, per visualizzare correttamente. La formula seguente è correlata a PAR, alle proporzioni di visualizzazione (DAR) e alle dimensioni dell'immagine in pixel:

DAR = (larghezza dell'immagine in pixel / ) × PAR

Si noti che la larghezza dell'immagine e l'altezza dell'immagine in questa formula fanno riferimento all'immagine in memoria, non all'immagine visualizzata.

Ecco un esempio reale: il video analogico NTSC-M contiene 480 linee di scansione nell'area dell'immagine attiva. ITU-R Rec. BT.601 specifica una frequenza di campionamento orizzontale di 704 pixel visibili per riga, producendo un'immagine digitale con 704 x 480 pixel. Le proporzioni dell'immagine desiderate sono pari a 4:3, con una par pari a 10:11.

  • DAR: 4:3
  • Larghezza in pixel: 704
  • Altezza in pixel: 480
  • PAR: 10/11

4/3 = (704/480) x (10/11)

Per visualizzare correttamente questa immagine in un dispositivo di visualizzazione con pixel quadrati, è necessario ridimensionare la larghezza di 10/11 o l'altezza di 11/10.

Uso delle proporzioni

La forma corretta di un fotogramma video è definita dalle proporzioni dei pixel (PAR) e dall'area di visualizzazione.

  • Par definisce la forma dei pixel in un'immagine. I pixel quadrati hanno proporzioni pari a 1:1. Qualsiasi altra proporzione descrive un pixel non quadrato. Ad esempio, il televisore NTSC usa una PAR 10:11. Supponendo di presentare il video su un monitor del computer, lo schermo avrà pixel quadrati (1:1 PAR). La par del contenuto di origine viene assegnata nell'attributo MF_MT_PIXEL_ASPECT_RATIO sul tipo di supporto.
  • L'area di visualizzazione è l'area dell'immagine video che deve essere visualizzata. Esistono due aree di visualizzazione rilevanti che possono essere specificate nel tipo di supporto:
    • Apertura panoramica e analisi. L'apertura panoramica e analisi è un'area video 4×3 che deve essere visualizzata in modalità panoramica/analisi. Viene usato per visualizzare contenuto a schermo intero su un display 4×3 senza cartella di posta in arrivo. L'apertura panoramica e analisi viene specificata nell'attributo MF_MT_PAN_SCAN_APERTURE e deve essere usata solo quando l'attributo MF_MT_PAN_SCAN_ENABLED è TRUE.
    • Apertura dello schermo. Questa apertura è definita in alcuni standard video. Qualsiasi elemento all'esterno dell'apertura dello schermo è l'area di overscan e non deve essere visualizzato. Ad esempio, il televisore NTSC è 720×480 pixel con un'apertura dello schermo di 704×480. L'apertura dello schermo viene specificata nell'attributo MF_MT_MINIMUM_DISPLAY_APERTURE . Se presente, deve essere usato quando la modalità panoramica e analisi è FAL edizione Standard.

Se la modalità pan-and-can è FAL edizione Standard e non è definita alcuna apertura dello schermo, l'intero fotogramma video deve essere visualizzato. Infatti, questo è il caso per la maggior parte dei contenuti video diversi dalla televisione e dvd video. Le proporzioni dell'intera immagine vengono calcolate come (altezza dell'area / di visualizzazione dell'area di visualizzazione) × PAR.

Esempi di codice

Ricerca dell'area di visualizzazione

Il codice seguente illustra come ottenere l'area di visualizzazione dal tipo di supporto.

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;
}

Conversione tra proporzioni pixel

Nel codice seguente viene illustrato come convertire un rettangolo da una proporzione di pixel (PAR) a un'altra, mantenendo al tempo stesso le proporzioni dell'immagine.

//-----------------------------------------------------------------------------
// 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;
}

Calcolo dell'area casella di lettere

Il codice seguente calcola l'area della casella di lettere, in base a un rettangolo di origine e di destinazione. Si presuppone che entrambi i rettangoli abbiano lo stesso 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;
}

Tipi di supporti

Tipi di supporti video

MF_MT_MINIMUM_DISPLAY_APERTURE

MF_MT_PAN_SCAN_APERTURE

MF_MT_PAN_SCAN_ENABLED

MF_MT_PIXEL_ASPECT_RATIO