Varias formas de calcular el costo de RD en x265

Además del costo RD tradicional en x265, existen Psy-RdCost y SSIM-RdCost. El uso de estos tres costos RD se controla mediante parámetros de línea de comando. Si no se establece, el valor predeterminado es Psy-RDCost, líneas de comando relacionadas Los parámetros son como sigue:

  • - [no-] psy-rd <0… 5.0> Intensidad de la optimización de la distorsión de frecuencia psico-visual, 0 para deshabilitar. Por defecto 2.0
  • - [no-] psy-rdoq <0… 50.0> Fuerza de optimización psico-visual en la cuantificación RDO, 0 para deshabilitar. Por defecto 0.0
  • - [no-] ssim-rd Habilita la optimización de la distorsión de la tasa de ssim, 0 para deshabilitar. Por defecto deshabilitado
  • –Dynamic-rd <0… 4.0> Fuerza de RD dinámica, 0 para deshabilitar. Por defecto 0.00

一 、 Distorsión de frecuencia psico-visual

La fórmula para calcular el costo Psy-RD en x265 es la siguiente:

RD = D + \ lambda _ {1} * psyRD * psyCost + \ lambda _ {2} * Rate

Donde D se refiere a la distorsión del bloque reconstruido, psyRD indica la fuerza de psy-RDCost, psyCost se refiere a la diferencia entre la energía de CA del bloque reconstruido y el bloque original, y Rate se refiere a la tasa de código requerida para codificar la corriente block, en x265 El código para calcular PsyRDCost es el siguiente:

 inline uint64_t calcPsyRdCost(sse_t distortion, uint32_t bits, uint32_t psycost) const
    {
#if X265_DEPTH < 10
        X265_CHECK((bits <= (UINT64_MAX / m_lambda2)) && (psycost <= UINT64_MAX / (m_lambda * m_psyRd)),
                   "calcPsyRdCost wrap detected dist: %u, bits: %u, lambda: " X265_LL ", lambda2: " X265_LL "\n",
                   distortion, bits, m_lambda, m_lambda2);
#else
        X265_CHECK((bits <= (UINT64_MAX / m_lambda2)) && (psycost <= UINT64_MAX / (m_lambda * m_psyRd)),
                   "calcPsyRdCost wrap detected dist: " X265_LL ", bits: %u, lambda: " X265_LL ", lambda2: " X265_LL "\n",
                   distortion, bits, m_lambda, m_lambda2);
#endif
        return distortion + ((m_lambda * m_psyRd * psycost) >> 24) + ((bits * m_lambda2) >> 8);
    }

Es decir, psy-RD Cost tiene un elemento más m_lambda * m_psyRd * psycost que el cálculo tradicional de RD Cost, donde m_lambda está relacionado con QP, y m_psyRd está controlado por el parámetro de línea de comando psy-rd, que indica la fuerza de Psy-RD Costo

 /* Scale PSY RD factor by a slice type factor */
static const uint32_t psyScaleFix8[3] = { 300, 256, 96 }; /* B, P, I */
m_psyRd = (m_psyRdBase * psyScaleFix8[slice.m_sliceType]) >> 8;
m_rdCost.setPsyRdScale(param.psyRd);
void setPsyRdScale(double scale)                { m_psyRdBase = (uint32_t)floor(65536.0 * scale * 0.33); }

El código de cálculo de psyRDCost es el siguiente:

El psyRD aquí representa la diferencia entre la energía CA del bloque reconstruido y la energía CA del bloque original, es decir AC_ {energía} = SATD (bloque, 0) - SAD (bloque, 0)(no entiendo por qué el SATD del bloque de píxeles y 0 menos el SAD de la suma de 0 representa el Energía CA)

template<int size>
int psyCost_pp(const pixel* source, intptr_t sstride, const pixel* recon, intptr_t rstride)
{
    static pixel zeroBuf[8] /* = { 0 } */;

    if (size)
    {
        int dim = 1 << (size + 2);
        uint32_t totEnergy = 0;
        for (int i = 0; i < dim; i += 8)
        {
            for (int j = 0; j < dim; j+= 8)
            {
                /* AC energy, measured by sa8d (AC + DC) minus SAD (DC) */
                int sourceEnergy = sa8d_8x8(source + i * sstride + j, sstride, zeroBuf, 0) - 
                                   (sad<8, 8>(source + i * sstride + j, sstride, zeroBuf, 0) >> 2);
                int reconEnergy =  sa8d_8x8(recon + i * rstride + j, rstride, zeroBuf, 0) - 
                                   (sad<8, 8>(recon + i * rstride + j, rstride, zeroBuf, 0) >> 2);

                totEnergy += abs(sourceEnergy - reconEnergy);
            }
        }
        return totEnergy;
    }
    else
    {
        /* 4x4 is too small for sa8d */
        int sourceEnergy = satd_4x4(source, sstride, zeroBuf, 0) - (sad<4, 4>(source, sstride, zeroBuf, 0) >> 2);
        int reconEnergy = satd_4x4(recon, rstride, zeroBuf, 0) - (sad<4, 4>(recon, rstride, zeroBuf, 0) >> 2);
        return abs(sourceEnergy - reconEnergy);
    }
}

二 、 Distorsión de velocidad SSIM

La fórmula para calcular el costo de SSIM RD en x265 es la siguiente:

RD = D + \ lambda _ {1} * ssimCost + \ lambda _ {2} * Tarifa

El código de cálculo en x265 es el siguiente:

    inline uint64_t calcSsimRdCost(uint64_t distortion, uint32_t bits, uint32_t ssimCost) const
    {
#if X265_DEPTH < 10
        X265_CHECK((bits <= (UINT64_MAX / m_lambda2)) && (ssimCost <= UINT64_MAX / m_lambda),
                   "calcPsyRdCost wrap detected dist: " X265_LL " bits: %u, lambda: " X265_LL ", lambda2: " X265_LL "\n",
                   distortion, bits, m_lambda, m_lambda2);
#else
        X265_CHECK((bits <= (UINT64_MAX / m_lambda2)) && (ssimCost <= UINT64_MAX / m_lambda),
                   "calcPsyRdCost wrap detected dist: " X265_LL ", bits: %u, lambda: " X265_LL ", lambda2: " X265_LL "\n",
                   distortion, bits, m_lambda, m_lambda2);
#endif
        return distortion + ((m_lambda * ssimCost) >> 14) + ((bits * m_lambda2) >> 8);
    }

Entre ellos, SSIMCost es la distorsión bajo el índice SSIM, y la fórmula de cálculo de SSIMCost se deriva del documento

El cálculo en x265 es el siguiente

uint64_t Quant::ssimDistortion(const CUData& cu, const pixel* fenc, uint32_t fStride, const pixel* recon, intptr_t rstride, uint32_t log2TrSize, TextType ttype, uint32_t absPartIdx)
{
    static const int ssim_c1 = (int)(.01 * .01 * PIXEL_MAX * PIXEL_MAX * 64 + .5); // 416
    static const int ssim_c2 = (int)(.03 * .03 * PIXEL_MAX * PIXEL_MAX * 64 * 63 + .5); // 235963
    int shift = (X265_DEPTH - 8);

    int trSize = 1 << log2TrSize;
    uint64_t ssDc = 0, ssBlock = 0, ssAc = 0;

    // Calculation of (X(0) - Y(0)) * (X(0) - Y(0)), DC
    ssDc = 0; //ssDc 表示整个块内所有4x4为块的左上角像素差值的平方和
    for (int y = 0; y < trSize; y += 4)
    {
        for (int x = 0; x < trSize; x += 4)
        {
            int temp = fenc[y * fStride + x] - recon[y * rstride + x]; // copy of residual coeff
            ssDc += temp * temp;
        }
    }

    // Calculation of (X(k) - Y(k)) * (X(k) - Y(k)), AC
    ssBlock = 0; //ssBlock 表示整个块内的原始像素-重建像素的差值的平方和
    uint64_t ac_k = 0; //ac_k表示整个块内原始像素的平方和
    primitives.cu[log2TrSize - 2].ssimDist(fenc, fStride, recon, rstride, &ssBlock, shift, &ac_k);
    ssAc = ssBlock - ssDc;

    // 1. Calculation of fdc'
    // Calculate numerator of dc normalization factor 计算dc归一化因子的分子
    uint64_t fDc_num = 0;

    // 2. Calculate dc component
    uint64_t dc_k = 0; //表示整个块内所有4x4为块的左上角像素平方和
    for (int block_yy = 0; block_yy < trSize; block_yy += 4)
    {
        for (int block_xx = 0; block_xx < trSize; block_xx += 4)
        {
            uint32_t temp = fenc[block_yy * fStride + block_xx] >> shift;
            dc_k += temp * temp;
        }
    }

    fDc_num = (2 * dc_k)  + (trSize * trSize * ssim_c1); // 16 pixels -> for each 4x4 block
    fDc_num /= ((trSize >> 2) * (trSize >> 2));

    // 1. Calculation of fac'
    // Calculate numerator of ac normalization factor
    uint64_t fAc_num = 0;

    // 2. Calculate ac component
    ac_k -= dc_k;

    double s = 1 + 0.005 * cu.m_qp[absPartIdx];

    fAc_num = ac_k + uint64_t(s * ac_k) + ssim_c2;
    fAc_num /= ((trSize >> 2) * (trSize >> 2));

    // Calculate dc and ac normalization factor
    uint64_t ssim_distortion = ((ssDc * cu.m_fDc_den[ttype]) / fDc_num) + ((ssAc * cu.m_fAc_den[ttype]) / fAc_num);
    return ssim_distortion;
}

Costo de tres, Rd SATD

El costo de RD SATD se utiliza principalmente para una selección aproximada de modos de predicción intra. Para reducir la complejidad, la transformada residual de Hadamard se utiliza para aproximar la distorsión. Este método elimina los procesos de transformación, cuantificación, cuantificación inversa y transformación inversa. La complejidad puede reducirse considerablemente. La fórmula de cálculo es la siguiente:

RD = SATD (s, p) + \ lambda_ {modo} * R_ {modo}

Entre ellos, SATD representa el SATD del residuo del bloque original y el bloque predicho, y Rmdoe es solo el número de bits necesarios para codificar el modo actual.

    inline uint64_t calcRdSADCost(uint32_t sadCost, uint32_t bits) const
    {
        X265_CHECK(bits <= (UINT64_MAX - 128) / m_lambda,
                   "calcRdSADCost wrap detected dist: %u, bits %u, lambda: " X265_LL "\n", sadCost, bits, m_lambda);
        return sadCost + ((bits * m_lambda + 128) >> 8);
    }

 

Supongo que te gusta

Origin blog.csdn.net/BigDream123/article/details/112438054
Recomendado
Clasificación