#include "Arith_DetectSmallObj.h" #include "Arith_ImgOperate.h" #include API_DetectSmallObj * API_DetectSmallObj::Create(SINT32 nWidth, SINT32 nHeight) { return new DetectSmallObj(nWidth,nHeight); } API_DetectSmallObj * API_DetectSmallObj::Create(SINT32 nWidth, SINT32 nHeight, CENTERRECT mmCenterRect) { return new DetectSmallObj(nWidth,nHeight,mmCenterRect); } void API_DetectSmallObj::Destroy(API_DetectSmallObj * obj) { delete obj; } //小目标检测模板1 SINT32 g_DST_nFilter_9_13[DST_KERNAL_SIZE_9_13] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; //小目标检测模板2 SINT32 g_DST_nFilter_5_9[DST_KERNAL_SIZE_5_9] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; DetectSmallObj::DetectSmallObj(SINT32 nWidth, SINT32 nHeight) { CENTERRECT mmCenterRect; mmCenterRect.cx = nWidth / 2; mmCenterRect.cy = nHeight / 2; mmCenterRect.w = nWidth; mmCenterRect.h = nHeight; mmCenterRect.s = nWidth * nHeight; DST_pBlkMaxPoint = NULL; DST_pBlkPtBeTargetFlag = NULL; DST_pBlkMaxPntFlag = NULL; m_FrmObjsCnt = 0; Init(nWidth, nHeight, mmCenterRect); } DetectSmallObj::DetectSmallObj(SINT32 nWidth, SINT32 nHeight, CENTERRECT mmCenterRect) { DST_pBlkMaxPoint = NULL; DST_pBlkPtBeTargetFlag = NULL; DST_pBlkMaxPntFlag = NULL; m_FrmObjsCnt = 0; Init(nWidth, nHeight, mmCenterRect); } DetectSmallObj::~DetectSmallObj() { DST_ReleaseMemory(); } bool DetectSmallObj::Init(SINT32 nWidth, SINT32 nHeight, CENTERRECT mmCenterRect) { DST_Initialization(nWidth,nHeight, mmCenterRect); m_FrmObjsCnt = 0; bEnableSmallDet = true; return true; } int DetectSmallObj::Detect(GD_VIDEO_FRAME_S img, SINT32 nWidth, SINT32 nHeight, CENTERRECT mmCenterRect, GLB_STATUS nStatus) { if (!bEnableSmallDet) { m_FrmObjsCnt = 0; return ERR_UNInit; } m_DST_stInput.crCenterRect = mmCenterRect; m_FrmObjsCnt = DST_DetectSmallTarget(img, nWidth, nHeight, nStatus); return m_FrmObjsCnt; } void DetectSmallObj::SetSearchBLK(DST_INPUT inputBLK) { m_DST_stInput = inputBLK; } void DetectSmallObj::SetCombinDist(SINT32 ndistance) { m_DST_stPara.nObjCombineDist = ndistance; } TARGET_OBJECT* DetectSmallObj::GetTargetArray() { return DST_Target; } SINT32 DetectSmallObj::GetTargetNum() { return m_FrmObjsCnt; } void DetectSmallObj::SetTargetNum(SINT32 num) { m_FrmObjsCnt = num; } DST_PARAMETERS* DetectSmallObj::GetDstParm() { return &m_DST_stPara; } void DetectSmallObj::setDstParm(Param_SkyDetect* param) { m_DST_stPara.fgdk = param->fSmallDetectGDK; m_DST_stPara.nDetectGrayType = param->nDetectGrayType; } BBOOL DetectSmallObj::getDstDetState() { return bEnableSmallDet; } void DetectSmallObj::setDstDetState(BBOOL bEnableState) { bEnableSmallDet = bEnableState; } //////////////////////////////////////////////////////////////////////////////// //--函数定义 //////////////////////////////////////////////////////////////////////////////// /********************************************************** * 函数名称:DST_DetectSmallTarget() * 功能描述:基于分块极值的小目标检测 * 输入参数:UINT16 *pSrc -- 原始图像 * SINT32 nWidth -- 图像宽度 * SINT32 nHeight -- 图像高度 * 输出参数:无 * 返 回 值:小目标检测个数 * 调用关系: * 其它说明:无 **********************************************************/ SINT32 DetectSmallObj::DST_DetectSmallTarget(GD_VIDEO_FRAME_S img, SINT32 nWidth, SINT32 nHeight, GLB_STATUS nStatus) { //指向DSP数据空间 POINT16S* pBlkMaxPnt = (POINT16S*)DST_pBlkMaxPoint; TARGET_OBJECT* ptTargetArray = (TARGET_OBJECT*)DST_Target; SINT32* pBlkPtBeTargetFlag = (SINT32*)DST_pBlkPtBeTargetFlag; BYTE8* pbBlkMaxPntFlag = (BYTE8*)DST_pBlkMaxPntFlag; //20161130,极值点最大/最小标志 // 未初始化报错 if (!m_DST_bInitialize) { return ERR_UNInit; } //局部变量 SINT32 nObjsCnt = 0; //+++++++++++++++++++++++++++++++++++++++++++++++++++++++ //初始化算法输出结果 DST_CleanUpFrameDetectOutput(); //+++++++++++++++++++++++++++++++++++++++++++++++++++++++ //获取检测区域边界 m_DST_stInput.mmCenterRect.minX = m_DST_stInput.crCenterRect.cx - (m_DST_stInput.crCenterRect.w >> 1); m_DST_stInput.mmCenterRect.minY = m_DST_stInput.crCenterRect.cy - (m_DST_stInput.crCenterRect.h >> 1); m_DST_stInput.mmCenterRect.maxX = m_DST_stInput.crCenterRect.cx + (m_DST_stInput.crCenterRect.w >> 1); m_DST_stInput.mmCenterRect.maxY = m_DST_stInput.crCenterRect.cy + (m_DST_stInput.crCenterRect.h >> 1); //限制检测区域边界 m_DST_stInput.mmCenterRect.minX = MAX(0, MIN(m_DST_stInput.mmCenterRect.minX, nWidth - 1)); m_DST_stInput.mmCenterRect.maxX = MAX(0, MIN(m_DST_stInput.mmCenterRect.maxX, nWidth - 1)); m_DST_stInput.mmCenterRect.minY = MAX(0, MIN(m_DST_stInput.mmCenterRect.minY, nHeight - 1)); m_DST_stInput.mmCenterRect.maxY = MAX(0, MIN(m_DST_stInput.mmCenterRect.maxY, nHeight - 1)); //更新检测区域中心矩形 m_DST_stInput.crCenterRect.cx = (m_DST_stInput.mmCenterRect.minX + m_DST_stInput.mmCenterRect.maxX) >> 1; m_DST_stInput.crCenterRect.cy = (m_DST_stInput.mmCenterRect.minY + m_DST_stInput.mmCenterRect.maxY) >> 1; m_DST_stInput.crCenterRect.h = m_DST_stInput.mmCenterRect.maxY - m_DST_stInput.mmCenterRect.minY + 1; m_DST_stInput.crCenterRect.w = m_DST_stInput.mmCenterRect.maxX - m_DST_stInput.mmCenterRect.minX + 1; m_DST_stInput.crCenterRect.s = (SINT32)(m_DST_stInput.crCenterRect.h * m_DST_stInput.crCenterRect.w); // 分块方案不存在,返回0 if(m_DST_stInput.nBlkWidth == 0 || m_DST_stInput.nBlkHeight == 0) { return 0; } //调整分块大小和分块区域 m_DST_stInput.nBlkNumW = m_DST_stInput.crCenterRect.w / m_DST_stInput.nBlkWidth; m_DST_stInput.nBlkNumH = m_DST_stInput.crCenterRect.h / m_DST_stInput.nBlkHeight; m_DST_stInput.nBlkNum = m_DST_stInput.nBlkNumW * m_DST_stInput.nBlkNumH; if ((m_DST_stInput.nBlkNumW <= 0) || (m_DST_stInput.nBlkNumH <= 0)) { return 0; } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++ //图像分块并返回块极值点 if (nStatus == GLB_STATUS_TRACK) { DST_FindExtremum(img, nWidth, nHeight, pBlkMaxPnt, pbBlkMaxPntFlag, m_DST_stInput.mmCenterRect.minY, m_DST_stInput.mmCenterRect.minX, m_DST_stInput.nBlkWidth, m_DST_stInput.nBlkHeight, m_DST_stInput.nBlkNumW, m_DST_stInput.nBlkNumH); } else {// 搜索阶段螺旋输出极值点 DST_FindExtremumSpiral(img, nWidth, nHeight, pBlkMaxPnt, pbBlkMaxPntFlag, m_DST_stInput.mmCenterRect.minY, m_DST_stInput.mmCenterRect.minX, m_DST_stInput.nBlkWidth, m_DST_stInput.nBlkHeight, m_DST_stInput.nBlkNumW, m_DST_stInput.nBlkNumH); } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++ //判断极值点是否为目标 // wcw04046 面目标空间留出来 nObjsCnt = DST_DetectFrameTarget(img, nWidth, nHeight, ptTargetArray, DST_MAX_NUM, pBlkMaxPnt, m_DST_stInput.nBlkNumW, m_DST_stInput.nBlkNumH, pBlkPtBeTargetFlag); // 显式输出目标个数 m_DST_stOutput.nFrmObjsCnt = nObjsCnt; return nObjsCnt; } /********************************************************** * 函数名称:DST_Initialization() * 功能描述:算法初始化 * 输入参数:无 * 输出参数:无 * 返 回 值:无 * 调用关系:无 * 其它说明:无 **********************************************************/ void DetectSmallObj::DST_Initialization(SINT32 nWidth, SINT32 nHeight, CENTERRECT mmCenterRect) { //+++++++++++++++++++++++++++++++++++++++++++++++++++++++ //初始化算法输入 //搜索区域 m_DST_stInput.crCenterRect.cx = (SINT16)(mmCenterRect.cx); m_DST_stInput.crCenterRect.cy = (SINT16)(mmCenterRect.cy); m_DST_stInput.crCenterRect.w = mmCenterRect.w; m_DST_stInput.crCenterRect.h = mmCenterRect.h; m_DST_stInput.crCenterRect.s = m_DST_stInput.crCenterRect.w * m_DST_stInput.crCenterRect.h; m_DST_stInput.mmCenterRect.minX = m_DST_stInput.crCenterRect.cx - (m_DST_stInput.crCenterRect.w >> 1); m_DST_stInput.mmCenterRect.minY = m_DST_stInput.crCenterRect.cy - (m_DST_stInput.crCenterRect.h >> 1); m_DST_stInput.mmCenterRect.maxX = m_DST_stInput.crCenterRect.cx + (m_DST_stInput.crCenterRect.w >> 1); m_DST_stInput.mmCenterRect.maxY = m_DST_stInput.crCenterRect.cy + (m_DST_stInput.crCenterRect.h >> 1); //弱小目标强制搜索 m_DST_stInput.crnSemiSrRect.cx = m_DST_stInput.crCenterRect.cx; m_DST_stInput.crnSemiSrRect.cy = m_DST_stInput.crCenterRect.cy; m_DST_stInput.crnSemiSrRect.w = DST_DIMOBJ_SR_RGN_W; m_DST_stInput.crnSemiSrRect.h = DST_DIMOBJ_SR_RGN_H; m_DST_stInput.crnSemiSrRect.s = m_DST_stInput.crnSemiSrRect.w * m_DST_stInput.crnSemiSrRect.h; m_DST_stInput.mmnSemiSrRect.minX = m_DST_stInput.crnSemiSrRect.cx - (m_DST_stInput.crnSemiSrRect.w >> 1); m_DST_stInput.mmnSemiSrRect.minY = m_DST_stInput.crnSemiSrRect.cy - (m_DST_stInput.crnSemiSrRect.h >> 1); m_DST_stInput.mmnSemiSrRect.maxX = m_DST_stInput.crnSemiSrRect.cx + (m_DST_stInput.crnSemiSrRect.w >> 1); m_DST_stInput.mmnSemiSrRect.maxY = m_DST_stInput.crnSemiSrRect.cy + (m_DST_stInput.crnSemiSrRect.h >> 1); //分块大小 m_DST_stInput.nBlkHeight = 16; m_DST_stInput.nBlkWidth = 16; //搜索区域内分块个数 m_DST_stInput.nBlkNumH = m_DST_stInput.crCenterRect.w / m_DST_stInput.nBlkWidth; m_DST_stInput.nBlkNumW = m_DST_stInput.crCenterRect.h / m_DST_stInput.nBlkHeight; m_DST_stInput.nBlkNum = m_DST_stInput.nBlkNumH * m_DST_stInput.nBlkNumW; //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //初始化算法参数 //算法状态控制(上位机软件界面可调) //小目标检测参数(上位机软件界面可调) m_DST_stPara.nObjCombineDist = 9; m_DST_stPara.fgdk = DST_OBJ_SNR_MIN; m_DST_stPara.fKernalBGStdMin = DST_Bm_STD_LIMIT_MIN; m_DST_stPara.fKernalBGStdMax = DST_Bm_STD_LIMIT_MAX; m_DST_stPara.nObjSizeMin = DST_OBJ_SIZE_MIN; m_DST_stPara.nObjSizeMax = DST_KERNAL_SIZE_TG * DST_KERNAL_SIZE_TG; m_DST_stPara.nObjWHRatioMethod = DST_OBJ_WHRATIO_LINEWH; m_DST_stPara.fObjWHRatioMin = 0.2f; m_DST_stPara.fObjWHRatioMax = 5.0f; m_DST_stPara.fObjRectRatioMin = 0.2f; m_DST_stPara.nBGObjNumThres = 2; m_DST_stPara.nBTGrayMinThres = 10; m_DST_stPara.bDimDetecting = false; m_DST_stPara.bEnableDimDetect = false; m_DST_stPara.bEnableSecDetect = false; m_DST_stPara.bSecDetecting = FALSE; //小目标检测去虚警开关(上位机软件界面可调) m_DST_stPara.bUseDeFA_VarMin = 1; m_DST_stPara.bUseDeFA_VarMax = 0; m_DST_stPara.bUseDeFA_Size = 1; m_DST_stPara.bUseDeFA_WHRatio = 0;// m_DST_stPara.bUseDeFA_RectRatio = 0; m_DST_stPara.bUseDeFA_BGFACnt = 0; m_DST_stPara.bUseDeFA_BTGrayMin = 1; m_DST_stPara.bUseDeFA_CenFlag = 0; m_DST_stPara.bUseDeFA_XYPrj = 0; //目标检测类型 m_DST_stPara.nDetectGrayType = GLB_OBJ_GRAY_BRIGHT; // 模板参数 m_DST_stPara.pnFilter = g_DST_nFilter_9_13; m_DST_stPara.nFilterBGW = DST_KERNAL_SIZE_Bm_13; m_DST_stPara.nFilterTGW = DST_KERNAL_SIZE_Tm_9; // 申请内存 DST_MallocMemory(nWidth, nHeight, mmCenterRect); // 初始化算法输出结果 DST_CleanUpFrameDetectOutput(); // 初始化弱小目标检测结果 DST_CleanUpFrameDimDetectOutput(); m_DST_bInitialize = true; } /********************************************************** * 函数名称:DST_CleanUpFrameDetectOutput() * 功能描述:初始化单帧检测算法输出结果 * 输入参数:无 * 输出参数:无 * 返 回 值:无 * 调用关系:无 * 其它说明:无 **********************************************************/ void DetectSmallObj::DST_CleanUpFrameDetectOutput(void) { //小目标检测结果 m_DST_stOutput.nFrmObjsCnt = 0; m_DST_stOutput.nDimFrmsCnt = 0; //初始化数据空间 POINT16S* pBlkMaxPnt = (POINT16S*)DST_pBlkMaxPoint; TARGET_OBJECT* ptTargetArray = (TARGET_OBJECT*)DST_Target; SINT32* pBlkPtBeTargetFlag = (SINT32*)DST_pBlkPtBeTargetFlag; BYTE8* pBlkMaxPntFlag = (BYTE8*)DST_pBlkMaxPntFlag; memset(pBlkMaxPnt, 0, m_DST_stInput.nBlkNum * sizeof(POINT16S) * 2); memset(ptTargetArray, 0, DST_MAX_NUM * sizeof(TARGET_OBJECT)); memset(pBlkPtBeTargetFlag, 0, m_DST_stInput.nBlkNum * sizeof(SINT32) * 2); memset(pBlkMaxPntFlag, 0, m_DST_stInput.nBlkNum * sizeof(BYTE8) * 2); } /********************************************************** * 函数名称:DST_CleanUpFrameDimDetectOutput() * 功能描述:初始化单帧弱小目标检测算法输出结果 * 输入参数:无 * 输出参数:无 * 返 回 值:无 * 调用关系:无 * 其它说明:无 **********************************************************/ void DetectSmallObj::DST_CleanUpFrameDimDetectOutput(void) { //弱小目标强制搜索 if (m_DST_stOutput.nDimFrmsCnt <= 0) { m_DST_stOutput.pxSrImg = (UINT16*)DST_pxDimSrImg; memset(m_DST_stOutput.pxSrImg, 0, DST_DIMOBJ_SR_RGN_S * sizeof(UINT16)); } m_DST_stOutput.snDimSrImgSize.w = m_DST_stInput.crnSemiSrRect.w; m_DST_stOutput.snDimSrImgSize.h = m_DST_stInput.crnSemiSrRect.h; m_DST_stOutput.snDimSrImgSize.s = m_DST_stOutput.snDimSrImgSize.w * m_DST_stOutput.snDimSrImgSize.h; m_DST_stOutput.nDimPriorObjId = -1; m_DST_stOutput.nFrmDimObjsCnt = 0; m_DST_stOutput.nDimSmpScale = 1; //清空弱小目标数组 TARGET_OBJECT* ptDimTarget = (TARGET_OBJECT*)DST_DimTarget; memset(ptDimTarget, 0, DST_DIMOBJ_BLK_NUM * sizeof(TARGET_OBJECT)); //清空弱小目标检测极值点 POINT16S* pDimBlkMaxPnt = (POINT16S*)DST_pDimBlkMaxPoint; memset(pDimBlkMaxPnt, 0, DST_DIMOBJ_BLK_NUM * sizeof(POINT16S)); //搜索区域双边滤波 SINT16* pDimBFHighImg = (SINT16*)DST_pDimBFHighImg; UINT16* pDimBFLowImg = (UINT16*)DST_pDimBFLowImg; memset(pDimBFHighImg, 0, DST_DIMOBJ_SR_RGN_S * sizeof(SINT16)); memset(pDimBFLowImg, 0, DST_DIMOBJ_SR_RGN_S * sizeof(UINT16)); } /********************************************************** * 函数名称:DST_FindBlkExtremum() * 功能描述:查找块内极值点 * 输入参数:UINT16 *pFrame -- 原始图像 * SINT32 nWidth -- 图像宽度 * SINT32 nHeight -- 图像高度 * SINT32 pBlkStart -- 该分块在原始图像上的起始坐标 * SINT32 nBlkWidth -- 分块宽度 * SINT32 nBlkHeight -- 分块高度 * 输出参数:无 * 返 回 值:POINT16S pPnt -- 块内极值点坐标 * 调用关系:无 * 其它说明:MSSu, 20111115: 函数修改,增加查找块内极小值的功能, * 对于每个块的极大值和极小值,选两者中与块均值偏差较大的作为返回点。 **********************************************************/ POINT16S DetectSmallObj::DST_FindBlkExtremum(GD_VIDEO_FRAME_S img, SINT32 nWidth, SINT32 nHeight, SINT32 pBlkStart, SINT32 nBlkWidth, SINT32 nBlkHeight, BYTE8* pbMaxFlag,POINT16S * pSecondMax) { SINT32 i, j; SINT32 nLen = nBlkWidth * nBlkHeight; UINT16 pGray = 0; UINT16 pMax = 0; UINT16 pMax2 = 0;//次极大值 UINT16 pMin = 65535; UINT16 pMin2 = 65535;//次极小值 SINT32 pMean = 0; POINT16S pPntMax = { 0 }; POINT16S pPntMax2 = {0};//次极大值点坐标 POINT16S pPntMin = { 0 }; POINT16S pPnt = { 0 }; SINT32 nMaxIndex = 0; SINT32 nMinIndex = 0; SINT32 nMaxIndex2 = 0; SINT32 nMinIndex2 = 0; SINT32 nIndex = 0; FLOAT32 fPntMaxBkgMean = 0.0; //20170405,极大值点9*13模板邻域均值 FLOAT32 fPntMinBkgMean = 0.0; //20170405,极小值点9*13模板邻域均值 SINT32 nMaxI = 0; SINT32 nMaxJ = 0; UINT16 pDiffThres = m_DST_stPara.nBTGrayMinThres; //查找块内极值点 for (i = 0; i < nBlkHeight; i++) { for (j = 0; j < nBlkWidth; j++) { //获取块内每个像素点灰度 nIndex = pBlkStart + j; if (GD_PIXEL_FORMAT_GRAY_Y8 == img.enPixelFormat) { pGray = ((UBYTE8*)img.u64VirAddr[0])[nIndex]; } else { pGray = ((UINT16*)img.u64VirAddr[0])[nIndex]; } int x = nIndex % nWidth; int y = nIndex / nWidth; //if(x == 275 && y == 327) //{ // int a = 0; //} //查找极大值 if (pGray >= pMax) { pMax = pGray; nMaxIndex = nIndex; nMaxI = i; nMaxJ = j; } //查找极小值 if (pGray <= pMin) { pMin = pGray; nMinIndex = nIndex; } //统计块内灰度和 pMean += pGray; } //更新下一行的起始坐标 pBlkStart += nWidth; } pBlkStart -= nBlkHeight * nWidth; //查找块内次极值点(除去极大值周边) for (i = 0; i < nBlkHeight; i++) { for (j = 0; j < nBlkWidth; j++) { //获取块内每个像素点灰度 nIndex = pBlkStart + j; if (GD_PIXEL_FORMAT_GRAY_Y8 == img.enPixelFormat) { pGray = ((UBYTE8*)img.u64VirAddr[0])[nIndex]; } else { pGray = ((UINT16*)img.u64VirAddr[0])[nIndex]; } int x = nIndex % nWidth; int y = nIndex / nWidth; //if(x == 275 && y == 327) //{ // int a = 0; //} ////跳过极大值区域 // if (nIndex > (nMaxIndex - nWidth * g_DST_stPara.nObjCombineDist - nWidth / 2) && // nIndex < (nMaxIndex + nWidth * g_DST_stPara.nObjCombineDist + nWidth / 2)) //跳过极大值区域 //if (nIndex >= (nMaxIndex - nWidth * g_DST_stPara.nObjCombineDist - g_DST_stPara.nObjCombineDist / 2) && // nIndex <= (nMaxIndex + nWidth * g_DST_stPara.nObjCombineDist + g_DST_stPara.nObjCombineDist / 2)) // //跳过极大值区域,寻找次极大值 if( (i - nMaxI ) * (i - nMaxI ) + (j - nMaxJ) * (j - nMaxJ ) pMax2) { pMax2 = pGray; nMaxIndex2 = nIndex; } } //更新下一行的其实坐标 pBlkStart += nWidth; } //计算块内灰度均值,抛掉极大值 if (nLen <= 1) { pMean = pMean; } else if (nLen == 2) { pMean /= 2; } else { //pMean -= pMax; //pMean /= (nLen - 1); pMean -= (pMax + pMin); pMean /= (nLen - 2); } //抛掉与块均值灰度差异较小的点 //if (ABS(pMax - pMean) < pDiffThres) //{ // pPnt.x = DST_BLK_MAX_PNT_DELETE_FLAG; // pPnt.y = DST_BLK_MAX_PNT_DELETE_FLAG; //} //else //MSSu, 20160122: 抛掉平坦块 if ((pMax - pMin) < 2) { pPnt.x = DST_BLK_MAX_PNT_DELETE_FLAG; pPnt.y = DST_BLK_MAX_PNT_DELETE_FLAG; return pPnt; } // 极值点坐标 pPntMax.x = nMaxIndex % nWidth; pPntMax.y = nMaxIndex / nWidth; pPntMin.x = nMinIndex % nWidth; pPntMin.y = nMinIndex / nWidth; // 次极值点坐标 pPntMax2.x = nMaxIndex2 % nWidth; pPntMax2.y = nMaxIndex2 / nWidth; if (GLB_OBJ_GRAY_DARK == m_DST_stPara.nDetectGrayType) { pPnt = pPntMin; *pbMaxFlag = DST_BLK_MIN_PNT; } else if (GLB_OBJ_GRAY_BRIGHT == m_DST_stPara.nDetectGrayType) { pPnt = pPntMax; *pbMaxFlag = DST_BLK_MAX_PNT; if(pPntMax.x == pPntMax2.x && pPntMax.y == pPntMax2.y) { pSecondMax->x = -1; pSecondMax->y = -1; } else { *pSecondMax = pPntMax2; } } else if (GLB_OBJ_GRAY_ALL == m_DST_stPara.nDetectGrayType) { //20170405,分别计算极大值点与极小值点的邻域均值//原先做法是直接与分块均值比较 fPntMaxBkgMean = DST_CalObjBkgMean_UINT16(img, nWidth, nHeight, pPntMax); fPntMinBkgMean = DST_CalObjBkgMean_UINT16(img, nWidth, nHeight, pPntMin); //20170405,若邻域范围超出图像边界即均值为负,则直接取分块均值 if (fPntMaxBkgMean < 0 || fPntMinBkgMean < 0) { fPntMaxBkgMean = (FLOAT32)pMean; fPntMinBkgMean = (FLOAT32)pMean; } //20170810,wsa,抛掉与块均值灰度差异较小的点 if (ABS(pMax - (UINT16)fPntMaxBkgMean) < pDiffThres && ABS(pMin - (UINT16)fPntMinBkgMean) < pDiffThres) { pPnt.x = DST_BLK_MAX_PNT_DELETE_FLAG; pPnt.y = DST_BLK_MAX_PNT_DELETE_FLAG; return pPnt; } if (ABS(pMax - (UINT16)fPntMaxBkgMean) >= ABS(pMin - (UINT16)fPntMinBkgMean)) { pPnt = pPntMax; *pbMaxFlag = DST_BLK_MAX_PNT; } else { pPnt = pPntMin; *pbMaxFlag = DST_BLK_MIN_PNT; } } return pPnt; } void DetectSmallObj::DST_MallocMemory(SINT32 nWidth, SINT32 nHeight, CENTERRECT mmCenterRect) { DST_ReleaseMemory(); SINT32 DST_BLK_NUM = m_DST_stInput.nBlkNum; DST_pBlkMaxPoint = new POINT16S[DST_BLK_NUM * 2];//同时处理次极值点 DST_pBlkPtBeTargetFlag = new SINT32[DST_BLK_NUM * 2]; DST_pBlkMaxPntFlag = new BYTE8[DST_BLK_NUM * 2]; } void DetectSmallObj::DST_ReleaseMemory() { if (DST_pBlkMaxPoint) { delete[] DST_pBlkMaxPoint; DST_pBlkMaxPoint = NULL; } if (DST_pBlkPtBeTargetFlag) { delete[] DST_pBlkPtBeTargetFlag; DST_pBlkPtBeTargetFlag = NULL; } if (DST_pBlkMaxPntFlag) { delete[] DST_pBlkMaxPntFlag; DST_pBlkMaxPntFlag = NULL; } } /********************************************************** * 函数名称:DST_FindExtremum() * 功能描述:查找图像中的极值点 * 输入参数:UINT16 *pFrame -- 原始图像 * SINT32 nWidth -- 图像宽度 * SINT32 nHeight -- 图像高度 * SINT32 nSearchAreaT -- 检测区域左上角Y坐标 * SINT32 nSearchAreaL -- 检测区域左上角X坐标 * SINT32 nBlkWidth -- 分块宽度 * SINT32 nBlkHeight -- 分块高度 * SINT32 nBlkNumW -- 行方向分块个数 * SINT32 nBlkNumH -- 列方向分块个数 * 输出参数:POINT16S *pBlkMaxPnt-- 指向分块极值点坐标存储空间地址,BYTE8 *pbBlkMaxPntFlag --极值点类型标记数组 * 返 回 值:无 * 调用关系:DST_FindBlkExtremum(), DST_MergeBlkMaxPoint() * 其它说明:无 **********************************************************/ void DetectSmallObj::DST_FindExtremum(GD_VIDEO_FRAME_S img, SINT32 nWidth, SINT32 nHeight, POINT16S* pBlkMaxPnt, BYTE8* pbBlkMaxPntFlag, SINT32 nSearchAreaT, SINT32 nSearchAreaL, SINT32 nBlkWidth, SINT32 nBlkHeight, SINT32 nBlkNumW, SINT32 nBlkNumH) { SINT32 i, j; SINT32 pCenterStart, pBlkStart; SINT32 nRowBlkLine; SINT32 nRowBlkHSkip; SINT32 nLine, nIndex; SINT32 nBlkCnt; BYTE8 bMaxPntFalg = DST_BLK_MAX_PNT; //20161130,标记极大/极小 POINT16S pBlkSecondMaxPnt = {0};//次极大值 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++ pCenterStart = nSearchAreaT * nWidth + nSearchAreaL; nRowBlkLine = pCenterStart; nRowBlkHSkip = nBlkHeight * nWidth; pBlkStart = nRowBlkLine; nLine = 0; nIndex = 0; nBlkCnt = 0; for (i = 0; i < nBlkNumH; i++) //DSP移植优化:主频432Mhz 2.4ms { for (j = 0; j < nBlkNumW; j++) { //计算当前块的坐标 nIndex = 2 * (nLine + j); //查找块内灰度极大值 pBlkMaxPnt[nIndex] = DST_FindBlkExtremum(img, nWidth, nHeight, pBlkStart, nBlkWidth, nBlkHeight, &bMaxPntFalg, &pBlkSecondMaxPnt); // 次极值点 pBlkMaxPnt[nIndex + 1] = pBlkSecondMaxPnt; //20161130,标记极大/极小 pbBlkMaxPntFlag[nIndex] = bMaxPntFalg; //更新下一个块的起始坐标 pBlkStart += nBlkWidth; //防止出错 nBlkCnt++; if (nBlkCnt >= m_DST_stInput.nBlkNum) { break; } } //更新下一行块的行起始坐标 nRowBlkLine += nRowBlkHSkip; pBlkStart = nRowBlkLine; //更新下一行块的起始坐标 nLine += nBlkNumW; //防止出错 if (nBlkCnt >= m_DST_stInput.nBlkNum) { break; } } //+++++++++++++++++++++++++++++++++++++++++++++++++ //合并临近的极值点 //MSSu, 20111115: 若m_DST_nDectectMinPnt==TRUE,则为合并临近的极大或极小值 DST_MergeBlkMaxPoint(img, nWidth, nHeight, pBlkMaxPnt, nBlkNumH, nBlkNumW, m_DST_stPara.nObjCombineDist, pbBlkMaxPntFlag); } /********************************************************** * 函数名称:DST_FindExtremum() * 功能描述:螺旋查找图像中的极值点 * 输入参数:UINT16 *pFrame -- 原始图像 * SINT32 nWidth -- 图像宽度 * SINT32 nHeight -- 图像高度 * SINT32 nSearchAreaT -- 检测区域左上角Y坐标 * SINT32 nSearchAreaL -- 检测区域左上角X坐标 * SINT32 nBlkWidth -- 分块宽度 * SINT32 nBlkHeight -- 分块高度 * SINT32 nBlkNumW -- 行方向分块个数 * SINT32 nBlkNumH -- 列方向分块个数 * 输出参数:POINT16S *pBlkMaxPnt-- 指向分块极值点坐标存储空间地址,BYTE8 *pbBlkMaxPntFlag --极值点类型标记数组 * 返 回 值:无 * 调用关系:DST_FindBlkExtremum(), DST_MergeBlkMaxPoint() * 其它说明:无 **********************************************************/ void DetectSmallObj::DST_FindExtremumSpiral(GD_VIDEO_FRAME_S img, SINT32 nWidth, SINT32 nHeight, POINT16S* pBlkMaxPnt, BYTE8* pbBlkMaxPntFlag, SINT32 nSearchAreaT, SINT32 nSearchAreaL, SINT32 nBlkWidth, SINT32 nBlkHeight, SINT32 nBlkNumW, SINT32 nBlkNumH) { SINT32 i, j; SINT32 pCenterStart, pBlkStart; SINT32 nRowBlkLine; SINT32 nRowBlkHSkip; SINT32 nLine, nIndex; SINT32 nBlkCnt; BYTE8 bMaxPntFalg = DST_BLK_MAX_PNT; //20161130,标记极大/极小 POINT16S pBlkSecondMaxPnt = { 0 };//次极大值 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++ nRowBlkLine = nSearchAreaT * nWidth + nSearchAreaL; nRowBlkHSkip = nBlkHeight * nWidth; pBlkStart = nRowBlkLine; nLine = 0; nIndex = 0; nBlkCnt = 0; SINT32 r0 = nBlkNumH / 2; SINT32 c0 = nBlkNumW / 2; SINT32 R = nBlkNumH; SINT32 C = nBlkNumW; std::vector> around = { { 0, 1 },{ 1, 0 },{ 0, -1 },{ -1, 0 } }; //顺时针方向 SINT32 x = r0, y = c0, num = 1, dir = 0; //{x, y}为当前位置,num为当前查找的数字,dir为当前的方向 SINT32 Left = c0 - 1, Right = c0 + 1, Upper = r0 - 1, Bottom = r0 + 1; //四个方向的边界 while (num <= R * C) { if (x >= 0 && x < R && y >= 0 && y < C) { //{x, y}位置在矩阵中 //printf("x=%d, y=%d\n", x, y); //计算当前块的坐标 nIndex = 2 * nBlkCnt; //查找块内灰度极大值 POINT16S point = DST_FindBlkExtremum(img, nWidth, nHeight, pBlkStart, nBlkWidth, nBlkHeight, &bMaxPntFalg, &pBlkSecondMaxPnt); //if (point.x > 0 && point.y > 0) { pBlkMaxPnt[nIndex] = point; // 次极值点 pBlkMaxPnt[nIndex + 1] = pBlkSecondMaxPnt; //20161130,标记极大/极小 pbBlkMaxPntFlag[nIndex] = bMaxPntFalg; //更新下一个块的起始坐标 pBlkStart = nBlkWidth * y + x * nRowBlkHSkip; //防止出错 nBlkCnt++; if (nBlkCnt >= m_DST_stInput.nBlkNum) { break; } } num += 1; } if (dir == 0 && y == Right) { //向右到右边界 dir += 1; //调转方向向下 Right += 1; //右边界右移 } else if (dir == 1 && x == Bottom) { //向下到底边界 dir += 1; Bottom += 1; //底边界下移 } else if (dir == 2 && y == Left) { //向左到左边界 dir += 1; Left--; //左边界左移 } else if (dir == 3 && x == Upper) { //向上到上边界 dir = 0; Upper--; //上边界上移 } x += around[dir].first; //下一个节点 y += around[dir].second; } //for (i = 0; i < nBlkNumH; i++) //DSP移植优化:主频432Mhz 2.4ms //{ // for (j = 0; j < nBlkNumW; j++) // { // //计算当前块的坐标 // nIndex = 2 * (nBlkNumW * i + j); // //查找块内灰度极大值 // pBlkMaxPnt[nIndex] = DST_FindBlkExtremum(img, nWidth, nHeight, // pBlkStart, nBlkWidth, nBlkHeight, &bMaxPntFalg, &pBlkSecondMaxPnt); // // 次极值点 // pBlkMaxPnt[nIndex + 1] = pBlkSecondMaxPnt; // //20161130,标记极大/极小 // pbBlkMaxPntFlag[nIndex] = bMaxPntFalg; // //更新下一个块的起始坐标 // pBlkStart = nBlkWidth * j + i * nRowBlkHSkip; // //防止出错 // nBlkCnt++; // if (nBlkCnt >= m_DST_stInput.nBlkNum) // { // break; // } // } // ////更新下一行块的起始坐标 // //nLine += nBlkNumW; // ////防止出错 // //if (nBlkCnt >= m_DST_stInput.nBlkNum) // //{ // // break; // //} //} //+++++++++++++++++++++++++++++++++++++++++++++++++ //合并临近的极值点 //MSSu, 20111115: 若m_DST_nDectectMinPnt==TRUE,则为合并临近的极大或极小值 DST_MergeBlkMaxPoint(img, nWidth, nHeight, pBlkMaxPnt, nBlkNumH, nBlkNumW, m_DST_stPara.nObjCombineDist, pbBlkMaxPntFlag); } /********************************************************** * 函数名称:DST_MergeBlkMaxPoint() * 功能描述:合并临近的极值点 * 输入参数:UINT16 *pFrame -- 输入图像 * SINT32 nWidth -- 图像宽度 * SINT32 nHeight -- 图像高度 * POINT16S *pBlkPnt -- 分块极大值点坐标数组 * SINT32 nPntNumH -- 在列方向上的分块数 * SINT32 nPntNumW -- 在行方向上的分块数 * SINT32 nDist -- 相邻极值点合并的阈值 * 输出参数:无 * 返 回 值:无 * 调用关系:无 * 其它说明:MSSu, 20150608: 增加亮目标、暗目标、亮+暗目标3种情况处理。 **********************************************************/ void DetectSmallObj::DST_MergeBlkMaxPoint(GD_VIDEO_FRAME_S img, SINT32 nWidth, SINT32 nHeight, POINT16S* pBlkPnt, SINT32 nPntNumH, SINT32 nPntNumW, SINT32 nDist, BYTE8* pbBlkMaxPntFlag) { static SINT32 nX[8] = { -1, 0, 1, -1, 1, -1, 0, 1 }; static SINT32 nY[8] = { -1, -1, -1, 0, 0, 1, 1, 1 }; SINT32 i, k; POINT16S* pPntA, * pPntB; UINT16 pPntAValue, pPntBValue; SINT32 nDistAB; SINT32 nDistThres; SINT32 nNearIndex; SINT32 nPntNum; SINT32 nMeanAB, nCntAB; //参数计算 nDistThres = nDist * nDist; nPntNum = nPntNumH * nPntNumW * 2; nMeanAB = 0; nCntAB = 0; for (i = 0; i < nPntNum; i++) { //获取当前极值点A的坐标 pPntA = &pBlkPnt[i]; //若当前极值点A已被删除,则跳过该点,不进行后续处理 if (DST_BLK_MAX_PNT_DELETE_FLAG == pPntA->x && DST_BLK_MAX_PNT_DELETE_FLAG == pPntA->y) { continue; } //遍历周围8个极值点 for (k = 0; k < 8; k++) { for (int s = 0; s < 2; s++) { //计算临近点B下标 nNearIndex = i + 2 *(nY[k] * nPntNumW + nX[k]) + s; //防止临近点越界 if ((nNearIndex < 0) || (nNearIndex >= nPntNum) || (nNearIndex == i)) //MSSu, 20160409: 宽方向仅1个分块时,邻域点会计算回A点本身,导致A点被删除 { continue; } //// A点可能会在合并中被删掉,需要再判断一次,一个存在很久的bug? by wcw04046 @ 2020/02/20 if (DST_BLK_MAX_PNT_DELETE_FLAG == pPntA->x && DST_BLK_MAX_PNT_DELETE_FLAG == pPntA->y) { continue; } //获取临近点B的坐标 pPntB = &pBlkPnt[nNearIndex]; //若临近点B已被删除,则跳过该点,不进行后续处理 if (DST_BLK_MAX_PNT_DELETE_FLAG == pPntB->x && DST_BLK_MAX_PNT_DELETE_FLAG == pPntB->y) { continue; } //计算A、B点距离 nDistAB = (pPntA->x - pPntB->x) * (pPntA->x - pPntB->x); nDistAB += (pPntA->y - pPntB->y) * (pPntA->y - pPntB->y); //若A、B点距离小于阈值,则合并 //MSSu, 20111115: 若m_DST_nDectectMinPnt==TRUE,则两个相邻的极值点中,优先选择极大值点 if (nDistAB < nDistThres && nDistAB != 0) { //获取A、B点的亮度 //pPntAValue = pFrame[pPntA->y * nWidth + pPntA->x]; //pPntBValue = pFrame[pPntB->y * nWidth + pPntB->x]; if (GD_PIXEL_FORMAT_GRAY_Y8 == img.enPixelFormat) { pPntAValue = ((UBYTE8*)img.u64VirAddr[0])[pPntA->y * nWidth + pPntA->x]; pPntBValue = ((UBYTE8*)img.u64VirAddr[0])[pPntB->y * nWidth + pPntB->x]; } else { pPntAValue = ((UINT16*)img.u64VirAddr[0])[pPntA->y * nWidth + pPntA->x]; pPntBValue = ((UINT16*)img.u64VirAddr[0])[pPntB->y * nWidth + pPntB->x]; } //检测亮目标 if (GLB_OBJ_GRAY_BRIGHT == m_DST_stPara.nDetectGrayType) { if (pPntAValue > pPntBValue) { pPntB->x = DST_BLK_MAX_PNT_DELETE_FLAG; pPntB->y = DST_BLK_MAX_PNT_DELETE_FLAG; } else { pPntA->x = DST_BLK_MAX_PNT_DELETE_FLAG; pPntA->y = DST_BLK_MAX_PNT_DELETE_FLAG; } } //检测暗目标 else if (GLB_OBJ_GRAY_DARK == m_DST_stPara.nDetectGrayType) { if (pPntAValue < pPntBValue) { pPntB->x = DST_BLK_MAX_PNT_DELETE_FLAG; pPntB->y = DST_BLK_MAX_PNT_DELETE_FLAG; } else { pPntA->x = DST_BLK_MAX_PNT_DELETE_FLAG; pPntA->y = DST_BLK_MAX_PNT_DELETE_FLAG; } } //亮暗都检测 else if (GLB_OBJ_GRAY_ALL == m_DST_stPara.nDetectGrayType) { //20161130,按大大/大小/小小三种情况处理 if (DST_BLK_MAX_PNT == pbBlkMaxPntFlag[i] && DST_BLK_MAX_PNT == pbBlkMaxPntFlag[nNearIndex]) { if (pPntAValue >= pPntBValue) { pPntB->x = DST_BLK_MAX_PNT_DELETE_FLAG; pPntB->y = DST_BLK_MAX_PNT_DELETE_FLAG; } else { pPntA->x = DST_BLK_MAX_PNT_DELETE_FLAG; pPntA->y = DST_BLK_MAX_PNT_DELETE_FLAG; } } else if (DST_BLK_MIN_PNT == pbBlkMaxPntFlag[i] && DST_BLK_MIN_PNT == pbBlkMaxPntFlag[nNearIndex]) { if (pPntAValue <= pPntBValue) { pPntB->x = DST_BLK_MAX_PNT_DELETE_FLAG; pPntB->y = DST_BLK_MAX_PNT_DELETE_FLAG; } else { pPntA->x = DST_BLK_MAX_PNT_DELETE_FLAG; pPntA->y = DST_BLK_MAX_PNT_DELETE_FLAG; } } else { //20170330,极大值点和极小值点不做合并处理 } } } } } } } /********************************************************** * 函数名称:DST_DetectExtremumTarget() * 功能描述:判断当前帧极值点是否为目标 * 输入参数:UINT16 *pFrame -- 原始图像 * SINT32 nWidth -- 图像宽度 * SINT32 nHeight -- 图像高度 * SINT32 nTargetNumMax -- 单帧检测目标的最大个数 * POINT16S *pBlkMaxPnt -- 当前帧极值点数组 * SINT32 nBlkNumW -- 行方向分块个数 * SINT32 nBlkNumH -- 列方向分块个数 * SINT32 *pBlkPtBeTargetFlag -- 极大值点是否为目标的标记 * 输出参数:TARGET_OBJECT *ptTargetArray-- 当前帧目标检测结果数组 * 返 回 值:SINT32 nTargetCnt -- 当前帧检测到的目标个数 * 调用关系: * 其它说明:无 **********************************************************/ SINT32 DetectSmallObj::DST_DetectFrameTarget(GD_VIDEO_FRAME_S img, SINT32 nWidth, SINT32 nHeight, TARGET_OBJECT* ptTargetArray, SINT32 nTargetNumMax, POINT16S* pBlkMaxPnt, SINT32 nBlkNumW, SINT32 nBlkNumH, SINT32* pBlkPtBeTargetFlag) { SINT32 i; SINT32 nBlkNumCnt; SINT32 nTargetCnt; BBOOL bFindTarget; POINT16S pPnt; TARGET_OBJECT tTarget; //初始化 nTargetCnt = 0; //参数计算 nBlkNumCnt = MIN(nBlkNumW * nBlkNumH, m_DST_stInput.nBlkNum); //判断极值点是否为目标 for (i = 0; i < nBlkNumCnt * 2; i++) { //获取第i个极值点 pPnt = pBlkMaxPnt[i]; //跳过被删除的极值点 if ((DST_BLK_MAX_PNT_DELETE_FLAG == pPnt.x) && (DST_BLK_MAX_PNT_DELETE_FLAG == pPnt.y)) { continue; } //查看此极值点,前面(上面和左边)4个极值点是否已被判断为目标, //若当前点落在该目标的上下左右边界之内,或者与该目标距离小于阈值,则将当前点删除不处理 //UINT16 pxPntGray = pFrame[pPnt.y * nWidth + pPnt.x];//from S332 UINT16 pxPntGray = 0;//from S332 if (GD_PIXEL_FORMAT_GRAY_Y8 == img.enPixelFormat) { pxPntGray = ((UBYTE8*)img.u64VirAddr[0])[pPnt.y * nWidth + pPnt.x]; } else { pxPntGray = ((UINT16*)img.u64VirAddr[0])[pPnt.y * nWidth + pPnt.x]; } if (DST_JudgeIfBlkPntBelongToTarget(i, nBlkNumH, nBlkNumW, pBlkMaxPnt, pBlkPtBeTargetFlag, ptTargetArray, m_DST_stPara.nObjCombineDist, pxPntGray)) { continue; } //初始化 memset(&tTarget, 0, sizeof(TARGET_OBJECT)); bFindTarget = false; //以极值点为中心查找目标 bFindTarget = DST_BlkMaxTargetDetect(img, nWidth, nHeight, pPnt, m_DST_stPara.pnFilter, m_DST_stPara.nFilterBGW, m_DST_stPara.nFilterTGW, &tTarget, m_DST_stPara.fgdk); //若该极值点为目标,则加入当前帧目标数组 if (bFindTarget) { //标记为目标,加入当前帧目标数组 tTarget.bObject = true; // tTarget.unFrmID = m_GLB_stInput.stParaLn.unFrmId; // 适应目标识别算法的加入,传统检测无法获取目标类型,此处约定目标类别ID置为DT_TARGET_CLS_ID,置信度为1 tTarget.unClsType = DT_TARGET_CLS_ID; tTarget.fDetConf = 1.0; tTarget.nObjTypeSrc = ObjSrc::Arith_DST; ptTargetArray[nTargetCnt] = tTarget; //标记该极值点处是目标 //Flag大于0,表明该点是目标,且其(Flag-1)表示该目标的编号 pBlkPtBeTargetFlag[i] = nTargetCnt + 1; //更新当帧目标个数统计 nTargetCnt++; //若目标个数超过上限,则跳出查找 if (nTargetCnt >= nTargetNumMax) break; } } return nTargetCnt; } #if 0 /********************************************************** * 函数名称:DST_BlkMaxTargetDetect() * 功能描述:判断极大值区域是否为目标 * 输入参数:UINT16 *pFrame -- 原始图像 * SINT32 nWidth -- 图像宽度 * SINT32 nHeight -- 图像高度 * POINT16S pPnt -- 极值点坐标 * SINT32 *pnFilter -- 目标背景模板 * SINT32 nFilterBGW -- 目标背景模板 - 背景宽度 * SINT32 nFilterTGW -- 目标背景模板 - 目标宽度 * FLOAT32 fgdk -- 目标SNR阈值 * 输出参数:TARGET_OBJECT *tTarget -- 当前目标结构体 * 返 回 值:1-该极值点是目标,0-该极值点不是目标。 * 调用关系:无 * 其它说明:无 **********************************************************/ BBOOL DetectSmallObj::DST_BlkMaxTargetDetect1(UINT16* pFrame, SINT32 nWidth, SINT32 nHeight, POINT16S pPnt, SINT32* pnFilter, SINT32 nFilterBGW, SINT32 nFilterTGW, TARGET_OBJECT* ptTarget, FLOAT32 fgdk) { SINT32* pnBlkTargetFlag = (SINT32*)DST_pnBlkTargetFlag; SINT32 i, j; BBOOL bIsTarget; //标记该极值点是否为目标 SINT32 nBGRadius, nTGRadius; //背景模板半径、目标模板半径 MINMAXRECT mmTGRect, mmBGRect; //目标、背景窗口边界 SINT32 nBGIndex, nBGFlter; //背景模板下标、背景模板系数 SINT32 nImgIndex; //背景点/邻域点对应的原始图像坐标 SINT32 nBGValue, nBGCnt; //背景点灰度、背景点计数 double dBGMean, dBGStd; //背景均值、方差 double dObjStd, dObjMean; //目标均值、方差 SINT32 nCenterValue; //中心点pPnt的灰度 SINT32 nPntValue; //目标模板内像素的灰度值 FLOAT32 fBGStdOutput; //背景方差 -- 用于显示,没有经过下限限制 BBOOL bTargetPixel; //标记某像素点是否属于目标。用于统计目标大小。 FLOAT32 fgdkCoeff; //gdk下降系数。用于统计目标大小。 SINT32 nObjWH_LineW; //目标宽高比统计 - 每行宽度 SINT32 nObjWH_LineWMax; //目标宽高比统计 - 行宽度的最大值 FLOAT32 fPntgdk; //各点的gdk系数 SINT32 nTGValue; //目标点灰度 SINT32 nCenterValueSumX; //目标点灰度-X坐标乘积累加、目标点灰度-Y坐标乘积累加 SINT32 nCenterValueSumY; //目标点灰度-X坐标乘积累加、目标点灰度-Y坐标乘积累加 SINT32 nValueDiff; //背景点与中心点的灰度差值 SINT32 nValueDiffMin; //背景点与中心点的灰度差的最小值 FLOAT32 fWHRatio; //目标宽高比 FLOAT32 fRectRatio; //目标矩形度 SINT32 nObjCenX, nObjCenY; //目标形心X、Y坐标 FLOAT32 fKernalBGVarMin2; //背景方差下限阈值(可调参数-标准差下限的平方) FLOAT32 fKernalBGVarMax2; //背景方差上限阈值(可调参数-标准差上限的平方) SINT32 nBGCntArray[4] = { 0 }; //20180115,记录上下左右邻域背景点个数 DOUBLE64 dBGMeanArray[4] = { 0.0f }; //20180115,记录上下左右邻域背景均值 DOUBLE64 dBGStdArray[4] = { 0.0f }; //20180115,记录上下左右邻域背景标准差 SINT32 nBGOuterRadius = 0; //20180115,回字形的外半径 SINT32 nMaxStdIndex = 0; //20180115,std最大的背景块下标 DOUBLE64 bBGStdMax = -1.0f; //20180115,方差最大的块 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++ //初始化 bIsTarget = false; nValueDiffMin = (SINT32)1e6; memset(ptTarget, 0, sizeof(TARGET_OBJECT)); //+++++++++++++++++++++++++++++++++++++++++++++++++++++++ //参数设置 fgdkCoeff = 0.7f; fKernalBGVarMin2 = m_DST_stPara.fKernalBGStdMin * m_DST_stPara.fKernalBGStdMin; fKernalBGVarMax2 = m_DST_stPara.fKernalBGStdMax * m_DST_stPara.fKernalBGStdMax; nBGRadius = (SINT32)(nFilterBGW >> 1); nTGRadius = (SINT32)(nFilterTGW >> 1); nBGOuterRadius = nBGRadius - nTGRadius; //20180115,回字形的外半径 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++ //获取中心点灰度值 nCenterValue = pFrame[pPnt.y * nWidth + pPnt.x]; //+++++++++++++++++++++++++++++++++++++++++++++++++++++++ //统计背景均值、方差 //计算背景窗口边界 mmBGRect.minX = pPnt.x - nBGRadius; mmBGRect.maxX = pPnt.x + nBGRadius; mmBGRect.minY = pPnt.y - nBGRadius; mmBGRect.maxY = pPnt.y + nBGRadius; //防止越界 if (mmBGRect.minX<0 || mmBGRect.maxX>nWidth - 1 || mmBGRect.minY<0 || mmBGRect.maxY>nHeight - 1) { return false; } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++ //统计背景均值、方差 nBGCnt = 0; dBGMean = 0; dBGStd = 0; dObjStd = 0; dObjMean = 0; SINT32 nBGLine = 0; SINT32 nImgLine = mmBGRect.minY * nWidth + mmBGRect.minX; //for (i = 0; i < nFilterBGW; i++) //{ // for (j = 0; j < nFilterBGW; j++) // { // nBGIndex = nBGLine + j; // nImgIndex= nImgLine + j; // nBGFlter = pnFilter[nBGIndex]; // nBGValue = pFrame[nImgIndex]; // if (1 == nBGFlter) // { // //背景灰度及灰度平方累加 // nBGCnt++; // dBGMean += (double)nBGValue; // dBGStd += (double)nBGValue * nBGValue; // //查找背景中与中心点灰度差异最小的点的灰度 // nValueDiff = ABS(nBGValue - nCenterValue); // if (nValueDiff < nValueDiffMin) // { // nValueDiffMin = nValueDiff; // } // } // } // //更新行起始坐标 // nBGLine += nFilterBGW; // nImgLine += nWidth; //} for (i = 0; i < nFilterBGW; i++) { for (j = 0; j < nFilterBGW; j++) { nBGIndex = nBGLine + j; nImgIndex = nImgLine + j; nBGFlter = pnFilter[nBGIndex]; nBGValue = pFrame[nImgIndex]; if (1 == nBGFlter) { //背景灰度及灰度平方累加 //20180115,【屏蔽】采用取4邻域方差最小值的方式,防止背景混入目标点 //按上下左右顺序存邻域背景参数 if (j < nBGOuterRadius) { nBGCntArray[0]++; dBGMeanArray[0] += (double)nBGValue; dBGStdArray[0] += (double)nBGValue * nBGValue; } else if (j >= nFilterTGW + nBGOuterRadius) { nBGCntArray[1]++; dBGMeanArray[1] += (double)nBGValue; dBGStdArray[1] += (double)nBGValue * nBGValue; } else { //左邻域 if (i < nBGOuterRadius) { nBGCntArray[2]++; dBGMeanArray[2] += (double)nBGValue; dBGStdArray[2] += (double)nBGValue * nBGValue; } else { nBGCntArray[3]++; dBGMeanArray[3] += (double)nBGValue; dBGStdArray[3] += (double)nBGValue * nBGValue; } } //查找背景中与中心点灰度差异最小的点的灰度 nValueDiff = ABS(nBGValue - nCenterValue); if (nValueDiff < nValueDiffMin) { nValueDiffMin = nValueDiff; } } } //更新行起始坐标 nBGLine += nFilterBGW; nImgLine += nWidth; } //20180115,【屏蔽】采用取4邻域方差最小值的方式,防止背景混入目标点 //计算4邻域的均值与方差 for (i = 0; i < 4; i++) { nBGCnt += nBGCntArray[i]; dBGMean += dBGMeanArray[i]; dBGStd += dBGStdArray[i]; dBGMeanArray[i] /= nBGCntArray[i]; dBGStdArray[i] /= nBGCntArray[i]; dBGStdArray[i] -= dBGMeanArray[i] * dBGMeanArray[i]; //找到方差最大的块 if (dBGStdArray[i] > bBGStdMax) { bBGStdMax = dBGStdArray[i]; nMaxStdIndex = i; } } //抛掉方差最大的块 nBGCnt -= nBGCntArray[nMaxStdIndex]; dBGMean -= (dBGMeanArray[nMaxStdIndex] * nBGCntArray[nMaxStdIndex]); dBGStd -= (nBGCntArray[nMaxStdIndex] * (dBGStdArray[nMaxStdIndex] + dBGMeanArray[nMaxStdIndex] * dBGMeanArray[nMaxStdIndex])); dBGMean /= nBGCnt; dBGStd /= nBGCnt; dBGStd -= dBGMean * dBGMean; //保存计算的背景均值及方差 fBGStdOutput = (FLOAT32)dBGStd; //+++++++++++++++++++++++++++++++++++++++++++++++++++++++ //抛掉方差过大的块 if (m_DST_stPara.bUseDeFA_VarMax //去虚警策略“邻域方差上限限制”的开关 && dBGStd > fKernalBGVarMax2) //判断邻域方差是否大于上限限制。 return false; //设置背景方差下限 if (m_DST_stPara.bUseDeFA_VarMin //去虚警策略“邻域方差下限限制”的开关 && dBGStd < m_DST_stPara.fKernalBGStdMin) //判断邻域方差是否小于下限限制。 { dBGStd = (double)fKernalBGVarMin2; } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++ //gdk不做自适应调节,直接赋给PC机传入的可调参数m_DST_stPara.fgdk fPntgdk = fgdk; //+++++++++++++++++++++++++++++++++++++++++++++++++++++++ //目标检测初始化 //计算目标核边界 mmTGRect.minX = pPnt.x - nTGRadius; mmTGRect.maxX = pPnt.x + nTGRadius; mmTGRect.minY = pPnt.y - nTGRadius; mmTGRect.maxY = pPnt.y + nTGRadius; //初始化 ptTarget->mrnRect.minY = mmTGRect.maxY; ptTarget->mrnRect.maxY = mmTGRect.minY; ptTarget->mrnRect.minX = mmTGRect.maxX; ptTarget->mrnRect.maxX = mmTGRect.minX; nCenterValueSumX = 0; nCenterValueSumY = 0; nTGValue = 0; //记录目标的类型 ptTarget->nObjTypeGray = (nCenterValue > (SINT32)dBGMean) ? GLB_OBJ_GRAY_BRIGHT : GLB_OBJ_GRAY_DARK; //MSSu, 20120304:根据系统所要检测的目标类型进行区分 if (GLB_OBJ_GRAY_DARK == m_DST_stPara.nDetectGrayType) //只检测暗目标 { //MSSu, 20120229: 剔除亮目标。根据夜晚试验气球为暗目标的特性,做出目标类型的限制。 if (GLB_OBJ_GRAY_BRIGHT == ptTarget->nObjTypeGray) return FALSE; } else if (GLB_OBJ_GRAY_BRIGHT == m_DST_stPara.nDetectGrayType) //只检测亮目标 { //跳过暗目标 if (GLB_OBJ_GRAY_DARK == ptTarget->nObjTypeGray) return FALSE; } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++ //提前计算参数,简化计算 double fPntgdkByStd = fPntgdk * fPntgdk * dBGStd; //+++++++++++++++++++++++++++++++++++++++++++++++++++++++ //目标检测:基于目标信噪比的检测方法 //首先判断极值点是否为目标 //MSSu, 20111115: 若m_DST_nDectectMinPnt==TRUE,则为判断极大值点或极小值点是否为目标 //若极值点不满足SNR条件,则判断该点是否满足灰度阈值判断的条件 if ((nCenterValue - dBGMean) * (nCenterValue - dBGMean) <= fPntgdkByStd) { //标记该点不是目标,直接返回 return false; } //若极值点是目标,则统计目标的大小 else { //标记该点为目标 bIsTarget = true; //去虚警:抛掉方差过大的块 if (m_DST_stPara.bUseDeFA_VarMax && dBGStd > m_DST_stPara.fKernalBGStdMax) { bIsTarget = false; } //去虚警:抛掉极值点与背景最小灰度差小于阈值的块 if (m_DST_stPara.bUseDeFA_BTGrayMin && nValueDiffMin < m_DST_stPara.nBTGrayMinThres) { bIsTarget = false; } //若该点不是目标,则跳过剩余计算 if (!bIsTarget) { return false; } //降低gdk阈值统计目标大小 fPntgdk *= fgdkCoeff; fPntgdk = MAX(fPntgdk, 4.0f); //提前计算参数,简化计算 double fPntgdkByStdNew = fPntgdk * fPntgdk * dBGStd; //搜索目标边界 nObjWH_LineWMax = 0; SINT32 nLine = (pPnt.y - nTGRadius) * nWidth + pPnt.x - nTGRadius; //SINT32 nIndex = 0; SINT32 nFlagLine = 0; SINT32 nFlagIndex = 0; for (i = 0; i < nFilterTGW; i++) { //初始化每行宽度 nObjWH_LineW = 0; for (j = 0; j < nFilterTGW; j++) { //获取目标区域各点的图像坐标 nImgIndex = nLine + j; //获取目标区域各点灰度值 nPntValue = pFrame[nImgIndex]; //提前计算参数,简化计算 double dValueDiff = nPntValue - dBGMean; double dValueDiffSquare = dValueDiff * dValueDiff; //判断该点是否属于目标点(采用SNR判断方法) bTargetPixel = false; if ((i == j && i == nTGRadius) || (GLB_OBJ_GRAY_BRIGHT == m_DST_stPara.nDetectGrayType && nPntValue > dBGMean && dValueDiffSquare > fPntgdkByStdNew) || (GLB_OBJ_GRAY_DARK == m_DST_stPara.nDetectGrayType && nPntValue < dBGMean && dValueDiffSquare > fPntgdkByStdNew) || (GLB_OBJ_GRAY_ALL == m_DST_stPara.nDetectGrayType && dValueDiffSquare > fPntgdkByStdNew)) { bTargetPixel = true; } //查找目标边界,并统计大小 if (bTargetPixel) { dObjMean += nPntValue; dObjStd += nPntValue * nPntValue; //统计行宽 nObjWH_LineW++; //查找目标边界 SINT32 nImgX = j + mmTGRect.minX; SINT32 nImgY = i + mmTGRect.minY; ptTarget->mrnRect.minY = MIN(ptTarget->mrnRect.minY, nImgY); ptTarget->mrnRect.maxY = MAX(ptTarget->mrnRect.maxY, nImgY); ptTarget->mrnRect.minX = MIN(ptTarget->mrnRect.minX, nImgX); ptTarget->mrnRect.maxX = MAX(ptTarget->mrnRect.maxX, nImgX); //统计目标质心. MSSu, 20110524 nCenterValueSumX += nImgX * nPntValue; nCenterValueSumY += nImgY * nPntValue; nTGValue += nPntValue; //统计目标大小 ptTarget->unObjPxlsCnt++; //标记目标区域内目标点 nFlagIndex = nFlagLine + j; pnBlkTargetFlag[nFlagIndex] = 1; // 目标极值 ptTarget->pxObjMaxGray = MAX(ptTarget->pxObjMaxGray, nPntValue); } } //查找最大行宽 nObjWH_LineWMax = MAX(nObjWH_LineWMax, nObjWH_LineW); //更新下一行起始坐标 nLine += nWidth; nFlagLine += nFilterTGW; }//end of for (j = 0; j < nKernelSize_TG; j++)... }//end of else... if (ptTarget->unObjPxlsCnt > 0) { dObjMean /= ptTarget->unObjPxlsCnt; dObjStd /= ptTarget->unObjPxlsCnt; dObjStd -= dObjMean * dObjMean; } else { dObjStd = 0.0; } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++ //统计目标信息 if (bIsTarget) { //计算统计目标质心 if (0 == nTGValue) //防止出错,例如当阈值设置不恰当时,连目标的极大值点都未统计到目标的大小中 { ptTarget->pfCenPos.x = (FLOAT32)pPnt.x; ptTarget->pfCenPos.y = (FLOAT32)pPnt.y; } else { ptTarget->pfCenPos.x = (FLOAT32)nCenterValueSumX / nTGValue; ptTarget->pfCenPos.y = (FLOAT32)nCenterValueSumY / nTGValue; } //统计目标的灰度(极大值灰度) ptTarget->pxObjGray = nCenterValue; //记录目标极大值点坐标 ptTarget->pnMaxPos = pPnt; //计算目标宽、高、面积 ptTarget->snSize.h = ptTarget->mrnRect.maxY - ptTarget->mrnRect.minY + 1; ptTarget->snSize.w = ptTarget->mrnRect.maxX - ptTarget->mrnRect.minX + 1; ptTarget->snSize.s = ptTarget->snSize.h * ptTarget->snSize.w; //记录背景均值、背景方差、目标背景信噪比 ptTarget->fBGMean = (FLOAT32)dBGMean; ptTarget->fBGStd = (FLOAT32)sqrt(fBGStdOutput); ptTarget->fSNR = (FLOAT32)(nCenterValue - dBGMean) / (ptTarget->fBGStd + 0.01f); //计算目标的伺服方位角、俯仰角 // ptTarget->afAngle.fAz = SERVO_CalcObjAzimuth (pPnt.x, nWidth, m_SERVO_stInput.fAzimuth, m_SERVO_stInput.fResolAz); // ptTarget->afAngle.fPt = SERVO_CalcObjPitching(pPnt.y, nHeight, m_SERVO_stInput.fPitching, m_SERVO_stInput.fResolPt); //标记目标类型 ptTarget->nObjTypeSize = GLB_OBJ_SIZE_SMALL; //标记为目标 bIsTarget = true; //去虚警:抛掉大小不符合要求的目标 if (m_DST_stPara.bUseDeFA_Size //去虚警策略“目标大小限制”的开关 && (ptTarget->unObjPxlsCnt < (UINT32)m_DST_stPara.nObjSizeMin || ptTarget->unObjPxlsCnt >(UINT32)m_DST_stPara.nObjSizeMax)) { bIsTarget = false; } //去虚警:抛掉长宽比不符合要求的目标 //目标宽高比计算方式2 - 最大行宽度/总高度 if (DST_OBJ_WHRATIO_LINEWH == m_DST_stPara.nObjWHRatioMethod) { fWHRatio = (FLOAT32)nObjWH_LineWMax / ptTarget->snSize.h; } //目标宽高比计算方式1 - 总宽度/总高度 else { fWHRatio = (FLOAT32)(ptTarget->snSize.w) / ptTarget->snSize.h; } if (m_DST_stPara.bUseDeFA_WHRatio //去虚警策略“目标宽高比限制”的开关 && ((fWHRatio < 1 && fWHRatio < m_DST_stPara.fObjWHRatioMin) || (fWHRatio > 1 && fWHRatio > m_DST_stPara.fObjWHRatioMax))) { bIsTarget = false; } //去虚警:抛掉矩形度不符合要求的目标 fRectRatio = (FLOAT32)ptTarget->unObjPxlsCnt / ptTarget->snSize.s; if (m_DST_stPara.bUseDeFA_RectRatio //去虚警策略“目标矩形度限制”的开关 && fRectRatio < m_DST_stPara.fObjRectRatioMin) { bIsTarget = false; } //去虚警:抛掉形心不是目标标记点的目标(形状不规则) //nObjCenX = (SINT32)((tTarget->mrnRect.minX + tTarget->mrnRect.maxX) / 2.0 + 0.5); //nObjCenY = (SINT32)((tTarget->mrnRect.minY + tTarget->mrnRect.maxY) / 2.0 + 0.5); nObjCenX = (ptTarget->mrnRect.minX + ptTarget->mrnRect.maxX) >> 1; nObjCenY = (ptTarget->mrnRect.minY + ptTarget->mrnRect.maxY) >> 1; if (m_DST_stPara.bUseDeFA_CenFlag //去虚警策略“形心为目标点”的开关 && !pnBlkTargetFlag[(nObjCenY - mmTGRect.minY) * nFilterTGW + nObjCenX - mmTGRect.minX]) { if ((nObjCenX - ptTarget->pfCenPos.x) * (nObjCenX - ptTarget->pfCenPos.x) + (nObjCenY - ptTarget->pfCenPos.y) * (nObjCenY - ptTarget->pfCenPos.y) > 2.0f) { bIsTarget = false; } } } return bIsTarget; } #endif /********************************************************** * 函数名称:DST_JudgeIfBlkPntBelongToTarget() * 功能描述:判断当前极值点是否落在前面已检测到的目标上,或与前面的目标邻近 * 输入参数:SINT32 nPntIndex -- 极值点在数组中的序号 * SINT32 nBlkNumW -- 行方向分块个数 * SINT32 nBlkNumH -- 列方向分块个数 * POINT16S *pBlkMaxPnt -- 当前帧极值点数组 * SINT32 *pBlkPtBeTargetFlag -- 极大值点是否为目标的标记 * TARGET_OBJECT *ptTargetArray-- 当前帧目标检测结果数组 * SINT32 nDistThres -- 极值点合并的距离阈值 * 输出参数:无 * 返 回 值:1-当前极值点被合并,0-当前极值点未被合并 * 调用关系:无 * 其它说明:无 **********************************************************/ BBOOL DetectSmallObj::DST_JudgeIfBlkPntBelongToTarget(SINT32 nPntIndex, SINT32 nBlkNumH, SINT32 nBlkNumW, POINT16S* pBlkMaxPnt, SINT32* pBlkPtBeTargetFlag, TARGET_OBJECT* ptTargetArray, SINT32 nDistThres, UINT16 pxPntGray) { SINT32 nX[4] = { -1, 0, 1, -1 }; SINT32 nY[4] = { -1, -1, -1, 0 }; SINT32 k = 0; POINT16S* pPntA = NULL; POINT16S* pPntB = NULL; SINT32 nDistAB = 0; SINT32 nNearIndex = 0; SINT32 nDistThres2 = 0; TARGET_OBJECT* ptTarget = NULL; //计算参数 nDistThres2 = nDistThres * nDistThres; //获取当前极值点A的坐标 pPntA = &pBlkMaxPnt[nPntIndex]; for (k = 0; k <= 3; k++) { //计算临近点B下标 nNearIndex = nPntIndex + nY[k] * nBlkNumW + nX[k]; //防止临近点越界 if (nNearIndex < 0 || nNearIndex >= nBlkNumH * nBlkNumW) { continue; } //若该邻域极值点不是目标,则跳过 if (pBlkPtBeTargetFlag[nNearIndex] <= 0) { continue; } //ptTarget指向该目标信息 ptTarget = &ptTargetArray[pBlkPtBeTargetFlag[nNearIndex] - 1]; //若当前点位于邻域极值目标上,删除该点,返回真 if (pPntA->x >= ptTarget->mrnRect.minX && pPntA->x <= ptTarget->mrnRect.maxX && pPntA->y >= ptTarget->mrnRect.minY && pPntA->y <= ptTarget->mrnRect.maxY) { if (GLB_OBJ_GRAY_BRIGHT == ptTarget->nObjTypeGray) { if (ptTarget->pxObjGray > pxPntGray) { pPntA->x = DST_BLK_MAX_PNT_DELETE_FLAG; pPntA->y = DST_BLK_MAX_PNT_DELETE_FLAG; return true; } } else { if (ptTarget->pxObjGray < pxPntGray) { pPntA->x = DST_BLK_MAX_PNT_DELETE_FLAG; pPntA->y = DST_BLK_MAX_PNT_DELETE_FLAG; return true; } } } //获取邻域极值目标的坐标 pPntB = &ptTarget->pnMaxPos; //计算该点与目标的距离 nDistAB = (pPntA->x - pPntB->x) * (pPntA->x - pPntB->x); nDistAB += (pPntA->y - pPntB->y) * (pPntA->y - pPntB->y); //若当前点不在邻域极值目标上,但两者距离小于阈值,也删除该点,返回真 if (nDistAB < nDistThres2) { pPntA->x = DST_BLK_MAX_PNT_DELETE_FLAG; pPntA->y = DST_BLK_MAX_PNT_DELETE_FLAG; return true; } } return false; } /********************************************************** * 函数名称:DST_CalObjBkgMean_UINT16() * 功能描述:计算目标背景均值 * 输入参数:UINT16 *pFrame -- 原始图像 * SINT32 nWidth -- 图像宽度 * SINT32 nHeight -- 图像高度 * POINT16S pPnt -- 目标坐标 * 输出参数:FLOAT32 dBGMean -- 目标背景均值信息 * 返 回 值:无 * 调用关系:无 * 其它说明:无 **********************************************************/ FLOAT32 DetectSmallObj::DST_CalObjBkgMean_UINT16(GD_VIDEO_FRAME_S img, SINT32 nWidth, SINT32 nHeight, POINT16S pPnt) { SINT32 i, j; SINT32 nFilterBGW; //极大值滤波窗口 - 背景核区域大小,目标核区域大小 SINT32 nBGRadius, nTGRadius; //背景模板半径、目标模板半径 SINT32 nBGIndex, nBGFlter; //背景模板下标、背景模板系数 SINT32 nImgIndex; //背景点/邻域点对应的原始图像坐标 SINT32 nBGValue, nBGCnt; //背景点灰度、背景点计数 FLOAT32 dBGMean; //背景均值、方差 SINT32* pnFilter = (SINT32*)g_DST_nFilter_9_13;//目标背景模板 MINMAXRECT mmBGRect; //目标、背景窗口边界 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++ nFilterBGW = DST_KERNAL_SIZE_Bm_13; nBGRadius = (SINT32)(nFilterBGW >> 1); nTGRadius = (SINT32)(DST_KERNAL_SIZE_Tm_9 >> 1); //+++++++++++++++++++++++++++++++++++++++++++++++++++++++ //统计背景均值、方差 //计算背景窗口边界 mmBGRect.minX = pPnt.x - nBGRadius; mmBGRect.maxX = pPnt.x + nBGRadius; mmBGRect.minY = pPnt.y - nBGRadius; mmBGRect.maxY = pPnt.y + nBGRadius; //防止越界 if (mmBGRect.minX<0 || mmBGRect.maxX>nWidth - 1 || mmBGRect.minY<0 || mmBGRect.maxY>nHeight - 1) { return -1.0; } //统计背景均值、方差 nBGCnt = 0; dBGMean = 0; //小目标检测:在原图上计算背景均值、背景标准差 SINT32 nBGLine = 0; SINT32 nImgLine = mmBGRect.minY * nWidth + mmBGRect.minX; for (i = 0; i < nFilterBGW; i++) { for (j = 0; j < nFilterBGW; j++) { nBGIndex = nBGLine + j; nImgIndex = nImgLine + j; nBGFlter = pnFilter[nBGIndex]; if (GD_PIXEL_FORMAT_GRAY_Y8 == img.enPixelFormat) { nBGValue = ((UBYTE8*)img.u64VirAddr[0])[nImgIndex]; } else { nBGValue = ((UINT16*)img.u64VirAddr[0])[nImgIndex]; } if (1 == nBGFlter) { //背景灰度及灰度平方累加 nBGCnt++; dBGMean += (FLOAT32)nBGValue; } } //更新行起始坐标 nBGLine += nFilterBGW; nImgLine += nWidth; } dBGMean /= nBGCnt; //保存计算的背景均值及方差 return dBGMean; } /********************************************************** * 函数名称:DST_PipeTargetReDetect() * 功能描述:管道目标二次搜索 * 输入参数:UINT16 *pSrc -- 原始图像 * SINT32 nWidth -- 图像宽度 * SINT32 nHeight -- 图像高度 * POINT32F ptPipeCenPos -- 管道目标在当前帧的中心坐标 * SPEED32F sfPipeSpeed -- 管道目标速度 * MINMAXRECT mrnSrRect -- 搜索区域边界 * FLOAT32 fgdk -- SNR阈值 * TARGET_OBJECT *ptTargetArray-- 当前帧目标检测结果数组 * PIPE *pPipeArray -- 管道数组 * SINT32 *pnFrmObjsCnt -- 单帧检测目标个数 * 输出参数:TARGET_OBJECT *ptTarget -- 二次检测到的目标 * SINT32 *bPipeTargetIndex -- 管道在当前帧查找到的目标 * TARGET_OBJECT *ptTargetArray-- 当前帧目标检测结果数组 * SINT32 *pnFrmObjsCnt -- 单帧检测目标个数 * 返 回 值:1-二次检测找到目标,0-未检测到目标。 * 调用关系: * 其它说明:在前一帧管道中心区域,重新查找极大或极小值点。 **********************************************************/ BBOOL DetectSmallObj::DST_PipeTargetReDetect(GD_VIDEO_FRAME_S img, SINT32 nWidth, SINT32 nHeight, POINT32F ptPipeCenPos, SPEED32F sfPipeSpeed, MINMAXRECT mrnSrRect, TARGET_OBJECT* ptTarget, TARGET_OBJECT* ptTargetArray, SINT32* pnFrmObjsCnt) { BBOOL bRefoundTarget; //标记管道目标二次搜索是否成功 SINT32 nBlkStart; //管道目标二次搜索时,中心区域的左上角起始坐标 POINT16S pnPipeSearchPoint; //管道目标二次搜索时,中心区域的极值点坐标 SINT32 nFrmObjsCnt; //当前帧目标个数 SINT32 nSrRadiusW; //宽方向搜索半径 SINT32 nSrRadiusH; //高方向搜索半径 //初始化 bRefoundTarget = false; nFrmObjsCnt = (*pnFrmObjsCnt); nSrRadiusW = MAX(2, MIN((SINT32)(sfPipeSpeed.vx * 2.0f), DST_PIPE_CENTER_BLK_W / 2)); nSrRadiusH = MAX(2, MIN((SINT32)(sfPipeSpeed.vy * 2.0f), DST_PIPE_CENTER_BLK_H / 2)); POINT16S pBlkSecondMaxPnt = {0};//次极大值 //MSSu, 20150609: 防止越界 MINMAXRECT32S mrnRect; mrnRect.minX = ptPipeCenPos.x - nSrRadiusW; mrnRect.maxX = ptPipeCenPos.x + nSrRadiusW; mrnRect.minY = ptPipeCenPos.y - nSrRadiusH; mrnRect.maxY = ptPipeCenPos.y + nSrRadiusH; if ((mrnRect.minX < 0) || (mrnRect.maxX >= nWidth) || (mrnRect.minY < 0) || (mrnRect.maxY >= nHeight)) { return bRefoundTarget; } //获取管道中心区域图像起始位置 nBlkStart = mrnRect.minY * nWidth + mrnRect.minX; //查找块内极值:极大值或极小值 //MSSu, 20111115: 若m_DST_nDectectMinPnt==TRUE,则为查找块内极大或极小值 BYTE8 bMaxPntFalg = DST_BLK_MAX_PNT; //20161130,标记极大/极小 pnPipeSearchPoint = DST_FindBlkExtremum(img, nWidth, nHeight, nBlkStart, nSrRadiusW * 2 + 1, nSrRadiusH * 2 + 1, &bMaxPntFalg,&pBlkSecondMaxPnt); //二次检测前,关闭部分去虚警开关(需先保存关闭前的状态) SINT32 bUseDeFA_VarMax = m_DST_stPara.bUseDeFA_VarMax; SINT32 bUseDeFA_Size = m_DST_stPara.bUseDeFA_Size; SINT32 bUseDeFA_BGFACnt = m_DST_stPara.bUseDeFA_BGFACnt; SINT32 bUseDeFA_BTGrayMin = m_DST_stPara.bUseDeFA_BTGrayMin; SINT32 bUseDeFA_CenFlag = m_DST_stPara.bUseDeFA_CenFlag; SINT32 bUseDeFA_XYPrj = m_DST_stPara.bUseDeFA_XYPrj; m_DST_stPara.bUseDeFA_VarMax = FALSE; m_DST_stPara.bUseDeFA_Size = FALSE; m_DST_stPara.bUseDeFA_BGFACnt = FALSE; m_DST_stPara.bUseDeFA_BTGrayMin = FALSE; m_DST_stPara.bUseDeFA_CenFlag = FALSE; m_DST_stPara.bUseDeFA_XYPrj = FALSE; FLOAT32 fgdk = MAX(m_DST_stPara.fgdk / 2.0f,2.0f); //若目标超出搜索区域,则不降低阈值再查找,让管道消失 //if (mrnSrRect.minX < pnPipeSearchPoint.x // && pnPipeSearchPoint.x < mrnSrRect.maxX // && mrnSrRect.minY < pnPipeSearchPoint.y // && pnPipeSearchPoint.y < mrnSrRect.maxY) if (mrnRect.minX < pnPipeSearchPoint.x && pnPipeSearchPoint.x < mrnRect.maxX && mrnRect.minY < pnPipeSearchPoint.y && pnPipeSearchPoint.y < mrnRect.maxY) { //若检测到目标,则重置管道待删除标记pPipe->bLost清零 memset(ptTarget, 0, sizeof(TARGET_OBJECT)); bRefoundTarget = DST_BlkMaxTargetDetect(img, nWidth, nHeight, pnPipeSearchPoint, m_DST_stPara.pnFilter, m_DST_stPara.nFilterBGW, m_DST_stPara.nFilterTGW, ptTarget, fgdk); ptTarget->nObjTypeSize = GLB_OBJ_SIZE_DIMSMALL; ptTarget->nObjTypeSrc = ObjSrc::Arith_DIM;//标记为弱目标 } //if (bRefoundTarget && (ABS(ptTarget->pfCenPos.x - m_GLB_stOutput.crnObjPrediRtLong.cx) > 10 // || ABS(ptTarget->pfCenPos.y - m_GLB_stOutput.crnObjPrediRtLong.cy) > 10)) //{ // bRefoundTarget = false; //} //将二次检测到的目标,加入单帧目标数组 if (bRefoundTarget) { //标记为目标,加入当前帧目标数组 ptTarget->bObject = true; // ptTarget->unFrmID = m_GLB_stInput.stParaLn.unFrmId; //(*bPipeTargetIndex) = nFrmObjsCnt; memcpy(&ptTargetArray[nFrmObjsCnt], ptTarget, sizeof(TARGET_OBJECT)); nFrmObjsCnt++; //更新当帧目标个数统计 (*pnFrmObjsCnt) = nFrmObjsCnt; } //二次检测后,还原去虚警开关(需先保存关闭前的状态) m_DST_stPara.bUseDeFA_VarMax = bUseDeFA_VarMax; m_DST_stPara.bUseDeFA_Size = bUseDeFA_Size; m_DST_stPara.bUseDeFA_BGFACnt = bUseDeFA_BGFACnt; m_DST_stPara.bUseDeFA_BTGrayMin = bUseDeFA_BTGrayMin; m_DST_stPara.bUseDeFA_CenFlag = bUseDeFA_CenFlag; m_DST_stPara.bUseDeFA_XYPrj = bUseDeFA_XYPrj; return bRefoundTarget; } /********************************************************** * 函数名称:DST_FindBlkExtremum() * 功能描述:查找块内极值点 * 输入参数:PIXELTYPE *pFrame -- 原始图像 * SINT32 nWidth -- 图像宽度 * SINT32 nHeight -- 图像高度 * SINT32 pBlkStart -- 该分块在原始图像上的起始坐标 * SINT32 nBlkWidth -- 分块宽度 * SINT32 nBlkHeight -- 分块高度 * 输出参数:无 * 返 回 值:POINT16S pPnt -- 块内极值点坐标 * 调用关系:无 * 其它说明:MSSu, 20111115: 函数修改,增加查找块内极小值的功能, * 对于每个块的极大值和极小值,选两者中与块均值偏差较大的作为返回点。 **********************************************************/ POINT16S DetectSmallObj::DST_FindBlk4Neighbor(GD_VIDEO_FRAME_S img, SINT32 nWidth, SINT32 nHeight, SINT32 pBlkStart, SINT32 nBlkWidth, SINT32 nBlkHeight, POINT16S* pSecondMax) { SINT32 i, j; SINT32 nLen = nBlkWidth * nBlkHeight; UINT16 pGrayGap = 0; UINT16 pMax = 20; // 起始灰度差阈值,并记录最大的pGrayGap,低于该阈值不作为候选目标 UINT16 pMax2 = 0; UINT16 pMin = 65535; SINT32 pMean = 0; POINT16S pPntMax = { 0 }; POINT16S pPntMax2 = { 0 }; POINT16S pPntMin = { 0 }; POINT16S pPnt = { 0 }; SINT32 nMaxIndex = 0; SINT32 nMaxIndex2 = 0; SINT32 nMinIndex = 0; SINT32 nIndex = 0; SINT32 nMaxI = 0; SINT32 nMaxJ = 0; //查找块内极值点 for (i = 0; i < nBlkHeight; i++) { for (j = 0; j < nBlkWidth; j++) { //获取块内每个像素点灰度 nIndex = pBlkStart + j; int nnIndex_left = nIndex - 1; int nnIndex_right = nIndex + 1; int nnIndex_top = nIndex - nWidth; int nnIndex_bottom = nIndex + nWidth; if (GD_PIXEL_FORMAT_GRAY_Y8 == img.enPixelFormat) { UBYTE8 * pFrame = ((UBYTE8*)img.u64VirAddr[0]); pGrayGap = (pFrame[nIndex] - pFrame[nnIndex_left]) > 0 ? (pFrame[nIndex] - pFrame[nnIndex_left]) : 0 + (pFrame[nIndex] - pFrame[nnIndex_right]) > 0 ? (pFrame[nIndex] - pFrame[nnIndex_right]) : 0 + (pFrame[nIndex] - pFrame[nnIndex_top]) > 0 ? (pFrame[nIndex] - pFrame[nnIndex_top]) : 0 + (pFrame[nIndex] - pFrame[nnIndex_bottom]) > 0 ? (pFrame[nIndex] - pFrame[nnIndex_bottom]) : 0; } else { UINT16* pFrame = ((UINT16*)img.u64VirAddr[0]); pGrayGap = (pFrame[nIndex] - pFrame[nnIndex_left]) > 0 ? (pFrame[nIndex] - pFrame[nnIndex_left]) : 0 + (pFrame[nIndex] - pFrame[nnIndex_right]) > 0 ? (pFrame[nIndex] - pFrame[nnIndex_right]) : 0 + (pFrame[nIndex] - pFrame[nnIndex_top]) > 0 ? (pFrame[nIndex] - pFrame[nnIndex_top]) : 0 + (pFrame[nIndex] - pFrame[nnIndex_bottom]) > 0 ? (pFrame[nIndex] - pFrame[nnIndex_bottom]) : 0; } //查找极大值 if (pGrayGap > pMax) { pMax = pGrayGap; nMaxIndex = nIndex; nMaxI = i; nMaxJ = j; } } //更新下一行的其实坐标 pBlkStart += nWidth; } //计算块内灰度均值,抛掉极大值 if (nLen <= 1) { pMean = pMean; } else if (nLen == 2) { pMean /= 2; } else { //pMean -= pMax; //pMean /= (nLen - 1); pMean -= (pMax + pMin); pMean /= (nLen - 2); } //抛掉与块均值灰度差异较小的点 //if (ABS(pMax - pMean) < pDiffThres) //{ // pPnt.x = DST_BLK_MAX_PNT_DELETE_FLAG; // pPnt.y = DST_BLK_MAX_PNT_DELETE_FLAG; //} //else pPntMax.x = nMaxIndex % nWidth; pPntMax.y = nMaxIndex / nWidth; pPntMax2.x = nMaxIndex2 % nWidth; pPntMax2.y = nMaxIndex2 / nWidth; pPntMin.x = nMinIndex % nWidth; pPntMin.y = nMinIndex / nWidth; if (GLB_OBJ_GRAY_DARK == m_DST_stPara.nDetectGrayType) { pPnt = pPntMin; } else if (DST_DETECT_OBJ_TYPE_BRIGHT == m_DST_stPara.nDetectGrayType) { pPnt = pPntMax; if (pPntMax.x == pPntMax2.x && pPntMax.y == pPntMax2.y) { pSecondMax->x = -1; pSecondMax->y = -1; } else { *pSecondMax = pPntMax2; } } else if (DST_DETECT_OBJ_TYPE_ALL == m_DST_stPara.nDetectGrayType) { if (ABS(pMax - pMean) >= ABS(pMin - pMean)) pPnt = pPntMax; else pPnt = pPntMin; } return pPnt; } /********************************************************** * 函数名称:DST_PipeTargetReDetect() * 功能描述:管道目标二次搜索 * 输入参数:UINT16 *pSrc -- 原始图像 * SINT32 nWidth -- 图像宽度 * SINT32 nHeight -- 图像高度 * POINT32F ptPipeCenPos -- 管道目标在当前帧的中心坐标 * SPEED32F sfPipeSpeed -- 管道目标速度 * MINMAXRECT mrnSrRect -- 搜索区域边界 * FLOAT32 fgdk -- SNR阈值 * TARGET_OBJECT *ptTargetArray-- 当前帧目标检测结果数组 * PIPE *pPipeArray -- 管道数组 * SINT32 *pnFrmObjsCnt -- 单帧检测目标个数 * 输出参数:TARGET_OBJECT *ptTarget -- 二次检测到的目标 * SINT32 *bPipeTargetIndex -- 管道在当前帧查找到的目标 * TARGET_OBJECT *ptTargetArray-- 当前帧目标检测结果数组 * SINT32 *pnFrmObjsCnt -- 单帧检测目标个数 * 返 回 值:1-二次检测找到目标,0-未检测到目标。 * 调用关系: * 其它说明:在前一帧管道中心区域,重新查找极大或极小值点。 **********************************************************/ BBOOL DetectSmallObj::DST_PipeTargetRReDetect(GD_VIDEO_FRAME_S img, SINT32 nWidth, SINT32 nHeight, POINT32F ptPipeCenPos, SPEED32F sfPipeSpeed, MINMAXRECT mrnSrRect, TARGET_OBJECT* ptTarget, TARGET_OBJECT* ptTargetArray, SINT32* pnFrmObjsCnt) { BBOOL bRefoundTarget; //标记管道目标二次搜索是否成功 SINT32 nBlkStart; //管道目标二次搜索时,中心区域的左上角起始坐标 POINT16S pnPipeSearchPoint; //管道目标二次搜索时,中心区域的极值点坐标 SINT32 nFrmObjsCnt; //当前帧目标个数 SINT32 nSrRadiusW; //宽方向搜索半径 SINT32 nSrRadiusH; //高方向搜索半径 SINT32 nSrWidth; //宽方向搜索直径 SINT32 nSrHeight; //高方向搜索直径 //初始化 bRefoundTarget = false; nFrmObjsCnt = (*pnFrmObjsCnt); nSrRadiusW = mrnSrRect.maxX - mrnSrRect.minX; nSrRadiusH = mrnSrRect.maxY - mrnSrRect.minY; POINT16S pBlkSecondMaxPnt = {0};//次极大值 //MSSu, 20150609: 防止越界 MINMAXRECT32S mrnRect; mrnRect.minX = ptPipeCenPos.x - nSrRadiusW; mrnRect.maxX = ptPipeCenPos.x + nSrRadiusW; mrnRect.minY = ptPipeCenPos.y - nSrRadiusH; mrnRect.maxY = ptPipeCenPos.y + nSrRadiusH; if ((mrnRect.minX < 0) || (mrnRect.maxX >= nWidth) || (mrnRect.minY < 0) || (mrnRect.maxY >= nHeight)) { return bRefoundTarget; } //获取管道中心区域图像起始位置 nBlkStart = mrnRect.minY * nWidth + mrnRect.minX; nSrWidth = (nSrRadiusW << 1) + 1; nSrHeight = (nSrRadiusH << 1) + 1; //查找块内极值:极大值或极小值 //MSSu, 20111115: 若m_DST_nDectectMinPnt==TRUE,则为查找块内极大或极小值 BYTE8 bMaxPntFalg = DST_BLK_MAX_PNT; //20161130,标记极大/极小 //pnPipeSearchPoint = DST_FindBlkExtremum(img, nWidth, nHeight, // nBlkStart, nSrRadiusW * 2 + 1, nSrRadiusH * 2 + 1, &bMaxPntFalg,&pBlkSecondMaxPnt); POINT16S pSecondMax; pnPipeSearchPoint = DST_FindBlk4Neighbor(img, nWidth, nHeight, nBlkStart, nSrWidth, nSrHeight, &pSecondMax); //三次检测前,关闭部分去虚警开关(需先保存关闭前的状态) SINT32 bUseDeFA_VarMax = m_DST_stPara.bUseDeFA_VarMax; SINT32 bUseDeFA_Size = m_DST_stPara.bUseDeFA_Size; SINT32 bUseDeFA_BGFACnt = m_DST_stPara.bUseDeFA_BGFACnt; SINT32 bUseDeFA_BTGrayMin = m_DST_stPara.bUseDeFA_BTGrayMin; SINT32 bUseDeFA_CenFlag = m_DST_stPara.bUseDeFA_CenFlag; SINT32 bUseDeFA_XYPrj = m_DST_stPara.bUseDeFA_XYPrj; m_DST_stPara.bUseDeFA_VarMax = FALSE; m_DST_stPara.bUseDeFA_Size = FALSE; m_DST_stPara.bUseDeFA_BGFACnt = FALSE; m_DST_stPara.bUseDeFA_BTGrayMin = FALSE; m_DST_stPara.bUseDeFA_CenFlag = FALSE; m_DST_stPara.bUseDeFA_XYPrj = FALSE; FLOAT32 fgdk = MIN(m_DST_stPara.fgdk / 2.0f, 2.0f); //若目标超出搜索区域,则不降低阈值再查找,让管道消失 if (mrnRect.minX < pnPipeSearchPoint.x && pnPipeSearchPoint.x < mrnRect.maxX && mrnRect.minY < pnPipeSearchPoint.y && pnPipeSearchPoint.y < mrnRect.maxY) { //若检测到目标,则重置管道待删除标记pPipe->bLost清零 memset(ptTarget, 0, sizeof(TARGET_OBJECT)); bRefoundTarget = DST_BlkMaxTargetDetect(img, nWidth, nHeight, pnPipeSearchPoint, m_DST_stPara.pnFilter, m_DST_stPara.nFilterBGW, m_DST_stPara.nFilterTGW, ptTarget, fgdk); ptTarget->nObjTypeSize = GLB_OBJ_SIZE_DIMSMALL; ptTarget->nObjTypeSrc = ObjSrc::Arith_DIM;//标记为弱目标 } //if (bRefoundTarget && (ABS(ptTarget->pfCenPos.x - m_GLB_stOutput.crnObjPrediRtLong.cx) > 10 // || ABS(ptTarget->pfCenPos.y - m_GLB_stOutput.crnObjPrediRtLong.cy) > 10)) //{ // bRefoundTarget = false; //} //将三次检测到的目标,加入单帧目标数组 if (bRefoundTarget) { //标记为目标,加入当前帧目标数组 ptTarget->bObject = true; // ptTarget->unFrmID = m_GLB_stInput.stParaLn.unFrmId; memcpy(&ptTargetArray[nFrmObjsCnt], ptTarget, sizeof(TARGET_OBJECT)); nFrmObjsCnt++; //更新当帧目标个数统计 (*pnFrmObjsCnt) = nFrmObjsCnt; } //三次检测后,还原去虚警开关(需先保存关闭前的状态) m_DST_stPara.bUseDeFA_VarMax = bUseDeFA_VarMax; m_DST_stPara.bUseDeFA_Size = bUseDeFA_Size; m_DST_stPara.bUseDeFA_BGFACnt = bUseDeFA_BGFACnt; m_DST_stPara.bUseDeFA_BTGrayMin = bUseDeFA_BTGrayMin; m_DST_stPara.bUseDeFA_CenFlag = bUseDeFA_CenFlag; m_DST_stPara.bUseDeFA_XYPrj = bUseDeFA_XYPrj; return bRefoundTarget; } POINT16S * DetectSmallObj::getMaxPoint() { return DST_pBlkMaxPoint; } /********************************************************** * 函数名称:DST_CalObjSNR_UINT16() * 功能描述:计算目标SNR * 输入参数:UINT16 *pFrame -- 原始图像 * SINT32 nWidth -- 图像宽度 * SINT32 nHeight -- 图像高度 * POINT16S pPnt -- 目标坐标 * 输出参数:OBJECTSNR *objSNR -- 目标SNR信息 * 返 回 值:无 * 调用关系:无 * 其它说明:DSP不移植 **********************************************************/ void DetectSmallObj::DST_CalObjSNR_UINT16(UINT16* pFrame, SINT32 nWidth, SINT32 nHeight, POINT16S pPnt, OBJECTSNR* objSNR) { SINT32 i, j; SINT32 nFilterBGW; //极大值滤波窗口 - 背景核区域大小,目标核区域大小 SINT32 nBGRadius, nTGRadius; //背景模板半径、目标模板半径 SINT32 nBGIndex, nBGFlter; //背景模板下标、背景模板系数 SINT32 nImgIndex; //背景点/邻域点对应的原始图像坐标 SINT32 nBGValue, nBGCnt; //背景点灰度、背景点计数 double dBGMean, dBGStd; //背景均值、方差 SINT32 nCenterValue; //中心点pPnt的灰度 FLOAT32 fBGStdOutput; //背景方差 -- 用于显示,没有经过下限限制 SINT32* pnFilter = (SINT32*)m_DST_stPara.pnFilter; MINMAXRECT mmBGRect; //目标、背景窗口边界 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++ //参数设置 nFilterBGW = m_DST_stPara.nFilterBGW; nBGRadius = (SINT32)(nFilterBGW >> 1); nTGRadius = (SINT32)(DST_KERNAL_SIZE_Tm_9 >> 1); //+++++++++++++++++++++++++++++++++++++++++++++++++++++++ //获取中心点灰度值 nCenterValue = pFrame[pPnt.y * nWidth + pPnt.x]; //+++++++++++++++++++++++++++++++++++++++++++++++++++++++ //统计背景均值、方差 //计算背景窗口边界 mmBGRect.minX = pPnt.x - nBGRadius; mmBGRect.maxX = pPnt.x + nBGRadius; mmBGRect.minY = pPnt.y - nBGRadius; mmBGRect.maxY = pPnt.y + nBGRadius; //防止越界 if (mmBGRect.minX<0 || mmBGRect.maxX>nWidth - 1 || mmBGRect.minY<0 || mmBGRect.maxY>nHeight - 1) { memset(objSNR, 0, sizeof(OBJECTSNR)); return; } //统计背景均值、方差 nBGCnt = 0; dBGMean = 0; dBGStd = 0; //小目标检测:在原图上计算背景均值、背景标准差 SINT32 nBGLine = 0; SINT32 nImgLine = mmBGRect.minY * nWidth + mmBGRect.minX; for (i = 0; i < nFilterBGW; i++) { for (j = 0; j < nFilterBGW; j++) { nBGIndex = nBGLine + j; nImgIndex = nImgLine + j; nBGFlter = pnFilter[nBGIndex]; nBGValue = pFrame[nImgIndex]; if (1 == nBGFlter) { //背景灰度及灰度平方累加 nBGCnt++; dBGMean += (double)nBGValue; dBGStd += (double)nBGValue * nBGValue; } } //更新行起始坐标 nBGLine += nFilterBGW; nImgLine += nWidth; } dBGMean /= nBGCnt; dBGStd /= nBGCnt; dBGStd -= dBGMean * dBGMean; //保存计算的背景均值及方差 fBGStdOutput = (FLOAT32)dBGStd; //设置背景方差下限 if (m_DST_stPara.bUseDeFA_VarMin //去虚警策略“邻域方差下限限制”的开关 && dBGStd < m_DST_stPara.fKernalBGStdMin) //判断邻域方差是否小于下限限制。 { dBGStd = (double)m_DST_stPara.fKernalBGStdMin * m_DST_stPara.fKernalBGStdMin; } //保存目标SNR信息 objSNR->Pnt = pPnt; objSNR->nTGR = (SINT16)(nTGRadius); objSNR->nBGR = (SINT16)(nBGRadius); objSNR->ObjGray = (FLOAT32)nCenterValue; objSNR->BGMean = (FLOAT32)dBGMean; objSNR->BGStd = (FLOAT32)sqrt(dBGStd); objSNR->fSNR = (dBGStd < 0.01) ? 1e6f : (FLOAT32)((nCenterValue - dBGMean) / sqrt(dBGStd)); } /********************************************************** * 函数名称:DST_DetectDimTarget_BFilter() * 功能描述:基于分块极值的弱小目标检测(基于双边滤波的方法) * 输入参数:UINT16 *pSrc -- 原始图像 * SINT32 nWidth -- 图像宽度 * SINT32 nHeight -- 图像高度 * 输出参数:无 * 返 回 值:ubSuccessFlag跟踪成功标志位 * 调用关系: * 其它说明:在低频图上计算背景均值,在高频图上计算噪声标准差。 **********************************************************/ UBYTE8 DetectSmallObj::DST_DetectDimTarget_BF(GD_VIDEO_FRAME_S img, SINT32 nWidth, SINT32 nHeight) { //指向DSP数据空间 UINT16* pxSrImg = (UINT16*)m_DST_stOutput.pxSrImg; TARGET_OBJECT* ptDimTargets = (TARGET_OBJECT*)DST_DimTarget; POINT16S* pDimBlkMaxPnt = (POINT16S*)DST_pDimBlkMaxPoint; SINT32* pBlkPtBeTargetFlag = (SINT32*)DST_pBlkPtBeTargetFlag; SINT16* pDimBFHighImg = (SINT16*)DST_pDimBFHighImg; //搜索区域双边滤波高频 UINT16* pDimBFLowImg = (UINT16*)DST_pDimBFLowImg; //搜索区域双边滤波低频 BYTE8* pbBlkMaxPntFlag = (BYTE8*)DST_pBlkMaxPntFlag; //20161130 //局部变量 UBYTE8 ubObjsCnt = 0; //截获区域目标个数 SINT32 nSrRadiusW, nSrRadiusH; //截获区域半径 SIZE32S snImgSize; //截获区域图像尺寸 CENTERRECT crnSrRect; //半自动截获搜索区域中心矩形 MINMAXRECT mmnSrRect; //半自动截获搜索区域边界矩形 SINT32 nBlkWidth, nBlkHeight; //分块宽度、高度 SINT32 nBlkNumW, nBlkNumH; //宽、高方向分块个数 SINT32 nBlkWidthMin; //最小分块宽度 SINT32 nSmpScale = 1; //降采样倍数 MINMAXRECT32S mmnSrSmpRect; //搜索区域边界矩形,MINMAXRECT32S格式 SIZE32S snSmpImgSize; //降采样图像尺寸 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++ //初始化算法输出结果 DST_CleanUpFrameDimDetectOutput(); m_DST_stPara.bDimDetecting = true; //+++++++++++++++++++++++++++++++++++++++++++++++++++++++ //获取弱小目标搜索区域 //以锁定点位置为中心 crnSrRect.cx = m_DST_stInput.crnSemiSrRect.cx; crnSrRect.cy = m_DST_stInput.crnSemiSrRect.cy; //根据参考区域大小调整降采样倍数和大小 if ((m_DST_stInput.crnSemiSrRect.w >> 1) < 33) { nSmpScale = 1; } else { nSmpScale = 2; } m_DST_stOutput.nDimSmpScale = nSmpScale; //以所设置的锁定波门宽高设定半径,并设定上下限 nSrRadiusW = MIN(m_DST_stInput.crnSemiSrRect.w >> 1, DST_DIMOBJ_RADIUS_MAX); nSrRadiusW = MIN(MAX(nSrRadiusW, DST_DIMOBJ_RADIUS_MIN), DST_DIMOBJ_RADIUS_MAX); nSrRadiusH = MIN(m_DST_stInput.crnSemiSrRect.h >> 1, DST_DIMOBJ_RADIUS_MAX); nSrRadiusH = MIN(MAX(nSrRadiusH, DST_DIMOBJ_RADIUS_MIN), DST_DIMOBJ_RADIUS_MAX); crnSrRect.w = (nSrRadiusW << 1) + 1; crnSrRect.h = (nSrRadiusH << 1) + 1; crnSrRect.s = crnSrRect.w * crnSrRect.h; //计算获取弱小目标搜索区域边界矩形:防越界。 mmnSrRect.minX = MAX(0, MIN(crnSrRect.cx - nSrRadiusW, nWidth - 1)); mmnSrRect.minY = MAX(0, MIN(crnSrRect.cy - nSrRadiusH, nHeight - 1)); mmnSrRect.maxX = MAX(0, MIN(crnSrRect.cx + nSrRadiusW, nWidth - 1)); mmnSrRect.maxY = MAX(0, MIN(crnSrRect.cy + nSrRadiusH, nHeight - 1)); m_DST_stInput.mmnSemiSrRect = mmnSrRect; mmnSrSmpRect.minX = mmnSrRect.minX; mmnSrSmpRect.maxX = mmnSrRect.maxX; mmnSrSmpRect.minY = mmnSrRect.minY; mmnSrSmpRect.maxY = mmnSrRect.maxY; //边界限制后,重新更新搜索区域中心矩形 crnSrRect.cx = (mmnSrRect.minX + mmnSrRect.maxX) >> 1; crnSrRect.cy = (mmnSrRect.minY + mmnSrRect.maxY) >> 1; crnSrRect.w = mmnSrRect.maxX - mmnSrRect.minX + 1; crnSrRect.h = mmnSrRect.maxY - mmnSrRect.minY + 1; crnSrRect.s = crnSrRect.w * crnSrRect.h; m_DST_stInput.crnSemiSrRect = crnSrRect; //计算搜索区域图像尺寸 snImgSize.w = crnSrRect.w; snImgSize.h = crnSrRect.h; snImgSize.s = snImgSize.w * snImgSize.h; m_DST_stOutput.snDimSrImgSize = snImgSize; //计算降采样图像尺寸 if (2 == nSmpScale) { snSmpImgSize.w = (crnSrRect.w + 1) / nSmpScale; snSmpImgSize.h = (crnSrRect.h + 1) / nSmpScale; snSmpImgSize.s = snSmpImgSize.w * snSmpImgSize.h; } else { snSmpImgSize.w = crnSrRect.w; snSmpImgSize.h = crnSrRect.h; snSmpImgSize.s = snSmpImgSize.w * snSmpImgSize.h; } m_DST_stOutput.snDimSrSmpImgSize = snSmpImgSize; //设置分块大小及分块个数:因强制检测针对的是弱小目标,故分块大小默认设置为4 //20170314,:弱目标检测不调高降采样后的分块大小,以免未被判为极值点 nBlkWidthMin = MAX((SINT32)(sqrt((double)(snImgSize.s) / DST_DIMOBJ_BLK_NUM) + 0.5), 1); nBlkWidth = MAX(8, nBlkWidthMin); nBlkWidth = MIN(nBlkWidth, 16); nBlkHeight = nBlkWidth; //降采样图像的分块宽高调整为16 if (2 == nSmpScale) { nBlkWidth = 16; nBlkHeight = 16; } nBlkNumW = snImgSize.w / nBlkWidth; nBlkNumH = snImgSize.h / nBlkHeight; //+++++++++++++++++++++++++++++++++++++++++++++++++++++++ //获取弱小目标检测区域图像或降采样图像 if (2 == nSmpScale) { IMGO_GDSGetSubMMRect2DownSample(img, nWidth, nHeight, pxSrImg, mmnSrSmpRect, 0); } else { IMGO_GDSGetSubMMRect(img, pxSrImg, (SINT16)nWidth, (SINT16)nHeight, mmnSrRect); } m_DST_stOutput.nDimFrmsCnt++; //+++++++++++++++++++++++++++++++++++++++++++++++++++++++ ////弱小目标检测算法未开启,则不执行后面的分块检测 //if (!m_GLB_bEanbleDimDetect) //{ // //20170311:清空正在检测弱小目标的标记,防错 // m_DST_stPara.bDimDetecting = false; // return ubObjsCnt; //} //+++++++++++++++++++++++++++++++++++++++++++++++++++++++ //计算弱小目标检测区域低频图、高频图--双边滤波 DST_BilateralFilterInt(pxSrImg, snSmpImgSize.w, snSmpImgSize.h, pDimBFLowImg, pDimBFHighImg); //小目标检测 DST_FindExtremum(img, nWidth, nHeight, pDimBlkMaxPnt, pbBlkMaxPntFlag, mmnSrRect.minY, mmnSrRect.minX, nBlkWidth, nBlkHeight, nBlkNumW, nBlkNumH); //判断极大值点是否为目标 ubObjsCnt = DST_DetectFrameTarget(img, nWidth, nHeight, ptDimTargets, DST_DIMOBJ_BLK_NUM, pDimBlkMaxPnt, nBlkNumW, nBlkNumH, pBlkPtBeTargetFlag); //弱小目标检测时,采用恒虚警处理 ubObjsCnt = DST_FixedFADetect(ptDimTargets, ubObjsCnt, DST_DIMOBJ_BLK_NUM); //更新弱小目标个数 m_DST_stOutput.nFrmDimObjsCnt = ubObjsCnt; //关闭弱小目标检测 m_DST_stPara.bDimDetecting = false; return ubObjsCnt; } /********************************************************** * 函数名称:DST_BilateralFilterInt() * 功能描述:恒虚警算法 * 输入参数:ptTargetArray -- 目标数组 * 输出参数:无 * 返 回 值:ubObjsCnt -- 目标个数 * 调用关系:无 * 其它说明:无 **********************************************************/ SINT32 DetectSmallObj::DST_FixedFADetect(TARGET_OBJECT* ptTargetArray, SINT32 ubObjsCnt, SINT32 nTargetNumMax) { SINT32 i; SINT32 NumSNRMax = 0; //信噪比超过15的目标计数 SINT32 NumSNRLarger = 0; //信噪比超过5且小于15的目标计数 SINT32 NumSNRSmaller = 0; //信噪比不足5的目标计数 //SO_BubbleSort_TargetSNR(ptTargetArray, ubObjsCnt); for (i = 0; i < ubObjsCnt; i++) { TARGET_OBJECT target = ptTargetArray[i]; if (target.bObject && target.fSNR >= 10) { NumSNRMax++; } else if (target.bObject && target.fSNR >= 5) { NumSNRLarger++; } else if (target.bObject) { NumSNRSmaller++; } else { //不处理; } } //若SNR≥5的目标个数大于阈值,关闭恒虚警检测 if ((NumSNRLarger >= 2) || (NumSNRMax >= 1)) { //m_GLB_stPara.nNoTargetFrameCnt = 0; //20171013,强制提取时 if ((NumSNRLarger + NumSNRMax) > DST_FA_GUIDE_TARGET_NUM) { ubObjsCnt = DST_FA_GUIDE_TARGET_NUM; } else { ubObjsCnt = NumSNRLarger + NumSNRMax; } } else if ((NumSNRLarger + NumSNRSmaller) >= DST_FA_GUIDE_TARGET_NUM) { ubObjsCnt = DST_FA_GUIDE_TARGET_NUM; } else { ubObjsCnt = NumSNRSmaller + NumSNRLarger; } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++ //恒虚警算法关闭条件 if (!m_DST_stPara.bDimDetecting) { if ((NumSNRLarger >= 1) || (NumSNRMax >= 1)) { //退出恒虚警帧计数器累加 //m_GLB_nExitFixedFA++; m_DST_stOutput.nExitFixedFA++; m_DST_stOutput.nExitFixedFA = MIN(m_DST_stOutput.nExitFixedFA, 65535); //防止数据溢出 } else { //清空退出恒虚警帧计数器 m_DST_stOutput.nExitFixedFA = 0; } //20170524,连续5帧满足条件,关闭恒虚警开关 if (m_DST_stOutput.nExitFixedFA >= 5) { m_DST_stOutput.nExitFixedFA = 0; //m_GLB_stPara.bEnableFixedFADetect = false; //m_GLB_bEanbleDimDetect = false; } } //memset(&ptTargetArray[ubObjsCnt], 0, sizeof(TARGET_OBJECT) * (nTargetNumMax - ubObjsCnt)); return ubObjsCnt; } /********************************************************** * 函数名称:DST_BlkMaxTargetDetect() * 功能描述:判断极大值区域是否为目标 * 输入参数:UINT16 *pFrame -- 原始图像 * SINT32 nWidth -- 图像宽度 * SINT32 nHeight -- 图像高度 * POINT16S pPnt -- 极值点坐标 * SINT32 *pnFilter -- 目标背景模板 * SINT32 nFilterBGW -- 目标背景模板 - 背景宽度 * SINT32 nFilterTGW -- 目标背景模板 - 目标宽度 * FLOAT32 fgdk -- 目标SNR阈值 * 输出参数:TARGET_OBJECT *tTarget -- 当前目标结构体 * 返 回 值:1-该极值点是目标,0-该极值点不是目标。 * 调用关系:无 * 其它说明:无 **********************************************************/ BBOOL DetectSmallObj::DST_BlkMaxTargetDetect(GD_VIDEO_FRAME_S img, SINT32 nWidth, SINT32 nHeight, POINT16S pPnt, SINT32* pnFilter, SINT32 nFilterBGW, SINT32 nFilterTGW, TARGET_OBJECT* ptTarget, FLOAT32 fgdk) { //指向数据空间: 标记检测到的目标像素点。0-非目标点,1-目标点。 SINT32* pnBlkTargetFlag = (SINT32*)DST_pnBlkTargetFlag; SINT32 i, j; BBOOL bIsTarget = false; //标记该极值点是否为目标 SINT32 nBGRadius = 0; //背景模板半径 SINT32 nTGRadius = 0; //目标模板半径 MINMAXRECT mmTGRect = { 0 }; //目标窗口边界 MINMAXRECT mmBGRect = { 0 }; //背景窗口边界 SINT32 nBGIndex = 0; //背景模板下标 SINT32 nBGFlter = 0; //背景模板系数 SINT32 nImgIndex = 0; //背景点/邻域点对应的原始图像坐标 SINT32 nBGValue = 0; //背景点灰度 SINT32 nBGCnt = 0; //背景点计数 double dBGMean = 0.0f; //背景均值 double dBGStd = 0.0f; //背景方差 SINT32 nCenterValue = 0; //中心点pPnt的灰度 SINT32 nPntValue = 0; //目标模板内像素的灰度值 FLOAT32 fBGStdOutput = 0.0f; //背景方差 -- 用于显示,没有经过下限限制 BBOOL bTargetPixel = false; //标记某像素点是否属于目标。用于统计目标大小。 FLOAT32 fgdkCoeff = 0.0f; //gdk下降系数。用于统计目标大小。 SINT32 nObjWH_LineW = 0; //目标宽高比统计 - 每行宽度 SINT32 nObjWH_LineWMax = 0; //目标宽高比统计 - 行宽度的最大值 FLOAT32 fPntgdk = 0.0f; //各点的gdk系数 SINT32 nTGValue = 0; //目标点灰度 SINT32 nCenterValueSumX = 0; //目标点灰度-X坐标乘积累加、目标点灰度-Y坐标乘积累加 SINT32 nCenterValueSumY = 0; //目标点灰度-X坐标乘积累加、目标点灰度-Y坐标乘积累加 SINT32 nValueDiff = 0; //背景点与中心点的灰度差值 SINT32 nValueDiffMin = 0; //背景点与中心点的灰度差的最小值 FLOAT32 fWHRatio = 0.0f; //目标宽高比 FLOAT32 fRectRatio = 0.0f; //目标矩形度 SINT32 nObjCenX = 0; //目标形心X、Y坐标 SINT32 nObjCenY = 0; //目标形心X、Y坐标 FLOAT32 fKernalBGVarMin2 = 0.0f; //背景方差下限阈值(可调参数-标准差下限的平方) FLOAT32 fKernalBGVarMax2 = 0.0f; //背景方差上限阈值(可调参数-标准差上限的平方) SINT32 nDimSmpScale = 1; //弱小检测搜索区域降采样倍数 SIZE32S snDimSrSmpImgSize = { 0 }; //弱小检测搜索区域尺寸:未降采样维持原尺寸,否则为降采样后尺寸 SINT32 nBGCntArray[4] = { 0 }; //20180115,记录上下左右邻域背景点个数 DOUBLE64 dBGMeanArray[4] = { 0.0f }; //20180115,记录上下左右邻域背景均值 DOUBLE64 dBGStdArray[4] = { 0.0f }; //20180115,记录上下左右邻域背景标准差 SINT32 nBGOuterRadius = 0; //20180115,回字形的外半径 SINT32 nMaxStdIndex = 0; //20180115,std最大的背景块下标 DOUBLE64 bBGStdMax = -1.0f; //20180115,方差最大的块 POINT16S pMaxPnt = pPnt; //20180918,极值点坐标 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++ //初始化 bIsTarget = false; nValueDiffMin = (SINT32)1e6; memset(ptTarget, 0, sizeof(TARGET_OBJECT)); //+++++++++++++++++++++++++++++++++++++++++++++++++++++++ //参数设置 fgdkCoeff = 0.7f; fKernalBGVarMin2 = m_DST_stPara.fKernalBGStdMin * m_DST_stPara.fKernalBGStdMin; fKernalBGVarMax2 = m_DST_stPara.fKernalBGStdMax * m_DST_stPara.fKernalBGStdMax; nBGRadius = (SINT32)(nFilterBGW >> 1); nTGRadius = (SINT32)(nFilterTGW >> 1); nBGOuterRadius = nBGRadius - nTGRadius; //20180115,回字形的外半径 nDimSmpScale = m_DST_stOutput.nDimSmpScale; snDimSrSmpImgSize.w = (2 == nDimSmpScale) ? (m_DST_stOutput.snDimSrImgSize.w / nDimSmpScale + 1) : m_DST_stOutput.snDimSrImgSize.w; snDimSrSmpImgSize.h = (2 == nDimSmpScale) ? (m_DST_stOutput.snDimSrImgSize.h / nDimSmpScale + 1) : m_DST_stOutput.snDimSrImgSize.h; snDimSrSmpImgSize.s = snDimSrSmpImgSize.w * snDimSrSmpImgSize.h; //+++++++++++++++++++++++++++++++++++++++++++++++++++++++ //获取中心点灰度值 //nCenterValue = pFrame[pPnt.y * nWidth + pPnt.x]; if (GD_PIXEL_FORMAT_GRAY_Y8 == img.enPixelFormat) { nCenterValue = ((UBYTE8*)img.u64VirAddr[0])[pPnt.y * nWidth + pPnt.x]; } else { nCenterValue = ((UINT16*)img.u64VirAddr[0])[pPnt.y * nWidth + pPnt.x]; } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++ //统计背景均值、方差 //计算背景窗口边界 if (m_DST_stPara.bDimDetecting && (m_DST_stOutput.nDimSmpScale > 1)) { SINT32 nBGRadiusRaw = nBGRadius * m_DST_stOutput.nDimSmpScale; mmBGRect.minX = pPnt.x - nBGRadiusRaw; mmBGRect.maxX = pPnt.x + nBGRadiusRaw; mmBGRect.minY = pPnt.y - nBGRadiusRaw; mmBGRect.maxY = pPnt.y + nBGRadiusRaw; } else { mmBGRect.minX = pPnt.x - nBGRadius; mmBGRect.maxX = pPnt.x + nBGRadius; mmBGRect.minY = pPnt.y - nBGRadius; mmBGRect.maxY = pPnt.y + nBGRadius; } //防止越界 if (mmBGRect.minX<0 || mmBGRect.maxX>nWidth - 1 || mmBGRect.minY<0 || mmBGRect.maxY>nHeight - 1) { return false; } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++ //统计背景均值、方差 nBGCnt = 0; dBGMean = 0; dBGStd = 0; SINT32 nDiffMinBkgCnt = 0; //基于双边滤波的弱目标检测:在低频图上计算背景均值,在高频图上计算背景标准差 if (!m_DST_stPara.bDimDetecting /*|| m_GLB_stPara.bEnableFixedFADetect*/) { SINT32 nBGLine = 0; SINT32 nImgLine = mmBGRect.minY * nWidth + mmBGRect.minX; for (i = 0; i < nFilterBGW; i++) { for (j = 0; j < nFilterBGW; j++) { nBGIndex = nBGLine + j; nImgIndex = nImgLine + j; nBGFlter = pnFilter[nBGIndex]; //nBGValue = pFrame[nImgIndex]; if (GD_PIXEL_FORMAT_GRAY_Y8 == img.enPixelFormat) { nBGValue = ((UBYTE8*)img.u64VirAddr[0])[nImgIndex]; } else { nBGValue = ((UINT16*)img.u64VirAddr[0])[nImgIndex]; } if (1 == nBGFlter) { //按上下左右顺序存邻域背景参数 if (j < nBGOuterRadius) { nBGCntArray[0]++; dBGMeanArray[0] += (double)nBGValue; dBGStdArray[0] += (double)nBGValue * nBGValue; } else if (j >= nFilterTGW + nBGOuterRadius) { nBGCntArray[1]++; dBGMeanArray[1] += (double)nBGValue; dBGStdArray[1] += (double)nBGValue * nBGValue; } else { //左邻域 if (i < nBGOuterRadius) { nBGCntArray[2]++; dBGMeanArray[2] += (double)nBGValue; dBGStdArray[2] += (double)nBGValue * nBGValue; } else { nBGCntArray[3]++; dBGMeanArray[3] += (double)nBGValue; dBGStdArray[3] += (double)nBGValue * nBGValue; } } //查找背景中与中心点灰度差异最小的点的灰度 nValueDiff = ABS(nBGValue - nCenterValue); if (nValueDiff < nValueDiffMin) { nValueDiffMin = nValueDiff; } } } //更新行起始坐标 nBGLine += nFilterBGW; nImgLine += nWidth; } //计算4邻域的均值与方差 for (i = 0; i < 4; i++) { nBGCnt += nBGCntArray[i]; dBGMean += dBGMeanArray[i]; dBGStd += dBGStdArray[i]; dBGMeanArray[i] /= nBGCntArray[i]; dBGStdArray[i] /= nBGCntArray[i]; dBGStdArray[i] -= dBGMeanArray[i] * dBGMeanArray[i]; //找到方差最大的块 if (dBGStdArray[i] > bBGStdMax) { bBGStdMax = dBGStdArray[i]; nMaxStdIndex = i; } } //抛掉方差最大的块 nBGCnt -= nBGCntArray[nMaxStdIndex]; dBGMean -= (dBGMeanArray[nMaxStdIndex] * nBGCntArray[nMaxStdIndex]); dBGStd -= (nBGCntArray[nMaxStdIndex] * (dBGStdArray[nMaxStdIndex] + dBGMeanArray[nMaxStdIndex] * dBGMeanArray[nMaxStdIndex])); dBGMean /= nBGCnt; dBGStd /= nBGCnt; dBGStd -= dBGMean * dBGMean; } else { //防止越界 if ((mmBGRect.minX < m_DST_stInput.mmnSemiSrRect.minX) || (mmBGRect.maxX > m_DST_stInput.mmnSemiSrRect.maxX) || (mmBGRect.minY < m_DST_stInput.mmnSemiSrRect.minY) || (mmBGRect.maxY > m_DST_stInput.mmnSemiSrRect.maxY)) { return false; } SINT32 nBGLine = 0; SINT32 nImgLine = ((mmBGRect.minY - m_DST_stInput.mmnSemiSrRect.minY) / nDimSmpScale) * snDimSrSmpImgSize.w + (mmBGRect.minX - m_DST_stInput.mmnSemiSrRect.minX) / nDimSmpScale; SINT32 nBGValueLow = 0; double dBGMeanLow = 0; double dBGStdLow = 0; SINT32 nBGValueHigh = 0; double dBGMeanHigh = 0; double dBGStdHigh = 0; UINT16* pDimBFLowImg = (UINT16*)DST_pDimBFLowImg; //搜索区域双边滤波低频 SINT16* pDimBFHighImg = (SINT16*)DST_pDimBFHighImg; //搜索区域双边滤波高频 for (i = 0; i < nFilterBGW; i++) { for (j = 0; j < nFilterBGW; j++) { nBGIndex = nBGLine + j; nImgIndex = nImgLine + j; nBGFlter = pnFilter[nBGIndex]; nBGValueLow = pDimBFLowImg[nImgIndex]; nBGValueHigh = pDimBFHighImg[nImgIndex]; if (1 == nBGFlter) { //背景灰度及灰度平方累加 nBGCnt++; dBGMeanLow += (double)nBGValueLow; dBGStdLow += (double)nBGValueLow * nBGValueLow; dBGMeanHigh += (double)nBGValueHigh; dBGStdHigh += (double)nBGValueHigh * nBGValueHigh; //查找背景中与中心点灰度差异最小的点的灰度 nValueDiff = ABS(nBGValueLow - nCenterValue); // add 新增统计灰度差小于阈值的背景点数 if (nValueDiff < m_DST_stPara.nBTGrayMinThres) { nDiffMinBkgCnt++; } if (nValueDiff < nValueDiffMin) { nValueDiffMin = nValueDiff; } } } //更新行起始坐标 nBGLine += nFilterBGW; nImgLine += snDimSrSmpImgSize.w; } //低频均值、方差 dBGMeanLow /= nBGCnt; dBGStdLow /= nBGCnt; dBGStdLow -= dBGMeanLow * dBGMeanLow; //高频均值、方差 dBGMeanHigh /= nBGCnt; dBGStdHigh /= nBGCnt; dBGStdHigh -= dBGMeanHigh * dBGMeanHigh; //背景均值、方差 dBGMean = dBGMeanLow; dBGStd = dBGStdHigh; } //保存计算的背景均值及方差 fBGStdOutput = (FLOAT32)dBGStd; //+++++++++++++++++++++++++++++++++++++++++++++++++++++++ //抛掉方差过大的块 if (m_DST_stPara.bUseDeFA_VarMax //去虚警策略“邻域方差上限限制”的开关 && dBGStd > fKernalBGVarMax2) //判断邻域方差是否大于上限限制。 return false; //设置背景方差下限 if (m_DST_stPara.bUseDeFA_VarMin //去虚警策略“邻域方差下限限制”的开关 && !m_DST_stPara.bDimDetecting && !m_DST_stPara.bSecDetecting && dBGStd < fKernalBGVarMin2) //背景方差下限修改,20190508 { dBGStd = (double)fKernalBGVarMin2; } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++ //gdk不做自适应调节,直接赋给PC机传入的可调参数m_DST_stPara.fgdk fPntgdk = fgdk; //20160409: 基于双边滤波的弱目标检测,提高阈值 //20170311: 针对阿拉善试验对S-200探测距离不足,降低弱目标检测阈值。 if (m_DST_stPara.bDimDetecting) { fPntgdk = MAX(2.0f, fgdk - 2.0f); } //else if (m_GLB_stPara.bEnableFixedFADetect) //{ // fPntgdk = MAX(2.0f, fgdk - 5.0f); //} else { //不处理 } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++ //目标检测初始化 //计算目标核边界 if (m_DST_stPara.bDimDetecting && (m_DST_stOutput.nDimSmpScale > 1)) { SINT32 nTGRadiusRaw = nTGRadius * m_DST_stOutput.nDimSmpScale; mmTGRect.minX = pPnt.x - nTGRadiusRaw; mmTGRect.maxX = pPnt.x + nTGRadiusRaw; mmTGRect.minY = pPnt.y - nTGRadiusRaw; mmTGRect.maxY = pPnt.y + nTGRadiusRaw; nTGRadius = nTGRadius * m_DST_stOutput.nDimSmpScale; nFilterTGW = (nTGRadius << 1) + 1; } else { mmTGRect.minX = pPnt.x - nTGRadius; mmTGRect.maxX = pPnt.x + nTGRadius; mmTGRect.minY = pPnt.y - nTGRadius; mmTGRect.maxY = pPnt.y + nTGRadius; } //初始化 ptTarget->mrnRect.minY = mmTGRect.maxY; ptTarget->mrnRect.maxY = mmTGRect.minY; ptTarget->mrnRect.minX = mmTGRect.maxX; ptTarget->mrnRect.maxX = mmTGRect.minX; nCenterValueSumX = 0; nCenterValueSumY = 0; nTGValue = 0; //记录目标的类型 ptTarget->nObjTypeGray = (nCenterValue < (SINT32)dBGMean) ? GLB_OBJ_GRAY_DARK : GLB_OBJ_GRAY_BRIGHT; //20120304:根据系统所要检测的目标类型进行区分 if (DST_DETECT_OBJ_TYPE_DARK == m_DST_stPara.nDetectGrayType) //只检测暗目标 { //20120229: 剔除亮目标。根据夜晚试验气球为暗目标的特性,做出目标类型的限制。 if (GLB_OBJ_GRAY_BRIGHT == ptTarget->nObjTypeGray) return FALSE; } else if (DST_DETECT_OBJ_TYPE_BRIGHT == m_DST_stPara.nDetectGrayType) //只检测亮目标 { //跳过暗目标 if (GLB_OBJ_GRAY_DARK == ptTarget->nObjTypeGray) return FALSE; } else { //不处理 } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++ //提前计算参数,简化计算 double fPntgdkByStd = fPntgdk * fPntgdk * dBGStd; //+++++++++++++++++++++++++++++++++++++++++++++++++++++++ //目标检测:基于目标信噪比的检测方法 //首先判断极值点是否为目标 //20111115: 若m_DST_nDectectMinPnt==TRUE,则为判断极大值点或极小值点是否为目标 //若极值点不满足SNR条件,则判断该点是否满足灰度阈值判断的条件 if ((nCenterValue - dBGMean) * (nCenterValue - dBGMean) <= fPntgdkByStd) { //标记该点不是目标,直接返回 return false; } //若极值点是目标,则统计目标的大小 else { //标记该点为目标 bIsTarget = true; //去虚警:抛掉方差过大的块 if (m_DST_stPara.bUseDeFA_VarMax && dBGStd > m_DST_stPara.fKernalBGStdMax) { bIsTarget = false; } //去虚警:抛掉极值点与背景最小灰度差小于阈值的块 SINT32 nBTGrayMinThres = m_DST_stPara.nBTGrayMinThres; if (m_DST_stPara.bDimDetecting) { nBTGrayMinThres = 3; m_DST_stPara.bUseDeFA_BTGrayMin = false; } if (m_DST_stPara.bUseDeFA_BTGrayMin && nValueDiffMin < nBTGrayMinThres && nDiffMinBkgCnt > nBGCnt * 0.3) { bIsTarget = false; } //若该点不是目标,则跳过剩余计算 if (!bIsTarget) { return false; } //降低gdk阈值统计目标大小 fPntgdk *= fgdkCoeff; fPntgdk = MAX(fPntgdk, 4.0f); //20170313,二次检测降低阈值 if (m_DST_stPara.bSecDetecting && m_DST_stPara.bEnableSecDetect) { fPntgdk = MAX(fPntgdk, 2.0f); } //20160409: 基于双边滤波的弱目标检测,提高阈值 if (m_DST_stPara.bDimDetecting) { fPntgdk = (float)(sqrt((nCenterValue - dBGMean) * (nCenterValue - dBGMean) / MAX(dBGStd, 0.01))); fPntgdk = MAX(5.0f, fPntgdk * 0.9f); } //提前计算参数,简化计算 double fPntgdkByStdNew = fPntgdk * fPntgdk * dBGStd; //搜索目标边界 nObjWH_LineWMax = 0; SINT32 nLine = (pPnt.y - nTGRadius) * nWidth + pPnt.x - nTGRadius; SINT32 nFlagLine = 0; SINT32 nFlagIndex = 0; for (i = 0; i < nFilterTGW; i++) { //初始化每行宽度 nObjWH_LineW = 0; for (j = 0; j < nFilterTGW; j++) { //获取目标区域各点的图像坐标 nImgIndex = nLine + j; //获取目标区域各点灰度值 //nPntValue = pFrame[nImgIndex]; if (GD_PIXEL_FORMAT_GRAY_Y8 == img.enPixelFormat) { nPntValue = ((UBYTE8*)img.u64VirAddr[0])[nImgIndex]; } else { nPntValue = ((UINT16*)img.u64VirAddr[0])[nImgIndex]; } //提前计算参数,简化计算 double dValueDiff = nPntValue - dBGMean; double dValueDiffSquare = dValueDiff * dValueDiff; //判断该点是否属于目标点(采用SNR判断方法) //20180918,应根据当前点的目标灰度类型判别 bTargetPixel = false; if ((i == j && i == nTGRadius) || (DST_DETECT_OBJ_TYPE_BRIGHT == ptTarget->nObjTypeGray && nPntValue > dBGMean && dValueDiffSquare > fPntgdkByStdNew) || (DST_DETECT_OBJ_TYPE_DARK == ptTarget->nObjTypeGray && nPntValue < dBGMean && dValueDiffSquare > fPntgdkByStdNew)) { bTargetPixel = true; //20170330,对于弱小目标认为是孤立点,不再遍历邻域区域 if ((m_DST_stPara.bSecDetecting || m_DST_stPara.bDimDetecting) && !(i == j && i == nTGRadius)) { bTargetPixel = false; } } //查找目标边界,并统计大小 if (bTargetPixel) { //统计行宽 nObjWH_LineW++; //查找目标边界 SINT32 nImgX = j + mmTGRect.minX; SINT32 nImgY = i + mmTGRect.minY; ptTarget->mrnRect.minY = MIN(ptTarget->mrnRect.minY, nImgY); ptTarget->mrnRect.maxY = MAX(ptTarget->mrnRect.maxY, nImgY); ptTarget->mrnRect.minX = MIN(ptTarget->mrnRect.minX, nImgX); ptTarget->mrnRect.maxX = MAX(ptTarget->mrnRect.maxX, nImgX); //统计目标质心. 20110524 nCenterValueSumX += nImgX * nPntValue; nCenterValueSumY += nImgY * nPntValue; nTGValue += nPntValue; //统计目标大小 ptTarget->unObjPxlsCnt++; //标记目标区域内目标点 nFlagIndex = nFlagLine + j; pnBlkTargetFlag[nFlagIndex] = 1; //20180918,更新极值点坐标和值 if (GLB_OBJ_GRAY_BRIGHT == ptTarget->nObjTypeGray) { //若当前点灰度大于极值点,更新极值点 if (nPntValue > nCenterValue) { nCenterValue = nPntValue; pMaxPnt.x = pPnt.x - nTGRadius + j; pMaxPnt.y = pPnt.y - nTGRadius + i; } } else { //若当前点灰度小于极值点,更新极值点 if (nPntValue < nCenterValue) { nCenterValue = nPntValue; pMaxPnt.x = pPnt.x - nTGRadius + j; pMaxPnt.y = pPnt.y - nTGRadius + i; } } } } //查找最大行宽 nObjWH_LineWMax = MAX(nObjWH_LineWMax, nObjWH_LineW); //更新下一行起始坐标 nLine += nWidth; nFlagLine += nFilterTGW; }//end of for (j = 0; j < nKernelSize_TG; j++)... }//end of else... //+++++++++++++++++++++++++++++++++++++++++++++++++++++++ //统计目标信息 if (bIsTarget) { //计算统计目标质心 if (0 == nTGValue) //防止出错,例如当阈值设置不恰当时,连目标的极大值点都未统计到目标的大小中 { //ptTarget->pfCenPos.x = (FLOAT32)pPnt.x; //ptTarget->pfCenPos.y = (FLOAT32)pPnt.y; ptTarget->pfCenPos.x = (FLOAT32)pMaxPnt.x; ptTarget->pfCenPos.y = (FLOAT32)pMaxPnt.y; } else { ptTarget->pfCenPos.x = (FLOAT32)nCenterValueSumX / nTGValue; ptTarget->pfCenPos.y = (FLOAT32)nCenterValueSumY / nTGValue; } //统计目标的灰度(极大值灰度) //20180918,取极大值灰度 //ptTarget->pxObjGray = (UINT16)((pFrame[pPnt.y * nWidth + pPnt.x] + pFrame[(pPnt.y + 1) * nWidth + pPnt.x] + pFrame[(pPnt.y ) * nWidth + pPnt.x + 1] // + pFrame[(pPnt.y - 1) * nWidth + pPnt.x] + pFrame[pPnt.y * nWidth + pPnt.x - 1] ) / 5); //ptTarget->pxObjGray = (UINT16)(pFrame[pMaxPnt.y * nWidth + pMaxPnt.x]); //ptTarget->pxObjMaxGray = (UINT16)(pFrame[pMaxPnt.y * nWidth + pMaxPnt.x]); //20200511 if (GD_PIXEL_FORMAT_GRAY_Y8 == img.enPixelFormat) { ptTarget->pxObjGray = (((UBYTE8*)img.u64VirAddr[0])[pMaxPnt.y * nWidth + pMaxPnt.x]); ptTarget->pxObjMaxGray = (((UBYTE8*)img.u64VirAddr[0])[pMaxPnt.y * nWidth + pMaxPnt.x]); //20200511 ptTarget->fGrayNeighbor[0] = (((UBYTE8*)img.u64VirAddr[0])[(pMaxPnt.y - 1) * nWidth + pMaxPnt.x]); ptTarget->fGrayNeighbor[1] = (((UBYTE8*)img.u64VirAddr[0])[pMaxPnt.y * nWidth + pMaxPnt.x + 1]); ptTarget->fGrayNeighbor[2] = (((UBYTE8*)img.u64VirAddr[0])[(pMaxPnt.y + 1) * nWidth + pMaxPnt.x]); ptTarget->fGrayNeighbor[3] = (((UBYTE8*)img.u64VirAddr[0])[pMaxPnt.y * nWidth + pMaxPnt.x - 1]); } else { ptTarget->pxObjGray = (((UINT16*)img.u64VirAddr[0])[pMaxPnt.y * nWidth + pMaxPnt.x]); ptTarget->pxObjMaxGray = (((UINT16*)img.u64VirAddr[0])[pMaxPnt.y * nWidth + pMaxPnt.x]); //20200511 ptTarget->fGrayNeighbor[0] = (((UINT16*)img.u64VirAddr[0])[(pMaxPnt.y - 1) * nWidth + pMaxPnt.x]); ptTarget->fGrayNeighbor[1] = (((UINT16*)img.u64VirAddr[0])[pMaxPnt.y * nWidth + pMaxPnt.x + 1]); ptTarget->fGrayNeighbor[2] = (((UINT16*)img.u64VirAddr[0])[(pMaxPnt.y + 1) * nWidth + pMaxPnt.x]); ptTarget->fGrayNeighbor[3] = (((UINT16*)img.u64VirAddr[0])[pMaxPnt.y * nWidth + pMaxPnt.x - 1]); } //记录目标极大值点坐标 //ptTarget->pnMaxPos = pPnt; ptTarget->pnMaxPos = pMaxPnt; //计算目标宽、高、面积 ptTarget->snSize.h = ptTarget->mrnRect.maxY - ptTarget->mrnRect.minY + 1; ptTarget->snSize.w = ptTarget->mrnRect.maxX - ptTarget->mrnRect.minX + 1; ptTarget->snSize.s = ptTarget->snSize.h * ptTarget->snSize.w; //记录背景均值、背景方差、目标背景信噪比 ptTarget->fBGMean = (FLOAT32)dBGMean; ptTarget->fBGStd = (FLOAT32)sqrt(fBGStdOutput); ptTarget->fSNR = (FLOAT32)(nCenterValue - dBGMean) / (ptTarget->fBGStd + 0.01f); // 适应目标识别算法的加入,传统检测无法获取目标类型,此处约定目标类别ID置为DT_TARGET_CLS_ID,置信度为1 ptTarget->unClsType = DT_TARGET_CLS_ID; ptTarget->fDetConf = 1.0; ptTarget->nObjTypeSrc = ObjSrc::Arith_DST; //标记目标类型 ptTarget->nObjTypeSize = GLB_OBJ_SIZE_SMALL; //20160409: 标记弱目标 if (m_DST_stPara.bDimDetecting) { ptTarget->nObjTypeSize = GLB_OBJ_SIZE_DIMSMALL; } //20170311:若当前为弱小目标检测,则抛掉尺寸过大的目标 if (m_DST_stPara.bDimDetecting && (ptTarget->unObjPxlsCnt > 4 || ptTarget->snSize.w > 3 || ptTarget->snSize.h > 3)) { bIsTarget = false; } //20210323wl 屏蔽掉不适合本项目 ////20170313,对像素点个数小于2的暗目标不检测 ////20171223,检测阶段 //if (ptTarget->nObjTypeGray == DST_OBJ_TYPE_DARK // && ptTarget->unObjPxlsCnt < 4 // /*&& GLB_STATUS_TRACK != m_GLB_stPara.nStatus*/) //{ // bIsTarget = false; //} //去虚警:抛掉大小不符合要求的目标 if (m_DST_stPara.bUseDeFA_Size //去虚警策略“目标大小限制”的开关 && !m_DST_stPara.bDimDetecting && !m_DST_stPara.bSecDetecting && (ptTarget->unObjPxlsCnt < (UINT32)m_DST_stPara.nObjSizeMin || ptTarget->unObjPxlsCnt >(UINT32)m_DST_stPara.nObjSizeMax)) { bIsTarget = false; } //去虚警:抛掉长宽比不符合要求的目标 //目标宽高比计算方式2 - 最大行宽度/总高度 //if (GLB_STATUS_TRACK == m_GLB_stPara.nStatus) //{ // m_DST_stPara.nObjWHRatioMethod = DST_OBJ_WHRATIO_TOTALWH; //} //else //{ // m_DST_stPara.nObjWHRatioMethod = DST_OBJ_WHRATIO_LINEWH; //} if (DST_OBJ_WHRATIO_LINEWH == m_DST_stPara.nObjWHRatioMethod) { fWHRatio = (FLOAT32)nObjWH_LineWMax / ptTarget->snSize.h; } //目标宽高比计算方式1 - 总宽度/总高度 else { fWHRatio = (FLOAT32)(ptTarget->snSize.w) / ptTarget->snSize.h; } if (m_DST_stPara.bUseDeFA_WHRatio //去虚警策略“目标宽高比限制”的开关 && ((fWHRatio < 1 && fWHRatio < m_DST_stPara.fObjWHRatioMin) || (fWHRatio > 1 && fWHRatio > m_DST_stPara.fObjWHRatioMax))) { bIsTarget = false; } //去虚警:抛掉矩形度不符合要求的目标 fRectRatio = (FLOAT32)ptTarget->unObjPxlsCnt / ptTarget->snSize.s; if (m_DST_stPara.bUseDeFA_RectRatio //去虚警策略“目标矩形度限制”的开关 && fRectRatio < m_DST_stPara.fObjRectRatioMin) { bIsTarget = false; } //去虚警:抛掉形心不是目标标记点的目标(形状不规则) nObjCenX = (ptTarget->mrnRect.minX + ptTarget->mrnRect.maxX) >> 1; nObjCenY = (ptTarget->mrnRect.minY + ptTarget->mrnRect.maxY) >> 1; if (m_DST_stPara.bUseDeFA_CenFlag //去虚警策略“形心为目标点”的开关 && !pnBlkTargetFlag[(nObjCenY - mmTGRect.minY) * nFilterTGW + nObjCenX - mmTGRect.minX]) { if (ABS(nObjCenX - ptTarget->pfCenPos.x) > 1 || ABS(nObjCenY - ptTarget->pfCenPos.y) > 1) { bIsTarget = false; } } } return bIsTarget; } /********************************************************** * 函数名称:CalGuassGrayWeightTable() * 功能描述:计算双边滤波灰度权重表 * 输入参数:UINT16 *pnGrayWeightTable-- 灰度权重表指针 * SINT32 nLen -- 灰度权重表长度 * SINT32 nStd -- 标准差 * 输出参数:UINT16 *pnGrayWeightTable-- 灰度权重表指针 * 返 回 值:无 * 调用关系:无 * 其它说明:无 **********************************************************/ void DetectSmallObj::DST_CalGuassGrayWeightTable(UINT16* pnGrayWeightTable, SINT32 nLen, SINT32 nStd) { SINT32 i; double dArg = 0.0; for (i = 0; i < nLen; i++) { dArg = -(i * i * 1.0) / (2 * nStd * nStd); pnGrayWeightTable[i] = (UINT16)(exp(dArg) * 4096 + 0.5); } } /********************************************************** * 函数名称:DST_GetGuassGrayWeightFromTable() * 功能描述:查表得到局部窗口像素对应的权重值 * 输入参数:UINT16 *pFrame -- 原始图像 * UINT16 *pnTable -- 权重表 * UINT16 *pnGrayWeight -- 局部权重表 * SINT32 nTableLen -- 权重表长度 * SINT32 nWidth -- 图像宽度 * SINT32 nHeight -- 图像高度 * 输出参数:UINT16 *pnGrayWeight -- 局部权重表 * 返 回 值:无 * 调用关系:无 * 其它说明:无 **********************************************************/ void DetectSmallObj::DST_GetGuassGrayWeightFromTable(UINT16* pFrame, UINT16* pnTable, UINT16* pnGrayWeight, SINT32 nTableLen, SINT32 nWidth, SINT32 nHeight) { SINT32 i; SINT32 nLen = nWidth * nHeight; SINT32 nCenterY = (nHeight - 1) / 2; SINT32 nCenterX = (nWidth - 1) / 2; SINT32 fCen_data = pFrame[nCenterY * nWidth + nCenterX]; SINT32 nIndex; for (i = 0; i < nLen; i++) { nIndex = abs(pFrame[i] - fCen_data); nIndex = MIN(nIndex, nTableLen - 1); pnGrayWeight[i] = (UINT16)(pnTable[nIndex]); } } /********************************************************** * 函数名称:DST_BilateralFilterInt() * 功能描述:二维双边滤波(整型) * 输入参数:UINT16 *pFrame -- 原始图像 * SINT32 nWidth -- 图像宽度 * SINT32 nHeight -- 图像高度 * 输出参数:UINT16 *pnLowImg -- 低频图 * SINT16 *pnHighImg -- 高频图 * 返 回 值:无 * 调用关系:无 * 其它说明:无 **********************************************************/ void DetectSmallObj::DST_BilateralFilterInt(UINT16* pFrame, SINT32 nWidth, SINT32 nHeight, UINT16* pnLowImg, SINT16* pnHighImg) { UINT16* pGrayWeightTable = (UINT16*)DST_pDimBFGrayWeightTable; SINT32 i, j, m, n; SINT32 nLen = nWidth * nHeight; SINT32 nFilterWidth = 3; //滤波窗口宽度 SINT32 nFilterHeight = 3; //滤波窗口高度 SINT32 nFilterHalfW = (SINT32)(nFilterWidth / 2); //滤波窗口半径-宽度 SINT32 nFilterHalfH = (SINT32)(nFilterHeight / 2); //滤波窗口半径-高度 SINT32 nFilterSize = nFilterWidth * nFilterHeight; //滤波窗口总像素个数 SINT32 nGrayStd = 20; //灰度标准差 double dWeight = 0.0; //注意数据位宽 double dSum = 0.0; //注意数据位宽,不能用long //滤波数据临时空间 UINT16 pnNearGrayWeight[9] = { 0 }; //滤波窗口灰度权重表 UINT16 pnNearImg[9] = { 0 }; //滤波数据临时空间 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++ //计算灰度高斯权值映射表 DST_CalGuassGrayWeightTable(pGrayWeightTable, DST_DIM_BFGWEIGHT_LEN, nGrayStd); //+++++++++++++++++++++++++++++++++++++++++++++++++++++++ //计算低频图:对每个点进行双边滤波 for (i = 0; i < nHeight; i++) { for (j = 0; j < nWidth; j++) { SINT32 nCnt = 0; SINT32 posX = 0; SINT32 posY = 0; //遍历该点邻域 for (m = -nFilterHalfH; m <= nFilterHalfH; m++) { for (n = -nFilterHalfW; n <= nFilterHalfW; n++) { //防止越界 if (m + i < 0 || m + i >= nHeight) posY = i; else posY = m + i; if (n + j < 0 || n + j >= nWidth) posX = j; else posX = j + n; //获取邻域像素 pnNearImg[nCnt] = pFrame[posY * nWidth + posX]; nCnt++; } } //查表得到当前的灰度高斯加权系数 DST_GetGuassGrayWeightFromTable(pnNearImg, pGrayWeightTable, pnNearGrayWeight, DST_DIM_BFGWEIGHT_LEN, nFilterWidth, nFilterHeight); //计算去噪窗口滤波结果及权重值 dWeight = 0.0; dSum = 0.0; for (m = 0; m < nFilterSize; m++) { dSum += pnNearImg[m] * pnNearGrayWeight[m]; dWeight += pnNearGrayWeight[m]; } pnLowImg[i * nWidth + j] = (UINT16)(dSum / dWeight); } } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++ //计算高频图 for (i = 0; i < nLen; i++) { pnHighImg[i] = pFrame[i] - pnLowImg[i]; if (pnHighImg[i] > 200) { int a = 0; } } }