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.

3280 lines
127 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.

/*********版权所有C2017武汉高德红外股份有限公司***************
* 文件名称Arith_DetectAreaObj.h
* 文件标识:面目标检测
* 内容摘要:基于灰度特征+梯度特征+Ostu阈值分割的面目标检测
* 其它说明:"DetectAreaObj"的函数、全局变量、宏定义,统一前缀为简写"DAT"。
* 当前版本《面目标检测标准化V1.0》
* 创建作者zy
* 创建日期2017.11.13
*******************************************************************/
#include "Arith_DetectAreaObj.h"
#include "Arith_ImgOperate.h"
#include "Arith_DetectAreaObj.h"
#include "API_DetectSAObj.h"
//#include "../Version.h"
#include "opencv2/opencv.hpp"
API_DetectAreaObj * API_DetectAreaObj::Create(SINT32 nWidth, SINT32 nHeight)
{
return new DetectAreaObj(nWidth,nHeight);
}
API_DetectAreaObj * API_DetectAreaObj::Create(SINT32 nWidth, SINT32 nHeight, CENTERRECT mmCenterRect)
{
return new DetectAreaObj(nWidth,nHeight,mmCenterRect);
}
void API_DetectAreaObj::Destroy(API_DetectAreaObj * obj)
{
delete obj;
}
TARGET_OBJECT CreateNewTarget(GD_VIDEO_FRAME_S img, SINT32 nWidth, SINT32 nHeight, RECT32S bbox, SINT32 unFrmId)
{
MINMAXRECT32S mrnObjRect;
OBJECTSNR objSNR;
TARGET_OBJECT tNewTarget = { 0 };
TARGET_OBJECT* pNewTarget = NULL;
POINT32F ptfObjPos = { 0 };
ptfObjPos.x = FLOAT32(bbox.x + bbox.w / 2);
ptfObjPos.y = FLOAT32(bbox.y + bbox.h / 2);
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//计算目标边界矩形
mrnObjRect.minY = MAX(0, MIN((SINT32)(bbox.y), nHeight - 1));
mrnObjRect.maxY = MAX(0, MIN((SINT32)(bbox.y + bbox.h), nHeight - 1));
mrnObjRect.minX = MAX(0, MIN((SINT32)(bbox.x), nWidth - 1));
mrnObjRect.maxX = MAX(0, MIN((SINT32)(bbox.x + bbox.w), nWidth - 1));
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//新建目标
memset(&tNewTarget, 0, sizeof(TARGET_OBJECT));
tNewTarget.bObject = true;
tNewTarget.unFrmID = unFrmId;
tNewTarget.pfCenPos = ptfObjPos;
tNewTarget.pnMaxPos.x = (SINT16)(ptfObjPos.x);
tNewTarget.pnMaxPos.y = (SINT16)(ptfObjPos.y);
tNewTarget.mrnRect.minY = (SINT16)(mrnObjRect.minY);
tNewTarget.mrnRect.maxY = (SINT16)(mrnObjRect.maxY);
tNewTarget.mrnRect.minX = (SINT16)(mrnObjRect.minX);
tNewTarget.mrnRect.maxX = (SINT16)(mrnObjRect.maxX);
tNewTarget.snSize.w = (SINT16)(bbox.w);
tNewTarget.snSize.h = (SINT16)(bbox.h);
tNewTarget.snSize.s = (SINT32)(bbox.w * bbox.h);
tNewTarget.unObjPxlsCnt = (SINT32)(tNewTarget.snSize.s);
//计算目标的背景均值、背景标准差、SNR
memset(&objSNR, 0, sizeof(OBJECTSNR));
DAT_CalRectObjSNR_IMG(img, nWidth, nHeight, mrnObjRect, 3, &objSNR, DAT_DETECT_OBJ_TYPE_ALL);
tNewTarget.pxObjGray = (UINT16)objSNR.ObjGray;
tNewTarget.nObjTypeSize = GLB_OBJ_SIZE_FACE;
tNewTarget.nObjTypeGray = objSNR.fSNR > 0.0f ? GLB_OBJ_GRAY_BRIGHT : GLB_OBJ_GRAY_DARK;
tNewTarget.fBGMean = objSNR.BGMean;
tNewTarget.fBGStd = objSNR.BGStd;
tNewTarget.fSNR = objSNR.fSNR;
return tNewTarget;
}
DetectAreaObj::DetectAreaObj(int nWidth, int nHeight)
{
DAT_pxDetectArea = NULL;
DAT_pnMagArry = NULL;
DAT_pFlagHasSearch = NULL;
DAT_fGradX = NULL;
DAT_fGradY = NULL;
DAT_pxDetectAreaIntegral = NULL;
DAT_pBinary_Mag = NULL;
DAT_pBinary_Gray = NULL;
DAT_pBinary_GrayNew = NULL;
DAT_DIFF = NULL;
DAT_pxDetectAreaGradIntegral = NULL;
m_DAT_bInitialize = FALSE;
m_FrmObjsCnt = 0;
CENTERRECT mmCenterRect;
mmCenterRect.cx = nWidth / 2;
mmCenterRect.cy = nHeight / 2;
mmCenterRect.w = nWidth;
mmCenterRect.h = nHeight;
mmCenterRect.s = nWidth * nHeight;
Init(nWidth, nHeight, mmCenterRect);
}
DetectAreaObj::DetectAreaObj(int nWidth, int nHeight, CENTERRECT mmCenterRect)
{
DAT_pxDetectArea = NULL;
DAT_pnMagArry = NULL;
DAT_pFlagHasSearch = NULL;
DAT_fGradX = NULL;
DAT_fGradY = NULL;
DAT_pxDetectAreaIntegral = NULL;
DAT_pBinary_Mag = NULL;
DAT_pBinary_Gray = NULL;
DAT_pBinary_GrayNew = NULL;
DAT_DIFF = NULL;
DAT_pxDetectAreaGradIntegral = NULL;
m_DAT_bInitialize = FALSE;
m_FrmObjsCnt = 0;
Init(nWidth, nHeight, mmCenterRect);
}
DetectAreaObj::~DetectAreaObj()
{
DAT_ReleaseMemory();
}
bool DetectAreaObj::Init(SINT32 nWidth, SINT32 nHeight, CENTERRECT mmCenterRect)
{
DAT_Initialization(nWidth, nHeight, mmCenterRect);
m_FrmObjsCnt = 0;
bEnableAreaObjDetect = true;
return TRUE;
}
int DetectAreaObj::GetAreaSegInfo(GD_VIDEO_FRAME_S img, CENTERRECT mmCenterRect, GLB_STATUS nStatus, PixcelsCnt *pCnt)
{
int landsNum = DAT_ObjectAreaSeg(img, mmCenterRect, nStatus, pCnt);
return landsNum;
}
int DetectAreaObj::Detect(GD_VIDEO_FRAME_S img, CENTERRECT mmCenterRect, SINT32 nObjCombineDist, GLB_STATUS nStatus)
{
if (!bEnableAreaObjDetect)
{
m_FrmObjsCnt = 0;
return ERR_UNInit;
}
if (GLB_STATUS::GLB_STATUS_TRACK == nStatus)
{
if (0 == nObjCombineDist)
{
nObjCombineDist = m_DAT_stPara.nObjCombineDist;
}
}
else
{
nObjCombineDist = m_DAT_stPara.nObjCombineDist;
}
m_DAT_stInput.crnSrRect = mmCenterRect;
m_FrmObjsCnt = DAT_DetectAreaTarget(img, nStatus, nObjCombineDist);
return m_FrmObjsCnt;
}
TARGET_OBJECT* DetectAreaObj::GetTargetArray()
{
return DAT_Target;
}
OBJECTSTATUS* DetectAreaObj::GetTargetMatched()
{
return &m_DatTrkTarget;
}
SINT32 DetectAreaObj::GetTargetNum()
{
return m_FrmObjsCnt;
}
void DetectAreaObj::SetTargetNum(SINT32 num)
{
m_FrmObjsCnt = num;
}
BBOOL DetectAreaObj::getDatDetState()
{
return bEnableAreaObjDetect;
}
void DetectAreaObj::setDatDetState(BBOOL bEnableState)
{
bEnableAreaObjDetect = bEnableState;
}
DAT_PARAMETERS* DetectAreaObj::GetDatParm()
{
return &m_DAT_stPara;
}
DAT_OUTPUT* DetectAreaObj::getDAT_stOutput()
{
return &m_DAT_stOutput;
}
void DetectAreaObj::setDatParm(Param_SkyDetect* param)
{
m_DAT_stPara.nDetectGrayType = param->nDetectGrayType;
m_DAT_stPara.nGrayThresMinBright = param->nGrayThresMinBright;
m_DAT_stPara.nGrayThresMinDark = param->nGrayThresMinDark;
m_DAT_stPara.nGradThresMin = param->fAreaDetectGradDiffThre;
m_DAT_stPara.nDSmpScale = param->nDSmpScale;
}
DAT_INPUT* DetectAreaObj::getDatInput()
{
return &m_DAT_stInput;
}
void DetectAreaObj::DAT_MallocMemory(SINT32 nWidth, SINT32 nHeight, CENTERRECT mmCenterRect)
{
DAT_ReleaseMemory();
// 处理尺寸,控制默认大小,并波门自适应时考虑该大小
DAT_CENTER_REGION_SIZE = DAT_SEARCH_RGN_H * DAT_SEARCH_RGN_W;
DAT_pxDetectArea = new UINT16[DAT_CENTER_REGION_SIZE];
DAT_pnMagArry = new UINT16[DAT_CENTER_REGION_SIZE];
DAT_pFlagHasSearch = new UBYTE8[DAT_CENTER_REGION_SIZE];
DAT_fGradX = new SINT16[DAT_TARGET_PXLS_MAX];
DAT_fGradY = new SINT16[DAT_TARGET_PXLS_MAX];
DAT_pxDetectAreaIntegral = new SINT32[DAT_CENTER_REGION_SIZE];
DAT_pBinary_Mag = new UBYTE8[DAT_CENTER_REGION_SIZE];
DAT_pBinary_Gray = new UBYTE8[DAT_CENTER_REGION_SIZE];
DAT_pBinary_GrayNew = new UBYTE8[DAT_CENTER_REGION_SIZE];
DAT_DIFF = new SINT16[DAT_CENTER_REGION_SIZE];
DAT_pxDetectAreaGradIntegral = new SINT32[DAT_CENTER_REGION_SIZE];
}
void DetectAreaObj::DAT_ReleaseMemory()
{
if (DAT_pxDetectArea)
{
delete[] DAT_pxDetectArea;
DAT_pxDetectArea = NULL;
}
if (DAT_pnMagArry)
{
delete[] DAT_pnMagArry;
DAT_pnMagArry = NULL;
}
if (DAT_pFlagHasSearch)
{
delete[] DAT_pFlagHasSearch;
DAT_pFlagHasSearch = NULL;
}
if (DAT_fGradX)
{
delete[] DAT_fGradX;
DAT_fGradX = NULL;
}
if (DAT_fGradY)
{
delete[] DAT_fGradY;
DAT_fGradY = NULL;
}
if (DAT_pxDetectAreaIntegral)
{
delete[] DAT_pxDetectAreaIntegral;
DAT_pxDetectAreaIntegral = NULL;
}
if (DAT_pBinary_Mag)
{
delete[] DAT_pBinary_Mag;
DAT_pBinary_Mag = NULL;
}
if (DAT_pBinary_Gray)
{
delete[] DAT_pBinary_Gray;
DAT_pBinary_Gray = NULL;
}
if (DAT_pBinary_GrayNew)
{
delete[] DAT_pBinary_GrayNew;
DAT_pBinary_GrayNew = NULL;
}
if (DAT_DIFF)
{
delete[] DAT_DIFF;
DAT_DIFF = NULL;
}
if (DAT_pxDetectAreaGradIntegral)
{
delete[] DAT_pxDetectAreaGradIntegral;
DAT_pxDetectAreaGradIntegral = NULL;
}
}
cv::Mat Array2Mat_uchar(const unsigned char* array, int cols, int rows)
{
cv::Mat img(rows, cols, CV_8UC1);
for (int i = 0; i < rows; ++i)
{
for (int j = 0; j < cols; ++j)
{
img.at<uchar>(i, j) = array[i * cols + j];
}
}
return img;
}
/**********************************************************
* 函数名称DAT_DetectAreaTarget()
* 功能描述:基于区域连通的面目标检测
* 输入参数UINT16 *pSrc -- 原始图像
* SINT32 nWidth -- 图像宽度
* SINT32 nHeight -- 图像高度
* GLB_STATUS nStatus -- 标识当前检测算法的用途(搜索的检测、跟踪的检测)
* 输出参数:无
* 返 回 值SINT32 nObjsCnt -- 单帧检测的目标数量
* 调用关系:无
* 其它说明根据目标大小进行了3倍降采样操作
可以根据实际需要修改是否进行降采样,并修改内存空间
**********************************************************/
SINT32 DetectAreaObj::DAT_DetectAreaTarget(GD_VIDEO_FRAME_S img, GLB_STATUS nStatus, SINT32 nObjCombineDist)
{
TARGET_OBJECT* ptTargetArray = (TARGET_OBJECT*)DAT_Target_Temp;
TARGET_OBJECT* ptTargetArrayCombine = (TARGET_OBJECT*)DAT_Target_Combine;
SINT32 nObjsCnt = 0;
SIZE32S snSrDSmp;
SIZE32S snSrDSmpInt;
CENTERRECT crnSrRect; //搜索区域中心矩形
MINMAXRECT32S mmrSrRect;//搜索区域边界矩形
SINT32 nWidth = img.u32Width;
SINT32 nHeight = img.u32Height;
// 未初始化报错
if (!m_DAT_bInitialize)
{
return ERR_UNInit;
}
#if 0
cv::Mat data1 = Array2Mat_uchar(img.u64VirAddr[0], nWidth, nHeight);
cv::imshow("imput", data1);
#endif
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//初始化单帧检测算法输出结果
DAT_CleanUpFrameDetectOutput();
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//计算搜索区域在图像上的矩形范围设置下限为64*64
SINT32 nDATUnvalidBorder = MAX(m_DAT_stInput.nGrayRadius, m_DAT_stInput.nGradRadius) + 1;
crnSrRect = m_DAT_stInput.crnSrRect;
//m_DAT_stPara.nDSmpScale = 8;
// 计算合适的降采样倍数如果是在搜索阶段默认4倍降采样如果是在跟踪阶段则需要依据质心跟踪目标的尺寸动态计算降采样倍数
//判断目标变化趋势,若尺寸大于阈值,则进行目标变大帧计数
if (nStatus == GLB_STATUS_TRACK)
{
FLOAT32 sSize = MAX(m_DatTrkTarget.sfSize.s, 0.58f * m_DatTrkTarget.snAIDetSize.s); // AI检测尺寸本身偏大内部有效像素更少乘以一个估计权重
if (sSize >= 3000)
{
GLB_Dat16SampleCnt++;
GLB_Dat8SampleCnt = 0;
GLB_Dat4SampleCnt = 0;
GLB_Dat2SampleCnt = 0;
GLB_Dat1SampleCnt = 0;
}
else if (sSize >= 900)
{
GLB_Dat16SampleCnt = 0;
GLB_Dat8SampleCnt++;
GLB_Dat4SampleCnt = 0;
GLB_Dat2SampleCnt = 0;
GLB_Dat1SampleCnt = 0;
}
else if (sSize < 900 && sSize >= 250)
{
GLB_Dat16SampleCnt = 0;
GLB_Dat8SampleCnt = 0;
GLB_Dat4SampleCnt++;
GLB_Dat2SampleCnt = 0;
GLB_Dat1SampleCnt = 0;
}
else if (sSize < 250 && sSize >= 100)
{
GLB_Dat16SampleCnt = 0;
GLB_Dat8SampleCnt = 0;
GLB_Dat4SampleCnt = 0;
GLB_Dat2SampleCnt++;
GLB_Dat1SampleCnt = 0;
}
else
{
GLB_Dat16SampleCnt = 0;
GLB_Dat8SampleCnt = 0;
GLB_Dat4SampleCnt = 0;
GLB_Dat2SampleCnt = 0;
GLB_Dat1SampleCnt++;
}
//目标降采样调整的帧连续计数器
if (GLB_Dat16SampleCnt > 5)
{
m_DAT_stPara.nDSmpScale = 16;
}
else if (GLB_Dat8SampleCnt > 5)
{
m_DAT_stPara.nDSmpScale = 8;
}
else if (GLB_Dat4SampleCnt > 5)
{
m_DAT_stPara.nDSmpScale = 4;
}
else if (GLB_Dat2SampleCnt > 5)
{
m_DAT_stPara.nDSmpScale = 2;
}
else if (GLB_Dat1SampleCnt > 5)
{
m_DAT_stPara.nDSmpScale = 1;
}
}
////自动调整降采样倍数
//if (nStatus != GLB_STATUS_TRACK)
//{
// //根据参考区域大小调整降采样倍数, 计算降采样后参考区域大小
// if (crnSrRect.s < 128 * 128)
// {
// m_DAT_stPara.nDSmpScale = 2;
// }
// else
// {
// m_DAT_stPara.nDSmpScale = 4;
// }
//}
//else
if (nStatus == GLB_STATUS_TRACK) // 跟踪阶段根据降采样倍数,扩大检测的波门范围
{
if (16 == m_DAT_stPara.nDSmpScale)
{
crnSrRect.w = (SINT16)(crnSrRect.w * 4);
crnSrRect.h = (SINT16)(crnSrRect.h * 4);
}
else if (8 == m_DAT_stPara.nDSmpScale)
{
crnSrRect.w = (SINT16)(crnSrRect.w * 3);
crnSrRect.h = (SINT16)(crnSrRect.h * 3);
}
else if (4 == m_DAT_stPara.nDSmpScale)
{
crnSrRect.w = (SINT16)(crnSrRect.w * 2);
crnSrRect.h = (SINT16)(crnSrRect.h * 2);
}
else if (2 == m_DAT_stPara.nDSmpScale)
{
crnSrRect.w = (SINT16)(crnSrRect.w);
crnSrRect.h = (SINT16)(crnSrRect.h);
}
else
{
//不处理
}
m_DAT_stOutput.crCenterRect = crnSrRect;
}
else
{
//不处理
}
// 根据固定模板限制降采样倍数最小值
FLOAT32 s_input = crnSrRect.w * crnSrRect.h;
FLOAT32 min_ratio = floor(sqrt(s_input / DAT_CENTER_REGION_SIZE)) + 1;
m_DAT_stPara.nDSmpScale = MAX(m_DAT_stPara.nDSmpScale, min_ratio);
//边界限制
crnSrRect.w = MAX(crnSrRect.w, DAT_SEARCH_RGN_W_MIN + nDATUnvalidBorder * m_DAT_stPara.nDSmpScale);
crnSrRect.h = MAX(crnSrRect.h, DAT_SEARCH_RGN_W_MIN + nDATUnvalidBorder * m_DAT_stPara.nDSmpScale);
crnSrRect.w = MIN(crnSrRect.w, nWidth - 2);
crnSrRect.h = MIN(crnSrRect.h, nHeight - 2);
crnSrRect.s = crnSrRect.w * crnSrRect.h;
IMGO_CenRect16S2MMRect32S(crnSrRect, &mmrSrRect, nWidth, nHeight);
//边界限制
mmrSrRect.minX = MAX(1, MIN(mmrSrRect.minX, nWidth - 2));
mmrSrRect.maxX = MAX(1, MIN(mmrSrRect.maxX, nWidth - 2));
mmrSrRect.minY = MAX(1, MIN(mmrSrRect.minY, nHeight - 2));
mmrSrRect.maxY = MAX(1, MIN(mmrSrRect.maxY, nHeight - 2));
//更新搜索区域矩形
IMGO_MMRect32S2CenRect16S(mmrSrRect, &crnSrRect);
//MSSu, 20150609: 防止越界
if ((crnSrRect.w <= 1) || (crnSrRect.h <= 1))
{
return nObjsCnt;
}
//计算降采样图像尺寸
snSrDSmp.w = (crnSrRect.w) / m_DAT_stPara.nDSmpScale;
snSrDSmp.h = (crnSrRect.h) / m_DAT_stPara.nDSmpScale;
snSrDSmp.s = snSrDSmp.w * snSrDSmp.h;
//计算积分图尺寸
snSrDSmpInt.w = snSrDSmp.w + 1;
snSrDSmpInt.h = snSrDSmp.h + 1;
snSrDSmpInt.s = snSrDSmpInt.w * snSrDSmpInt.h;
//记录算法结果
m_DAT_stOutput.snSrDSmp = snSrDSmp;
m_DAT_stOutput.mmrSrRect = mmrSrRect;
m_DAT_stOutput.snSrDSmpInt = snSrDSmpInt;
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//提取搜索区域图像二倍降采样后存入m_DAT_stOutput.pnSrDSmpImg
//20171213面目标检测不采用抽点的方式二倍降采样
IMGO_GDSGetSubMMRectDownSample(img, nWidth, nHeight,
m_DAT_stOutput.pnSrDSmpImg, mmrSrRect, m_DAT_stPara.nDSmpScale);
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//计算降采样后搜索区域图像pnSrDSmpImg上各点的梯度幅值pnGradMag
//20171110zym_DAT_stOutput.pnGradMag图像大小 和 snSrDSmp.w一样h不一定一样大
IMGO_CalcGradImg(m_DAT_stOutput.pnSrDSmpImg, snSrDSmp.w, snSrDSmp.h, m_DAT_stOutput.pnGradMag);
//计算梯度积分图
IMGO_CalcIntegralImg(m_DAT_stOutput.pnGradMag, snSrDSmp,
m_DAT_stOutput.pnGradInt, m_DAT_stOutput.snSrDSmpInt);
//梯度分割
DAT_GradSegmentation(m_DAT_stOutput.pnGradMag, snSrDSmp, m_DAT_stOutput.pnGradInt,
snSrDSmpInt, m_DAT_stInput.nGradRadius, m_DAT_stInput.nGradRadiusTG,
m_DAT_stPara.nGradThresMin, m_DAT_stOutput.pnGradBinary);
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//计算灰度积分图
IMGO_CalcIntegralImg(m_DAT_stOutput.pnSrDSmpImg, snSrDSmp,
m_DAT_stOutput.pnGrayInt, m_DAT_stOutput.snSrDSmpInt);
if (GLB_OBJ_GRAY_BRIGHT == m_DAT_stPara.nDetectGrayType)
{
SINT16* pnTgBgDiff = (SINT16*)DAT_DIFF;
//20161115计算背景目标灰度残差图
DAT_CalcTgBgDiff(m_DAT_stOutput.pnSrDSmpImg, snSrDSmp, m_DAT_stOutput.pnGrayInt,
snSrDSmpInt, m_DAT_stInput.nGrayRadius, m_DAT_stInput.nGrayRadiusTG, pnTgBgDiff);
DAT_GraySegmentation(snSrDSmp, m_DAT_stInput.nGrayRadius, m_DAT_stPara.nGrayThresMinBright, m_DAT_stOutput.pnGrayBinary, pnTgBgDiff, true);
//亮目标分割
nObjsCnt = DAT_ObjsSegmentation(m_DAT_stOutput.pnSrDSmpImg,
m_DAT_stOutput.pnGrayBinary, m_DAT_stOutput.pnGradBinary, snSrDSmp,
m_DAT_stOutput.pnGrayInt, m_DAT_stOutput.pnGradInt, snSrDSmpInt,
m_DAT_stInput.snSrBlksNum, m_DAT_stPara.nDSmpScale, mmrSrRect,
ptTargetArray, m_DAT_stPara.nFrmObjsMax, img.enPixelFormat);
//亮目标合并
nObjsCnt = DAT_MergeObjs(ptTargetArray, ptTargetArrayCombine,
m_DAT_stPara.nFrmObjsMax, nObjsCnt, nObjCombineDist);
#if 0
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
// 显示结果
//if (/*g_GLB_stPara.nStatus == GLB_STATUS_TRACK*/1)
{
cv::Mat TmpGrayBinary(snSrDSmp.h, snSrDSmp.w, CV_8UC1, DAT_pBinary_Gray);
cv::Mat TmpGradBinary(snSrDSmp.h, snSrDSmp.w, CV_8UC1, DAT_pBinary_Mag);
// for (int iH = 0; iH < snSrDSmp.h; iH++)
// {
// memcpy(TmpGrayBinary.data + (iH * DAT_CENTER_REGION_W), g_DAT_stOutput.pnGrayBinary + (iH * snSrDSmp.w), snSrDSmp.w * sizeof(UBYTE8));
// memcpy(TmpGradBinary.data + (iH * DAT_CENTER_REGION_W), g_DAT_stOutput.pnGradBinary + (iH * snSrDSmp.w), snSrDSmp.w * sizeof(UBYTE8));
// }
TmpGrayBinary = TmpGrayBinary * 255;
TmpGradBinary = TmpGradBinary * 255;
cv::resize(TmpGrayBinary, TmpGrayBinary, cv::Size(), m_DAT_stPara.nDSmpScale, m_DAT_stPara.nDSmpScale);
cv::resize(TmpGradBinary, TmpGradBinary, cv::Size(), m_DAT_stPara.nDSmpScale, m_DAT_stPara.nDSmpScale);
cv::Mat FuseImg(m_DAT_stPara.nDSmpScale * snSrDSmp.h, m_DAT_stPara.nDSmpScale * snSrDSmp.w, CV_8UC3);
std::vector<cv::Mat> planes;
cv::split(FuseImg, planes);
planes.at(0) = TmpGrayBinary;
planes.at(2) = TmpGradBinary;
planes.at(1) = 0;
cv::merge(planes, FuseImg);
for (int nIndex = 0; nIndex < nObjsCnt; nIndex++)
{
cv::Rect ret(ptTargetArray[nIndex].mrnRect.minX, ptTargetArray[nIndex].mrnRect.minY,
(ptTargetArray[nIndex].mrnRect.maxX - ptTargetArray[nIndex].mrnRect.minX),
(ptTargetArray[nIndex].mrnRect.maxY - ptTargetArray[nIndex].mrnRect.minY));
cv::rectangle(FuseImg, ret, cv::Scalar(0, 255, 0));
}
cv::imshow("分割结果:灰度(B)_梯度(R)", FuseImg);
cv::imshow("灰度分割结果", TmpGrayBinary);
cv::imshow("梯度分割结果", TmpGradBinary);
cv::waitKey(1);
}
#endif
}
else if (GLB_OBJ_GRAY_DARK == m_DAT_stPara.nDetectGrayType)
{
SINT16* pnTgBgDiff = (SINT16*)DAT_DIFF;
//20161115计算背景目标灰度残差图
DAT_CalcTgBgDiff(m_DAT_stOutput.pnSrDSmpImg, snSrDSmp, m_DAT_stOutput.pnGrayInt,
snSrDSmpInt, m_DAT_stInput.nGrayRadius, m_DAT_stInput.nGrayRadiusTG, pnTgBgDiff);
DAT_GraySegmentation(snSrDSmp, m_DAT_stInput.nGrayRadius, m_DAT_stPara.nGrayThresMinDark, m_DAT_stOutput.pnGrayBinary, pnTgBgDiff, true);
//暗目标分割
nObjsCnt = DAT_ObjsSegmentation(m_DAT_stOutput.pnSrDSmpImg,
m_DAT_stOutput.pnGrayBinary, m_DAT_stOutput.pnGradBinary, snSrDSmp,
m_DAT_stOutput.pnGrayInt, m_DAT_stOutput.pnGradInt, snSrDSmpInt,
m_DAT_stInput.snSrBlksNum, m_DAT_stPara.nDSmpScale, mmrSrRect,
ptTargetArray, m_DAT_stPara.nFrmObjsMax, img.enPixelFormat);
//暗目标合并
nObjsCnt = DAT_MergeObjs(ptTargetArray, ptTargetArrayCombine,
m_DAT_stPara.nFrmObjsMax, nObjsCnt, nObjCombineDist);
#if 0
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
// 显示结果
//if (/*g_GLB_stPara.nStatus == GLB_STATUS_TRACK*/1)
{
cv::Mat TmpGrayBinary(snSrDSmp.h, snSrDSmp.w, CV_8UC1, DAT_pBinary_Gray);
cv::Mat TmpGradBinary(snSrDSmp.h, snSrDSmp.w, CV_8UC1, DAT_pBinary_Mag);
// for (int iH = 0; iH < snSrDSmp.h; iH++)
// {
// memcpy(TmpGrayBinary.data + (iH * DAT_CENTER_REGION_W), g_DAT_stOutput.pnGrayBinary + (iH * snSrDSmp.w), snSrDSmp.w * sizeof(UBYTE8));
// memcpy(TmpGradBinary.data + (iH * DAT_CENTER_REGION_W), g_DAT_stOutput.pnGradBinary + (iH * snSrDSmp.w), snSrDSmp.w * sizeof(UBYTE8));
// }
TmpGrayBinary = TmpGrayBinary * 255;
TmpGradBinary = TmpGradBinary * 255;
cv::resize(TmpGrayBinary, TmpGrayBinary, cv::Size(), m_DAT_stPara.nDSmpScale, m_DAT_stPara.nDSmpScale);
cv::resize(TmpGradBinary, TmpGradBinary, cv::Size(), m_DAT_stPara.nDSmpScale, m_DAT_stPara.nDSmpScale);
cv::Mat FuseImg(m_DAT_stPara.nDSmpScale * snSrDSmp.h, m_DAT_stPara.nDSmpScale * snSrDSmp.w, CV_8UC3);
std::vector<cv::Mat> planes;
cv::split(FuseImg, planes);
planes.at(0) = TmpGrayBinary;
planes.at(2) = TmpGradBinary;
planes.at(1) = 0;
cv::merge(planes, FuseImg);
for (int nIndex = 0; nIndex < nObjsCnt; nIndex++)
{
cv::Rect ret(ptTargetArray[nIndex].mrnRect.minX, ptTargetArray[nIndex].mrnRect.minY,
(ptTargetArray[nIndex].mrnRect.maxX - ptTargetArray[nIndex].mrnRect.minX),
(ptTargetArray[nIndex].mrnRect.maxY - ptTargetArray[nIndex].mrnRect.minY));
cv::rectangle(FuseImg, ret, cv::Scalar(0, 255, 0));
}
cv::imshow("分割结果:灰度(B)_梯度(R)", FuseImg);
cv::imshow("灰度分割结果", TmpGrayBinary);
cv::imshow("梯度分割结果", TmpGradBinary);
cv::waitKey(1);
}
#endif
}
else
{
SINT32 nFrmBrightObjCnt = 0;
SINT32 nFrmDarkObjCnt = 0;
SINT16* pnTgBgDiff = (SINT16*)DAT_DIFF;
//20161112Whao初始化亮暗目标数组
TARGET_OBJECT* ptDATResultBright = (TARGET_OBJECT*)DAT_Target_Bright;
TARGET_OBJECT* ptDATResultDark = (TARGET_OBJECT*)DAT_Target_DARK;
memset(ptDATResultBright, 0, sizeof(TARGET_OBJECT) * DAT_TARGET_NUM_MAX);
memset(ptDATResultDark, 0, sizeof(TARGET_OBJECT) * DAT_TARGET_NUM_MAX);
//20161112先执行亮目标灰度
m_DAT_stPara.nDetectGrayType = GLB_OBJ_GRAY_BRIGHT;
//20161115计算背景目标灰度残差图
DAT_CalcTgBgDiff(m_DAT_stOutput.pnSrDSmpImg, snSrDSmp, m_DAT_stOutput.pnGrayInt,
snSrDSmpInt, m_DAT_stInput.nGrayRadius, m_DAT_stInput.nGrayRadiusTG, pnTgBgDiff);
//亮目标灰度分割
DAT_GraySegmentation(snSrDSmp, m_DAT_stInput.nGrayRadius, m_DAT_stPara.nGrayThresMinBright, m_DAT_stOutput.pnGrayBinary, pnTgBgDiff, true);
//亮目标分割
nFrmBrightObjCnt = DAT_ObjsSegmentation(m_DAT_stOutput.pnSrDSmpImg,
m_DAT_stOutput.pnGrayBinary, m_DAT_stOutput.pnGradBinary, snSrDSmp,
m_DAT_stOutput.pnGrayInt, m_DAT_stOutput.pnGradInt, snSrDSmpInt,
m_DAT_stInput.snSrBlksNum, m_DAT_stPara.nDSmpScale, mmrSrRect,
ptTargetArray, m_DAT_stPara.nFrmObjsMax, img.enPixelFormat);
//亮目标合并
nFrmBrightObjCnt = DAT_MergeObjs(ptTargetArray, ptTargetArrayCombine,
m_DAT_stPara.nFrmObjsMax, nFrmBrightObjCnt, nObjCombineDist);
//复制面目标结果到共享空间DSP双核移植时使用
TARGET_OBJECT* ptDATResultBrightTmp = (TARGET_OBJECT*)DAT_Target_Temp;
memcpy(ptDATResultBright, ptDATResultBrightTmp, nFrmBrightObjCnt * sizeof(TARGET_OBJECT));
//初始化单帧目标数组
memset(ptTargetArray, 0, sizeof(TARGET_OBJECT) * DAT_TARGET_NUM_MAX);
memset(ptTargetArrayCombine, 0, sizeof(TARGET_OBJECT) * DAT_TARGET_NUM_MAX);
memset(m_DAT_stOutput.pnGrayBinary, 0, sizeof(UBYTE8) * DAT_CENTER_REGION_SIZE);
memset(pnTgBgDiff, 0, sizeof(SINT16) * DAT_CENTER_REGION_SIZE); //初始化背景残差图数组
//20161112再执行暗目标灰度分割
m_DAT_stPara.nDetectGrayType = GLB_OBJ_GRAY_DARK;
//计算暗目标与背景残差图
DAT_CalcTgBgDiff(m_DAT_stOutput.pnSrDSmpImg, snSrDSmp, m_DAT_stOutput.pnGrayInt,
snSrDSmpInt, m_DAT_stInput.nGrayRadius, m_DAT_stInput.nGrayRadiusTG, pnTgBgDiff);
//暗目标灰度分割
DAT_GraySegmentation(snSrDSmp, m_DAT_stInput.nGrayRadius, m_DAT_stPara.nGrayThresMinDark, m_DAT_stOutput.pnGrayBinary, pnTgBgDiff, true);
//暗目标分割
nFrmDarkObjCnt = DAT_ObjsSegmentation(m_DAT_stOutput.pnSrDSmpImg,
m_DAT_stOutput.pnGrayBinary, m_DAT_stOutput.pnGradBinary, snSrDSmp,
m_DAT_stOutput.pnGrayInt, m_DAT_stOutput.pnGradInt, snSrDSmpInt,
m_DAT_stInput.snSrBlksNum, m_DAT_stPara.nDSmpScale, mmrSrRect,
ptTargetArray, m_DAT_stPara.nFrmObjsMax, img.enPixelFormat);
//暗目标合并
nFrmDarkObjCnt = DAT_MergeObjs(ptTargetArray, ptTargetArrayCombine,
m_DAT_stPara.nFrmObjsMax, nFrmDarkObjCnt, nObjCombineDist);
//复制暗面目标结果
TARGET_OBJECT* ptDATResultDarkTmp = (TARGET_OBJECT*)DAT_Target_Temp;
memcpy(ptDATResultDark, ptDATResultDarkTmp, nFrmDarkObjCnt * sizeof(TARGET_OBJECT));
//20161112合并检测结果
nObjsCnt = DAT_MergeTargets(ptDATResultBright, ptDATResultDark, nFrmBrightObjCnt, nFrmDarkObjCnt, m_DAT_stPara.nFrmObjsMax);
//20171110zy: 还原灰度检测类型,不与小目标检测类型相关联
m_DAT_stPara.nDetectGrayType = GLB_OBJ_GRAY_ALL;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//复制面目标结果到共享空间DSP双核移植时使用
TARGET_OBJECT* ptDATResult = (TARGET_OBJECT*)DAT_Target;
TARGET_OBJECT* ptDATResulTemp = (TARGET_OBJECT*)DAT_Target_Temp;
memcpy(ptDATResult, ptDATResulTemp, nObjsCnt * sizeof(TARGET_OBJECT));
// 导出分割图
m_DAT_stOutput.DAT_pBinary_Gray = DAT_pBinary_Gray;
m_DAT_stOutput.DAT_pBinary_Mag = DAT_pBinary_Mag;
// 显式输出目标个数
m_DAT_stOutput.nFrmObjsCnt = nObjsCnt;
return nObjsCnt;
}
void dfs(unsigned char * grid, int nr, int nc, int r, int c)
{
grid[r * nc + c] = '\0';
if (r - 1 >= 0 && grid[(r - 1) * nc + c] == '\x1') dfs(grid, nr, nc, r - 1, c);
if (r + 1 < nr && grid[(r + 1) * nc + c] == '\x1') dfs(grid, nr, nc, r + 1, c);
if (c - 1 >= 0 && grid[r * nc + (c - 1)] == '\x1') dfs(grid, nr, nc, r, c - 1);
if (c + 1 < nc && grid[r * nc + (c + 1)] == '\x1') dfs(grid, nr, nc, r, c + 1);
}
int numIslands(unsigned char *grid, int nr, int nc)
{
int num_islands = 0;
for (int r = 0; r < nr; ++r)
{
for (int c = 0; c < nc; ++c)
{
if (grid[r * nc + c] == '\x1')
{
++num_islands;
dfs(grid, nr, nc, r, c);
}
}
}
return num_islands;
}
int numPixcels(unsigned char* grid, int nr, int nc, int* holeXpixcel, int* holeYpixcel)
{
int num_pixcel = 0;
*holeXpixcel = 0;
// 统计行孔洞数
for (int r = 0; r < nr; ++r)
{
bool len_start = false;
bool len_end = true;
int lineXPixcel = 0;
int stepXPixcel = 0;
for (int c = 0; c < nc; ++c)
{
if (grid[r * nc + c] == '\x1')
{
num_pixcel++;
}
if (len_start == false && grid[r * nc + c] == '\x1')
{
len_start = true;
continue;
}
if (true == len_start)
{
if (grid[r * nc + c] == '\0')
{
stepXPixcel += 1;
}
else
{
if (stepXPixcel > 0)
{
lineXPixcel += stepXPixcel;
stepXPixcel = 0;
len_start = false;
}
}
}
}
(*holeXpixcel) += lineXPixcel;
}
//统计列孔洞数
for (int c = 0; c < nc; ++c)
{
bool col_start = false;
bool col_end = true;
int lineYPixcel = 0;
int stepYPixcel = 0;
for (int r = 0; r < nr; ++r)
{
if (col_start == false && grid[r * nc + c] == '\x1')
{
col_start = true;
continue;
}
if (true == col_start)
{
if (grid[r * nc + c] == '\0')
{
stepYPixcel += 1;
}
else
{
if (stepYPixcel > 0)
{
lineYPixcel += stepYPixcel;
stepYPixcel = 0;
col_start = false;
}
}
}
}
(*holeYpixcel) += lineYPixcel;
}
return num_pixcel;
}
/**********************************************************
* 函数名称DAT_DetectAreaTarget()
* 功能描述:基于区域连通的面目标检测
* 输入参数UINT16 *pSrc -- 原始图像
CENTERRECT crnSrRect; //搜索区域中心矩形
* GLB_STATUS nStatus -- 标识当前检测算法的用途(搜索的检测、跟踪的检测)
* 输出参数:无
* 返 回 值SINT32 nObjsCnt -- 单帧检测的目标数量
* 调用关系:无
* 其它说明根据目标大小进行了3倍降采样操作
可以根据实际需要修改是否进行降采样,并修改内存空间
**********************************************************/
SINT32 DetectAreaObj::DAT_ObjectAreaSeg(GD_VIDEO_FRAME_S img, CENTERRECT crnSrRect, GLB_STATUS nStatus, PixcelsCnt* pCnt)
{
SINT32 nObjsCnt = 0;
SIZE32S snSrDSmp;
SIZE32S snSrDSmpInt;
MINMAXRECT32S mmrSrRect;//搜索区域边界矩形
SINT32 nDSmpScale = 1;
SINT32 landsNum = 0;
//SINT32 numPixcel = 0;
//SINT32 holeXpixcel = 0; // x方向孔洞数
//SINT32 holeYpixcel = 0; // y方向孔洞数
#if 0
cv::Mat data1 = Array2Mat_uchar(img.u64VirAddr[0], nWidth, nHeight);
cv::imshow("imput", data1);
#endif
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//计算搜索区域在图像上的矩形范围设置下限为64*64
SINT32 nDATUnvalidBorder = MAX(m_DAT_stInput.nGrayRadius, m_DAT_stInput.nGradRadius) + 1;
//crnSrRect = m_DAT_stInput.crnSrRect;
//判断目标变化趋势,若尺寸大于阈值,则进行目标变大帧计数
if (nStatus != GLB_STATUS_TRACK)
{
return 0;
}
//边界限制
crnSrRect.w = MAX(crnSrRect.w, DAT_SEARCH_RGN_W_MIN + nDATUnvalidBorder * nDSmpScale);
crnSrRect.h = MAX(crnSrRect.h, DAT_SEARCH_RGN_W_MIN + nDATUnvalidBorder * nDSmpScale);
crnSrRect.w = MIN(crnSrRect.w, (SINT32)img.u32Width - 2);
crnSrRect.h = MIN(crnSrRect.h, (SINT32)img.u32Height - 2);
crnSrRect.s = crnSrRect.w * crnSrRect.h;
IMGO_CenRect16S2MMRect32S(crnSrRect, &mmrSrRect, img.u32Width, img.u32Height);
//边界限制
mmrSrRect.minX = MAX(1, MIN(mmrSrRect.minX, (SINT32)img.u32Width - 2));
mmrSrRect.maxX = MAX(1, MIN(mmrSrRect.maxX, (SINT32)img.u32Width - 2));
mmrSrRect.minY = MAX(1, MIN(mmrSrRect.minY, (SINT32)img.u32Height - 2));
mmrSrRect.maxY = MAX(1, MIN(mmrSrRect.maxY, (SINT32)img.u32Height - 2));
//更新搜索区域矩形
IMGO_MMRect32S2CenRect16S(mmrSrRect, &crnSrRect);
//MSSu, 20150609: 防止越界
if ((crnSrRect.w <= 1) || (crnSrRect.h <= 1))
{
return nObjsCnt;
}
//计算降采样图像尺寸
snSrDSmp.w = crnSrRect.w;
snSrDSmp.h = crnSrRect.h;
snSrDSmp.s = snSrDSmp.w * snSrDSmp.h;
//计算积分图尺寸
snSrDSmpInt.w = snSrDSmp.w + 1;
snSrDSmpInt.h = snSrDSmp.h + 1;
snSrDSmpInt.s = snSrDSmpInt.w * snSrDSmpInt.h;
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//提取搜索区域图像二倍降采样后存入m_DAT_stOutput.pnSrDSmpImgNew
//20171213面目标检测不采用抽点的方式二倍降采样
IMGO_GDSGetSubMMRectDownSample(img, img.u32Width, img.u32Height,
m_DAT_stOutput.pnSrDSmpImg, mmrSrRect, nDSmpScale);
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//计算灰度积分图
IMGO_CalcIntegralImg(m_DAT_stOutput.pnSrDSmpImg, snSrDSmp,
m_DAT_stOutput.pnGrayInt, snSrDSmpInt);
if (GLB_OBJ_GRAY_BRIGHT == m_DAT_stPara.nDetectGrayType)
{
SINT16* pnTgBgDiff = (SINT16*)DAT_DIFF;
//20161115计算背景目标灰度残差图
DAT_CalcTgBgDiff(m_DAT_stOutput.pnSrDSmpImg, snSrDSmp, m_DAT_stOutput.pnGrayInt,
snSrDSmpInt, m_DAT_stInput.nGrayRadius, m_DAT_stInput.nGrayRadiusTG, pnTgBgDiff);
DAT_GraySegmentation(snSrDSmp, m_DAT_stInput.nGrayRadius, m_DAT_stPara.nGrayThresMinBright, DAT_pBinary_GrayNew, pnTgBgDiff, false);
#if 0
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
cv::Mat TmpGrayBinary(snSrDSmp.h, snSrDSmp.w, CV_8UC1);
memcpy(TmpGrayBinary.data, DAT_pBinary_GrayNew, snSrDSmp.h * snSrDSmp.w * sizeof(UBYTE8));
TmpGrayBinary = TmpGrayBinary * 255;
cv::imshow("灰度分割结果", TmpGrayBinary);
cv::waitKey(1);
#endif
pCnt->nObjCnt = numPixcels(DAT_pBinary_GrayNew, snSrDSmp.h, snSrDSmp.w, &pCnt->nObjXHoleCnt, &pCnt->nObjYHoleCnt);
landsNum = numIslands(DAT_pBinary_GrayNew, snSrDSmp.h, snSrDSmp.w);
}
else if (GLB_OBJ_GRAY_DARK == m_DAT_stPara.nDetectGrayType)
{
SINT16* pnTgBgDiff = (SINT16*)DAT_DIFF;
//20161115计算背景目标灰度残差图
DAT_CalcTgBgDiff(m_DAT_stOutput.pnSrDSmpImg, snSrDSmp, m_DAT_stOutput.pnGrayInt,
snSrDSmpInt, m_DAT_stInput.nGrayRadius, m_DAT_stInput.nGrayRadiusTG, pnTgBgDiff);
DAT_GraySegmentation(snSrDSmp, m_DAT_stInput.nGrayRadius, m_DAT_stPara.nGrayThresMinDark, DAT_pBinary_GrayNew, pnTgBgDiff, false);
#if 0
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
cv::Mat TmpGrayBinary(snSrDSmp.h, snSrDSmp.w, CV_8UC1);
memcpy(TmpGrayBinary.data, DAT_pBinary_GrayNew, snSrDSmp.h * snSrDSmp.w * sizeof(UBYTE8));
TmpGrayBinary = TmpGrayBinary * 255;
cv::imshow("灰度分割结果", TmpGrayBinary);
cv::waitKey(1);
#endif
pCnt->nObjCnt = numPixcels(DAT_pBinary_GrayNew, snSrDSmp.h, snSrDSmp.w, &pCnt->nObjXHoleCnt, &pCnt->nObjYHoleCnt);
landsNum = numIslands(DAT_pBinary_GrayNew, snSrDSmp.h, snSrDSmp.w);
}
return landsNum;
}
/**********************************************************
* 函数名称DAT_Initialization()
* 功能描述:算法初始化
* 输入参数:无
* 输出参数:无
* 返 回 值:无
* 调用关系:无
* 其它说明:无
**********************************************************/
void DetectAreaObj::DAT_Initialization(SINT32 nWidth, SINT32 nHeight, CENTERRECT mmCenterRect)
{
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//初始化算法输入
//搜索区域
m_DAT_stInput.crnSrRect.cx = (SINT16)(mmCenterRect.cx); //搜索区域中心点cx
m_DAT_stInput.crnSrRect.cy = (SINT16)(mmCenterRect.cy); //搜索区域中心点cy
m_DAT_stInput.crnSrRect.w = mmCenterRect.w; //搜索区域宽度w
m_DAT_stInput.crnSrRect.h = mmCenterRect.h; //搜索区域高度h
m_DAT_stInput.crnSrRect.s = mmCenterRect.w * mmCenterRect.h;
//梯度分块尺寸
m_DAT_stInput.nGradRadius = DAT_GRAD_BLK_RADIUS;
m_DAT_stInput.nGradRadiusTG = DAT_GRAD_BLK_RADIUS_TG;
m_DAT_stInput.snGradBlkSize.w = m_DAT_stInput.nGradRadius * 2 + 1;
m_DAT_stInput.snGradBlkSize.h = m_DAT_stInput.snGradBlkSize.w;
m_DAT_stInput.snGradBlkSize.s = m_DAT_stInput.snGradBlkSize.w * m_DAT_stInput.snGradBlkSize.h;
//灰度分块尺寸
m_DAT_stInput.nGrayRadius = DAT_GRAY_BLK_RADIUS;
m_DAT_stInput.nGrayRadiusTG = DAT_GRAY_BLK_RADIUS_TG;
m_DAT_stInput.snGrayBlkSize.w = m_DAT_stInput.nGrayRadius * 2 + 1;
m_DAT_stInput.snGrayBlkSize.h = m_DAT_stInput.snGrayBlkSize.w;
m_DAT_stInput.snGrayBlkSize.s = m_DAT_stInput.snGrayBlkSize.w * m_DAT_stInput.snGrayBlkSize.h;
//搜索区域分块个数
m_DAT_stInput.snSrBlksNum.w = DAT_SR_RGN_BLKS_NUM_W;
m_DAT_stInput.snSrBlksNum.h = DAT_SR_RGN_BLKS_NUM_H;
m_DAT_stInput.snSrBlksNum.s = DAT_SR_RGN_BLKS_NUM;
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//初始化算法参数
//
m_DAT_stPara.nDetectGrayType = GLB_OBJ_GRAY_ALL; // 默认检测亮/暗目标
m_DAT_stPara.nFrmObjsMax = DAT_TARGET_NUM_MAX;
m_DAT_stPara.nDSmpScale = DAT_DSAMPLE_SCALE; // 默认降采样倍数
m_DAT_stPara.nGradThresMin = DAT_GRAD_THRES_MIN;
m_DAT_stPara.nObjSizeMin = DAT_TARGET_PXLS_MIN;
m_DAT_stPara.nObjSizeMax = DAT_TARGET_PXLS_MAX;
m_DAT_stPara.nObjWidthMax = DAT_TARGET_WIDTH_MAX;
m_DAT_stPara.nObjHeightMax = DAT_TARGET_HEIGHT_MAX;
m_DAT_stPara.fObjWHRatioMin = 0.4f;
m_DAT_stPara.fObjWHRatioMax = 4.0f;
m_DAT_stPara.fObjRectRatioMin = 0.3f;
m_DAT_stPara.nObjBkgGrayDiffMin = 10;
m_DAT_stPara.fBkgGrayDiffCoeff = 0.35f;
m_DAT_stPara.fgdk = DAT_OBJ_SNR_MIN;
m_DAT_stPara.nObjCombineDist = 11;
//20161113Whao亮暗目标两套阈值
m_DAT_stPara.nGrayThresMinBright = DAT_GRAY_THRES_BRIGHT_MIN;
m_DAT_stPara.nGrayThresMinDark = DAT_GRAY_THRES_DARK_MIN;
//面目标检测去虚警开关(上位机软件界面可调)
m_DAT_stPara.bUseDeFA_ObjVarMin = 1;
m_DAT_stPara.bUseDeFA_Size = 1;
m_DAT_stPara.bUseDeFA_WHRatio = 1;
m_DAT_stPara.bUseDeFA_RectRatio = 1;
m_DAT_stPara.bUseDeFA_BTGrayMin = 0;
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
// 内存申请
DAT_MallocMemory(nWidth, nHeight, mmCenterRect);
//初始化算法输出结果
memset(&m_DAT_stOutput, 0, sizeof(DAT_OUTPUT));
//初始化灰度图指针
m_DAT_stOutput.pnSrDSmpImg = (UINT16*)DAT_pxDetectArea;
m_DAT_stOutput.pnGrayBinary = (UBYTE8*)DAT_pBinary_Gray;
m_DAT_stOutput.pnGrayInt = (SINT32*)DAT_pxDetectAreaIntegral;
//m_DAT_stOutput.pnSrDSmpImgNew = (UINT16*)DAT_pxDetectAreaNew;
//初始化梯度图指针
m_DAT_stOutput.pnGradMag = (UINT16*)DAT_pnMagArry;
m_DAT_stOutput.pnGradBinary = (UBYTE8*)DAT_pBinary_Mag;
m_DAT_stOutput.pnGradInt = (SINT32*)DAT_pxDetectAreaGradIntegral;
//初始化单帧检测算法输出结果
DAT_CleanUpFrameDetectOutput();
//算法初始化标记
m_DAT_bInitialize = TRUE; //DAT算法初始化标志。1-初始化0-不初始化。
}
/**********************************************************
* 函数名称DAT_CleanUpFrameDetectOutput()
* 功能描述:初始化单帧检测算法输出结果
* 输入参数:无
* 输出参数:无
* 返 回 值:无
* 调用关系:无
* 其它说明:无
**********************************************************/
void DetectAreaObj::DAT_CleanUpFrameDetectOutput(void)
{
//初始化灰度图指针
memset(m_DAT_stOutput.pnSrDSmpImg, 0, sizeof(UINT16) * DAT_CENTER_REGION_SIZE);
memset(m_DAT_stOutput.pnGrayBinary, 0, sizeof(UBYTE8) * DAT_CENTER_REGION_SIZE);
memset(m_DAT_stOutput.pnGrayInt, 0, sizeof(SINT32) * DAT_CENTER_REGION_SIZE);
//初始化梯度图指针
memset(m_DAT_stOutput.pnGradMag, 0, sizeof(UINT16) * DAT_CENTER_REGION_SIZE);
memset(m_DAT_stOutput.pnGradBinary, 0, sizeof(UBYTE8) * DAT_CENTER_REGION_SIZE);
memset(m_DAT_stOutput.pnGradInt, 0, sizeof(SINT32) * DAT_CENTER_REGION_SIZE);
//初始化单帧目标数组
TARGET_OBJECT* ptTargetArray = (TARGET_OBJECT*)DAT_Target;
TARGET_OBJECT* ptTargetArrayTemp = (TARGET_OBJECT*)DAT_Target_Temp;
TARGET_OBJECT* ptTargetArrayCombine = (TARGET_OBJECT*)DAT_Target_Combine;
memset(ptTargetArray, 0, sizeof(TARGET_OBJECT) * DAT_TARGET_NUM_MAX);
memset(ptTargetArrayTemp, 0, sizeof(TARGET_OBJECT) * DAT_TARGET_NUM_MAX);
memset(ptTargetArrayCombine, 0, sizeof(TARGET_OBJECT) * DAT_TARGET_NUM_MAX);
//20161116初始化灰度残差图
SINT16* pnTgBgDiff = (SINT16*)DAT_DIFF;
memset(pnTgBgDiff, 0, sizeof(SINT16) * DAT_CENTER_REGION_SIZE);
}
/**********************************************************
* 函数名称DAT_GradSegmentation()
* 功能描述:梯度分割
* 输入参数UINT16 *pnImg -- 输入图像
* SIZE32S snImgSize -- 输入图像尺寸
* SINT32 *pnIntImg -- 输入图像积分图
* SIZE32S snIntImgSize-- 积分图尺寸
* SINT32 nRadius -- 邻域半径
* SINT32 nRadiusTG -- 目标半径
* SINT32 nThresMin -- 分割阈值下限
* 输出参数UBYTE8 *pnBinary -- 二值化图像
* 返 回 值:无
* 调用关系:无
* 其它说明:在输入图像上,查找与邻域背景均值差异满足阈值的点,作为二值化分割点。
* 1减少计算复杂度边界不处理将有效计算区域向内缩小邻域矩形块半径nRadius个像素。
* 2利用积分图g求(m,n)、(i,j)所成矩形内的像素值累加和:
* RectSum = g(m,n) - g(m,j)
* -g(i,n) + g(i,j)
* 3固定分割阈值为nThresMin
* 4输入图像(i,j)点,对应于积分图像上的(i+1,j+1)点。
**********************************************************/
void DetectAreaObj::DAT_GradSegmentation(UINT16* pnImg, SIZE32S snImgSize,
SINT32* pnIntImg, SIZE32S snIntImgSize,
SINT32 nRadius, SINT32 nRadiusTG, SINT32 nThresMin,
UBYTE8* pnBinary)
{
SINT32 i, j;
SINT32 nBorder = 1; //不处理的边界大小
SINT32 nUnvalid = nRadius + nBorder;//无效区域(不处理)的总大小
SINT32 nDiameter = 2 * nRadius + 1; //邻域直径
SINT32 nTGSize = (2 * nRadiusTG + 1) * (2 * nRadiusTG + 1); //目标矩形像素个数
SINT32 nBlkSize = nDiameter * nDiameter - nTGSize; //邻域矩形像素个数(去除目标矩形)
SINT32 nLine = 0; //当前点行起始坐标(输入图像、二值化图像)
SINT32 nBlkFirstLn = 0; //邻域起始行坐标(积分图)
SINT32 nBlkLastLn = 0; //邻域末尾行坐标(积分图)
SINT32 nTGFirstLn = 0; //目标起始行坐标(积分图)
SINT32 nTGLastLn = 0; //目标末尾行坐标(积分图)
SINT32 nCurrId = 0; //当前点图像坐标(输入图像、二值化图像)
SINT32 nCurrValue = 0; //当前像素值(输入图像)
SINT32 nBlkMean = 0; //邻域均值(积分图)
SINT32 nTGSum = 0; //目标像素值之和(积分图)
SINT32 nTGMean = 0; //目标均值(积分图)
MINMAXRECT32S mrnRectValid; //有效计算区域矩形
MINMAXRECT32S mrnIntBlkRect;//邻域块矩形(积分图)
MINMAXRECT32S mrnIntTGRect; //目标矩形(积分图)
SINT16 nMaxIters = DAT_MAX_SEG_TIMES;
//20161113Whao计算的总有效点数
UBYTE8 nIter = 0; //迭代次数
SINT32 nTotalPnts = 0; //总的点数
SINT32 nValidPnts = 0; //二値化为1的有效点数
FLOAT32 fValidRatio = 0.0f; //二值分割后的有效点占比
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//计算有效区域矩形
mrnRectValid.minX = nUnvalid;
mrnRectValid.maxX = snImgSize.w - 1 - nUnvalid;
mrnRectValid.minY = nUnvalid;
mrnRectValid.maxY = snImgSize.h - 1 - nUnvalid;
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//初始化背景邻域块矩形、起始及末尾行坐标
mrnIntBlkRect.minY = mrnRectValid.minY - nRadius;
mrnIntBlkRect.maxY = mrnRectValid.minY + 1 + nRadius;
mrnIntBlkRect.minX = mrnRectValid.minX - nRadius;
mrnIntBlkRect.maxX = mrnRectValid.minX + 1 + nRadius;
nBlkFirstLn = mrnIntBlkRect.minY * snIntImgSize.w;
nBlkLastLn = mrnIntBlkRect.maxY * snIntImgSize.w;
//初始化目标矩形、起始及末尾行坐标
mrnIntTGRect.minY = mrnRectValid.minY - nRadiusTG;
mrnIntTGRect.maxY = mrnRectValid.minY + 1 + nRadiusTG;
mrnIntTGRect.minX = mrnRectValid.minX - nRadiusTG;
mrnIntTGRect.maxX = mrnRectValid.minX + 1 + nRadiusTG;
nTGFirstLn = mrnIntTGRect.minY * snIntImgSize.w;
nTGLastLn = mrnIntTGRect.maxY * snIntImgSize.w;
//20161113Whao计算的总有效点数
nTotalPnts = (mrnRectValid.maxY - mrnRectValid.minY + 1) * (mrnRectValid.maxX - mrnRectValid.minX + 1);
for (nIter = 0; nIter < nMaxIters; nIter++)
{
//20161113重置二値化结果数组
memset(pnBinary, 0, sizeof(UBYTE8) * DAT_CENTER_REGION_SIZE);
nValidPnts = 0;
nLine = mrnRectValid.minY * snImgSize.w;
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//初始化背景邻域块矩形、起始及末尾行坐标
mrnIntBlkRect.minY = mrnRectValid.minY - nRadius;
mrnIntBlkRect.maxY = mrnRectValid.minY + 1 + nRadius;
mrnIntBlkRect.minX = mrnRectValid.minX - nRadius;
mrnIntBlkRect.maxX = mrnRectValid.minX + 1 + nRadius;
nBlkFirstLn = mrnIntBlkRect.minY * snIntImgSize.w;
nBlkLastLn = mrnIntBlkRect.maxY * snIntImgSize.w;
//初始化目标矩形、起始及末尾行坐标
mrnIntTGRect.minY = mrnRectValid.minY - nRadiusTG;
mrnIntTGRect.maxY = mrnRectValid.minY + 1 + nRadiusTG;
mrnIntTGRect.minX = mrnRectValid.minX - nRadiusTG;
mrnIntTGRect.maxX = mrnRectValid.minX + 1 + nRadiusTG;
nTGFirstLn = mrnIntTGRect.minY * snIntImgSize.w;
nTGLastLn = mrnIntTGRect.maxY * snIntImgSize.w;
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//在梯度图上,查找与邻域背景均值差异满足阈值的点,作为二值化特征点。
//注积分图pnIntImg比原始图像pnImg扩大了1行上侧、1列左侧
nLine = mrnRectValid.minY * snImgSize.w;
for (i = mrnRectValid.minY; i <= mrnRectValid.maxY; i++)
{
for (j = mrnRectValid.minX; j <= mrnRectValid.maxX; j++)
{
//当前点坐标、像素值(输入图像、二值化图像)
nCurrId = nLine + j;
nCurrValue = pnImg[nCurrId];
//计算目标均值
nTGSum = pnIntImg[nTGFirstLn + mrnIntTGRect.minX]
- pnIntImg[nTGFirstLn + mrnIntTGRect.maxX]
- pnIntImg[nTGLastLn + mrnIntTGRect.minX]
+ pnIntImg[nTGLastLn + mrnIntTGRect.maxX];
nTGMean = nTGSum / nTGSize;
//计算邻域均值(去除目标矩形后)
nBlkMean = pnIntImg[nBlkFirstLn + mrnIntBlkRect.minX]
- pnIntImg[nBlkFirstLn + mrnIntBlkRect.maxX]
- pnIntImg[nBlkLastLn + mrnIntBlkRect.minX]
+ pnIntImg[nBlkLastLn + mrnIntBlkRect.maxX];
nBlkMean = (nBlkMean - nTGSum) / nBlkSize;
//将梯度值比背景梯度均值大nThresMin的像素标记为显著点
if (nTGMean - nBlkMean > nThresMin)
{
pnBinary[nCurrId] = DAT_FLAG_BINARY;
nValidPnts++;
}
//更新邻域块矩形积分图X坐标范围
mrnIntBlkRect.minX++;
mrnIntBlkRect.maxX++;
//更新目标矩形积分图X坐标范围
mrnIntTGRect.minX++;
mrnIntTGRect.maxX++;
}
//更新当前点行起始坐标(输入图像、二值化图像)
nLine += snImgSize.w;
//邻域块矩形积分图Y坐标范围、X坐标范围
mrnIntBlkRect.minY++;
mrnIntBlkRect.maxY++;
mrnIntBlkRect.minX = mrnRectValid.minX - nRadius;
mrnIntBlkRect.maxX = mrnRectValid.minX + 1 + nRadius;
nBlkFirstLn += snIntImgSize.w;
nBlkLastLn += snIntImgSize.w;
//目标矩形积分图Y坐标范围、X坐标范围
mrnIntTGRect.minY++;
mrnIntTGRect.maxY++;
mrnIntTGRect.minX = mrnRectValid.minX - nRadiusTG;
mrnIntTGRect.maxX = mrnRectValid.minX + 1 + nRadiusTG;
nTGFirstLn += snIntImgSize.w;
nTGLastLn += snIntImgSize.w;
}
// 20171107zy对超大面目标不进行有效点的判断
//20161113Whao如果有效点数在阈值范围内跳出否则调整分割阈值
fValidRatio = (FLOAT32)nValidPnts / (FLOAT32)nTotalPnts;
if (fValidRatio > DAT_MIN_GRAD_SEG_RATIO && fValidRatio < DAT_MAX_GRAD_SEG_RATIO)
{
m_DAT_stPara.nGradThresMin = nThresMin;
break;
}
else if (fValidRatio < DAT_MIN_GRAD_SEG_RATIO)
{
nThresMin = (nThresMin + DAT_GRAD_THRES_MIN) / 2;
nThresMin = MAX(nThresMin, DAT_GRAD_THRES_MIN);
if (DAT_GRAD_THRES_MIN == nThresMin)
{
m_DAT_stPara.nGradThresMin = nThresMin;
break;
}
}
else if (fValidRatio > DAT_MAX_GRAD_SEG_RATIO)
{
nThresMin = (nThresMin + DAT_GRAD_THRES_MAX) / 2;
nThresMin = MIN(nThresMin, DAT_GRAD_THRES_MAX);
if (DAT_GRAD_THRES_MAX == nThresMin)
{
m_DAT_stPara.nGradThresMin = nThresMin;
break;
}
}
else
{
//不处理
}
}
//20161113Whao更新梯度分割阈值
m_DAT_stPara.nGradThresMin = nThresMin;
}
/**********************************************************
* 函数名称DAT_CalcTgBgDiff()
* 功能描述:计算目标背景差异图
* 输入参数UINT16 *pFrame -- 输入图像
* SIZE32S snImgSize -- 输入图像尺寸
* SINT32 *pnIntImg -- 输入图像积分图
* SIZE32S snIntImgSize-- 积分图尺寸
* SINT32 nRadius -- 邻域半径
* SINT32 nRadiusTG -- 目标半径
* SINT32 nThresMin -- 分割阈值下限
* 输出参数UBYTE8 *pnBinary -- 二值化图像
* 返 回 值:无
* 调用关系:无
* 其它说明:在输入图像上,查找与邻域背景均值差异满足阈值的点,作为二值化分割点。
* 1减少计算复杂度边界不处理将有效计算区域向内缩小邻域矩形块半径nRadius个像素。
* 2利用积分图g求(m,n)、(i,j)所成矩形内的像素值累加和:
* RectSum = g(m,n) - g(m,j)
* -g(i,n) + g(i,j)
* 3固定分割阈值为nThresMin
* 4输入图像(i,j)点,对应于积分图像上的(i+1,j+1)点。
**********************************************************/
void DetectAreaObj::DAT_CalcTgBgDiff(UINT16* pFrame, SIZE32S snImgSize,
SINT32* pnIntImg, SIZE32S snIntImgSize,
SINT32 nRadius, SINT32 nRadiusTG,
SINT16* pnTgBgDiff)
{
SINT32 i, j;
SINT32 nBorder = 1; //不处理的边界大小
SINT32 nUnvalid = nRadius + nBorder;//无效区域(不处理)的总大小
SINT32 nDiameter = 2 * nRadius + 1; //邻域直径
SINT32 nTGSize = (2 * nRadiusTG + 1) * (2 * nRadiusTG + 1); //目标矩形像素个数
SINT32 nBlkSize = nDiameter * nDiameter - nTGSize; //邻域矩形像素个数(去除目标矩形)
SINT32 nLine = 0; //当前点行起始坐标(输入图像、二值化图像)
SINT32 nBlkFirstLn = 0; //邻域起始行坐标(积分图)
SINT32 nBlkLastLn = 0; //邻域末尾行坐标(积分图)
SINT32 nTGFirstLn = 0; //目标起始行坐标(积分图)
SINT32 nTGLastLn = 0; //目标末尾行坐标(积分图)
SINT32 nCurrId = 0; //当前点图像坐标(输入图像、二值化图像)
SINT32 nCurrValue = 0; //当前像素值(输入图像)
SINT32 nBlkMean = 0; //邻域均值(积分图)
SINT32 nTGSum = 0; //目标像素值之和(积分图)
SINT32 nTGMean = 0; //目标均值(积分图)
SINT32 nImgMean = 0; //图像均值(输入图像)
MINMAXRECT32S mrnRectValid; //有效计算区域矩形
MINMAXRECT32S mrnIntBlkRect;//邻域块矩形(积分图)
MINMAXRECT32S mrnIntTGRect; //目标矩形(积分图)
//20161113Whao计算的总有效点数
//UBYTE8 nIter = 0; //迭代次数
//SINT32 nTotalPnts = 0; //总的点数
//SINT32 nValidPnts = 0; //二値化为1的有效点数
//FLOAT32 fValidRatio = 0.0f; //二值分割后的有效点占比
//20161114Whao计算邻域上下左右均值
SINT32 nBlkMeanUp = 0; //上邻域均值
SINT32 nBlkMeanDown = 0; //上邻域均值
SINT32 nBlkMeanLeft = 0; //上邻域均值
SINT32 nBlkMeanRight = 0; //上邻域均值
SINT32 nBlkSizeUp = 0; //上邻域矩形像素个数
SINT32 nBlkSizeDown = 0; //上邻域矩形像素个数
SINT32 nBlkSizeLeft = 0; //上邻域矩形像素个数
SINT32 nBlkSizeRight = 0; //上邻域矩形像素个数
SINT32 BlkMeanArray[4] = { 0 };
SINT32* pnBlkMeanArray = BlkMeanArray;
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//计算全图均值
nImgMean = pnIntImg[snIntImgSize.s - 1] / snImgSize.s;
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//计算有效区域矩形
mrnRectValid.minX = nUnvalid;
mrnRectValid.maxX = snImgSize.w - 1 - nUnvalid;
mrnRectValid.minY = nUnvalid;
mrnRectValid.maxY = snImgSize.h - 1 - nUnvalid;
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//初始化背景邻域块矩形、起始及末尾行坐标
mrnIntBlkRect.minY = mrnRectValid.minY - nRadius;
mrnIntBlkRect.maxY = mrnRectValid.minY + 1 + nRadius;
mrnIntBlkRect.minX = mrnRectValid.minX - nRadius;
mrnIntBlkRect.maxX = mrnRectValid.minX + 1 + nRadius;
nBlkFirstLn = mrnIntBlkRect.minY * snIntImgSize.w;
nBlkLastLn = mrnIntBlkRect.maxY * snIntImgSize.w;
//初始化目标矩形、起始及末尾行坐标
mrnIntTGRect.minY = mrnRectValid.minY - nRadiusTG;
mrnIntTGRect.maxY = mrnRectValid.minY + 1 + nRadiusTG;
mrnIntTGRect.minX = mrnRectValid.minX - nRadiusTG;
mrnIntTGRect.maxX = mrnRectValid.minX + 1 + nRadiusTG;
nTGFirstLn = mrnIntTGRect.minY * snIntImgSize.w;
nTGLastLn = mrnIntTGRect.maxY * snIntImgSize.w;
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//在梯度图上,查找与邻域背景均值差异满足阈值的点,作为二值化特征点。
//注积分图pnIntImg比原始图像pnImg扩大了1行上侧、1列左侧
nLine = mrnRectValid.minY * snImgSize.w;
//20161115上下左右邻域点个数仅计算一次
nBlkSizeUp = (mrnIntTGRect.minY - mrnIntBlkRect.minY)
* (mrnIntTGRect.maxX - mrnIntTGRect.minX);
nBlkSizeDown = nBlkSizeUp;
nBlkSizeLeft = nBlkSizeUp;
nBlkSizeRight = nBlkSizeUp;
//20161115计算目标背景残差图
for (i = mrnRectValid.minY; i <= mrnRectValid.maxY; i++)
{
for (j = mrnRectValid.minX; j <= mrnRectValid.maxX; j++)
{
//当前点坐标、像素值(输入图像、二值化图像)
nCurrId = nLine + j;
nCurrValue = pFrame[nCurrId];
//计算上背景邻域
nBlkMeanUp = pnIntImg[nBlkFirstLn + mrnIntTGRect.minX]
- pnIntImg[nTGFirstLn + mrnIntTGRect.minX]
- pnIntImg[nBlkFirstLn + mrnIntTGRect.maxX]
+ pnIntImg[nTGFirstLn + mrnIntTGRect.maxX];
nBlkMeanUp = nBlkMeanUp / nBlkSizeUp;
pnBlkMeanArray[0] = nBlkMeanUp;
//计算下背景邻域 ok
nBlkMeanDown = pnIntImg[nTGLastLn + mrnIntTGRect.minX]
- pnIntImg[nTGLastLn + mrnIntTGRect.maxX]
- pnIntImg[nBlkLastLn + mrnIntTGRect.minX]
+ pnIntImg[nBlkLastLn + mrnIntTGRect.maxX];
nBlkMeanDown = nBlkMeanDown / nBlkSizeDown;
pnBlkMeanArray[1] = nBlkMeanDown;
//计算左背景邻域 ok
nBlkMeanLeft = pnIntImg[nTGFirstLn + mrnIntBlkRect.minX]
- pnIntImg[nTGFirstLn + mrnIntTGRect.minX]
- pnIntImg[nTGLastLn + mrnIntBlkRect.minX]
+ pnIntImg[nTGLastLn + mrnIntTGRect.minX];
nBlkMeanLeft = nBlkMeanLeft / nBlkSizeLeft;
pnBlkMeanArray[2] = nBlkMeanLeft;
//计算右背景邻域 ok
nBlkMeanRight = pnIntImg[nTGFirstLn + mrnIntTGRect.maxX]
- pnIntImg[nTGFirstLn + mrnIntBlkRect.maxX]
- pnIntImg[nTGLastLn + mrnIntTGRect.maxX]
+ pnIntImg[nTGLastLn + mrnIntBlkRect.maxX];
nBlkMeanRight = nBlkMeanRight / nBlkSizeRight;
pnBlkMeanArray[3] = nBlkMeanRight;
//20161114排序取次小值
if (GLB_OBJ_GRAY_DARK == m_DAT_stPara.nDetectGrayType)
{
nBlkMean = FindMinOfFour(pnBlkMeanArray);
}
else if (GLB_OBJ_GRAY_BRIGHT == m_DAT_stPara.nDetectGrayType)
{
// 20171016zy: 仅筛选特别亮的点
nBlkMean = FindMaxOfFour(pnBlkMeanArray);
}
else
{
//不处理
}
pnTgBgDiff[nCurrId] = nCurrValue - nBlkMean;
//更新邻域块矩形积分图X坐标范围
mrnIntBlkRect.minX++;
mrnIntBlkRect.maxX++;
//更新目标矩形积分图X坐标范围
mrnIntTGRect.minX++;
mrnIntTGRect.maxX++;
}
//更新当前点行起始坐标(输入图像、二值化图像)
nLine += snImgSize.w;
//邻域块矩形积分图Y坐标范围、X坐标范围
mrnIntBlkRect.minY++;
mrnIntBlkRect.maxY++;
mrnIntBlkRect.minX = mrnRectValid.minX - nRadius;
mrnIntBlkRect.maxX = mrnRectValid.minX + 1 + nRadius;
nBlkFirstLn = mrnIntBlkRect.minY * snIntImgSize.w;
nBlkLastLn = mrnIntBlkRect.maxY * snIntImgSize.w;
//目标矩形积分图Y坐标范围、X坐标范围
mrnIntTGRect.minY++;
mrnIntTGRect.maxY++;
mrnIntTGRect.minX = mrnRectValid.minX - nRadiusTG;
mrnIntTGRect.maxX = mrnRectValid.minX + 1 + nRadiusTG;
nTGFirstLn += snIntImgSize.w;
nTGLastLn += snIntImgSize.w;
}
}
/**********************************************************
* 函数名称DAT_GraySegmentation()
* 功能描述:灰度分割
* 输入参数UINT16 *pFrame -- 输入图像
* SIZE32S snImgSize -- 输入图像尺寸
* SINT32 *pnIntImg -- 输入图像积分图
* SIZE32S snIntImgSize-- 积分图尺寸
* SINT32 nRadius -- 邻域半径
* SINT32 nRadiusTG -- 目标半径
* SINT32 nThresMin -- 分割阈值下限
* 输出参数UBYTE8 *pnBinary -- 二值化图像
* 返 回 值:无
* 调用关系:无
* 其它说明:在输入图像上,查找与邻域背景均值差异满足阈值的点,作为二值化分割点。
* 1减少计算复杂度边界不处理将有效计算区域向内缩小邻域矩形块半径nRadius个像素。
* 2利用积分图g求(m,n)、(i,j)所成矩形内的像素值累加和:
* RectSum = g(m,n) - g(m,j)
* -g(i,n) + g(i,j)
* 3固定分割阈值为nThresMin
* 4输入图像(i,j)点,对应于积分图像上的(i+1,j+1)点。
**********************************************************/
void DetectAreaObj::DAT_GraySegmentation(SIZE32S snImgSize, SINT32 nRadius, SINT32 nThresMin,
UBYTE8* pnBinary, SINT16* pnTgBgDiff, BBOOL changeDetParam)
{
SINT32 i, j;
SINT32 nBorder = 1; //不处理的边界大小
SINT32 nUnvalid = nRadius + nBorder;//无效区域(不处理)的总大小
SINT32 nLine = 0; //当前点行起始坐标(输入图像、二值化图像)
SINT32 nCurrId = 0; //当前点图像坐标(输入图像、二值化图像)
MINMAXRECT32S mrnRectValid; //有效计算区域矩形
SINT16 nMaxIters = DAT_MAX_SEG_TIMES; //最大迭代次数
//20161113Whao计算的总有效点数
UBYTE8 nIter = 0; //迭代次数
SINT32 nTotalPnts = 0; //总的点数
SINT32 nValidPnts = 0; //二値化为1的有效点数
FLOAT32 fValidRatio = 0.0f; //二值分割后的有效点占比
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//计算有效区域矩形
mrnRectValid.minX = nUnvalid;
mrnRectValid.maxX = snImgSize.w - 1 - nUnvalid;
mrnRectValid.minY = nUnvalid;
mrnRectValid.maxY = snImgSize.h - 1 - nUnvalid;
//20161113Whao计算的总有效点数
nTotalPnts = (mrnRectValid.maxY - mrnRectValid.minY + 1) * (mrnRectValid.maxX - mrnRectValid.minX + 1);
nLine = mrnRectValid.minY * snImgSize.w;
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//在梯度图上,查找与邻域背景均值差异满足阈值的点,作为二值化特征点。
//注积分图pnIntImg比原始图像pnImg扩大了1行上侧、1列左侧
//20161113Whao增加最大迭代次数和有效点占比判断
for (nIter = 0; nIter < nMaxIters; nIter++)
{
//20161113重置二値化结果数组
memset(pnBinary, 0, sizeof(UBYTE8) * DAT_CENTER_REGION_SIZE);
nValidPnts = 0;
nLine = mrnRectValid.minY * snImgSize.w;
for (i = mrnRectValid.minY; i <= mrnRectValid.maxY; i++)
{
for (j = mrnRectValid.minX; j <= mrnRectValid.maxX; j++)
{
//当前点坐标、像素值(输入图像、二值化图像)
nCurrId = nLine + j;
//将灰度值比背景均值大nThresMin的像素标记为显著点
//MSSu, 20150513: 面目标增加暗目标检测模式
if (GLB_OBJ_GRAY_BRIGHT == m_DAT_stPara.nDetectGrayType)
{
if (pnTgBgDiff[nCurrId] > nThresMin)
{
pnBinary[nCurrId] = DAT_FLAG_BINARY;
nValidPnts++;
}
}
else if (GLB_OBJ_GRAY_DARK == m_DAT_stPara.nDetectGrayType)
{
if (pnTgBgDiff[nCurrId] < -nThresMin)
{
pnBinary[nCurrId] = DAT_FLAG_BINARY; //DAT_FLAG_BINARY_DARK;
nValidPnts++;
}
}
else
{
//if (ABS(nCurrValue - nBlkMean) > nThresMin)
//{
// pnBinary[nCurrId] = DAT_FLAG_BINARY;
//}
//不处理
}
}
//更新当前点行起始坐标(输入图像、二值化图像)
nLine += snImgSize.w;
}
//跟踪状态不调整分割阈值(老版本)
//==========20171017zy: 跟踪状态下,也进行分割阈值的调整,注释下面=============
//if (GLB_STATUS_TRACK == m_GLB_stPara.nStatus)
//{
// break;
//}
// 20171107zy: 添加超大面目标限制,超不面目标不进行有效点判断
//20161113Whao如果有效点数在阈值范围内跳出否则调整分割阈值
if (false == changeDetParam)
{
continue;
}
fValidRatio = (FLOAT32)nValidPnts / (FLOAT32)nTotalPnts;
if (fValidRatio > DAT_MIN_GRAY_SEG_RATIO && fValidRatio < DAT_MAX_GRAY_SEG_RATIO)
{
if (GLB_OBJ_GRAY_BRIGHT == m_DAT_stPara.nDetectGrayType)
{
m_DAT_stPara.nGrayThresMinBright = nThresMin;
}
else
{
m_DAT_stPara.nGrayThresMinDark = nThresMin;
}
break;
}
else if (fValidRatio < DAT_MIN_GRAY_SEG_RATIO)
{
if (GLB_OBJ_GRAY_BRIGHT == m_DAT_stPara.nDetectGrayType)
{
nThresMin = (SINT32)(0.7 * nThresMin + 0.3 * DAT_GRAY_THRES_BRIGHT_MIN);
nThresMin = MAX(nThresMin, DAT_GRAY_THRES_BRIGHT_MIN);
if (DAT_GRAY_THRES_BRIGHT_MIN == nThresMin)
{
m_DAT_stPara.nGrayThresMinBright = nThresMin;
}
}
else
{
nThresMin = (SINT32)(0.7 * nThresMin + 0.3 * DAT_GRAY_THRES_DARK_MIN);
nThresMin = MAX(nThresMin, DAT_GRAY_THRES_DARK_MIN);
if (DAT_GRAY_THRES_DARK_MIN == nThresMin)
{
m_DAT_stPara.nGrayThresMinDark = nThresMin;
}
}
break;
}
else if (fValidRatio > DAT_MAX_GRAY_SEG_RATIO)
{
//nThresMin = (nThresMin + DAT_GRAY_THRES_MAX) / 2;
// 20171016zy 修改迭代阈值的变化比例
nThresMin = (SINT32)(0.7 * nThresMin + 0.3 * DAT_GRAY_THRES_MAX);
nThresMin = MIN(nThresMin, DAT_GRAY_THRES_MAX);
if (DAT_GRAY_THRES_MAX == nThresMin)
{
if (GLB_OBJ_GRAY_BRIGHT == m_DAT_stPara.nDetectGrayType)
{
m_DAT_stPara.nGrayThresMinBright = nThresMin;
}
else
{
m_DAT_stPara.nGrayThresMinDark = nThresMin;
}
break;
}
}
else
{
//不处理
}
}
if (true == changeDetParam)
{
//20161113Whao更新亮暗目标分割阈值
if (GLB_OBJ_GRAY_BRIGHT == m_DAT_stPara.nDetectGrayType)
{
m_DAT_stPara.nGrayThresMinBright = nThresMin;
}
else
{
m_DAT_stPara.nGrayThresMinDark = nThresMin;
}
}
}
/**********************************************************
* 函数名称DAT_ObjsSegmentation()
* 功能描述:目标分割
* 输入参数UINT16 *pFrame -- 原始图像(降采样后)
* UBYTE8 *pnGrayBinary -- 灰度二值图(降采样后)
* UBYTE8 *pnGradBinary -- 梯度二值图(降采样后)
* SIZE32S snImgSize -- 输入图像尺寸(降采样后)
* SINT32 *pnGrayInt -- 灰度积分图
* SINT32 *pnGradInt -- 梯度积分图
* SIZE32S snIntSize -- 积分图尺寸
* SIZE32S snBlksNum -- 分块个数
* SINT32 nDSmpScale -- 降采样倍数
* MINMAXRECT32S mrnSrRect -- 搜索区域矩形(原始图像)
* SINT32 nFrmObjsMax -- 单帧检测目标的最大个数
* 输出参数TARGET_OBJECT *ptTargetArray-- 当前帧目标检测结果数组
* 返 回 值SINT32 nObjsCnt -- 单帧检测的目标数量
* 调用关系:无
* 其它说明在2倍降采样图像上检测目标再还原回原始图像位置及大小。
**********************************************************/
SINT32 DetectAreaObj::DAT_ObjsSegmentation(UINT16* pFrame, UBYTE8* pnGrayBinary,
UBYTE8* pnGradBinary, SIZE32S snImgSize,
SINT32* pnGrayInt, SINT32* pnGradInt, SIZE32S snIntSize,
SIZE32S snBlksNum, SINT32 nDSmpScale, MINMAXRECT32S mrnSrRect,
TARGET_OBJECT* ptTargetArray, SINT32 nFrmObjsMax, GD_PIXEL_FORMAT_E enPixelFormat)
{
MINMAXRECT32S* pmrnBlksRect = (MINMAXRECT32S*)DAT_pmrnBlksRect;
UBYTE8* pnFlagHasSr = (UBYTE8*)DAT_pFlagHasSearch;
SINT32 k, i, j;
SINT32 nObjsCnt = 0;
SIZE32S snBlksNumNew = snBlksNum;
MINMAXRECT32S mrnRect;
SINT32 nLine, nIndex;
TARGET_OBJECT tTarget; //记录单个目标
//BBOOL bSuccessFlag = FALSE;
//BBOOL bStop = FALSE;
BBOOL bTarget = FALSE;
FLOAT32 fDSmpRatio = 1.0f / (nDSmpScale * nDSmpScale);
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//初始化
memset(ptTargetArray, 0, nFrmObjsMax * sizeof(TARGET_OBJECT));
memset(pnFlagHasSr, 0, snImgSize.s * sizeof(UBYTE8));
//限制更新分块个数为奇数
snBlksNumNew.w = (0 == snBlksNumNew.w % 2) ? snBlksNumNew.w + 1 : snBlksNumNew.w;
snBlksNumNew.w = MIN(snBlksNumNew.w, DAT_SR_RGN_BLKS_NUM_W);
snBlksNumNew.h = snBlksNumNew.w;
snBlksNumNew.s = snBlksNumNew.w * snBlksNumNew.h;
m_DAT_stInput.snSrBlksNum = snBlksNumNew;
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//对搜索区域进行分块
//分块的目的:因目标个数有限制,优先检测图像中心的目标
DAT_SetSearchBlks(snImgSize, snBlksNumNew, pmrnBlksRect);
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//目标分割(优先检测图像中心块)
for (k = 0; k < snBlksNumNew.s; k++)
{
mrnRect = pmrnBlksRect[k];
nLine = mrnRect.minY * snImgSize.w;
for (i = mrnRect.minY; i <= mrnRect.maxY; i++)
{
for (j = mrnRect.minX; j <= mrnRect.maxX; j++)
{
//计算当前像素坐标
nIndex = nLine + j;
//MSSu, 20150514: 弱目标检测时,灰度、梯度二值点取并集,否则取交集
BBOOL bSeedPt = FALSE;
if (DAT_FLAG_BINARY == pnGrayBinary[nIndex]
&& DAT_FLAG_BINARY == pnGradBinary[nIndex]
&& DAT_FLAG_CONNECTED != pnFlagHasSr[nIndex])
{
bSeedPt = TRUE;
}
//若当前点为二值化点,且未被归类,则将其作为种子点,进行连通域搜索
if (bSeedPt)
{
//目标初始化为空
memset(&tTarget, 0, sizeof(TARGET_OBJECT));
bTarget = FALSE;
//区域连通
//MSSu, 20150608: 连通像素个数阈值*0.8,目的:防止计算量过大。
DAT_GetConnectedArea(pFrame, pnGrayBinary, pnGradBinary,
pnFlagHasSr, snImgSize.w, snImgSize.h, j, i,
(SINT32)(m_DAT_stPara.nObjSizeMax * fDSmpRatio * 0.8), &tTarget);
//目标确认
bTarget = DAT_IsTarget(pFrame, snImgSize, pnGrayInt,
pnGradInt, snIntSize, &tTarget, enPixelFormat);
//若确认为目标,则加入面目标数组
if (bTarget)
{
//标记为真实目标
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_DAT;
//更新目标位置,还原到原始图像坐标系
tTarget.pfCenPos.x = (tTarget.pfCenPos.x) * nDSmpScale + mrnSrRect.minX + (nDSmpScale >> 1);
tTarget.pfCenPos.y = (tTarget.pfCenPos.y) * nDSmpScale + mrnSrRect.minY + (nDSmpScale >> 1);
tTarget.pnMaxPos.x = (SINT16)(tTarget.pnMaxPos.x * nDSmpScale + mrnSrRect.minX);
tTarget.pnMaxPos.y = (SINT16)(tTarget.pnMaxPos.y * nDSmpScale + mrnSrRect.minY);
tTarget.mrnRect.minX = tTarget.mrnRect.minX * nDSmpScale + mrnSrRect.minX;
//tTarget.mrnRect.maxX = tTarget.mrnRect.maxX * nDSmpScale + mrnSrRect.minX;
//20161207还原回去最小值指向原始长度的第一个点最大值指向原始长度的最后一个点
tTarget.mrnRect.maxX = tTarget.mrnRect.maxX * nDSmpScale + mrnSrRect.minX + nDSmpScale - 1;
tTarget.mrnRect.minY = tTarget.mrnRect.minY * nDSmpScale + mrnSrRect.minY;
//tTarget.mrnRect.maxY = tTarget.mrnRect.maxY * nDSmpScale + mrnSrRect.minY;
tTarget.mrnRect.maxY = tTarget.mrnRect.maxY * nDSmpScale + mrnSrRect.minY + nDSmpScale - 1;
//更新目标大小
tTarget.snSize.w *= nDSmpScale;
tTarget.snSize.h *= nDSmpScale;
tTarget.snSize.s *= (nDSmpScale * nDSmpScale);
tTarget.unObjPxlsCnt *= (nDSmpScale * nDSmpScale);
//标记目标类型
tTarget.nObjTypeSize = GLB_OBJ_SIZE_FACE;
tTarget.nObjTypeGray = (tTarget.fSNR > 0.0f) ? GLB_OBJ_GRAY_BRIGHT : GLB_OBJ_GRAY_DARK;
// //计算目标的方位角、俯仰角 (全局耦合)
// tTarget.afAngle.fAz = SERVO_CalcObjAzimuth(tTarget.pfCenPos.x,
// m_GLB_stInput.stParaLn.snImgSize.w,
// m_SERVO_stInput.fAzimuth, m_SERVO_stInput.fResolAz);
// tTarget.afAngle.fPt = SERVO_CalcObjPitching(tTarget.pfCenPos.y,
// m_GLB_stInput.stParaLn.snImgSize.h,
// m_SERVO_stInput.fPitching, m_SERVO_stInput.fResolPt);
//将目标加入单帧目标数组
ptTargetArray[nObjsCnt] = tTarget;
nObjsCnt++;
//目标个数达上限,则终止检测
if (nFrmObjsMax == nObjsCnt)
{
return nObjsCnt;
}
}
}
}
//更新下一行起始坐标
nLine += snImgSize.w;
}
//目标个数达上限,则终止检测
if (nObjsCnt > nFrmObjsMax)
{
break;
}
}
return nObjsCnt;
}
/**********************************************************
* 函数名称DAT_SetSearchBlks()
* 功能描述:对搜索区域进行分块,将最中心的块放在数组首位
* 输入参数SIZE32S snImgSize -- 输入图像尺寸(降采样后)
* SIZE32S snBlksNum -- 分块个数
* 输出参数MINMAXRECT32S *pmrnBlksRect -- 分块矩形坐标数组
* 返 回 值:无
* 调用关系:无
* 其它说明3*3分块顺序 5*5分块顺序
* 5 1 6 21 13 9 14 22
* 4 0 2 20 5 1 6 15
* 8 3 7 12 4 0 2 10
* 19 8 3 7 16
* 24 18 11 17 23
* 更多块排序效果参见SVN\Arith_Object_Detect_Recognise\S231-光电跟踪系统
* \trunk\src\S231_matlab_BlksSort\BlksSort.m
**********************************************************/
void DetectAreaObj::DAT_SetSearchBlks(SIZE32S snImgSize, SIZE32S snBlksNum, MINMAXRECT32S* pmrnBlksRect)
{
SINT32 i, j, k;
SINT32 nBlkId;
SINT32 nBlkWidth = snImgSize.w / snBlksNum.w;//分块宽度
SINT32 nBlkHeight = snImgSize.h / snBlksNum.h;//分块高度
SINT32 nCenBiggerW = nBlkWidth / 4; //中间分块扩大比例
SINT32 nCenBiggerH = nBlkHeight / 4; //中间分块扩大比例
SINT32 nCenBlkW = nBlkWidth + nCenBiggerW; //中间分块宽度
SINT32 nCenBlkH = nBlkHeight + nCenBiggerH; //中间分块高度
SINT32 nOtherBlksW = (snImgSize.w - nCenBlkW) / (snBlksNum.w - 1); //其它分块宽度
SINT32 nOtherBlksH = (snImgSize.h - nCenBlkH) / (snBlksNum.h - 1); //其它分块宽度
SINT32 nCenBlkIdX = snBlksNum.w / 2; //中间分块位置X
SINT32 nCenBlkIdY = snBlksNum.h / 2; //中间分块位置Y
MINMAXRECT32S mrnRectTop, mrnRectBottom, mrnRectLeft, mrnRectRight;
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//第0子块正中间
pmrnBlksRect[0].minY = MAX(0, MIN(nCenBlkIdY * nOtherBlksH, snImgSize.h - 1));
pmrnBlksRect[0].maxY = MAX(0, MIN(snImgSize.h - pmrnBlksRect[0].minY, snImgSize.h - 1));
pmrnBlksRect[0].minX = MAX(0, MIN(nCenBlkIdX * nOtherBlksW, snImgSize.w - 1));
pmrnBlksRect[0].maxX = MAX(0, MIN(snImgSize.w - pmrnBlksRect[0].minX, snImgSize.w - 1));
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//其它分块:从中间向外扩展
nBlkId = 1;
for (k = 1; k <= nCenBlkIdX; k++)
{
//------------------------------
//正上方
i = nCenBlkIdY - k;
j = nCenBlkIdX;
mrnRectTop.minY = MAX(pmrnBlksRect[0].minY - k * nOtherBlksH, 0);
mrnRectTop.maxY = MAX(mrnRectTop.minY + nOtherBlksH - 1, 0);
mrnRectTop.minX = pmrnBlksRect[0].minX;
mrnRectTop.maxX = pmrnBlksRect[0].maxX;
pmrnBlksRect[nBlkId] = mrnRectTop;
nBlkId++;
//正右方
i = nCenBlkIdY;
j = nCenBlkIdX + k;
mrnRectRight.minY = pmrnBlksRect[0].minY;
mrnRectRight.maxY = pmrnBlksRect[0].maxY;
mrnRectRight.minX = MIN(pmrnBlksRect[0].maxX + (k - 1) * nOtherBlksW + 1, snImgSize.w - 1);
mrnRectRight.maxX = MIN(mrnRectRight.minX + nOtherBlksW - 1, snImgSize.w - 1);
if (k == nCenBlkIdX)
{
mrnRectRight.maxX = snImgSize.w - 1;
}
pmrnBlksRect[nBlkId] = mrnRectRight;
nBlkId++;
//正下方
i = nCenBlkIdY + k;
j = nCenBlkIdX;
mrnRectBottom.minY = MIN(pmrnBlksRect[0].maxY + (k - 1) * nOtherBlksH + 1, snImgSize.h - 1);
mrnRectBottom.maxY = MIN(mrnRectBottom.minY + nOtherBlksH - 1, snImgSize.h - 1);
mrnRectBottom.minX = pmrnBlksRect[0].minX;
mrnRectBottom.maxX = pmrnBlksRect[0].maxX;
if (k == nCenBlkIdX)
{
mrnRectBottom.maxY = snImgSize.h - 1;
}
pmrnBlksRect[nBlkId] = mrnRectBottom;
nBlkId++;
//正左方
i = nCenBlkIdY;
j = nCenBlkIdX - k;
mrnRectLeft.minY = pmrnBlksRect[0].minY;
mrnRectLeft.maxY = pmrnBlksRect[0].maxY;
mrnRectLeft.minX = MAX(pmrnBlksRect[0].minX - k * nOtherBlksW, 0);
mrnRectLeft.maxX = MAX(mrnRectLeft.minX + nOtherBlksW - 1, 0);
pmrnBlksRect[nBlkId] = mrnRectLeft;
nBlkId++;
//------------------------------
//其它
for (j = 1; j < k; j++)
{
//上行其它列(左右对称)
pmrnBlksRect[nBlkId].minY = mrnRectTop.minY;
pmrnBlksRect[nBlkId].maxY = mrnRectTop.maxY;
pmrnBlksRect[nBlkId].minX = pmrnBlksRect[0].minX - j * nOtherBlksW;
pmrnBlksRect[nBlkId].maxX = pmrnBlksRect[nBlkId].minX + nOtherBlksW - 1;
nBlkId++;
pmrnBlksRect[nBlkId].minY = mrnRectTop.minY;
pmrnBlksRect[nBlkId].maxY = mrnRectTop.maxY;
pmrnBlksRect[nBlkId].minX = pmrnBlksRect[0].maxX + (j - 1) * nOtherBlksW + 1;
pmrnBlksRect[nBlkId].maxX = pmrnBlksRect[nBlkId].minX + nOtherBlksW - 1;
nBlkId++;
//右列其它行(上下对称)
pmrnBlksRect[nBlkId].minY = mrnRectRight.minY - j * nOtherBlksH;
pmrnBlksRect[nBlkId].maxY = pmrnBlksRect[nBlkId].minY + nOtherBlksH - 1;
pmrnBlksRect[nBlkId].minX = mrnRectRight.minX;
pmrnBlksRect[nBlkId].maxX = mrnRectRight.maxX;
nBlkId++;
pmrnBlksRect[nBlkId].minY = mrnRectRight.maxY + (j - 1) * nOtherBlksH + 1;
pmrnBlksRect[nBlkId].maxY = pmrnBlksRect[nBlkId].minY + nOtherBlksH - 1;
pmrnBlksRect[nBlkId].minX = mrnRectRight.minX;
pmrnBlksRect[nBlkId].maxX = mrnRectRight.maxX;
nBlkId++;
//下行其它列(左右对称)
pmrnBlksRect[nBlkId].minY = mrnRectBottom.minY;
pmrnBlksRect[nBlkId].maxY = mrnRectBottom.maxY;
pmrnBlksRect[nBlkId].minX = pmrnBlksRect[0].maxX + (j - 1) * nOtherBlksW + 1;
pmrnBlksRect[nBlkId].maxX = pmrnBlksRect[nBlkId].minX + nOtherBlksW - 1;
nBlkId++;
pmrnBlksRect[nBlkId].minY = mrnRectBottom.minY;
pmrnBlksRect[nBlkId].maxY = mrnRectBottom.maxY;
pmrnBlksRect[nBlkId].minX = pmrnBlksRect[0].minX - j * nOtherBlksW;
pmrnBlksRect[nBlkId].maxX = pmrnBlksRect[nBlkId].minX + nOtherBlksW - 1;
nBlkId++;
//左列其它行(上下对称)
pmrnBlksRect[nBlkId].minY = mrnRectLeft.maxY + (j - 1) * nOtherBlksH + 1;
pmrnBlksRect[nBlkId].maxY = pmrnBlksRect[nBlkId].minY + nOtherBlksH - 1;
pmrnBlksRect[nBlkId].minX = mrnRectLeft.minX;
pmrnBlksRect[nBlkId].maxX = mrnRectLeft.maxX;
nBlkId++;
pmrnBlksRect[nBlkId].minY = mrnRectLeft.minY - j * nOtherBlksH;
pmrnBlksRect[nBlkId].maxY = pmrnBlksRect[nBlkId].minY + nOtherBlksH - 1;
pmrnBlksRect[nBlkId].minX = mrnRectLeft.minX;
pmrnBlksRect[nBlkId].maxX = mrnRectLeft.maxX;
nBlkId++;
}
//------------------------------
//左上角
pmrnBlksRect[nBlkId].minY = mrnRectTop.minY;
pmrnBlksRect[nBlkId].maxY = mrnRectTop.maxY;
pmrnBlksRect[nBlkId].minX = mrnRectLeft.minX;
pmrnBlksRect[nBlkId].maxX = mrnRectLeft.maxX;
nBlkId++;
//右上角
pmrnBlksRect[nBlkId].minY = mrnRectTop.minY;
pmrnBlksRect[nBlkId].maxY = mrnRectTop.maxY;
pmrnBlksRect[nBlkId].minX = mrnRectRight.minX;
pmrnBlksRect[nBlkId].maxX = mrnRectRight.maxX;
nBlkId++;
//右下角
pmrnBlksRect[nBlkId].minY = mrnRectBottom.minY;
pmrnBlksRect[nBlkId].maxY = mrnRectBottom.maxY;
pmrnBlksRect[nBlkId].minX = mrnRectRight.minX;
pmrnBlksRect[nBlkId].maxX = mrnRectRight.maxX;
nBlkId++;
//左下角
pmrnBlksRect[nBlkId].minY = mrnRectBottom.minY;
pmrnBlksRect[nBlkId].maxY = mrnRectBottom.maxY;
pmrnBlksRect[nBlkId].minX = mrnRectLeft.minX;
pmrnBlksRect[nBlkId].maxX = mrnRectLeft.maxX;
nBlkId++;
}
}
/**********************************************************
* 函数名称DAT_GetConnectedArea()
* 功能描述对每个种子点进行区域连通得到1个目标
* 输入参数UINT16 *pFrame -- 输入待区域连通的图像
* UBYTE8 *pnGrayBi -- 输入图像的二值化结果
* UBYTE8 *pnFlagHasSr -- 标记每个像素点是否被归类的图像
* SINT32 nWidth -- 输入图像宽度
* SINT32 nHeight -- 输入图像高度
* SINT32 nSeedX -- 种子点的X坐标
* SINT32 nSeedY -- 种子点的Y坐标
* SINT32 nPxlsThresMax -- 最大像素个数阈值
* 输出参数TARGET_OBJECT *ptTarget -- 目标像素阈值下限
* 返 回 值:无
* 调用关系:无
* 其它说明:无
**********************************************************/
void DetectAreaObj::DAT_GetConnectedArea(UINT16* pFrame, UBYTE8* pnGrayBi, UBYTE8* pnGradBi,
UBYTE8* pnFlagHasSr, SINT32 nWidth, SINT32 nHeight,
SINT32 nSeedX, SINT32 nSeedY, SINT32 nPxlsThresMax,
TARGET_OBJECT* ptTarget)
{
SINT16* pnGrowQueX = (SINT16*)DAT_fGradX;
SINT16* pnGrowQueY = (SINT16*)DAT_fGradY;
SINT32 i, j, xx, yy;
SINT32 nStart = 0; //定义堆栈的起点和终点/当nStart=nEnd, 表示堆栈中只有一个点
SINT32 nEnd = 0;
SINT32 nFilterHalf = 1;
BBOOL bConnAdd = FALSE;
//UBYTE8 *pBinaryValue = NULL;
UBYTE8* pFlagSearch = NULL;
SINT32 nPos = 0;
SINT32 nSeedPos = nSeedY * nWidth + nSeedX;
SINT32 nGraySum = pFrame[nSeedPos];
UINT16 nGrayMax = pFrame[nSeedPos];
POINT32F pfCenPos = { 0 };
POINT16S pnMaxPos = { 0 };
//OBJECTSNR objSNR = {0};
//MINMAXRECT32S mrnObj = {0};
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//1.把种子点的坐标压入栈
pnGrowQueX[nEnd] = nSeedX;
pnGrowQueY[nEnd] = nSeedY;
//初始化
//pnGrayBi[nSeedPos] = 0;
pnFlagHasSr[nSeedPos] = DAT_FLAG_CONNECTED;
pfCenPos.x += nSeedX;
pfCenPos.y += nSeedY;
pnMaxPos.x = (SINT16)nSeedX;
pnMaxPos.y = (SINT16)nSeedY;
ptTarget->mrnRect.minX = ptTarget->mrnRect.maxX = nSeedX;
ptTarget->mrnRect.minY = ptTarget->mrnRect.maxY = nSeedY;
ptTarget->unObjPxlsCnt = 1;
ptTarget->pxObjGray = pFrame[nSeedPos];
ptTarget->pxObjMaxGray = pFrame[nSeedPos];
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//2.遍历栈
while (nStart <= nEnd)
{
//2.1.当前种子点的坐标
SINT32 nCurrX = pnGrowQueX[nStart];
SINT32 nCurrY = pnGrowQueY[nStart];
//2.3.对当前点的8邻域进行遍历
for (i = -nFilterHalf; i <= nFilterHalf; i++)
{
for (j = -nFilterHalf; j <= nFilterHalf; j++)
{
//2.3.1.获取8-邻域象素的坐标
xx = nCurrX + j;
yy = nCurrY + i;
//2.3.2.邻域搜索
if ((xx < nWidth)
&& (xx >= 0)
&& (yy < nHeight)
&& (yy >= 0)
&& !(0 == j && 0 == i))//不越界,且不为中心点
{
//2.3.2.1.获取指针
nPos = nWidth * yy + xx;
//pBinaryValue = pnGrayBi;
pFlagSearch = pnFlagHasSr;
//2.3.2.2.标记已搜索过的点
if (DAT_FLAG_CONNECTED == pFlagSearch[nPos])
{
continue;
}
else
{
pFlagSearch[nPos] = DAT_FLAG_CONNECTED;
}
//2.3.2.4.若该点为二值化点,或与最近已压栈点的灰度差小于阈值,则将该点加入栈
bConnAdd = FALSE;
if (DAT_FLAG_BINARY == pnGrayBi[nPos] /*|| DAT_FLAG_BINARY == pnGradBi[nPos]*/)
{
bConnAdd = TRUE;
}
// 横向
//if (j = -nFilterHalf || j <= nFilterHalf)
//{
// if()
//}
if (bConnAdd)
{
//堆栈的尾部指针后移一位
nEnd++;
//目标过大:栈将发生溢出,不再继续搜索该连通域
if (nEnd >= nPxlsThresMax)
{
goto EndConnect;
}
//2.3.2.4.3.把被归类的点从二值化点中清除
//MSSu, 20150409: 不清除
//pnGrayBi[nPos] = DAT_FLAG_NONBINARY;
//2.3.2.4.4.象素(xxyy) 压入栈
pnGrowQueX[nEnd] = xx;
pnGrowQueY[nEnd] = yy;
//2.3.2.4.5.更新目标的边界
ptTarget->mrnRect.minY = MIN(ptTarget->mrnRect.minY, yy);
ptTarget->mrnRect.maxY = MAX(ptTarget->mrnRect.maxY, yy);
ptTarget->mrnRect.minX = MIN(ptTarget->mrnRect.minX, xx);
ptTarget->mrnRect.maxX = MAX(ptTarget->mrnRect.maxX, xx);
//2.3.2.4.6.目标形心、大小累计
pfCenPos.x += xx;
pfCenPos.y += yy;
//ptTarget->pfCenPos.x += xx;
//ptTarget->pfCenPos.y += yy;
//mww,计算目标灰度值,2014.06.13
nGraySum += pFrame[nPos];
// 面目标计算极值亮度
ptTarget->pxObjMaxGray = MAX(ptTarget->pxObjMaxGray, pFrame[nPos]);
//查找极值点
//20161112Whao区分亮目标和暗目标
if (((GLB_OBJ_GRAY_BRIGHT == m_DAT_stPara.nDetectGrayType) && (pFrame[nPos] > nGrayMax))
|| ((GLB_OBJ_GRAY_DARK == m_DAT_stPara.nDetectGrayType) && (pFrame[nPos] < nGrayMax)))
{
nGrayMax = pFrame[nPos];
pnMaxPos.x = xx;
pnMaxPos.y = yy;
}
//目标像素个数累加
ptTarget->unObjPxlsCnt++;
}//end of if(*pnGrayBi==255)...
}//end of if( (xx < nWidth) && (xx>=0) && (yy<nHeight) && (yy>=0) )...
}//end of for (j = -nFilterHalf; j <= nFilterHalf; j++)...
}//end of for (i = -nFilterHalf; i <= nFilterHalf; i++)...
//2.4.指向下一个当前点
nStart++;
}//end of while(nStart <= nEnd)...
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
EndConnect:
//3.计算目标形心、大小
if (ptTarget->unObjPxlsCnt > 0)
{
//计算目标形心
ptTarget->pfCenPos.x = pfCenPos.x / ptTarget->unObjPxlsCnt;
ptTarget->pfCenPos.y = pfCenPos.y / ptTarget->unObjPxlsCnt;
//计算目标极大值
ptTarget->pnMaxPos.x = (SINT16)pnMaxPos.x;
ptTarget->pnMaxPos.y = (SINT16)pnMaxPos.y;
//计算目标灰度均值
ptTarget->pxObjGray = (UINT16)(nGraySum / ptTarget->unObjPxlsCnt);
//计算目标宽高、大小(矩形面积)
ptTarget->snSize.w = ptTarget->mrnRect.maxX - ptTarget->mrnRect.minX + 1;
ptTarget->snSize.h = ptTarget->mrnRect.maxY - ptTarget->mrnRect.minY + 1;
ptTarget->snSize.s = ptTarget->snSize.h * ptTarget->snSize.w;
}
}
/**********************************************************
* 函数名称DAT_IsTarget()
* 功能描述:目标确认
* 输入参数UINT16 *pFrame -- 原始图像
* SIZE32S snImgSize -- 输入图像尺寸(降采样后)
* SINT32 *pnGrayInt -- 灰度积分图
* SINT32 *pnGradInt -- 梯度积分图
* SIZE32S snIntSize -- 积分图尺寸
* TARGET_OBJECT *ptTarget -- 待确认目标
* 输出参数:无
* 返 回 值1-是目标0-不是目标。
* 调用关系:无
* 其它说明:无
**********************************************************/
BBOOL DetectAreaObj::DAT_IsTarget(UINT16* pnSrDSmpImg, SIZE32S snImgSize, SINT32* pnGrayInt,
SINT32* pnGradInt, SIZE32S snIntSize, TARGET_OBJECT* ptTarget, GD_PIXEL_FORMAT_E enPixelFormat)
{
BBOOL bTarget = TRUE;
FLOAT32 fWHRatio; //宽高比
FLOAT32 fRectRatio; //矩形度
MINMAXRECT32S mrnObj; //目标矩形
MINMAXRECT32S mrnBkg; //背景矩形
MINMAXRECT32S mrnBkgBlk;//背景分块矩形
OBJECTSNR objSNR; //目标SNR结构体
SINT32 nObjBigger; //目标矩形扩展大小
SINT32 nBkgBigger; //背景矩形扩展大小
SINT32 nBkgPxlsCnt; //背景分块矩形内的像素个数
SINT32 nBkgMeanT = 0, nBkgMeanB = 0, nBkgMeanL = 0, nBkgMeanR = 0; //背景分块均值
SINT32 nBkgMaxVeri, nBkgMaxHori; //背景水平、垂直方向最大值
SINT32 nBkgMinVeri, nBkgMinHori; //背景水平、垂直方向最大值
SINT32 nDiffThresV, nDiffThresH; //水平、垂直方向灰度差阈值
SINT32 unObjPxlsCntReal;//目标实际像素个数
SIZE16S snObjSizeReal; //目标实际尺寸
BBOOL bEnableDeFABySize = m_DAT_stPara.bUseDeFA_Size;
BBOOL bEnableDeFAByWHR = m_DAT_stPara.bUseDeFA_WHRatio;
BBOOL bEnableDeFAByRR = m_DAT_stPara.bUseDeFA_RectRatio;
BBOOL bEnableDeFAByGrayDiff = m_DAT_stPara.bUseDeFA_BTGrayMin;
BBOOL bEnableDeFaByObjStd = m_DAT_stPara.bUseDeFA_ObjVarMin;
BBOOL bEnableDeFABySNR = false; //20171017飞机穿云过程中SNR过小易排除真实目标改为FALSE
BBOOL bAtSkyLandLine = FALSE;
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//目标矩形
nObjBigger = MIN(MAX(3, (MIN(ptTarget->snSize.w, ptTarget->snSize.h) >> 2)), 6);
mrnObj.minX = MAX(0, MIN(ptTarget->mrnRect.minX - nObjBigger, snImgSize.w - 1));
mrnObj.maxX = MAX(0, MIN(ptTarget->mrnRect.maxX + nObjBigger, snImgSize.w - 1));
mrnObj.minY = MAX(0, MIN(ptTarget->mrnRect.minY - nObjBigger, snImgSize.h - 1));
mrnObj.maxY = MAX(0, MIN(ptTarget->mrnRect.maxY + nObjBigger, snImgSize.h - 1));
//背景矩形
nBkgBigger = MIN(MAX(3, (MIN(ptTarget->snSize.w, ptTarget->snSize.h) >> 2)), 10);
mrnBkg.minX = MAX(0, MIN(mrnObj.minX - nBkgBigger, snImgSize.w - 1));
mrnBkg.maxX = MAX(0, MIN(mrnObj.maxX + nBkgBigger, snImgSize.w - 1));
mrnBkg.minY = MAX(0, MIN(mrnObj.minY - nBkgBigger, snImgSize.h - 1));
mrnBkg.maxY = MAX(0, MIN(mrnObj.maxY + nBkgBigger, snImgSize.h - 1));
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//目标大小限制
if (bEnableDeFABySize) // 20171107zy:对超大目标不进行大小限制
{
unObjPxlsCntReal = ptTarget->unObjPxlsCnt * m_DAT_stPara.nDSmpScale * m_DAT_stPara.nDSmpScale;
snObjSizeReal.w = ptTarget->snSize.w * m_DAT_stPara.nDSmpScale;
snObjSizeReal.h = ptTarget->snSize.h * m_DAT_stPara.nDSmpScale;
snObjSizeReal.s = snObjSizeReal.w * snObjSizeReal.h;
if (unObjPxlsCntReal < m_DAT_stPara.nObjSizeMin
|| unObjPxlsCntReal > m_DAT_stPara.nObjSizeMax
|| snObjSizeReal.w > m_DAT_stPara.nObjWidthMax
|| snObjSizeReal.h > m_DAT_stPara.nObjHeightMax)
{
bTarget = FALSE;
}
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//目标宽高比限制
if (bEnableDeFAByWHR)
{
fWHRatio = (FLOAT32)ptTarget->snSize.w / ptTarget->snSize.h;
if (fWHRatio < m_DAT_stPara.fObjWHRatioMin
|| fWHRatio > m_DAT_stPara.fObjWHRatioMax)
{
bTarget = FALSE;
}
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//目标矩形度限制(只有红外适应做矩形度限制)
if (bEnableDeFAByRR && GD_PIXEL_FORMAT_GRAY_Y16 == enPixelFormat)
{
fRectRatio = (FLOAT32)ptTarget->unObjPxlsCnt / ptTarget->snSize.s;
if (fRectRatio < m_DAT_stPara.fObjRectRatioMin)
{
bTarget = FALSE;
}
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//目标、背景均值灰度差限制
//20161112Whao仅对亮目标打开该限制
if (GLB_OBJ_GRAY_BRIGHT == m_DAT_stPara.nDetectGrayType && bEnableDeFAByGrayDiff)
{
//计算背景上分块灰度均值
mrnBkgBlk = mrnBkg;
mrnBkgBlk.maxY = mrnObj.minY - 1;
nBkgPxlsCnt = (mrnBkgBlk.maxY - mrnBkgBlk.minY + 1) * (mrnBkgBlk.maxX - mrnBkgBlk.minX + 1);
if (0 == nBkgPxlsCnt)
{
bTarget = FALSE;
return bTarget;
}
else
{
nBkgMeanT = IMGO_CalcIntegralInMMRect(pnGrayInt, snIntSize, mrnBkgBlk) / nBkgPxlsCnt;
}
//计算背景下分块灰度均值
mrnBkgBlk = mrnBkg;
mrnBkgBlk.minY = mrnObj.maxY + 1;
nBkgPxlsCnt = (mrnBkgBlk.maxY - mrnBkgBlk.minY + 1) * (mrnBkgBlk.maxX - mrnBkgBlk.minX + 1);
if (0 == nBkgPxlsCnt)
{
bTarget = FALSE;
return bTarget;
}
else
{
nBkgMeanB = IMGO_CalcIntegralInMMRect(pnGrayInt, snIntSize, mrnBkgBlk) / nBkgPxlsCnt;
}
//计算背景左分块灰度均值
mrnBkgBlk = mrnBkg;
mrnBkgBlk.maxX = mrnObj.minX - 1;
nBkgPxlsCnt = (mrnBkgBlk.maxY - mrnBkgBlk.minY + 1) * (mrnBkgBlk.maxX - mrnBkgBlk.minX + 1);
if (0 == nBkgPxlsCnt)
{
bTarget = FALSE;
return bTarget;
}
else
{
nBkgMeanL = IMGO_CalcIntegralInMMRect(pnGrayInt, snIntSize, mrnBkgBlk) / nBkgPxlsCnt;
}
//计算背景右分块灰度均值
mrnBkgBlk = mrnBkg;
mrnBkgBlk.minX = mrnObj.maxX + 1;
nBkgPxlsCnt = (mrnBkgBlk.maxY - mrnBkgBlk.minY + 1) * (mrnBkgBlk.maxX - mrnBkgBlk.minX + 1);
if (0 == nBkgPxlsCnt)
{
bTarget = FALSE;
return bTarget;
}
else
{
nBkgMeanR = IMGO_CalcIntegralInMMRect(pnGrayInt, snIntSize, mrnBkgBlk) / nBkgPxlsCnt;
}
//若目标灰度与垂直方向背景最大灰度的差值,小于(上下背景灰度差异*系数),则认为是虚警。
//MSSu, 20150513: 面目标增加暗目标检测模式
//MSSu, 20150515: S231外场实验远距离目标在天地线附近垂直方向最大值与目标的灰度较接近
// 因此,垂直方向最大值取上下背景的最小值。
//nBkgMaxVeri = MAX(nBkgMeanT, nBkgMeanB);
if (nBkgMeanT > nBkgMeanB)
{
nBkgMaxVeri = nBkgMeanB;
// bAtSkyLandLine = TRUE;
}
else
{
nBkgMaxVeri = MAX(nBkgMeanT, nBkgMeanB);
}
nBkgMinVeri = MIN(nBkgMeanT, nBkgMeanB);
nDiffThresV = (SINT32)(ABS(nBkgMeanT - nBkgMeanB) * m_DAT_stPara.fBkgGrayDiffCoeff);
nDiffThresV = MAX(nDiffThresV, m_DAT_stPara.nObjBkgGrayDiffMin);
if (GLB_OBJ_GRAY_BRIGHT == m_DAT_stPara.nDetectGrayType)
{
if (ptTarget->pxObjGray - nBkgMaxVeri < nDiffThresV)
{
bTarget = FALSE;
}
}
else if (GLB_OBJ_GRAY_DARK == m_DAT_stPara.nDetectGrayType)
{
if (ptTarget->pxObjGray - nBkgMinVeri > -nDiffThresV)
{
bTarget = FALSE;
}
}
else if (GLB_OBJ_GRAY_ALL == m_DAT_stPara.nDetectGrayType)
{
if (((ptTarget->pxObjGray > nBkgMaxVeri)
&& ptTarget->pxObjGray - nBkgMaxVeri < nDiffThresV)
|| ((ptTarget->pxObjGray < nBkgMinVeri)
&& (ptTarget->pxObjGray - nBkgMinVeri > -nDiffThresV)))
{
bTarget = FALSE;
}
}
//若目标灰度与水平方向背景最大灰度的差值,小于(左右背景灰度差异*系数),则认为是虚警。
//MSSu, 20150513: 面目标增加暗目标检测模式
nBkgMaxHori = MAX(nBkgMeanL, nBkgMeanR);
nBkgMinHori = MIN(nBkgMeanL, nBkgMeanR);
nDiffThresH = (SINT32)(ABS(nBkgMeanL - nBkgMeanR) * m_DAT_stPara.fBkgGrayDiffCoeff);
nDiffThresH = MAX(nDiffThresH, m_DAT_stPara.nObjBkgGrayDiffMin);
if (GLB_OBJ_GRAY_BRIGHT == m_DAT_stPara.nDetectGrayType)
{
if (ptTarget->pxObjGray - nBkgMaxHori < nDiffThresH)
{
bTarget = FALSE;
}
}
else if (GLB_OBJ_GRAY_DARK == m_DAT_stPara.nDetectGrayType)
{
if (ptTarget->pxObjGray - nBkgMinHori > -nDiffThresH)
{
bTarget = FALSE;
}
}
else if (GLB_OBJ_GRAY_ALL == m_DAT_stPara.nDetectGrayType)
{
if (((ptTarget->pxObjGray > nBkgMaxHori)
&& ptTarget->pxObjGray - nBkgMaxHori < nDiffThresH)
|| ((ptTarget->pxObjGray < nBkgMinHori)
&& (ptTarget->pxObjGray - nBkgMinHori > -nDiffThresH)))
{
bTarget = FALSE;
}
}
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//仅对确认为目标的计算SNR
if (!bTarget)
{
return bTarget;
}
//目标SNR限制
//计算目标的背景均值、背景标准差、SNR
memset(&objSNR, 0, sizeof(OBJECTSNR));
DAT_CalRectObjSNR_UINT16(pnSrDSmpImg, snImgSize.w, snImgSize.h, mrnObj, nBkgBigger, &objSNR, m_DAT_stPara.nDetectGrayType);
ptTarget->fBGMean = objSNR.BGMean;
ptTarget->fBGStd = objSNR.BGStd;
ptTarget->fSNR = objSNR.fSNR;
ptTarget->fObjStd = objSNR.ObjStd;
ptTarget->fGrayNeighbor[0] = nBkgMeanT;
ptTarget->fGrayNeighbor[1] = nBkgMeanB;
ptTarget->fGrayNeighbor[2] = nBkgMeanL;
ptTarget->fGrayNeighbor[3] = nBkgMeanR;
//20161112Whao仅对亮目标打开该限制
if (GLB_OBJ_GRAY_BRIGHT == m_DAT_stPara.nDetectGrayType && bEnableDeFABySNR && !bAtSkyLandLine)
{
if (GLB_OBJ_GRAY_BRIGHT == m_DAT_stPara.nDetectGrayType)
{
if (ptTarget->fSNR < m_DAT_stPara.fgdk)
{
bTarget = FALSE;
}
}
else if (GLB_OBJ_GRAY_DARK == m_DAT_stPara.nDetectGrayType)
{
if (ptTarget->fSNR > -m_DAT_stPara.fgdk)
{
bTarget = FALSE;
}
}
else if (GLB_OBJ_GRAY_ALL == m_DAT_stPara.nDetectGrayType)
{
if (fabs(ptTarget->fSNR) < m_DAT_stPara.fgdk)
{
bTarget = FALSE;
}
}
}
if (bEnableDeFaByObjStd && ((ptTarget->fObjStd / (ptTarget->unObjPxlsCnt + 0.001)) < 3 && ptTarget->unObjPxlsCnt > 4))
{
//bTarget = false;
}
return bTarget;
}
/**********************************************************
* 函数名称DAT_MergeObjs()
* 功能描述:目标合并
* 输入参数TARGET_OBJECT *ptTargetArray -- 目标数组指针
* TARGET_OBJECT *ptTargetArrayCombine -- 用于合并的临时目标数组指针
* SINT32 nFrmObjsMax -- 单帧检测目标的最大个数
* SIZE32S nObjsCnt -- 输入目标个数
* SINT32 nObjsCombineDist -- 目标合并距离
* 输出参数TARGET_OBJECT *ptTargetArr -- 目标数组指针
* 返 回 值SINT32 nObjsCntNew -- 合并后目标个数
* 调用关系:无
* 其它说明:合并后的最终目标数组,拷贝到*ptTargetArray中返回。
**********************************************************/
SINT32 DetectAreaObj::DAT_MergeObjs(TARGET_OBJECT* ptTargetArray, TARGET_OBJECT* ptTargetArrayCombine,
SINT32 nFrmObjsMax, SINT32 nObjsCnt, SINT32 nObjsCombineDist)
{
SINT32 i, j;
SINT32 nObjsCntNew = 0; //合并后目标个数
TARGET_OBJECT* pTargetA = NULL;
TARGET_OBJECT* pTargetB = NULL;
MINMAXRECT mrnRectA, mrnRectB;
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//判断面目标检测数目是否为零或仅有1个目标
if (nObjsCnt < 2)
{
return nObjsCnt;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//初始化
memcpy(ptTargetArrayCombine, ptTargetArray, nObjsCnt * sizeof(TARGET_OBJECT));
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//遍历已检测的目标
for (i = 0; i < nObjsCnt; i++)
{
//A目标
pTargetA = &ptTargetArrayCombine[i];
mrnRectA = pTargetA->mrnRect;
//A目标已被合并则跳过
if (!pTargetA->bObject)
{
continue;
}
//搜索与A邻近的目标
for (j = i + 1; j < nObjsCnt; j++)
{
//B目标
pTargetB = &ptTargetArrayCombine[j];
mrnRectB = pTargetB->mrnRect;
//若A、B两个目标距离很近更新目标大小和位置
if ((mrnRectA.minX < mrnRectB.minX && mrnRectA.maxX < mrnRectB.minX - nObjsCombineDist)
|| (mrnRectA.maxX > mrnRectB.maxX && mrnRectA.minX > mrnRectB.maxX + nObjsCombineDist)
|| (mrnRectA.minY < mrnRectB.minY && mrnRectA.maxY < mrnRectB.minY - nObjsCombineDist)
|| (mrnRectA.maxY > mrnRectB.maxY && mrnRectA.minY > mrnRectB.maxY + nObjsCombineDist))
{
continue;
}
//20161113跟踪过程中对重合的目标不合并
//将B目标合并到A目标中
pTargetA->pfCenPos.x = (pTargetA->pfCenPos.x * pTargetA->unObjPxlsCnt + pTargetB->pfCenPos.x * pTargetB->unObjPxlsCnt);
pTargetA->pfCenPos.x /= (pTargetA->unObjPxlsCnt + pTargetB->unObjPxlsCnt);
pTargetA->pfCenPos.y = (pTargetA->pfCenPos.y * pTargetA->unObjPxlsCnt + pTargetB->pfCenPos.y * pTargetB->unObjPxlsCnt);
pTargetA->pfCenPos.y /= (pTargetA->unObjPxlsCnt + pTargetB->unObjPxlsCnt);
pTargetA->unObjPxlsCnt = pTargetA->unObjPxlsCnt + pTargetB->unObjPxlsCnt;
pTargetA->mrnRect.minX = MIN(mrnRectA.minX, mrnRectB.minX);
pTargetA->mrnRect.maxX = MAX(mrnRectA.maxX, mrnRectB.maxX);
pTargetA->mrnRect.minY = MIN(mrnRectA.minY, mrnRectB.minY);
pTargetA->mrnRect.maxY = MAX(mrnRectA.maxY, mrnRectB.maxY);
pTargetA->snSize.h = pTargetA->mrnRect.maxY - pTargetA->mrnRect.minY + 1;
pTargetA->snSize.w = pTargetA->mrnRect.maxX - pTargetA->mrnRect.minX + 1;
pTargetA->snSize.s = pTargetA->snSize.h * pTargetA->snSize.w;
//更新A目标的方位角、俯仰角 (全局耦合)
//pTargetA->afAngle.fAz = SERVO_CalcObjAzimuth(pTargetA->pfCenPos.x,
// m_GLB_stInput.stParaLn.snImgSize.w,
// m_SERVO_stInput.fAzimuth, m_SERVO_stInput.fResolAz);
//pTargetA->afAngle.fPt = SERVO_CalcObjPitching(pTargetA->pfCenPos.y,
// m_GLB_stInput.stParaLn.snImgSize.h,
// m_SERVO_stInput.fPitching, m_SERVO_stInput.fResolPt);
//清空B目标
memset(pTargetB, 0, sizeof(TARGET_OBJECT));
}
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//将临时目标数组ptTargetArrayCombine赋给合并后目标数组ptTargetArray
memset(ptTargetArray, 0, nFrmObjsMax * sizeof(TARGET_OBJECT));
nObjsCntNew = 0;
for (i = 0; i < nObjsCnt; i++)
{
pTargetA = &ptTargetArrayCombine[i];
if (pTargetA->bObject)
{
pTargetB = &ptTargetArray[nObjsCntNew++];
memcpy(pTargetB, pTargetA, sizeof(TARGET_OBJECT));
}
}
return nObjsCntNew;
}
/**********************************************************
* 函数名称DAT_MergeTargets()
* 功能描述:亮暗目标数组合并
* 输入参数TARGET_OBJECT *ptDATResultBright -- 亮目标数组指针
* TARGET_OBJECT *ptDATResultDark -- 暗目标数组指针
* SINT32 TnFrmBrightObjCnt -- 亮目标数组个数
* SINT32 nFrmDarkObjCnt -- 暗目标数组个数
* SINT32 nFrmObjsMax -- 单帧检测目标的最大个数
* 输出参数TARGET_OBJECT *ptTargetArr -- 目标数组指针
* 返 回 值SINT32 nObjsCntNew -- 合并后目标个数
* 调用关系:无
* 其它说明:合并后的最终目标数组,拷贝到*ptTargetArray中返回。
**********************************************************/
SINT32 DetectAreaObj::DAT_MergeTargets(TARGET_OBJECT* ptDATResultBright, TARGET_OBJECT* ptDATResultDark,
SINT32 nFrmBrightObjCnt, SINT32 nFrmDarkObjCnt, SINT32 nFrmObjsMax)
{
TARGET_OBJECT* ptTargetArr = (TARGET_OBJECT*)DAT_Target_Temp;
memset(ptTargetArr, 0, sizeof(TARGET_OBJECT) * DAT_TARGET_NUM_MAX);
SINT32 i, j;
FLOAT32 fDistMax = 0.0f; //距离中心的最大值
SINT32 nMaxIndex = 0; //距离中心的最大值的元素下标
SINT32 nIndex = 0; //合并后数组下标
//距离数组
FLOAT32 DistArray[DAT_TARGET_NUM_MAX] = { 0 };
FLOAT32* pfDistArray = DistArray;
FLOAT32 fDist = 0.0f;
SINT32 GLB_CURSORX = m_DAT_stInput.crnSrRect.cx;
SINT32 GLB_CURSORY = m_DAT_stInput.crnSrRect.cy;
for (i = 0; i < nFrmBrightObjCnt; i++)
{
pfDistArray[nIndex] = (ptDATResultBright[i].pfCenPos.x - GLB_CURSORX) * (ptDATResultBright[i].pfCenPos.x - GLB_CURSORX)
+ (ptDATResultBright[i].pfCenPos.y - GLB_CURSORY) * (ptDATResultBright[i].pfCenPos.y - GLB_CURSORY);
ptTargetArr[nIndex] = ptDATResultBright[i];
if (pfDistArray[nIndex] - fDistMax > 0)
{
fDistMax = pfDistArray[nIndex];
nMaxIndex = nIndex;
}
nIndex++;
}
for (j = 0; j < nFrmDarkObjCnt; j++)
{
fDist = (ptDATResultDark[j].pfCenPos.x - GLB_CURSORX) * (ptDATResultDark[j].pfCenPos.x - GLB_CURSORX)
+ (ptDATResultDark[j].pfCenPos.y - GLB_CURSORY) * (ptDATResultDark[j].pfCenPos.y - GLB_CURSORY);
if (nIndex < nFrmObjsMax)
{
pfDistArray[nIndex] = fDist;
ptTargetArr[nIndex] = ptDATResultDark[j];
if (fDist - fDistMax > 0)
{
fDistMax = fDist;
nMaxIndex = nIndex;
}
nIndex++;
}
else
{
if (fDist - fDistMax < 0)
{
ptTargetArr[nMaxIndex] = ptDATResultDark[j];
pfDistArray[nMaxIndex] = fDist;
fDistMax = fDist;
//更新距离最大值和最大值的下标
for (i = 0; i < nFrmObjsMax; i++)
{
if (pfDistArray[i] - fDistMax > 0)
{
fDistMax = pfDistArray[i];
nMaxIndex = i;
}
}
}
}
}
return nIndex;
}
/**********************************************************
* 函数名称DAT_CalRectObjSNR_UINT16()
* 功能描述计算矩形目标SNR
* 输入参数UINT16 *pFrame -- 原始图像
* SINT32 nWidth -- 图像宽度
* SINT32 nHeight -- 图像高度
* MINMAXRECT32S mrnObj-- 目标矩形坐标
* UBYTE8 nDetectGrayType -- 面目标检测类型 1-只检测亮目标2-只检测暗目标3-同时检测亮暗目标
* 输出参数OBJECTSNR *objSNR -- 目标SNR信息
* 返 回 值:无
* 调用关系:无
* 其它说明:无
**********************************************************/
void DAT_CalRectObjSNR_IMG(GD_VIDEO_FRAME_S img, SINT32 nWidth, SINT32 nHeight,
MINMAXRECT32S mrnObj, SINT32 nBkgRadius,
OBJECTSNR* objSNR, UBYTE8 nDetectGrayType)
{
SINT32 i, j;
SINT32 nBGValue, nBGCnt; //背景点灰度、背景点计数
double dBGMean, dBGStd, dObjStd; //背景均值、方差
MINMAXRECT32S mrnBkg; //背景区域矩形
SINT32 nLineIndex, nIndex;
FLOAT32 fGrayMax, fGrayMin, fGrayMean;
POINT16S ptPntMax, ptPntMin;
SINT32 nGrayCnt;
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//获取目标最大灰度值及其坐标
nLineIndex = mrnObj.minY * nWidth;
objSNR->Pnt.x = (mrnObj.minX + mrnObj.maxX) >> 1;
objSNR->Pnt.y = (mrnObj.minY + mrnObj.maxY) >> 1;
//objSNR->ObjGray = pnSrDSmpImg[objSNR->Pnt.y * nWidth + objSNR->Pnt.x];
if (GD_PIXEL_FORMAT_GRAY_Y8 == img.enPixelFormat)
{
objSNR->ObjGray = ((UBYTE8*)img.u64VirAddr[0])[objSNR->Pnt.y * nWidth + objSNR->Pnt.x];
}
else
{
objSNR->ObjGray = ((UINT16*)img.u64VirAddr[0])[objSNR->Pnt.y * nWidth + objSNR->Pnt.x];
}
fGrayMax = objSNR->ObjGray;
fGrayMin = objSNR->ObjGray;
ptPntMax = objSNR->Pnt;
ptPntMin = objSNR->Pnt;
fGrayMean = 0.0f;
nGrayCnt = 0;
dObjStd = 0;
for (i = mrnObj.minY; i <= mrnObj.maxY; i++)
{
for (j = mrnObj.minX; j <= mrnObj.maxX; j++)
{
nIndex = nLineIndex + j;
if (GD_PIXEL_FORMAT_GRAY_Y8 == img.enPixelFormat)
{
//最大值
if (((UBYTE8*)img.u64VirAddr[0])[nIndex] > fGrayMax)
{
fGrayMax = (FLOAT32)(((UBYTE8*)img.u64VirAddr[0])[nIndex]);
ptPntMax.x = j;
ptPntMax.y = i;
}
//最小值
if (((UBYTE8*)img.u64VirAddr[0])[nIndex] < fGrayMin)
{
fGrayMin = (FLOAT32)(((UBYTE8*)img.u64VirAddr[0])[nIndex]);
ptPntMin.x = j;
ptPntMin.y = i;
}
//均值
fGrayMean += (FLOAT32)(((UBYTE8*)img.u64VirAddr[0])[nIndex]);
dObjStd += (FLOAT32)(((UBYTE8*)img.u64VirAddr[0])[nIndex]) * (FLOAT32)(((UBYTE8*)img.u64VirAddr[0])[nIndex]);
}
else
{
//最大值
if (((UINT16*)img.u64VirAddr[0])[nIndex] > fGrayMax)
{
fGrayMax = (FLOAT32)(((UINT16*)img.u64VirAddr[0])[nIndex]);
ptPntMax.x = j;
ptPntMax.y = i;
}
//最小值
if (((UINT16*)img.u64VirAddr[0])[nIndex] < fGrayMin)
{
fGrayMin = (FLOAT32)(((UINT16*)img.u64VirAddr[0])[nIndex]);
ptPntMin.x = j;
ptPntMin.y = i;
}
//均值
fGrayMean += (FLOAT32)(((UINT16*)img.u64VirAddr[0])[nIndex]);
dObjStd += (FLOAT32)(((UINT16*)img.u64VirAddr[0])[nIndex]) * (FLOAT32)(((UINT16*)img.u64VirAddr[0])[nIndex]);
}
nGrayCnt++;
}
nLineIndex += nWidth;
}
if (nGrayCnt > 0)
{
fGrayMean /= nGrayCnt;
dObjStd /= nGrayCnt;
dObjStd -= fGrayMean * fGrayMean;
}
//根据检测类型,获取目标灰度
//亮目标
if (GLB_OBJ_GRAY_BRIGHT == nDetectGrayType)
{
objSNR->ObjGray = fGrayMax;
objSNR->Pnt = ptPntMax;
}
//暗目标
else if (GLB_OBJ_GRAY_DARK == nDetectGrayType)
{
objSNR->ObjGray = fGrayMin;
objSNR->Pnt = ptPntMin;
}
//亮暗全检测
else
{
//MSSu, 20150608: 取目标中心点灰度,屏蔽下面语句
//objSNR->ObjGray = fGrayMean;
//objSNR->Pnt.x = (mrnObj.minX + mrnObj.maxX) >> 1;
//objSNR->Pnt.y = (mrnObj.minY + mrnObj.maxY) >> 1;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//统计背景均值、方差:划分为上、下、左、右四个背景区域
//计算背景窗口边界
mrnBkg.minX = MAX(0, MIN(mrnObj.minX - nBkgRadius, nWidth - 1));
mrnBkg.maxX = MAX(0, MIN(mrnObj.maxX + nBkgRadius, nWidth - 1));
mrnBkg.minY = MAX(0, MIN(mrnObj.minY - nBkgRadius, nHeight - 1));
mrnBkg.maxY = MAX(0, MIN(mrnObj.maxY + nBkgRadius, nHeight - 1));
//统计背景均值、方差
nBGCnt = 0;
dBGMean = 0;
dBGStd = 0;
//背景区域-上
nLineIndex = mrnBkg.minY * nWidth;
for (i = mrnBkg.minY; i <= mrnObj.minY; i++)
{
for (j = mrnBkg.minX; j <= mrnBkg.maxX; j++)
{
nIndex = nLineIndex + j;
//nBGValue = pnSrDSmpImg[nIndex];
if (GD_PIXEL_FORMAT_GRAY_Y8 == img.enPixelFormat)
{
nBGValue = ((UBYTE8*)img.u64VirAddr[0])[nIndex];
}
else
{
nBGValue = ((UINT16*)img.u64VirAddr[0])[nIndex];
}
//背景灰度及灰度平方累加
dBGMean += (double)nBGValue;
dBGStd += (double)nBGValue * nBGValue;
nBGCnt++;
}
nLineIndex += nWidth;
}
//背景区域-下
nLineIndex = (mrnObj.maxY + 1) * nWidth;
for (i = mrnObj.maxY + 1; i <= mrnBkg.maxY; i++)
{
for (j = mrnBkg.minX; j <= mrnBkg.maxX; j++)
{
nIndex = nLineIndex + j;
//nBGValue = pnSrDSmpImg[nIndex];
if (GD_PIXEL_FORMAT_GRAY_Y8 == img.enPixelFormat)
{
nBGValue = ((UBYTE8*)img.u64VirAddr[0])[nIndex];
}
else
{
nBGValue = ((UINT16*)img.u64VirAddr[0])[nIndex];
}
//背景灰度及灰度平方累加
dBGMean += (double)nBGValue;
dBGStd += (double)nBGValue * nBGValue;
nBGCnt++;
}
nLineIndex += nWidth;
}
//背景区域-左
nLineIndex = mrnObj.minY * nWidth;
for (i = mrnObj.minY; i <= mrnObj.maxY; i++)
{
for (j = mrnBkg.minX; j < mrnObj.minX; j++)
{
nIndex = nLineIndex + j;
//nBGValue = pnSrDSmpImg[nIndex];
if (GD_PIXEL_FORMAT_GRAY_Y8 == img.enPixelFormat)
{
nBGValue = ((UBYTE8*)img.u64VirAddr[0])[nIndex];
}
else
{
nBGValue = ((UINT16*)img.u64VirAddr[0])[nIndex];
}
//背景灰度及灰度平方累加
dBGMean += (double)nBGValue;
dBGStd += (double)nBGValue * nBGValue;
nBGCnt++;
}
nLineIndex += nWidth;
}
//背景区域-右
nLineIndex = mrnObj.minY * nWidth;
for (i = mrnObj.minY; i <= mrnObj.maxY; i++)
{
for (j = mrnObj.maxX + 1; j <= mrnBkg.maxX; j++)
{
nIndex = nLineIndex + j;
//nBGValue = pnSrDSmpImg[nIndex];
if (GD_PIXEL_FORMAT_GRAY_Y8 == img.enPixelFormat)
{
nBGValue = ((UBYTE8*)img.u64VirAddr[0])[nIndex];
}
else
{
nBGValue = ((UINT16*)img.u64VirAddr[0])[nIndex];
}
//背景灰度及灰度平方累加
dBGMean += (double)nBGValue;
dBGStd += (double)nBGValue * nBGValue;
nBGCnt++;
}
nLineIndex += nWidth;
}
//计算背景均值、方差
dBGMean /= nBGCnt;
dBGStd /= nBGCnt;
dBGStd -= dBGMean * dBGMean;
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//保存目标SNR信息
objSNR->nTGR = (mrnObj.maxX - mrnObj.minX) >> 1;
objSNR->nBGR = nBkgRadius;
objSNR->BGMean = (FLOAT32)dBGMean;
objSNR->BGStd = (FLOAT32)sqrt(dBGStd);
objSNR->fSNR = (0 == objSNR->BGMean || objSNR->BGStd == 0) ? 1e6f : (FLOAT32)((objSNR->ObjGray - objSNR->BGMean) / objSNR->BGStd);
objSNR->ObjStd = (FLOAT32)sqrt(dObjStd);
}
/**********************************************************
* 函数名称DAT_CalRectObjSNR_UINT16()
* 功能描述计算矩形目标SNR
* 输入参数UINT16 *pFrame -- 原始图像
* SINT32 nWidth -- 图像宽度
* SINT32 nHeight -- 图像高度
* MINMAXRECT32S mrnObj-- 目标矩形坐标
* UBYTE8 nDetectGrayType -- 面目标检测类型 1-只检测亮目标2-只检测暗目标3-同时检测亮暗目标
* 输出参数OBJECTSNR *objSNR -- 目标SNR信息
* 返 回 值:无
* 调用关系:无
* 其它说明:无
**********************************************************/
void DAT_CalRectObjSNR_UINT16(UINT16* pnSrDSmpImg, SINT32 nWidth, SINT32 nHeight,
MINMAXRECT32S mrnObj, SINT32 nBkgRadius,
OBJECTSNR* objSNR, UBYTE8 nDetectGrayType)
{
SINT32 i, j;
SINT32 nBGValue, nBGCnt; //背景点灰度、背景点计数
double dBGMean, dBGStd, dObjStd; //背景均值、方差
MINMAXRECT32S mrnBkg; //背景区域矩形
SINT32 nLineIndex, nIndex;
FLOAT32 fGrayMax, fGrayMin, fGrayMean;
POINT16S ptPntMax, ptPntMin;
SINT32 nGrayCnt;
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//获取目标最大灰度值及其坐标
nLineIndex = mrnObj.minY * nWidth;
objSNR->Pnt.x = (mrnObj.minX + mrnObj.maxX) >> 1;
objSNR->Pnt.y = (mrnObj.minY + mrnObj.maxY) >> 1;
objSNR->ObjGray = pnSrDSmpImg[objSNR->Pnt.y * nWidth + objSNR->Pnt.x];
fGrayMax = objSNR->ObjGray;
fGrayMin = objSNR->ObjGray;
ptPntMax = objSNR->Pnt;
ptPntMin = objSNR->Pnt;
fGrayMean = 0.0f;
nGrayCnt = 0;
dObjStd = 0;
for (i = mrnObj.minY; i <= mrnObj.maxY; i++)
{
for (j = mrnObj.minX; j <= mrnObj.maxX; j++)
{
nIndex = nLineIndex + j;
//最大值
if (pnSrDSmpImg[nIndex] > fGrayMax)
{
fGrayMax = (FLOAT32)(pnSrDSmpImg[nIndex]);
ptPntMax.x = j;
ptPntMax.y = i;
}
//最小值
if (pnSrDSmpImg[nIndex] < fGrayMin)
{
fGrayMin = (FLOAT32)(pnSrDSmpImg[nIndex]);
ptPntMin.x = j;
ptPntMin.y = i;
}
//均值
fGrayMean += (FLOAT32)(pnSrDSmpImg[nIndex]);
dObjStd += (FLOAT32)(pnSrDSmpImg[nIndex]) * (FLOAT32)(pnSrDSmpImg[nIndex]);
nGrayCnt++;
}
nLineIndex += nWidth;
}
if (nGrayCnt > 0)
{
fGrayMean /= nGrayCnt;
dObjStd /= nGrayCnt;
dObjStd -= fGrayMean * fGrayMean;
}
//根据检测类型,获取目标灰度
//亮目标
if (GLB_OBJ_GRAY_BRIGHT == nDetectGrayType)
{
objSNR->ObjGray = fGrayMax;
objSNR->Pnt = ptPntMax;
}
//暗目标
else if (GLB_OBJ_GRAY_DARK == nDetectGrayType)
{
objSNR->ObjGray = fGrayMin;
objSNR->Pnt = ptPntMin;
}
//亮暗全检测
else
{
//MSSu, 20150608: 取目标中心点灰度,屏蔽下面语句
//objSNR->ObjGray = fGrayMean;
//objSNR->Pnt.x = (mrnObj.minX + mrnObj.maxX) >> 1;
//objSNR->Pnt.y = (mrnObj.minY + mrnObj.maxY) >> 1;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//统计背景均值、方差:划分为上、下、左、右四个背景区域
//计算背景窗口边界
mrnBkg.minX = MAX(0, MIN(mrnObj.minX - nBkgRadius, nWidth - 1));
mrnBkg.maxX = MAX(0, MIN(mrnObj.maxX + nBkgRadius, nWidth - 1));
mrnBkg.minY = MAX(0, MIN(mrnObj.minY - nBkgRadius, nHeight - 1));
mrnBkg.maxY = MAX(0, MIN(mrnObj.maxY + nBkgRadius, nHeight - 1));
//统计背景均值、方差
nBGCnt = 0;
dBGMean = 0;
dBGStd = 0;
//背景区域-上
nLineIndex = mrnBkg.minY * nWidth;
for (i = mrnBkg.minY; i <= mrnObj.minY; i++)
{
for (j = mrnBkg.minX; j <= mrnBkg.maxX; j++)
{
nIndex = nLineIndex + j;
nBGValue = pnSrDSmpImg[nIndex];
//背景灰度及灰度平方累加
dBGMean += (double)nBGValue;
dBGStd += (double)nBGValue * nBGValue;
nBGCnt++;
}
nLineIndex += nWidth;
}
//背景区域-下
nLineIndex = (mrnObj.maxY + 1) * nWidth;
for (i = mrnObj.maxY + 1; i <= mrnBkg.maxY; i++)
{
for (j = mrnBkg.minX; j <= mrnBkg.maxX; j++)
{
nIndex = nLineIndex + j;
nBGValue = pnSrDSmpImg[nIndex];
//背景灰度及灰度平方累加
dBGMean += (double)nBGValue;
dBGStd += (double)nBGValue * nBGValue;
nBGCnt++;
}
nLineIndex += nWidth;
}
//背景区域-左
nLineIndex = mrnObj.minY * nWidth;
for (i = mrnObj.minY; i <= mrnObj.maxY; i++)
{
for (j = mrnBkg.minX; j < mrnObj.minX; j++)
{
nIndex = nLineIndex + j;
nBGValue = pnSrDSmpImg[nIndex];
//背景灰度及灰度平方累加
dBGMean += (double)nBGValue;
dBGStd += (double)nBGValue * nBGValue;
nBGCnt++;
}
nLineIndex += nWidth;
}
//背景区域-右
nLineIndex = mrnObj.minY * nWidth;
for (i = mrnObj.minY; i <= mrnObj.maxY; i++)
{
for (j = mrnObj.maxX + 1; j <= mrnBkg.maxX; j++)
{
nIndex = nLineIndex + j;
nBGValue = pnSrDSmpImg[nIndex];
//背景灰度及灰度平方累加
dBGMean += (double)nBGValue;
dBGStd += (double)nBGValue * nBGValue;
nBGCnt++;
}
nLineIndex += nWidth;
}
//计算背景均值、方差
dBGMean /= nBGCnt;
dBGStd /= nBGCnt;
dBGStd -= dBGMean * dBGMean;
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
//保存目标SNR信息
objSNR->nTGR = (mrnObj.maxX - mrnObj.minX) >> 1;
objSNR->nBGR = nBkgRadius;
objSNR->BGMean = (FLOAT32)dBGMean;
objSNR->BGStd = (FLOAT32)sqrt(dBGStd);
objSNR->fSNR = (0 == objSNR->BGMean || objSNR->BGStd == 0) ? 1e6f : (FLOAT32)((objSNR->ObjGray - objSNR->BGMean) / objSNR->BGStd);
objSNR->ObjStd = (FLOAT32)sqrt(dObjStd);
}
// TARGET_OBJECT _CreateNewTarget(UINT16* pFrame, SINT32 nWidth, SINT32 nHeight, RECT32S bbox, SINT32 unFrmId)
// {
// MINMAXRECT32S mrnObjRect;
// OBJECTSNR objSNR;
// TARGET_OBJECT tNewTarget = { 0 };
// TARGET_OBJECT* pNewTarget = NULL;
// POINT32F ptfObjPos = { 0 };
// ptfObjPos.x = FLOAT32(bbox.x + bbox.w / 2);
// ptfObjPos.y = FLOAT32(bbox.y + bbox.h / 2);
// //+++++++++++++++++++++++++++++++++++++++++++++++++++++++
// //计算目标边界矩形
// mrnObjRect.minY = MAX(0, MIN((SINT32)(bbox.y), nHeight - 1));
// mrnObjRect.maxY = MAX(0, MIN((SINT32)(bbox.y + bbox.h), nHeight - 1));
// mrnObjRect.minX = MAX(0, MIN((SINT32)(bbox.x), nWidth - 1));
// mrnObjRect.maxX = MAX(0, MIN((SINT32)(bbox.x + bbox.w), nWidth - 1));
// //+++++++++++++++++++++++++++++++++++++++++++++++++++++++
// //新建目标
// memset(&tNewTarget, 0, sizeof(TARGET_OBJECT));
// tNewTarget.bObject = true;
// tNewTarget.unFrmID = unFrmId;
// tNewTarget.pfCenPos = ptfObjPos;
// tNewTarget.pnMaxPos.x = (SINT16)(ptfObjPos.x);
// tNewTarget.pnMaxPos.y = (SINT16)(ptfObjPos.y);
// tNewTarget.mrnRect.minY = (SINT16)(mrnObjRect.minY);
// tNewTarget.mrnRect.maxY = (SINT16)(mrnObjRect.maxY);
// tNewTarget.mrnRect.minX = (SINT16)(mrnObjRect.minX);
// tNewTarget.mrnRect.maxX = (SINT16)(mrnObjRect.maxX);
// tNewTarget.snSize.w = (SINT16)(bbox.w);
// tNewTarget.snSize.h = (SINT16)(bbox.h);
// tNewTarget.snSize.s = (SINT32)(bbox.w * bbox.h);
// tNewTarget.unObjPxlsCnt = (SINT32)(tNewTarget.snSize.s);
// //计算目标的背景均值、背景标准差、SNR
// memset(&objSNR, 0, sizeof(OBJECTSNR));
// _DAT_CalRectObjSNR_PIXELTYPE(pFrame, nWidth, nHeight, mrnObjRect,
// 3, &objSNR, DAT_DETECT_OBJ_TYPE_ALL);
// tNewTarget.pxObjGray = (UINT16)objSNR.ObjGray;
// tNewTarget.nObjTypeSize = GLB_OBJ_SIZE_FACE;
// tNewTarget.nObjTypeGray = objSNR.fSNR > 0.0f ? GLB_OBJ_GRAY_BRIGHT : GLB_OBJ_GRAY_DARK;
// tNewTarget.fBGMean = objSNR.BGMean;
// tNewTarget.fBGStd = objSNR.BGStd;
// tNewTarget.fSNR = objSNR.fSNR;
// return tNewTarget;
// }