欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

360Lib:Lanczos插值

程序员文章站 2022-03-16 15:10:59
...

在360Lib中定义了多种插值滤波器:
360Lib:Lanczos插值
在格式转换中使用的是Lanczos插值滤波器,色度分量使用的是Lanczos-2,亮度分量使用的是Lanczos-3。

Lanczos插值滤波器原理见:
http://blog.csdn.net/lin453701006/article/details/78205170
360Lib中,TGeometry中对Lanczos滤波器进行了相关定义:
1.initInterpolation——初始化滤波器大小和抽头数,并计算了Lanczos一维权重。
2.initFilterWeightLut——初始化滤波器权重,这里计算了Lanczos归一化的二维权重。
3.interpolate_lanczos_weight——根据输入的位置计算lanczos权重序号。


initInterpolation

功能:对360Lib中的滤波器大小和抽头数进行了初始化,计算了Lanczos一维权重存储在m_pfLanczosFltCoefLut[][]中。这里删除了其它滤波器的代码部分。其中滤波器窗口大小为6x6(亮度)和4x4(色度),而这里还定义了一个S_LANCZOS_LUT_SCALE变量,S_LANCZOS_LUT_SCALE实际是细化了窗口中心位置,理解起来稍有困难,会在倒数第二部分interpolate_lanczos_weight单独说明一下。

Void TGeometry::initInterpolation(Int *pInterpolateType)
{
  for(Int ch=CHANNEL_TYPE_LUMA; ch<MAX_NUM_CHANNEL_TYPE; ch++)
  {
    m_InterpolationType[ch] = (SInterpolationType)pInterpolateType[ch];
    switch(pInterpolateType[ch])
    {
      //删除了其它滤波器代码
      case SI_LANCZOS2:
      case SI_LANCZOS3:
        m_iLanczosParamA[ch] = (pInterpolateType[ch] == SI_LANCZOS2)? 2 : 3;        //lanczos参数α,亮度=3,色度=2
        if(m_pfLanczosFltCoefLut[ch])
          delete[] m_pfLanczosFltCoefLut[ch];
        m_pfLanczosFltCoefLut[ch] = new POSType[(m_iLanczosParamA[ch]<<1)*S_LANCZOS_LUT_SCALE+1];       
        memset(m_pfLanczosFltCoefLut[ch], 0, sizeof(POSType)*((m_iLanczosParamA[ch]<<1)*S_LANCZOS_LUT_SCALE+1));
        for(Int i=0; i<(m_iLanczosParamA[ch]<<1)*S_LANCZOS_LUT_SCALE; i++)
        {
          Double x = (Double)i / S_LANCZOS_LUT_SCALE - m_iLanczosParamA[ch];
          m_pfLanczosFltCoefLut[ch][i] = (POSType)(sinc(x) * sinc(x / m_iLanczosParamA[ch]));       //计算权重L(x)
        }
        m_interpolateWeight[ch] = &TGeometry::interpolate_lanczos_weight;
        m_iInterpFilterTaps[ch][0] = m_iInterpFilterTaps[ch][1] = m_iLanczosParamA[ch]*2;
        break;
      default:
        assert(!"Not supported yet!");
        break;
    }
  }
}


initFilterWeightLut

功能:计算滤波器权重,其中计算了Lanczos归一化二维权重,存储在m_pWeightLut[][]中。这里删除了其它滤波器的代码部分。

//初始化插值滤波器权重
Void TGeometry::initFilterWeightLut()
{
  if(!m_pWeightLut[0])  //m_pWeightLut[0][0]=0
  {
    //calculate the weight based on sampling pattern and interpolation filter;
    Int iNumWLuts = (m_chromaFormatIDC==CHROMA_400 || (m_InterpolationType[0]==m_InterpolationType[1]))? 1 : 2;
    for(Int i=0; i<iNumWLuts; i++)
    {
        Int iFilterSize = getFilterSize(m_InterpolationType[i]);        //获取滤波器大小
        m_pWeightLut[i] = new Int*[(S_LANCZOS_LUT_SCALE+1)*(S_LANCZOS_LUT_SCALE+1)];        
        m_pWeightLut[i][0] = new Int[(S_LANCZOS_LUT_SCALE+1)*(S_LANCZOS_LUT_SCALE+1)*iFilterSize];
        for(Int k=1; k<(S_LANCZOS_LUT_SCALE+1)*(S_LANCZOS_LUT_SCALE+1); k++)
          m_pWeightLut[i][k] = m_pWeightLut[i][0] + k*iFilterSize;

        //删除了其它滤波器代码
        //calculate the weight;
       if(m_InterpolationType[i] == SI_LANCZOS2 || m_InterpolationType[i] == SI_LANCZOS3)
        {
          Int mul = 1<<(S_INTERPOLATE_PrecisionBD);     //插值精度2^14
          assert((m_InterpolationType[i] == SI_LANCZOS2 && iFilterSize == 16) || (m_InterpolationType[i] == SI_LANCZOS3 && iFilterSize == 36));
          Double dScale = 1.0/S_LANCZOS_LUT_SCALE;      //0.01
          POSType *pfLanczosFltCoefLut;
          pfLanczosFltCoefLut = m_pfLanczosFltCoefLut[i];   //一维权重L(x)
          for(Int m=0; m<(S_LANCZOS_LUT_SCALE+1); m++)
          {
            Double t = m*dScale;
            POSType wy[6];
            for(Int k=-m_iLanczosParamA[i]; k<m_iLanczosParamA[i]; k++)
              wy[k + m_iLanczosParamA[i]] = pfLanczosFltCoefLut[(Int)((sfabs(t-k-1) + m_iLanczosParamA[i])* S_LANCZOS_LUT_SCALE + 0.5)];        //y的权重

            for(Int n=0; n<(S_LANCZOS_LUT_SCALE+1); n++)
            {
              POSType wx[6];
              Int *pW = m_pWeightLut[i][m*(S_LANCZOS_LUT_SCALE+1)+n];
              Int sum=0;
              t = n*dScale;
              for(Int k=-m_iLanczosParamA[i]; k<m_iLanczosParamA[i]; k++)
                wx[k + m_iLanczosParamA[i]] = pfLanczosFltCoefLut[(Int)((sfabs(t-k-1) + m_iLanczosParamA[i])* S_LANCZOS_LUT_SCALE + 0.5)];      //x的权重
              //normalize; 
              //归一化
              POSType dSum = 0;
              for(Int r=0; r<(m_iLanczosParamA[i]<<1); r++)
                for(Int c=0; c<(m_iLanczosParamA[i]<<1); c++)
                    dSum += wy[r]*wx[c];    //二维权重求和
              for(Int r=0; r<(m_iLanczosParamA[i]<<1); r++)
                for(Int c=0; c<(m_iLanczosParamA[i]<<1); c++)
                {
                  Int w;
                  if(c!=(m_iLanczosParamA[i]<<1)-1 || r!=(m_iLanczosParamA[i]<<1)-1)
                    w = round((POSType)(wy[r]*wx[c]*mul/dSum)); 
                  else
                    w = mul - sum;      
                  pW[r*(m_iLanczosParamA[i]<<1)+c] = w; //存储权重
                  sum += w;     
                }
            }
          }
        }
    }
  }
}


interpolate_lanczos_weight

功能:根据输入的位置求权重序号,对于Lanczos滤波器,实际是α x α滤波窗口的序号。
这里来单独说明一下S_LANCZOS_LUT_SCALE,实际是细化了窗口中心位置,在interpolate_lanczos_weight函数中理解比较容易。这里输入的点坐标(x,y)为浮点数,会向下取整得到整数点设为(x’,y’),(x’,y’)即为滤波器窗口中心位置。然后根据与(x,y)与(x’,y’)的偏移来确定滤波器序号,S_LANCZOS_LUT_SCALE实际细化了这个偏移。我打印了一下对应的滤波器权重分布为,下面给出几个典型位置的值。
1.偏移为(0,0)时,此时实际不需要插值,亮度滤波器权重分布为:

0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 16384, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0

2.偏移为(0.01,0.01)时,根据计算滤波器序号为102,亮度滤波器权重分布为:

0, 0, 33, 0, 0, 0,
0, 1, -134, -1, 0, 0,
33, -134, 16378, 137, -34, 0,
0, -1, 137, 1, 0, 0,
0, 0, -34, 0, 0, 0,
0, 0, 0, 0, 0, 2,

3.偏移为(0.5,0.5)时,根据计算滤波器序号为30600,亮度滤波器权重为:

10, -54, 245, 245, -54, 10,
-54, 302, -1361, -1361, 302, -54,
245, -1361, 6125, 6125, -1361, 245,
245, -1361, 6125, 6125, -1361, 245,
-54, 302, -1361, -1361, 302, -54,
10, -54, 245, 245, -54, 6,

Void TGeometry::interpolate_lanczos_weight(ComponentID chId, SPos *pSPosIn, PxlFltLut &wlist)
{
  //Int iChannels = getNumChannels();
  Int x = (Int)sfloor(pSPosIn->x);      //取小于等于它的整数
  Int y = (Int)sfloor(pSPosIn->y); 
  ChannelType chType = toChannelType(chId);     //根据色度类型转换通道
  assert(x >=- (m_iMarginX >> getComponentScaleX(chId))+m_iLanczosParamA[chType]-1 && x<((m_sVideoInfo.iFaceWidth + m_iMarginX)>>getComponentScaleX(chId))-m_iLanczosParamA[chType]);
  assert(y >=- (m_iMarginY >> getComponentScaleY(chId))+m_iLanczosParamA[chType]-1 && y<((m_sVideoInfo.iFaceHeight + m_iMarginY)>>getComponentScaleY(chId))-m_iLanczosParamA[chType]);

  wlist.facePos = ((y*getStride(chId) +x)<<m_WeightMap_NumOfBits4Faces) | pSPosIn->faceIdx;
  wlist.weightIdx = round((pSPosIn->y -y)*S_LANCZOS_LUT_SCALE)*(S_LANCZOS_LUT_SCALE+1) + round((pSPosIn->x-x)*S_LANCZOS_LUT_SCALE);     //S_LANCZOS_LUT_SCALE=100
}


插值过程

插值过程比较简单,调用interpolate_lanczos_weight计算权重序号,然后加权计算插值后的像素值。比如来看S-PSNR-I中的插值:

(this->*m_interpolateWeight[chType])(chId, &inPos, wList);      //根据位置计算权重序号

  Int face = (wList.facePos)&iWeightMapFaceMask;
  Int iTLPos = (wList.facePos)>>m_WeightMap_NumOfBits4Faces;
  Int iWLutIdx = (m_chromaFormatIDC==CHROMA_400 || (m_InterpolationType[0]==m_InterpolationType[1]))? 0 : chType;
  Int *pWLut = m_pWeightLut[iWLutIdx][wList.weightIdx];
  Pel *pPelLine = m_pFacesOrig[face][chId] +iTLPos -((m_iInterpFilterTaps[chType][1]-1)>>1)*iWidthPW -((m_iInterpFilterTaps[chType][0]-1)>>1);

  //插值
  for(Int m=0; m<m_iInterpFilterTaps[chType][1]; m++)
  {
    for(Int n=0; n<m_iInterpFilterTaps[chType][0]; n++)
      sum += pPelLine[n]*pWLut[n];
    pPelLine += iWidthPW;
    pWLut += m_iInterpFilterTaps[chType][0];
  }
相关标签: 360