360Lib:Lanczos插值
在360Lib中定义了多种插值滤波器:
在格式转换中使用的是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];
}
上一篇: 帧动画(Frame)Drawable Animation
下一篇: Linux入门——目录格式