You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3558 lines
134 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include "Arith_DetectSmallObj.h"
#include "Arith_ImgOperate.h"
#include <vector>
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 ) <m_DST_stPara.nObjCombineDist * m_DST_stPara.nObjCombineDist )
{
continue;
}
//查找次极大值
if (pGray > 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;
}
//20170810wsa抛掉与块均值灰度差异较小的点
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<std::pair<SINT32, SINT32>> 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; //20180115std最大的背景块下标
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; //20180115std最大的背景块下标
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;
}
}
}