CPP-PSNR是360Lib采纳的一种360视频的客观质量评估标准。该评估标准认为,把2D图像投影到球型视野上,不同纬度的像素具有不同的权重,通过给360视频投影得到的2D图像的不同纬度增加权重,来对360视频进行评估。

TWSPSNRMetric类

下面来看360Lib中定义的CPP-PSNR类TWSPSNRMetric,其中有两个重要函数createTable(创建投影格式对应的权重列表)和xCalculateWSPSNR(计算WS-PSNR)。

class TWSPSNRMetric
{private:Bool      m_bEnabled;Double    m_dWSPSNR[3];Int       m_outputBitDepth[MAX_NUM_CHANNEL_TYPE];         ///< bit-depth of output fileInt       m_referenceBitDepth[MAX_NUM_CHANNEL_TYPE];      ///< bit-depth of reference file//各投影格式权重,Y:亮度权重,C:色度权重Double* m_fErpWeight_Y;Double* m_fErpWeight_C;Double* m_fCubeWeight_Y;Double* m_fCubeWeight_C;Double* m_fEapWeight_Y;Double* m_fEapWeight_C;Double* m_fOctaWeight_Y;Double* m_fOctaWeight_C;Double* m_fIcoWeight_Y;Double* m_fIcoWeight_C;
#if SVIDEO_WSPSNR_SSPDouble* m_fSspWeight_Y;Double* m_fSspWeight_C;
#endifInt     m_codingGeoType;      //编码几何类型Int     m_iCodingFaceWidth;       //编码面宽度Int     m_iCodingFaceHeight;      //编码面高度Int     m_iChromaSampleLocType;       //采样色度格式
#if SVIDEO_WSPSNR_E2E//for E2E WS-PSNR calculation;
#if !SVIDEO_E2E_METRICSTVideoIOYuv *m_pcTVideoIOYuvInputFile;  //note: reference;TGeometry   *m_pRefGeometry;TGeometry   *m_pRecGeometry;TComPicYuv  *m_pcOrgPicYuv;TComPicYuv  *m_pcRecPicYuv;             //in original geometry domain;
#endif
#if !SVIDEO_E2E_METRICSInt         m_iLastFrmPOC;UInt        m_temporalSubsampleRatio;Int         m_iInputWidth;Int         m_iInputHeight;ChromaFormat m_inputChromaFomat;
#endif
#endif
public:TWSPSNRMetric();virtual ~TWSPSNRMetric();Bool    getWSPSNREnabled()  { return m_bEnabled; }        //获取m_bEnabledVoid    setWSPSNREnabledFlag(Bool bEnabledFlag)  { m_bEnabled = bEnabledFlag; }       //设置m_bEnabledVoid    setOutputBitDepth(Int iOutputBitDepth[MAX_NUM_CHANNEL_TYPE]);     //输出图像bit深度Void    setReferenceBitDepth(Int iReferenceBitDepth[MAX_NUM_CHANNEL_TYPE]);       //参考图像bit深度//设置视频几何信息Void    setCodingGeoInfo(SVideoInfo& sVidInfo, Int iChromaSampleLocType) { m_codingGeoType = sVidInfo.geoType; m_iCodingFaceWidth = sVidInfo.iFaceWidth; m_iCodingFaceHeight = sVidInfo.iFaceHeight; m_iChromaSampleLocType =iChromaSampleLocType; }
#if SVIDEO_WSPSNR_E2E
#if SVIDEO_E2E_METRICSVoid    setCodingGeoInfo2(SVideoInfo& sRefVideoInfo, SVideoInfo& sRecVideoInfo, InputGeoParam *pInGeoParam);Void    xCalculateE2EWSPSNR(TComPicYuv *pcRecPicYuv, TComPicYuv *pcOrigPicYuv);
#elseVoid    setCodingGeoInfo2(SVideoInfo& sRefVideoInfo, SVideoInfo& sRecVideoInfo, InputGeoParam *pInGeoParam, TVideoIOYuv& yuvInputFile, Int iInputWidth, Int iInputHeight, UInt tempSubsampleRatio);Void    xCalculateE2EWSPSNR(TComPicYuv *pcPicD, Int iPOC);
#endif
#endifDouble* getWSPSNR() {return m_dWSPSNR;}       //获取WS-PSNRVoid    createTable(TComPicYuv* pcPicD, TGeometry *pcCodingGeomtry);      //创建投影格式对应的权重列表Void    xCalculateWSPSNR( TComPicYuv* pcOrgPicYuv, TComPicYuv* pcPicD );      //计算WS-PSNR//inline Int round(POSType t) { return (Int)(t+ (t>=0? 0.5 :-0.5)); };
};

createTable

createTable:创建投影格式对应的权重列表。这里只截取了最常用的ERP和CMP对应的部分。每一种投影格式都对应一种权重,可以看到ERP的权重只与高度位置相关,CMP的权重与所在面的x,y坐标位置相关。因此WS-PSNR的参考图像和当前图像必须是相同投影格式,无法进行跨投影格式质量评估。

//创建投影格式对应的权重列表
void TWSPSNRMetric::createTable(TComPicYuv* pcPicD, TGeometry *pcCodingGeomtry)
{if(!m_bEnabled){return;}SVideoInfo *pCodingSVideoInfo = pcCodingGeomtry->getSVideoInfo();Int iFaceWidth = pCodingSVideoInfo->iFaceWidth;Int iFaceHeight = pCodingSVideoInfo->iFaceHeight;Int iScaleX = pcPicD->getComponentScaleX(COMPONENT_Cb);Int iScaleY = pcPicD->getComponentScaleY(COMPONENT_Cb);Double dChromaOffset[2] = {0.0, 0.0}; //[0: X; 1: Y];if(pcPicD->getChromaFormat() == CHROMA_420){dChromaOffset[0] = (m_iChromaSampleLocType == 0 || m_iChromaSampleLocType == 2)? 0 : 0.5;dChromaOffset[1] = (m_iChromaSampleLocType == 2 || m_iChromaSampleLocType == 3)? 0 : 0.5;}//ERP投影if(pcCodingGeomtry->getType()==SVIDEO_EQUIRECT){Double fWeightSum_Y=0;Double fWeightSum_C=0;Int   iWidth = pcPicD->getWidth(COMPONENT_Y) ;      //获取亮度宽度Int   iHeight = pcPicD->getHeight(COMPONENT_Y) ;    //获取亮度高度Int   iWidthC = pcPicD->getWidth(COMPONENT_Cb) ;        //获取色度宽度Int   iHeightC = pcPicD->getHeight(COMPONENT_Cb) ;  //获取色度高度m_fErpWeight_Y=(Double*)malloc(iHeight*sizeof(Double));     //亮度权重和高度有关m_fErpWeight_C=(Double*)malloc(iHeightC*sizeof(Double));        //色度权重和高度有关//计算亮度和色度的纬度权重for(Int y=0; y< iHeight; y++){m_fErpWeight_Y[y]=scos((y-(iHeight/2-0.5))*S_PI/iHeight);fWeightSum_Y += m_fErpWeight_Y[y];}for(Int y=0; y< iHeightC; y++){m_fErpWeight_C[y]=scos(((y<<iScaleY)+dChromaOffset[1]+0.5-iHeight/2)*S_PI/iHeight);fWeightSum_C += m_fErpWeight_C[y];}for(Int y=0; y< iHeight; y++){m_fErpWeight_Y[y]=m_fErpWeight_Y[y]/fWeightSum_Y/iWidth;}for(Int y=0; y< iHeightC; y++){m_fErpWeight_C[y]=m_fErpWeight_C[y]/fWeightSum_C/(iWidthC);}}//CMP投影else if(pcCodingGeomtry->getType()==SVIDEO_CUBEMAP){Double fWeightSum_Y=0;Double fWeightSum_C=0;    //亮度、色度权重和面的高度宽度都有关m_fCubeWeight_Y=(Double*)malloc(iFaceHeight * iFaceWidth*sizeof(Double));       m_fCubeWeight_C=(Double*)malloc((iFaceHeight >> iScaleY) * (iFaceWidth >> iScaleX)*sizeof(Double));//计算亮度和色度权重for(Int y = 0; y < iFaceHeight; y++ ){for(Int x=0; x < iFaceWidth; x++){Int ci, cj, r2;Double d2;ci= iFaceWidth/2;cj= iFaceHeight/2;d2 = (x+0.5-ci)*(x+0.5-ci)+(y+0.5-cj)*(y+0.5-cj);r2 = (iFaceWidth/2)*(iFaceWidth/2);Double weight= 1.0/((1+d2/r2)*ssqrt(1.0*(1+d2/r2)));m_fCubeWeight_Y[iFaceWidth*y+x] = weight;fWeightSum_Y += weight;}}for(Int y = 0; y < iFaceHeight; y++ ){for(Int x=0; x<iFaceWidth; x++){m_fCubeWeight_Y[iFaceHeight*y+x] = (m_fCubeWeight_Y[iFaceHeight*y+x])/fWeightSum_Y/6.0;}}for(Int y = 0; y < (iFaceHeight>>iScaleY); y++ ){for(Int x=0; x< (iFaceWidth>>iScaleX); x++){Int ci, cj, r2;Double d2;ci= iFaceWidth/2;cj= iFaceHeight/2;d2 = (x*(1<<iScaleX)+dChromaOffset[0]+0.5 - ci)*(x*(1<<iScaleX)+dChromaOffset[0]+0.5 - ci) + (y*(1<<iScaleY)+dChromaOffset[1]+0.5 -cj)*(y*(1<<iScaleY)+dChromaOffset[1]+0.5 -cj);r2 = (iFaceWidth/2)*(iFaceWidth/2);Double weight= 1.0/((1+d2/r2)*sqrt(1.0*(1+d2/r2)));m_fCubeWeight_C[(iFaceWidth>>iScaleX)*y+x]=weight;fWeightSum_C += weight;}}for(Int y = 0; y < (iFaceHeight>>iScaleY); y++ ){for(Int x=0; x< (iFaceWidth>>iScaleX); x++){m_fCubeWeight_C[(iFaceWidth>>iScaleX)*y+x]=(m_fCubeWeight_C[(iFaceWidth>>iScaleX)*y+x])/fWeightSum_C/6.0;}}}
}

xCalculateWSPSNR

xCalculateWSPSNR:计算WS-PSNR。这里只截取了最常用的ERP和CMP对应的部分。使用已计算好的权重,计算加权SSD,得到PSNR。

//计算WS-PSNR
Void TWSPSNRMetric::xCalculateWSPSNR( TComPicYuv* pcOrgPicYuv, TComPicYuv* pcPicD )
{//初始化亮度色度bit信息Int iBitDepthForPSNRCalc[MAX_NUM_CHANNEL_TYPE];Int iReferenceBitShift[MAX_NUM_CHANNEL_TYPE];Int iOutputBitShift[MAX_NUM_CHANNEL_TYPE];iBitDepthForPSNRCalc[CHANNEL_TYPE_LUMA] = std::max(m_outputBitDepth[CHANNEL_TYPE_LUMA], m_referenceBitDepth[CHANNEL_TYPE_LUMA]);iBitDepthForPSNRCalc[CHANNEL_TYPE_CHROMA] = std::max(m_outputBitDepth[CHANNEL_TYPE_CHROMA], m_referenceBitDepth[CHANNEL_TYPE_CHROMA]);iReferenceBitShift[CHANNEL_TYPE_LUMA] = iBitDepthForPSNRCalc[CHANNEL_TYPE_LUMA] - m_referenceBitDepth[CHANNEL_TYPE_LUMA];iReferenceBitShift[CHANNEL_TYPE_CHROMA] = iBitDepthForPSNRCalc[CHANNEL_TYPE_CHROMA] - m_referenceBitDepth[CHANNEL_TYPE_CHROMA];iOutputBitShift[CHANNEL_TYPE_LUMA] = iBitDepthForPSNRCalc[CHANNEL_TYPE_LUMA] - m_outputBitDepth[CHANNEL_TYPE_LUMA];iOutputBitShift[CHANNEL_TYPE_CHROMA] = iBitDepthForPSNRCalc[CHANNEL_TYPE_CHROMA] - m_outputBitDepth[CHANNEL_TYPE_CHROMA];memset(m_dWSPSNR, 0, sizeof(Double)*3);TComPicYuv &picd=*pcPicD;//Double SSDspsnr[3]={0, 0 ,0};//ChromaFormat chromaFormat = pcPicD->getChromaFormat();for(Int chan=0; chan<pcPicD->getNumberValidComponents(); chan++){const ComponentID ch=ComponentID(chan);const Pel*  pOrg       = pcOrgPicYuv->getAddr(ch);const Int   iOrgStride = pcOrgPicYuv->getStride(ch);const Pel*  pRec       = picd.getAddr(ch);const Int   iRecStride = picd.getStride(ch);const Int   iWidth  = pcPicD->getWidth (ch) ;const Int   iHeight = pcPicD->getHeight(ch) ;Double fWeight =1;Double fWeightSum=0;//Int   iSize   = iWidth*iHeight;Double SSDwpsnr=0;//WS-PSNRfor(Int y = 0; y < iHeight; y++ ){//ERP格式只与高度有关if (m_codingGeoType==SVIDEO_EQUIRECT){      if(!chan)   //亮度{fWeight=m_fErpWeight_Y[y];}else        //色度{fWeight=m_fErpWeight_C[y];}}for(Int x = 0; x < iWidth; x++ ){//参考图像和输出图像差值Intermediate_Int iDiff = (Intermediate_Int)( (pOrg[x]<<iReferenceBitShift[toChannelType(ch)]) - (pRec[x]<<iOutputBitShift[toChannelType(ch)]) );//CMP格式和x,y都有关if (m_codingGeoType==SVIDEO_CUBEMAP){if(!chan){if(iWidth/4 == iHeight/3 && x >= iWidth/4 && (y< iHeight/3 || y>= 2*iHeight/3)){fWeight=0;}else {fWeight=m_fCubeWeight_Y[(m_iCodingFaceWidth)*(y%(m_iCodingFaceHeight)) +(x%(m_iCodingFaceWidth))];}}else{if(iWidth/4 == iHeight/3 && x >= iWidth/4 && (y< iHeight/3 || y>= 2*iHeight/3)){fWeight=0;}else{fWeight=m_fCubeWeight_C[(m_iCodingFaceWidth>>(pcPicD->getComponentScaleX(COMPONENT_Cb)))*(y%(m_iCodingFaceHeight>>(pcPicD->getComponentScaleY(COMPONENT_Cb)))) +(x%(m_iCodingFaceWidth>>(pcPicD->getComponentScaleX(COMPONENT_Cb))))];}  }}if(fWeight>0)fWeightSum += fWeight;SSDwpsnr   += iDiff * iDiff*fWeight;        //加权SSD     }pOrg += iOrgStride;pRec += iRecStride;}const Int maxval = 255<<(iBitDepthForPSNRCalc[toChannelType(ch)]-8) ;//const Double fRefValue = (Double) maxval * maxval * iSize;m_dWSPSNR[ch]         = ( SSDwpsnr ? 10.0 * log10( (maxval * maxval*fWeightSum) / (Double)SSDwpsnr ) : 999.99 );        //计算PSNR}}

360Lib:WS-PSNR相关推荐

  1. 360Lib:Lanczos插值

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

  2. 图像评估指标:PSNR

    公式: MSEMSEMSE:模型的输出图像与真实图像之间的均方误差 MAXMAXMAX:nnn位RGB图像所能取到的最大值(例如nnn===888,此时MAXMAXMAX===2228^{8}8−-− ...

  3. J. Cheminform. | DrugEx v2:多重药理学中基于pareto的多目标强化学习的药物分子从头设计...

    本文介绍的是由荷兰莱顿药物研究学术中心.西安交通大学电子与信息工程学院和莱顿高级计算机科学研究所联合发表在Journal of Cheminformatics上的研究成果.作者在之前的一项研究中提出了 ...

  4. [WS]使用Axis发布简单的Web服务

    使用Axis,要发布一个Web服务非常简单,简直不能再简单了,尽管看起来过程和相关代码有些长.我这个帖子里用到了这些软件:Axis 1.1.Eclipse 2.1和Eclipse的Tomcat插件2. ...

  5. 转载:k2pdfopt详细教程-让kindle看遍所有pdf

    pdf拿什么拯救6寸kindle 救世主登场 一步一步解决图文混排扫描版pdf 书籍 总结 原文链接:https://blog.csdn.net/laoxuan2011/article/details ...

  6. websocket之一:websocket简介

    Websocket websocket为一次HTTP握手后,后续通讯为tcp协议的通讯方式. WebSocket 使用一种被称作"Upgrade handshake(升级握手)"的 ...

  7. TensorFlow:简单的卷积层、池化层(采样层)示例

    卷积层: ws=tf.get_variable('w',[5,5,3,16],initializer=tf.truncated_normal_initializer(stddev=0.1)) bs=t ...

  8. C++学习笔记:(九)输入/输出流

    目录 9.输入/输出流 9.1C++流类库简介 9.2输入/输出流 9.3自定义类型的输入/输出 9.4文件输入/输出 9.输入/输出流 数据的输入.输出是最重要的操作,C++ 的输入.输出有 ios ...

  9. 谈谈surging引擎的tcp、http、ws协议和如何容器化部署

    1.前言 分布式已经成为了当前最热门的话题,分布式框架也百花齐放,群雄逐鹿.从中心化服务治理框架,到去中心化分布式服务框架,再到分布式微服务引擎,这都是通过技术不断积累改进而形成的结果.esb,网关, ...

最新文章

  1. C#中base关键字的几种用法
  2. 在WinForm应用程序中嵌入WPF控件(转)
  3. 渥太华大学计算机工程,渥太华大学电气与计算机工程硕士专业.pdf
  4. java基础:数据类型
  5. Qualcomm QXDM工具简介和log抓取
  6. Thinkphp 配置不用输入index.php
  7. Kafka.net使用编程入门(一)
  8. 上周回顾:艾妮闹春 Sun/HP高层人士震荡
  9. opencv android
  10. WPF实现无线扫码枪无焦点自动获取数据并逻辑处理
  11. Windows10连接局域网打印机
  12. html中如何写平方根等,excel平方根
  13. 中央财经大学研究生入学考试 901C语言程序设计
  14. 编码器的集电极输出、电压输出、互补输出和线性驱动输出
  15. 逆透视变换车道线检测
  16. Flutter教程之Flutter 中的磨砂玻璃效果
  17. JIRA6.3安装及alige插件破解
  18. 曲速未来:区块链用于房地产是否会起作用
  19. Winform平台的HTML编辑控件——Zeta HTML
  20. Github上的英文解释

热门文章

  1. 阿里云数字化转型方案再升级,移动研发平台EMAS助力海底捞超级App“云上捞”
  2. AndroidStudio项目组件化maven上传gradle-module aar上传
  3. 「MOSS - 33」MOSS队:Beta阶段总结和反思
  4. win10设置开机自动自动
  5. idea将目录设置为模块
  6. 给我个春天,我就跟你走。。----上
  7. 善用Navicat的SSH代理
  8. 会声会影2019六大新功能盘点
  9. 基于瑞芯微芯片RK3399学习
  10. 腾讯官宣 | 腾讯策略协作型 AI「绝悟」升级至王者荣耀电竞职业水平