/*********版权所有(C)2017,武汉高德红外股份有限公司*************** * 文件名称: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 SINT32[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(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 //20171110zy:m_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) { SINT32* pnTgBgDiff = (SINT32*)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 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) { SINT32* pnTgBgDiff = (SINT32*)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 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; SINT32* pnTgBgDiff = (SINT32*)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) { SINT32* pnTgBgDiff = (SINT32*)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) { SINT32* pnTgBgDiff = (SINT32*)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.2f; m_DAT_stPara.fObjWHRatioMax = 5.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,初始化灰度残差图 SINT32* pnTgBgDiff = (SINT32*)DAT_DIFF; memset(pnTgBgDiff, 0, sizeof(SINT32) * 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, SINT32* 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, SINT32* 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.象素(xx,yy) 压入栈 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=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; // }