Merge pull request #535 from volvet/add-scene-change-detector
Add scene change detector
This commit is contained in:
commit
3238c913cc
@ -603,7 +603,7 @@ void CWelsPreProcess::BilateralDenoising (SPicture* pSrc, const int32_t kiWidth,
|
|||||||
|
|
||||||
bool CWelsPreProcess::DetectSceneChange (SPicture* pCurPicture, SPicture* pRefPicture) {
|
bool CWelsPreProcess::DetectSceneChange (SPicture* pCurPicture, SPicture* pRefPicture) {
|
||||||
bool bSceneChangeFlag = false;
|
bool bSceneChangeFlag = false;
|
||||||
int32_t iMethodIdx = METHOD_SCENE_CHANGE_DETECTION;
|
int32_t iMethodIdx = METHOD_SCENE_CHANGE_DETECTION_VIDEO;
|
||||||
SSceneChangeResult sSceneChangeDetectResult = { SIMILAR_SCENE };
|
SSceneChangeResult sSceneChangeDetectResult = { SIMILAR_SCENE };
|
||||||
SPixMap sSrcPixMap = {0};
|
SPixMap sSrcPixMap = {0};
|
||||||
SPixMap sRefPixMap = {0};
|
SPixMap sRefPixMap = {0};
|
||||||
|
@ -122,7 +122,8 @@ typedef enum {
|
|||||||
METHOD_NULL = 0,
|
METHOD_NULL = 0,
|
||||||
METHOD_COLORSPACE_CONVERT ,//not support yet
|
METHOD_COLORSPACE_CONVERT ,//not support yet
|
||||||
METHOD_DENOISE ,
|
METHOD_DENOISE ,
|
||||||
METHOD_SCENE_CHANGE_DETECTION ,
|
METHOD_SCENE_CHANGE_DETECTION_VIDEO ,
|
||||||
|
METHOD_SCENE_CHANGE_DETECTION_SCREEN ,
|
||||||
METHOD_DOWNSAMPLE ,
|
METHOD_DOWNSAMPLE ,
|
||||||
METHOD_VAA_STATISTICS ,
|
METHOD_VAA_STATISTICS ,
|
||||||
METHOD_BACKGROUND_DETECTION ,
|
METHOD_BACKGROUND_DETECTION ,
|
||||||
|
@ -265,8 +265,9 @@ IStrategy* CVpFrameWork::CreateStrategy (EMethods m_eMethod, int32_t iCpuFlag) {
|
|||||||
case METHOD_DENOISE:
|
case METHOD_DENOISE:
|
||||||
pStrategy = WelsDynamicCast (IStrategy*, new CDenoiser (iCpuFlag));
|
pStrategy = WelsDynamicCast (IStrategy*, new CDenoiser (iCpuFlag));
|
||||||
break;
|
break;
|
||||||
case METHOD_SCENE_CHANGE_DETECTION:
|
case METHOD_SCENE_CHANGE_DETECTION_VIDEO:
|
||||||
pStrategy = WelsDynamicCast (IStrategy*, new CSceneChangeDetection (iCpuFlag));
|
case METHOD_SCENE_CHANGE_DETECTION_SCREEN:
|
||||||
|
pStrategy = BuildSceneChangeDetection(m_eMethod, iCpuFlag);
|
||||||
break;
|
break;
|
||||||
case METHOD_DOWNSAMPLE:
|
case METHOD_DOWNSAMPLE:
|
||||||
pStrategy = WelsDynamicCast (IStrategy*, new CDownsampling (iCpuFlag));
|
pStrategy = WelsDynamicCast (IStrategy*, new CDownsampling (iCpuFlag));
|
||||||
|
@ -35,108 +35,17 @@
|
|||||||
|
|
||||||
WELSVP_NAMESPACE_BEGIN
|
WELSVP_NAMESPACE_BEGIN
|
||||||
|
|
||||||
#define HIGH_MOTION_BLOCK_THRESHOLD 320
|
IStrategy * BuildSceneChangeDetection(EMethods eMethod, int32_t iCpuFlag){
|
||||||
#define SCENE_CHANGE_MOTION_RATIO 0.85f
|
switch(eMethod){
|
||||||
|
case METHOD_SCENE_CHANGE_DETECTION_VIDEO:
|
||||||
|
return new CSceneChangeDetection<CSceneChangeDetectorVideo>(eMethod, iCpuFlag);
|
||||||
|
break;
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
case METHOD_SCENE_CHANGE_DETECTION_SCREEN:
|
||||||
|
default:
|
||||||
CSceneChangeDetection::CSceneChangeDetection (int32_t iCpuFlag) {
|
// not support yet
|
||||||
m_iCpuFlag = iCpuFlag;
|
return NULL;
|
||||||
m_eMethod = METHOD_SCENE_CHANGE_DETECTION;
|
|
||||||
m_pfSad = NULL;
|
|
||||||
WelsMemset (&m_sSceneChangeParam, 0, sizeof (m_sSceneChangeParam));
|
|
||||||
InitSadFuncs (m_pfSad, m_iCpuFlag);
|
|
||||||
}
|
|
||||||
|
|
||||||
CSceneChangeDetection::~CSceneChangeDetection() {
|
|
||||||
}
|
|
||||||
|
|
||||||
EResult CSceneChangeDetection::Process (int32_t iType, SPixMap* pSrcPixMap, SPixMap* pRefPixMap) {
|
|
||||||
EResult eReturn = RET_INVALIDPARAM;
|
|
||||||
|
|
||||||
int32_t iWidth = pSrcPixMap->sRect.iRectWidth;
|
|
||||||
int32_t iHeight = pSrcPixMap->sRect.iRectHeight;
|
|
||||||
int32_t iBlock8x8Width = iWidth >> 3;
|
|
||||||
int32_t iBlock8x8Height = iHeight >> 3;
|
|
||||||
int32_t iBlock8x8Num = iBlock8x8Width * iBlock8x8Height;
|
|
||||||
int32_t iSceneChangeThreshold = WelsStaticCast (int32_t, SCENE_CHANGE_MOTION_RATIO * iBlock8x8Num + 0.5f + PESN);
|
|
||||||
|
|
||||||
int32_t iBlockSad = 0;
|
|
||||||
int32_t iMotionBlockNum = 0;
|
|
||||||
|
|
||||||
uint8_t* pRefY = NULL, *pCurY = NULL;
|
|
||||||
int32_t iRefStride = 0, iCurStride = 0;
|
|
||||||
int32_t iRefRowStride = 0, iCurRowStride = 0;
|
|
||||||
|
|
||||||
uint8_t* pRefTmp = NULL, *pCurTmp = NULL;
|
|
||||||
|
|
||||||
pRefY = (uint8_t*)pRefPixMap->pPixel[0];
|
|
||||||
pCurY = (uint8_t*)pSrcPixMap->pPixel[0];
|
|
||||||
|
|
||||||
iRefStride = pRefPixMap->iStride[0];
|
|
||||||
iCurStride = pSrcPixMap->iStride[0];
|
|
||||||
|
|
||||||
iRefRowStride = pRefPixMap->iStride[0] << 3;
|
|
||||||
iCurRowStride = pSrcPixMap->iStride[0] << 3;
|
|
||||||
|
|
||||||
m_sSceneChangeParam.eSceneChangeIdc = SIMILAR_SCENE;
|
|
||||||
|
|
||||||
for (int32_t j = 0; j < iBlock8x8Height; j ++) {
|
|
||||||
pRefTmp = pRefY;
|
|
||||||
pCurTmp = pCurY;
|
|
||||||
|
|
||||||
for (int32_t i = 0; i < iBlock8x8Width; i++) {
|
|
||||||
iBlockSad = m_pfSad (pRefTmp, iRefStride, pCurTmp, iCurStride);
|
|
||||||
|
|
||||||
iMotionBlockNum += (iBlockSad > HIGH_MOTION_BLOCK_THRESHOLD);
|
|
||||||
|
|
||||||
pRefTmp += 8;
|
|
||||||
pCurTmp += 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
pRefY += iRefRowStride;
|
|
||||||
pCurY += iCurRowStride;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iMotionBlockNum >= iSceneChangeThreshold) {
|
|
||||||
m_sSceneChangeParam.eSceneChangeIdc = LARGE_CHANGED_SCENE;
|
|
||||||
}
|
|
||||||
|
|
||||||
eReturn = RET_SUCCESS;
|
|
||||||
|
|
||||||
return eReturn;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
EResult CSceneChangeDetection::Get (int32_t iType, void* pParam) {
|
|
||||||
if (pParam == NULL) {
|
|
||||||
return RET_INVALIDPARAM;
|
|
||||||
}
|
|
||||||
|
|
||||||
* (SSceneChangeResult*)pParam = m_sSceneChangeParam;
|
|
||||||
|
|
||||||
return RET_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void CSceneChangeDetection::InitSadFuncs (SadFuncPtr& pfSad, int32_t iCpuFlag) {
|
|
||||||
pfSad = WelsSampleSad8x8_c;
|
|
||||||
|
|
||||||
#ifdef X86_ASM
|
|
||||||
if (iCpuFlag & WELS_CPU_SSE2) {
|
|
||||||
pfSad = WelsSampleSad8x8_sse21;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_NEON
|
|
||||||
if (iCpuFlag & WELS_CPU_NEON) {
|
|
||||||
pfSad = WelsProcessingSampleSad8x8_neon;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
WELSVP_NAMESPACE_END
|
WELSVP_NAMESPACE_END
|
||||||
|
|
||||||
|
@ -44,29 +44,117 @@
|
|||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
#include "cpu.h"
|
||||||
#include "WelsFrameWork.h"
|
#include "WelsFrameWork.h"
|
||||||
#include "IWelsVP.h"
|
#include "IWelsVP.h"
|
||||||
#include "SceneChangeDetectionCommon.h"
|
#include "SceneChangeDetectionCommon.h"
|
||||||
|
|
||||||
|
#define HIGH_MOTION_BLOCK_THRESHOLD 320
|
||||||
|
#define SCENE_CHANGE_MOTION_RATIO 0.85f
|
||||||
|
|
||||||
WELSVP_NAMESPACE_BEGIN
|
WELSVP_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
class CSceneChangeDetectorVideo {
|
||||||
|
public:
|
||||||
|
CSceneChangeDetectorVideo(int32_t iCpuFlag) {
|
||||||
|
m_pfSad = WelsSampleSad8x8_c;
|
||||||
|
#ifdef X86_ASM
|
||||||
|
if (iCpuFlag & WELS_CPU_SSE2){
|
||||||
|
m_pfSad = WelsSampleSad8x8_sse21;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_NEON
|
||||||
|
if (iCpuFlag & WELS_CPU_NEON){
|
||||||
|
m_pfSad = WelsProcessingSampleSad8x8_neon;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
virtual ~CSceneChangeDetectorVideo() {
|
||||||
|
}
|
||||||
|
virtual int32_t operator () (uint8_t* pSrcY, int32_t iSrcStrideY, uint8_t* pRefY, int32_t iRefStrideY) {
|
||||||
|
return m_pfSad(pSrcY, iSrcStrideY, pRefY, iSrcStrideY);
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
SadFuncPtr m_pfSad;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
class CSceneChangeDetection : public IStrategy {
|
class CSceneChangeDetection : public IStrategy {
|
||||||
public:
|
public:
|
||||||
CSceneChangeDetection (int32_t iCpuFlag);
|
CSceneChangeDetection (EMethods eMethod, int32_t iCpuFlag): m_cDetector(iCpuFlag) {
|
||||||
~CSceneChangeDetection();
|
m_eMethod = eMethod;
|
||||||
|
WelsMemset (&m_sSceneChangeParam, 0, sizeof (m_sSceneChangeParam));
|
||||||
|
}
|
||||||
|
|
||||||
EResult Process (int32_t iType, SPixMap* pSrc, SPixMap* pRef);
|
~CSceneChangeDetection(){
|
||||||
EResult Get (int32_t iType, void* pParam);
|
}
|
||||||
|
|
||||||
|
EResult Process (int32_t iType, SPixMap* pSrcPixMap, SPixMap* pRefPixMap){
|
||||||
|
EResult eReturn = RET_INVALIDPARAM;
|
||||||
|
int32_t iWidth = pSrcPixMap->sRect.iRectWidth;
|
||||||
|
int32_t iHeight = pSrcPixMap->sRect.iRectHeight;
|
||||||
|
int32_t iBlock8x8Width = iWidth >> 3;
|
||||||
|
int32_t iBlock8x8Height = iHeight >> 3;
|
||||||
|
int32_t iBlock8x8Num = iBlock8x8Width * iBlock8x8Height;
|
||||||
|
int32_t iSceneChangeThreshold = WelsStaticCast (int32_t, SCENE_CHANGE_MOTION_RATIO * iBlock8x8Num + 0.5f + PESN);
|
||||||
|
int32_t iBlockSad = 0;
|
||||||
|
int32_t iMotionBlockNum = 0;
|
||||||
|
uint8_t* pRefY = NULL, *pCurY = NULL;
|
||||||
|
int32_t iRefStride = 0, iCurStride = 0;
|
||||||
|
int32_t iRefRowStride = 0, iCurRowStride = 0;
|
||||||
|
uint8_t* pRefTmp = NULL, *pCurTmp = NULL;
|
||||||
|
|
||||||
|
pRefY = (uint8_t*)pRefPixMap->pPixel[0];
|
||||||
|
pCurY = (uint8_t*)pSrcPixMap->pPixel[0];
|
||||||
|
|
||||||
|
iRefStride = pRefPixMap->iStride[0];
|
||||||
|
iCurStride = pSrcPixMap->iStride[0];
|
||||||
|
|
||||||
|
iRefRowStride = pRefPixMap->iStride[0] << 3;
|
||||||
|
iCurRowStride = pSrcPixMap->iStride[0] << 3;
|
||||||
|
|
||||||
|
m_sSceneChangeParam.eSceneChangeIdc = SIMILAR_SCENE;
|
||||||
|
|
||||||
|
for (int32_t j = 0; j < iBlock8x8Height; j ++) {
|
||||||
|
pRefTmp = pRefY;
|
||||||
|
pCurTmp = pCurY;
|
||||||
|
|
||||||
|
for (int32_t i = 0; i < iBlock8x8Width; i++) {
|
||||||
|
iBlockSad = m_cDetector(pRefTmp, iRefStride, pCurTmp, iCurStride);
|
||||||
|
iMotionBlockNum += (iBlockSad > HIGH_MOTION_BLOCK_THRESHOLD);
|
||||||
|
|
||||||
|
pRefTmp += 8;
|
||||||
|
pCurTmp += 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
pRefY += iRefRowStride;
|
||||||
|
pCurY += iCurRowStride;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iMotionBlockNum >= iSceneChangeThreshold) {
|
||||||
|
m_sSceneChangeParam.eSceneChangeIdc = LARGE_CHANGED_SCENE;
|
||||||
|
}
|
||||||
|
|
||||||
|
eReturn = RET_SUCCESS;
|
||||||
|
|
||||||
|
return eReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
EResult Get (int32_t iType, void* pParam) {
|
||||||
|
if (pParam == NULL) {
|
||||||
|
return RET_INVALIDPARAM;
|
||||||
|
}
|
||||||
|
* (SSceneChangeResult*)pParam = m_sSceneChangeParam;
|
||||||
|
return RET_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void InitSadFuncs (SadFuncPtr& pfSadFunc, int32_t iCpuFlag);
|
|
||||||
|
|
||||||
private:
|
|
||||||
SadFuncPtr m_pfSad;
|
|
||||||
int32_t m_iCpuFlag;
|
|
||||||
SSceneChangeResult m_sSceneChangeParam;
|
SSceneChangeResult m_sSceneChangeParam;
|
||||||
|
T m_cDetector;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
IStrategy * BuildSceneChangeDetection(EMethods eMethod, int32_t iCpuFlag);
|
||||||
|
|
||||||
WELSVP_NAMESPACE_END
|
WELSVP_NAMESPACE_END
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user