openh264 帧间预测编码过程源码分析
openh264
OpenH264 是一个开源的 H.264 编码和解码器,由思科系统开发并维护。它专为实时应用程序如 WebRTC 设计,提供了从基础到高级特性的广泛支持。OpenH264 的编码器支持从 Constrained Baseline Profile 到 5.2 级别,允许任意分辨率的编码,不限于 16x16 的倍数,并且具有自适应量化或恒定量化的速率控制、多切片选项、多线程自动用于多切片等特性。此外,它还支持高达 4 层的时序可伸缩性、单一输入的 4 种空间分辨率的 Spatial Simulcast、长期参考帧(LTR)、内存管理控制操作(MMCO)等功能。
帧间预测编码
视频帧间预测编码(Inter-frame prediction coding)是视频压缩技术中的一种关键方法,主要用于减少视频序列中时间维度上的冗余。这种编码方式依赖于视频帧之间的空间相关性,通过预测和补偿来减少数据量,从而实现高效的视频压缩。
帧间预测编码是视频编码中非常有效的技术,广泛应用于各种视频编码标准,如H.264/AVC、H.265/HEVC、VP9和AV1等。通过减少时间冗余,帧间预测编码显著提高了视频数据的压缩率,同时保持了视频质量。
帧间预测的核心技术主要包括以下几个方面:
运动估计(Motion Estimation, ME):
- 运动估计是指在参考帧中搜索与当前块最匹配的区域,以确定最佳匹配块的位置。
运动补偿(Motion Compensation, MC):
- 运动补偿使用运动估计得到的运动向量来预测当前块,通过补偿先前图像的抽样点来生成当前图像块的预测值。
宏块(Macroblock, MB)和子宏块(Sub-Macroblock)的树状结构分块:
- H.264 支持多种宏块分割方式,如16x16、16x8、8x16和8x8,以及更细致的子宏块分割,如8x8、8x4、4x8和4x4。
多参考帧预测:
- 特别是在B帧中,可以使用两个方向的参考帧(List0和List1)进行双向预测。
亚像素精度的运动估计:
- 除了整像素精度外,H.264还支持1/2像素和1/4像素的亚像素插值,以提高预测精度。
快速搜索算法:
- 为了减少计算复杂度,使用快速搜索算法来确定最佳匹配块。
运动向量的编码:
- 运动向量的编码通常涉及编码运动向量与预测值的差值(MVD),而不是直接编码运动向量本身。
预测模式的选择:
- H.264定义了多种预测模式,包括直接模式、双向模式、List0和List1模式等。
参考帧管理:
- 管理参考帧以确保解码器能够正确地重建预测图像。
变换/量化编码和熵编码:
- 这些步骤与帧内编码相同或相似,用于进一步压缩预测残差。
帧间预测通过这些技术有效地减少了视频序列中的时间冗余,提高了压缩效率。
openh264 帧间预测编码过程
- 帧间预测过程函数关系图:
- 关键模块说明:
- 通过API 函数
EncodeFrame
完成具体的编码过程,可执行程序封装该函数进行编码;- 通过二维数组g_pWelsSliceCoding[2][2]来完成具体的I 帧、P 帧,以及变化片数和非变化片数编码;
- 在非变化片数帧间编码过程中,在
WelsMdInterMbLoop
函数中循环处理每个宏块;- 在变化片数帧间编码过程中,在
WelsMdInterMbLoopOverDynamicSlice
函数中循环处理每个宏块;pfInterMd
函数指针指向具体的增强层WelsMdInterMbEnhancelayer
或基本层WelsMdInterMb
帧间预测过程;- 在基本层预测过程中,
WelsMdInterSecondaryModesEnc
函数完成二级帧间预测过程编码;- 在增强层预测过程中,
WelsMdSpatialelInterMbIlfmdNoilp
函数完成具体的预测过程编码;
- 帧间预测过程核心函数介绍:
WelsMdInterMbLoopOverDynamicSlice
函数
- 用于动态切片的宏块编码过程,循环处理每个 MB;
// Only for inter dynamic slicing
int32_t WelsMdInterMbLoopOverDynamicSlice (sWelsEncCtx* pEncCtx, SSlice* pSlice, void* pWelsMd,const int32_t kiSliceFirstMbXY) {SWelsMD* pMd = (SWelsMD*)pWelsMd;SBitStringAux* pBs = pSlice->pSliceBsa;SDqLayer* pCurLayer = pEncCtx->pCurDqLayer;SSliceCtx* pSliceCtx = &pCurLayer->sSliceEncCtx;SMbCache* pMbCache = &pSlice->sMbCacheInfo;SMB* pMbList = pCurLayer->sMbDataP;SMB* pCurMb = NULL;int32_t iNumMbCoded = 0;const int32_t kiTotalNumMb = pCurLayer->iMbWidth * pCurLayer->iMbHeight;int32_t iNextMbIdx = kiSliceFirstMbXY;int32_t iCurMbIdx = -1;const int32_t kiMvdInterTableStride = pEncCtx->iMvdCostTableStride;uint16_t* pMvdCostTable = &pEncCtx->pMvdCostTable[pEncCtx->iMvdCostTableSize];const int32_t kiSliceIdx = pSlice->iSliceIdx;const int32_t kiPartitionId = (kiSliceIdx % pEncCtx->iActiveThreadsNum);const uint8_t kuiChromaQpIndexOffset = pCurLayer->sLayerInfo.pPpsP->uiChromaQpIndexOffset;int32_t iEncReturn = ENC_RETURN_SUCCESS;SDynamicSlicingStack sDss;if (pEncCtx->pSvcParam->iEntropyCodingModeFlag) {WelsInitSliceCabac (pEncCtx, pSlice);sDss.iStartPos = sDss.iCurrentPos = 0;sDss.pRestoreBuffer = pEncCtx->pDynamicBsBuffer[kiPartitionId];} else {sDss.iStartPos = BsGetBitsPos (pBs);}pSlice->iMbSkipRun = 0;for (;;) {//DYNAMIC_SLICING_ONE_THREAD - MultiD//stack pBs pointerpEncCtx->pFuncList->pfStashMBStatus (&sDss, pSlice, pSlice->iMbSkipRun);//point to current pMbiCurMbIdx = iNextMbIdx;pCurMb = &pMbList[ iCurMbIdx ];//step(1): set QP for the current MBpEncCtx->pFuncList->pfRc.pfWelsRcMbInit (pEncCtx, pCurMb, pSlice);// if already reaches the largest number of slices, set QPs to the upper boundif (pSlice->bDynamicSlicingSliceSizeCtrlFlag) {//a clearer logic may be://if there is no need from size control from the pSlice size, the QP will be decided by RC; else it will be set to the max QP// however, there are some parameter updating in the rc_mb_init() function, so it cannot be skipped?pCurMb->uiLumaQp = pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId].iMaxQp;pCurMb->uiChromaQp = g_kuiChromaQpTable[CLIP3_QP_0_51 (pCurMb->uiLumaQp + kuiChromaQpIndexOffset)];}//step (2). save some vale for future use, initial pWelsMdWelsMdIntraInit (pEncCtx, pCurMb, pMbCache, kiSliceFirstMbXY);WelsMdInterInit (pEncCtx, pSlice, pCurMb, kiSliceFirstMbXY);TRY_REENCODING:WelsInitInterMDStruc (pCurMb, pMvdCostTable, kiMvdInterTableStride, pMd);pEncCtx->pFuncList->pfInterMd (pEncCtx, pMd, pSlice, pCurMb, pMbCache);//mb_qp//step (4): save from the MD process from future useWelsMdInterSaveSadAndRefMbType ((pCurLayer->pDecPic->uiRefMbType), pMbCache, pCurMb, pMd);pEncCtx->pFuncList->pfMdBackgroundInfoUpdate (pCurLayer, pCurMb, pMbCache->bCollocatedPredFlag,pEncCtx->pRefPic->iPictureType);//step (5): update cacheUpdateNonZeroCountCache (pCurMb, pMbCache);//step (6): begin to write bit stream; if the pSlice size is controlled, the writing may be skippediEncReturn = pEncCtx->pFuncList->pfWelsSpatialWriteMbSyn (pEncCtx, pSlice, pCurMb);if (iEncReturn == ENC_RETURN_VLCOVERFLOWFOUND && (pCurMb->uiLumaQp < 50)) {pSlice->iMbSkipRun = pEncCtx->pFuncList->pfStashPopMBStatus (&sDss, pSlice);UpdateQpForOverflow (pCurMb, kuiChromaQpIndexOffset);goto TRY_REENCODING;}if (ENC_RETURN_SUCCESS != iEncReturn)return iEncReturn;//DYNAMIC_SLICING_ONE_THREAD - MultiDsDss.iCurrentPos = pEncCtx->pFuncList->pfGetBsPosition (pSlice);if (DynSlcJudgeSliceBoundaryStepBack (pEncCtx, pSlice, pSliceCtx, pCurMb, &sDss)) {pSlice->iMbSkipRun = pEncCtx->pFuncList->pfStashPopMBStatus (&sDss, pSlice);pCurLayer->LastCodedMbIdxOfPartition[kiPartitionId] = iCurMbIdx -1; // update LastCodedMbIdxOfPartition, need to -1 due to stepping back++ pCurLayer->NumSliceCodedOfPartition[kiPartitionId];break;}//step (7): reconstruct current MBpCurMb->uiSliceIdc = kiSliceIdx;OutputPMbWithoutConstructCsRsNoCopy (pEncCtx, pCurLayer, pSlice, pCurMb);#if defined(MB_TYPES_CHECK)WelsCountMbType (pEncCtx->sPerInfo.iMbCount, P_SLICE, pCurMb);
#endif//MB_TYPES_CHECK//step (8): update status and other parameterspEncCtx->pFuncList->pfRc.pfWelsRcMbInfoUpdate (pEncCtx, pCurMb, pMd->iCostLuma, pSlice);/*judge if all pMb in cur pSlice has been encoded*/++ iNumMbCoded;iNextMbIdx = WelsGetNextMbOfSlice (pCurLayer, iCurMbIdx);//whether all of MB in current pSlice encoded or notif (iNextMbIdx == -1 || iNextMbIdx >= kiTotalNumMb || iNumMbCoded >= kiTotalNumMb) {pCurLayer->LastCodedMbIdxOfPartition[kiPartitionId] = iCurMbIdx;++ pCurLayer->NumSliceCodedOfPartition[kiPartitionId];break;}}if (pSlice->iMbSkipRun) {BsWriteUE (pBs, pSlice->iMbSkipRun);}return iEncReturn;
}}//namespace WelsEnc
WelsMdInterMbLoop
函数
- 用于固定切片的宏块编码过程,循环处理每个 MB;
// for inter non-dynamic pSlice
int32_t WelsMdInterMbLoop (sWelsEncCtx* pEncCtx, SSlice* pSlice, void* pWelsMd, const int32_t kiSliceFirstMbXY) {SWelsMD* pMd = (SWelsMD*)pWelsMd;SBitStringAux* pBs = pSlice->pSliceBsa;SDqLayer* pCurLayer = pEncCtx->pCurDqLayer;SMbCache* pMbCache = &pSlice->sMbCacheInfo;SMB* pMbList = pCurLayer->sMbDataP;SMB* pCurMb = NULL;int32_t iNumMbCoded = 0;int32_t iNextMbIdx = kiSliceFirstMbXY;int32_t iCurMbIdx = -1;const int32_t kiTotalNumMb = pCurLayer->iMbWidth * pCurLayer->iMbHeight;const int32_t kiMvdInterTableStride = pEncCtx->iMvdCostTableStride;uint16_t* pMvdCostTable = &pEncCtx->pMvdCostTable[pEncCtx->iMvdCostTableSize];const int32_t kiSliceIdx = pSlice->iSliceIdx;const uint8_t kuiChromaQpIndexOffset = pCurLayer->sLayerInfo.pPpsP->uiChromaQpIndexOffset;int32_t iEncReturn = ENC_RETURN_SUCCESS;SDynamicSlicingStack sDss;if (pEncCtx->pSvcParam->iEntropyCodingModeFlag) {WelsInitSliceCabac (pEncCtx, pSlice);sDss.pRestoreBuffer = NULL;sDss.iStartPos = sDss.iCurrentPos = 0;}pSlice->iMbSkipRun = 0;for (;;) {if (!pEncCtx->pSvcParam->iEntropyCodingModeFlag)pEncCtx->pFuncList->pfStashMBStatus (&sDss, pSlice, pSlice->iMbSkipRun);//point to current pMbiCurMbIdx = iNextMbIdx;pCurMb = &pMbList[ iCurMbIdx ];//step(1): set QP for the current MBpEncCtx->pFuncList->pfRc.pfWelsRcMbInit (pEncCtx, pCurMb, pSlice);//step (2). save some vale for future use, initial pWelsMdWelsMdIntraInit (pEncCtx, pCurMb, pMbCache, kiSliceFirstMbXY);WelsMdInterInit (pEncCtx, pSlice, pCurMb, kiSliceFirstMbXY);TRY_REENCODING:WelsInitInterMDStruc (pCurMb, pMvdCostTable, kiMvdInterTableStride, pMd);pEncCtx->pFuncList->pfInterMd (pEncCtx, pMd, pSlice, pCurMb, pMbCache);//mb_qp//step (4): save from the MD process from future useWelsMdInterSaveSadAndRefMbType ((pCurLayer->pDecPic->uiRefMbType), pMbCache, pCurMb, pMd);pEncCtx->pFuncList->pfMdBackgroundInfoUpdate (pCurLayer, pCurMb, pMbCache->bCollocatedPredFlag,pEncCtx->pRefPic->iPictureType);//step (5): update cacheUpdateNonZeroCountCache (pCurMb, pMbCache);//step (6): begin to write bit stream; if the pSlice size is controlled, the writing may be skippediEncReturn = pEncCtx->pFuncList->pfWelsSpatialWriteMbSyn (pEncCtx, pSlice, pCurMb);if (!pEncCtx->pSvcParam->iEntropyCodingModeFlag) {if (iEncReturn == ENC_RETURN_VLCOVERFLOWFOUND && (pCurMb->uiLumaQp < 50)) {pSlice->iMbSkipRun = pEncCtx->pFuncList->pfStashPopMBStatus (&sDss, pSlice);UpdateQpForOverflow (pCurMb, kuiChromaQpIndexOffset);goto TRY_REENCODING;}}if (ENC_RETURN_SUCCESS != iEncReturn)return iEncReturn;//step (7): reconstruct current MBpCurMb->uiSliceIdc = kiSliceIdx;OutputPMbWithoutConstructCsRsNoCopy (pEncCtx, pCurLayer, pSlice, pCurMb);#if defined(MB_TYPES_CHECK)WelsCountMbType (pEncCtx->sPerInfo.iMbCount, P_SLICE, pCurMb);
#endif//MB_TYPES_CHECK//step (8): update status and other parameterspEncCtx->pFuncList->pfRc.pfWelsRcMbInfoUpdate (pEncCtx, pCurMb, pMd->iCostLuma, pSlice);/*judge if all pMb in cur pSlice has been encoded*/++ iNumMbCoded;iNextMbIdx = WelsGetNextMbOfSlice (pCurLayer, iCurMbIdx);//whether all of MB in current pSlice encoded or notif (iNextMbIdx == -1 || iNextMbIdx >= kiTotalNumMb || iNumMbCoded >= kiTotalNumMb) {break;}}if (pSlice->iMbSkipRun) {BsWriteUE (pBs, pSlice->iMbSkipRun);}return iEncReturn;
}
WelsMdInterMb
函数
- 基本层的预测编码的核心实现函数,主要用模式决策等过程;
void WelsMdInterMb (sWelsEncCtx* pEncCtx, SWelsMD* pWelsMd, SSlice* pSlice, SMB* pCurMb, SMbCache* pUnused) {SDqLayer* pCurDqLayer = pEncCtx->pCurDqLayer;SMbCache* pMbCache = &pSlice->sMbCacheInfo;const uint32_t kuiNeighborAvail = pCurMb->uiNeighborAvail;const int32_t kiMbWidth = pCurDqLayer->iMbWidth;const SMB* top_mb = pCurMb - kiMbWidth;const bool bMbLeftAvailPskip = ((kuiNeighborAvail & LEFT_MB_POS) ? IS_SKIP ((pCurMb - 1)->uiMbType) : false);const bool bMbTopAvailPskip = ((kuiNeighborAvail & TOP_MB_POS) ? IS_SKIP (top_mb->uiMbType) : false);const bool bMbTopLeftAvailPskip = ((kuiNeighborAvail & TOPLEFT_MB_POS) ? IS_SKIP ((top_mb - 1)->uiMbType) : false);const bool bMbTopRightAvailPskip = ((kuiNeighborAvail & TOPRIGHT_MB_POS) ? IS_SKIP ((top_mb + 1)->uiMbType) : false);bool bTrySkip = bMbLeftAvailPskip || bMbTopAvailPskip || bMbTopLeftAvailPskip || bMbTopRightAvailPskip;bool bKeepSkip = bMbLeftAvailPskip && bMbTopAvailPskip && bMbTopRightAvailPskip;bool bSkip = false;//try BGD skipif (pEncCtx->pFuncList->pfInterMdBackgroundDecision (pEncCtx, pWelsMd, pSlice, pCurMb, pMbCache, &bKeepSkip)) {return;}//try static or scrolled Pskipif (pEncCtx->pFuncList->pfSCDPSkipDecision (pEncCtx, pWelsMd, pSlice, pCurMb, pMbCache)) {return;}//step 1: try SKIPbSkip = WelsMdInterJudgePskip (pEncCtx, pWelsMd, pSlice, pCurMb, pMbCache, bTrySkip);if (bSkip) {if (bKeepSkip) {WelsMdInterDecidedPskip (pEncCtx, pSlice, pCurMb, pMbCache);return;}} else {PredictSad (pMbCache->sMvComponents.iRefIndexCache, pMbCache->iSadCost, 0, &pWelsMd->iSadPredMb);//step 2: P_16x16pWelsMd->iCostLuma = WelsMdP16x16 (pEncCtx->pFuncList, pCurDqLayer, pWelsMd, pSlice, pCurMb);pCurMb->uiMbType = MB_TYPE_16x16;}WelsMdInterSecondaryModesEnc (pEncCtx, pWelsMd, pSlice, pCurMb, pMbCache, bSkip);
}
WelsMdInterSecondaryModesEnc
函数
- 基本层帧间二级模式的编码实现函数,主要用与判断出了 skip 和 p16x16 块类型之外的模式决策;
void WelsMdInterSecondaryModesEnc (sWelsEncCtx* pEncCtx, SWelsMD* pWelsMd, SSlice* pSlice, SMB* pCurMb,SMbCache* pMbCache, const bool bSkip) {//step 2: Intraconst bool kbTrySkip = pEncCtx->pFuncList->pfFirstIntraMode (pEncCtx, pWelsMd, pCurMb, pMbCache);if (kbTrySkip)return;if (bSkip) {WelsMdInterDecidedPskip (pEncCtx, pSlice, pCurMb, pMbCache);} else {//Step 3: SubP16 MDpEncCtx->pFuncList->pfSetScrollingMv (pEncCtx->pVaa, pWelsMd); //SCCpEncCtx->pFuncList->pfInterFineMd (pEncCtx, pWelsMd, pSlice, pCurMb, pWelsMd->iCostLuma);//refinement for inter typeWelsMdInterMbRefinement (pEncCtx, pWelsMd, pCurMb, pMbCache);//step 7: invoke encodingWelsMdInterEncode (pEncCtx, pSlice, pCurMb, pMbCache);//step 8: double check PskipWelsMdInterDoubleCheckPskip (pCurMb, pMbCache);}
}
WelsMdSpatialelInterMbIlfmdNoilp
函数
- 增强层的预测编码的核心实现函数,主要用模式决策等过程;
//
// MD for enhancement layers
//
void WelsMdSpatialelInterMbIlfmdNoilp (sWelsEncCtx* pEncCtx, SWelsMD* pWelsMd, SSlice* pSlice,SMB* pCurMb, const Mb_Type kuiRefMbType) {SDqLayer* pCurDqLayer = pEncCtx->pCurDqLayer;SMbCache* pMbCache = &pSlice->sMbCacheInfo;const uint32_t kuiNeighborAvail = pCurMb->uiNeighborAvail;const int32_t kiMbWidth = pCurDqLayer->iMbWidth;const SMB* kpTopMb = pCurMb - kiMbWidth;const bool kbMbLeftAvailPskip = ((kuiNeighborAvail & LEFT_MB_POS) ? IS_SKIP ((pCurMb - 1)->uiMbType) : false);const bool kbMbTopAvailPskip = ((kuiNeighborAvail & TOP_MB_POS) ? IS_SKIP (kpTopMb->uiMbType) : false);const bool kbMbTopLeftAvailPskip = ((kuiNeighborAvail & TOPLEFT_MB_POS) ? IS_SKIP ((kpTopMb - 1)->uiMbType) : false);const bool kbMbTopRightAvailPskip = ((kuiNeighborAvail & TOPRIGHT_MB_POS) ? IS_SKIP ((kpTopMb + 1)->uiMbType) : false);bool bTrySkip = kbMbLeftAvailPskip | kbMbTopAvailPskip | kbMbTopLeftAvailPskip | kbMbTopRightAvailPskip;bool bKeepSkip = kbMbLeftAvailPskip & kbMbTopAvailPskip & kbMbTopRightAvailPskip;bool bSkip = false;if (pEncCtx->pFuncList->pfInterMdBackgroundDecision (pEncCtx, pWelsMd, pSlice, pCurMb, pMbCache, &bKeepSkip)) {return;}//step 1: try SKIPbSkip = WelsMdInterJudgePskip (pEncCtx, pWelsMd, pSlice, pCurMb, pMbCache, bTrySkip);if (bSkip && bKeepSkip) {WelsMdInterDecidedPskip (pEncCtx, pSlice, pCurMb, pMbCache);return;}if (! IS_SVC_INTRA (kuiRefMbType)) {if (!bSkip) {PredictSad (pMbCache->sMvComponents.iRefIndexCache, pMbCache->iSadCost, 0, &pWelsMd->iSadPredMb);//step 2: P_16x16pWelsMd->iCostLuma = WelsMdP16x16 (pEncCtx->pFuncList, pCurDqLayer, pWelsMd, pSlice, pCurMb);pCurMb->uiMbType = MB_TYPE_16x16;}WelsMdInterSecondaryModesEnc (pEncCtx, pWelsMd, pSlice, pCurMb, pMbCache, bSkip);} else { //BLMODE == SVC_INTRA//initial prediction memory for I_16x16const int32_t kiCostI16x16 = WelsMdI16x16 (pEncCtx->pFuncList, pEncCtx->pCurDqLayer, pMbCache, pWelsMd->iLambda);if (bSkip && (pWelsMd->iCostLuma <= kiCostI16x16)) {WelsMdInterDecidedPskip (pEncCtx, pSlice, pCurMb, pMbCache);} else {pWelsMd->iCostLuma = kiCostI16x16;pCurMb->uiMbType = MB_TYPE_INTRA16x16;WelsMdIntraSecondaryModesEnc (pEncCtx, pWelsMd, pCurMb, pMbCache);}}
}
相关文章:

openh264 帧间预测编码过程源码分析
openh264 OpenH264 是一个开源的 H.264 编码和解码器,由思科系统开发并维护。它专为实时应用程序如 WebRTC 设计,提供了从基础到高级特性的广泛支持。OpenH264 的编码器支持从 Constrained Baseline Profile 到 5.2 级别,允许任意分辨率的编…...

Linux网络 - HTTP协议
文章目录 前言一、HTTP协议1.urlurl特殊字符 requestrespond 总结 前言 上一章内容我们讲了在应用层制定了我们自己自定义的协议、序列化和反序列化。 协议的制定相对来讲还是比较麻烦的,不过既然应用层的协议制定是必要的,那么肯定已经有许多计算机大佬…...
面试题——Nginx
1.Nginx是什么? 是一个高性能的Web服务器和反向代理服务器,也可以作为静态文件的缓存服务器,也能够进行负载均衡。 2.Nginx的作用? 1.反向代理:将多台服务器代理为一台服务器。客户端不了解底层服务端。 2.负载均衡…...

持续学习的综述: 理论、方法与应用
摘要 为了应对现实世界的动态,智能系统需要在其整个生命周期中增量地获取、更新、积累和利用知识。这种能力被称为持续学习,为人工智能系统自适应发展提供了基础。从一般意义上讲,持续学习明显受到灾难性遗忘的限制,在这种情况下…...
跨域资源共享(CORS)问题与解决方案
跨域资源共享(CORS,Cross-Origin Resource Sharing)是现代web开发中常见且重要的一个概念。它涉及到浏览器的同源策略(Same-Origin Policy),该策略用于防止恶意网站从不同来源窃取数据。然而,在…...

实用软件分享-----一款免费的人工智能替换face的神器
专栏介绍:本专栏主要分享一些实用的软件(Po Jie版); 声明1:软件不保证时效性;只能保证在写本文时,该软件是可用的;不保证后续时间该软件能一直正常运行;不保证没有bug;如果软件不可用了,我知道后会第一时间在题目上注明(已失效)。介意者请勿订阅。 声明2:本专栏的…...

不可思议!这款 Python 库竟然能自动生成GUI界面:MagicGUI
目录 什么是MagicGUI? 编辑 MagicGUI的工作原理 安装MagicGUI 创建你的第一个GUI 编辑 其他案例 输入值对话框 大家好,今天我们来聊一聊一个非常有趣且实用的Python库——MagicGUI。这个库可以让你用最少的代码,快速创建图形用户…...

论文发表CN期刊《高考》是什么级别的刊物?
论文发表CN期刊《高考》是什么级别的刊物? 《高考》是由吉林省长春出版社主管并主办的省级教育类期刊,期刊以科教兴国战略为服务宗旨,专门反映和探索国内外教育教学和科研实践的最新成果。该期刊致力于为广大教育工作者提供一个高质量的学术…...

离散数学复习
1.关系的介绍和性质 (1)序偶和笛卡尔积 两个元素按照一定的顺序组成的二元组就是序偶,使用尖括号进行表示,尖括号里面的元素一般都是有顺序的; 笛卡尔积就是有两个集合,从第一个集合里面选择一个元素&am…...
华为网络设备高频命令
1.system-view • 用法:在用户视图下执行 system-view 命令。 • 作用:进入系统视图,以便进行配置性的操作。 • 场景:当需要对设备进行系统级的配置时。 2.sysname XXX • 用法:执行 [Huawei]sysname XXX 命令。…...
信友队:南风的收集
C. [202406C]楠枫的收集 文件操作 时间限制: 1000ms 空间限制: 262144KB 输入文件名: 202406C.in 输出文件名: 202406C.out Accepted 100 分 题目描述 一年四季,寒暑交替,楠枫总是会收集每一个季节的树叶,并把它们制作成标本收集起来。当…...
找工作小项目:day16-重构核心库、使用智能指针(3)
day16-重构核心库、使用智能指针(3) 最后将使用这个库的方式进行展示。 1、客户端 在while ((o getopt(argc, argv, optstring)) ! -1)所有的操作都是获取参数的操作,threads 、msgs 和wait 分别指线程数、消息长度以及等待时间。 创建一…...

软考中级|软件设计师-知识点整理
目录 计算机网络概论 计算机系统基础知识 中央处理单元 数据表示 校验码 计算机体系结构 计算机体系结构的发展 存储系统 输入/输出技术 安全性、可靠性与系统性能评测基础知识 加密技术和认证技术 计算机可靠性 程序设计语言基础知识 程序设计语言概述 程序设计…...

HTML5基础
1 HTML基础概念(难点) WWW(World Wide Web,万维网)是一种建立在 Internet 上的信息资源网络。 WWW 有 3 个基本组成部分,分别是 URL:Universal Resource Locators,统一资源定位器 HT…...
python,ipython 和 jupyter notebook 之间的关系
python,ipython 和 jupyter notebook 之间的关系 文章目录 python,ipython 和 jupyter notebook 之间的关系1. Python2. IPython3. Jupyter Notebook启动 Jupyter Notebook 关系总结 Python、IPython 和 Jupyter Notebook 是相互关联但具有不同功能的工具…...

聊聊DoIP吧(三)-端口号port
DoIP在UDP和TCP建立连接和发送诊断报文的过程中使用的端口定义如下:...

【将xml文件转yolov5训练数据txt标签文件】连classes.txt都可以生成
将xml文件转yolov5训练数据txt标签文件 前言一、代码解析 二、使用方法总结 前言 找遍全网,我觉得写得最详细的就是这个博文⇨将xml文件转yolov5训练数据txt标签文件 虽然我还是没有跑成功。那个正则表达式我不会改QWQ,但是不妨碍我会训练ai。 最终成功…...

针对k8s集群已经加入集群的服务器进行驱逐
例如k8s 已经有很多服务器,现在由于服务器资源过剩,需要剥离一些服务器出来 查找节点名称: kubectl get nodes设置为不可调度: kubectl cordon k8s-node13恢复可调度 kubectl uncordon k8s-node13在驱逐之前先把需要剥离驱逐的节…...

go 1.22 增强 http.ServerMux 路由能力
之前 server func main() {http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {fmt.Println("Received request:", r.URL.Path)fmt.Fprintf(w, "Hello, client! You requested: %s\n", r.URL.Path)})log.Println("Serv…...
赶紧收藏!2024 年最常见 20道设计模式面试题(二)
上一篇地址:赶紧收藏!2024 年最常见 20道设计模式面试题(一)-CSDN博客 三、解释抽象工厂模式,并给出一个实际应用的例子。 抽象工厂模式是一种创建型设计模式,用于创建一系列相关或依赖对象的接口&#x…...

国防科技大学计算机基础课程笔记02信息编码
1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制,因此这个了16进制的数据既可以翻译成为这个机器码,也可以翻译成为这个国标码,所以这个时候很容易会出现这个歧义的情况; 因此,我们的这个国…...

调用支付宝接口响应40004 SYSTEM_ERROR问题排查
在对接支付宝API的时候,遇到了一些问题,记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...
python如何将word的doc另存为docx
将 DOCX 文件另存为 DOCX 格式(Python 实现) 在 Python 中,你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是,.doc 是旧的 Word 格式,而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...

AI病理诊断七剑下天山,医疗未来触手可及
一、病理诊断困局:刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断",医生需通过显微镜观察组织切片,在细胞迷宫中捕捉癌变信号。某省病理质控报告显示,基层医院误诊率达12%-15%,专家会诊…...
【安全篇】金刚不坏之身:整合 Spring Security + JWT 实现无状态认证与授权
摘要 本文是《Spring Boot 实战派》系列的第四篇。我们将直面所有 Web 应用都无法回避的核心问题:安全。文章将详细阐述认证(Authentication) 与授权(Authorization的核心概念,对比传统 Session-Cookie 与现代 JWT(JS…...

macOS 终端智能代理检测
🧠 终端智能代理检测:自动判断是否需要设置代理访问 GitHub 在开发中,使用 GitHub 是非常常见的需求。但有时候我们会发现某些命令失败、插件无法更新,例如: fatal: unable to access https://github.com/ohmyzsh/oh…...

在 Visual Studio Code 中使用驭码 CodeRider 提升开发效率:以冒泡排序为例
目录 前言1 插件安装与配置1.1 安装驭码 CodeRider1.2 初始配置建议 2 示例代码:冒泡排序3 驭码 CodeRider 功能详解3.1 功能概览3.2 代码解释功能3.3 自动注释生成3.4 逻辑修改功能3.5 单元测试自动生成3.6 代码优化建议 4 驭码的实际应用建议5 常见问题与解决建议…...

归并排序:分治思想的高效排序
目录 基本原理 流程图解 实现方法 递归实现 非递归实现 演示过程 时间复杂度 基本原理 归并排序(Merge Sort)是一种基于分治思想的排序算法,由约翰冯诺伊曼在1945年提出。其核心思想包括: 分割(Divide):将待排序数组递归地分成两个子…...
Windows 下端口占用排查与释放全攻略
Windows 下端口占用排查与释放全攻略 在开发和运维过程中,经常会遇到端口被占用的问题(如 8080、3306 等常用端口)。本文将详细介绍如何通过命令行和图形化界面快速定位并释放被占用的端口,帮助你高效解决此类问题。 一、准…...

Qt的学习(二)
1. 创建Hello Word 两种方式,实现helloworld: 1.通过图形化的方式,在界面上创建出一个控件,显示helloworld 2.通过纯代码的方式,通过编写代码,在界面上创建控件, 显示hello world; …...