short int iCEdgeMatch::iGetTemplateEdgeInfo1(int nIndex)
{
DV_FUNCNAME(“iCEdgeMatch::iGetTemplateEdgeInfo1”);
DvReturn nReturn = DV_StsOk;
Mat pEdgeGrdMatX;
Mat pEdgeGrdMatY;//K = dy / dx 矩阵
Mat pEdgeGrdKMat;
Mat dx;
Mat dy;
Mat dxy;
Mat pEdgeImg;
//
//
#if SECURITY_DOG
BOOL bResult = FALSE;
ELE_DEVICE_CONTEXT eleContext = {0};
unsigned long ulShareMode = 0;
unsigned long ulRet = 0;
unsigned long ulRealLen = 0;
char ModuleName[16] = {0};
unsigned long ulModuleNameLen = 16;
unsigned long ulIndex = 0;
unsigned char InputBuffer[8] = {0x80, 0x4A, 0xF1, 0xDD, 0xC7, 0xA3, 0xD2, 0xC4};
unsigned long ulInputLen = 8;
unsigned char OutputBuffer[32] = {0};
unsigned long ulOutputLen = 32;
#endif
__DV_BEGIN__;
//检验是否符合计算要求
//if ( !(m_nLayersEnableFlag[nIndex] & BZV_THREE_LAYERS)) return;
// cvNamedWindow(“edge1”);
Size size;
int nWidth, nHeight, nImgStep;
nWidth = m_pTemplateImg1[nIndex].cols;
nHeight = m_pTemplateImg1[nIndex].rows;
nImgStep = m_pTemplateImg1[nIndex].step;
unsigned char *pImgData = (unsigned char *)(m_pTemplateImg1[nIndex].data);
size.width = nWidth;
size.height = nHeight;
//计算图像的归一化梯度向量
//边缘点梯度方向数组
pEdgeGrdMatX = Mat( nHeight, nWidth, CV_32FC1 );
pEdgeGrdMatY = Mat( nHeight, nWidth, CV_32FC1 );
pEdgeGrdKMat = Mat( nHeight, nWidth, CV_32FC1 ); //K = dy / dx 矩阵
float *pEdgeGrdX = pEdgeGrdMatX.ptr<float>(0);
float *pEdgeGrdY = pEdgeGrdMatY.ptr<float>(0);
float *pEdgeGrdK = pEdgeGrdKMat.ptr<float>(0);
int nMatStep = pEdgeGrdMatX.step / sizeof(float);
for (int h = 1; h < nHeight - 1; h++) { //逐行变化
int s = nImgStep;//一行元素的字节数
float *pGrdX = pEdgeGrdX + h * nMatStep;
float *pGrdY = pEdgeGrdY + h * nMatStep;
float *pGrdK = pEdgeGrdK + h * nMatStep;
const unsigned char *pd = pImgData + h * nImgStep;
for (int w = 1; w < nWidth - 1; w++) {//每行元素变化 sobel方法求的,相当于【1,0,-1,2,0,-2,1,0,-1】
double kx = ( (pd - s)[w + 1] + pd[w + 1] + pd[w + 1] + (pd + s)[w + 1] )
- ( (pd - s)[w - 1] + pd[w - 1] + pd[w - 1] + (pd + s)[w - 1] );
double ky = ( (pd + s)[w - 1] + (pd + s)[w] + (pd + s)[w] + (pd + s)[w + 1] )
- ( (pd - s)[w - 1] + (pd - s)[w] + (pd - s)[w] + (pd - s)[w + 1] );
double kxy2 = sqrt(kx * kx + ky * ky) + 0.5;//防止除0
pGrdX[w] = (float)(kx / kxy2); //归一化梯度向量X方向
pGrdY[w] = (float)(ky / kxy2); //归一化梯度向量Y方向
pGrdK[w] = (float)(ky / (kx + 0.1)); //斜率系数(+0.1防止除零)
}
}
//Canny边缘检测
pEdgeImg = Mat(size.height, size.width, CV_8UC1);
int nLowThreshold = (int)(m_fCannyLowThd[nIndex] + 0.5);
int nHighThreshold = (int)(m_fCannyHighThd[nIndex] + 0.5);
int nThreshold = iCanny(m_pTemplateImg1[nIndex], pEdgeImg, m_fCannyThdRatio[nIndex]);
m_fAutoCannyThd[nIndex] = nThreshold;
dx = Mat(nHeight, nWidth, CV_16SC1);
dy = Mat(nHeight, nWidth, CV_16SC1);
dxy = Mat(nHeight, nWidth, CV_16SC1);
Sobel(m_pTemplateImg1[nIndex], dx, CV_16SC1, 1, 0, 3); //计算x方向梯度
Sobel(m_pTemplateImg1[nIndex], dy, CV_16SC1, 0, 1, 3); //计算y方向梯度
//统计像素级边缘点个数, 计算梯度值结果将结果存至dxy中
unsigned char *pEdge = (unsigned char *)pEdgeImg.data;
unsigned char *pMask = (unsigned char *)m_pMaskImg1[nIndex].data;
short *pdx = (short *)dx.ptr<short>(0);
short *pdy = (short *)dy.ptr<short>(0);
short *pdxy = (short *)dxy.ptr<short>(0);
int nWidthStep = pEdgeImg.step;
int ndxyStep = dxy.step / sizeof(short);
int nEdgePtsCounter = 0;
for (int h = 0; h < nHeight; h++) {
const unsigned char *pData = pEdge + h * nWidthStep;
const unsigned char *pMaskData = pMask + h * nWidthStep;
const short *px = pdx + h * ndxyStep;
const short *py = pdy + h * ndxyStep;
short *pxy = pdxy + h * ndxyStep;
for (int w = 0; w < nWidth; w++) {
if ((pData[w] > 128) && (pMaskData[w] >= 128)) nEdgePtsCounter++;//求得mask内的边缘点数
pxy[w] = (short)sqrt((double)(px[w] * px[w] + py[w] * py[w]));//求得x,y的梯度值
}
}
//
//
#if SECURITY_DOG
//打开精锐E设备
ulShareMode = ELE_SHARE_MODE;
eleContext.ulSize = sizeof(ELE_DEVICE_CONTEXT);
bResult = EleOpenFirstDevice(NULL, NULL, NULL, ulShareMode, &eleContext);
if (!bResult) __DV_EXIT__;
bResult = EleGetFirstModuleName(&eleContext, ModuleName, ulModuleNameLen, &ulRealLen, &ulIndex);
if (!bResult) __DV_EXIT__;
bResult = EleExecute(&eleContext, ModuleName, InputBuffer, ulInputLen, OutputBuffer, ulOutputLen, &ulRealLen);
if (!bResult) __DV_EXIT__;
if ( (OutputBuffer[0] != 'D') || (OutputBuffer[1] != 'I')) {
__DV_EXIT__;
}
if ( OutputBuffer[2] != OutputBuffer[3]) {
__DV_EXIT__;
}
EleClose(&eleContext);
if ( (OutputBuffer[4] != 'E') || (OutputBuffer[5] != 'R')) {
__DV_EXIT__;
}
int n2, n3, n6, n_true;
n2 = OutputBuffer[8];
n3 = OutputBuffer[9];
n6 = OutputBuffer[10];
n_true = OutputBuffer[11];
if ( (2 != n2) || (n3 != 3) ) {
__DV_EXIT__;
}
if (!n_true) {
nEdgePtsCounter = 0;
}
#endif
//
//
// cout<<"Template’s pixel edge points Num[1/1] = "<<nEdgePtsCounter<<endl;
//边缘点个数为零
if (0 == nEdgePtsCounter) {
nReturn = DV_MchTemplateIsBad;
__DV_EXIT__;
}
ReleaseMatrix(m_pEdgePtsX1[nIndex]);
ReleaseMatrix(m_pEdgePtsY1[nIndex]);
ReleaseMatrix(m_pEdgeGrdX1[nIndex]);
ReleaseMatrix(m_pEdgeGrdY1[nIndex]);
ReleaseMatrix(m_pEdgePtsRotX1[nIndex]);
ReleaseMatrix(m_pEdgePtsRotY1[nIndex]);
ReleaseMatrix(m_pEdgeGrdRotX1[nIndex]);
ReleaseMatrix(m_pEdgeGrdRotY1[nIndex]);
ReleaseMatrix(m_pTarSubGrdX1[nIndex]);
ReleaseMatrix(m_pTarSubGrdY1[nIndex]);
ReleaseMatrix(m_pTarSubDxy1[nIndex]);
ReleaseMatrix(m_pTarSubFlag1[nIndex]);
ReleaseMatrix(m_pTarSubEdgeX1[nIndex]);
ReleaseMatrix(m_pTarSubEdgeY1[nIndex]);
int nWH = (int)(9.6 + 1.2 * sqrt((double)(nWidth * nWidth + nHeight * nHeight)));
if ( ((nWH + 1) / 2) > (nWH / 2) ) nWH += 1; //判断是否为奇数
m_pTarSubGrdX1[nIndex] = Mat(nWH, nWH, CV_32FC1);
m_pTarSubGrdY1[nIndex] = Mat(nWH, nWH, CV_32FC1);
m_pTarSubDxy1[nIndex] = Mat(nWH, nWH, CV_16SC1);
m_pTarSubFlag1[nIndex] = Mat(nWH, nWH, CV_8UC1);
m_pTarSubEdgeX1[nIndex] = Mat(nWH, nWH, CV_32FC1);
m_pTarSubEdgeY1[nIndex] = Mat(nWH, nWH, CV_32FC1);
//临时存储亚像素边缘点的坐标
m_pEdgePtsX1[nIndex] = Mat(1, nEdgePtsCounter, CV_32FC1);
m_pEdgePtsY1[nIndex] = Mat(1, nEdgePtsCounter, CV_32FC1);
m_pEdgePtsRotX1[nIndex] = Mat(1, nEdgePtsCounter, CV_32SC1);
m_pEdgePtsRotY1[nIndex] = Mat(1, nEdgePtsCounter, CV_32SC1);
//边缘点的归一化梯度向量
m_pEdgeGrdX1[nIndex] = Mat(1, nEdgePtsCounter, CV_32FC1);
m_pEdgeGrdY1[nIndex] = Mat(1, nEdgePtsCounter, CV_32FC1);
m_pEdgeGrdRotX1[nIndex] = Mat(1, nEdgePtsCounter, CV_32FC1);
m_pEdgeGrdRotY1[nIndex] = Mat(1, nEdgePtsCounter, CV_32FC1);
float *pEPtsSubX = (float *)m_pEdgePtsX1[nIndex].ptr<float>(0);
float *pEPtsSubY = (float *)m_pEdgePtsY1[nIndex].ptr<float>(0);
float *pEGrdSubX = (float *)m_pEdgeGrdX1[nIndex].ptr<float>(0);
float *pEGrdSubY = (float *)m_pEdgeGrdY1[nIndex].ptr<float>(0);
//cvShowImage(“edge1”, pEdgeImg);
//cvWaitKey(0);
double fx0, fy0; // 图像的中心坐标
fx0 = (m_nTemplateWidth[nIndex] - 1) / 2.0;
fy0 = (m_nTemplateHeight[nIndex] - 1) / 2.0;
nMatStep = pEdgeGrdMatX.step / sizeof(float);
nEdgePtsCounter = 0; //清零,统计真正有效的亚像素边缘点个数
for (int h = 1; h < nHeight - 1; h++) {
int ds = ndxyStep;
const float *pGrdX = pEdgeGrdX + h * nMatStep;
const float *pGrdY = pEdgeGrdY + h * nMatStep;
const float *pGrdK = pEdgeGrdK + h * nMatStep;
unsigned char *pData = pEdge + h * nWidthStep;
const unsigned char *pMaskData = pMask + h * nWidthStep;
const short *pxy = pdxy + h * ndxyStep;
for (int w = 1; w < nWidth - 1; w++) {
if ((pData[w] < 128) || (pMaskData[w] < 128)) continue;
if (DV_MCH_EN_FAST_MODE == m_nIsEnableMchAcc[nIndex]) {
for (int j = -1; j <= 1; j++) {
for (int i = -1; i <= 1; i++) {
int nv = (pEdge + (h + j) * nWidthStep)[w + i];
if (nv > 100) (pEdge + (h + j) * nWidthStep)[w + i] = 120;
}
}
}
pData[w] = 0;
double k = pGrdK[w];
double t1, t2, t3, t4, t5, t6;
double k1, k2, k3, k4, k5;
//计算中间参数
t1 = (pxy - ds)[w + 1] + pxy[w + 1] + (pxy + ds)[w + 1];
t2 = (pxy - ds)[w - 1] + pxy[w - 1] + (pxy + ds)[w - 1];
t3 = (pxy + ds)[w - 1] + (pxy + ds)[w] + (pxy + ds)[w + 1];
t4 = (pxy - ds)[w - 1] + (pxy - ds)[w] + (pxy - ds)[w + 1];
t5 = (pxy - ds)[w] + pxy[w] + (pxy + ds)[w];
t6 = (pxy - ds)[w - 1] - (pxy - ds)[w + 1] - (pxy + ds)[w - 1] + (pxy + ds)[w + 1];
//计算拟合多项式系数
k1 = 0.5 * (t1 + t2) - 0.3333333 * (t1 + t2 + t5);
k2 = 0.5 * (t3 + t4) - 0.3333333 * (t1 + t2 + t5);
k3 = 0.25 * t6;
k4 = 0.16666667 * (t1 - t2);
k5 = 0.16666667 * (t3 - t4);
//计算亚像素坐标
if ( fabs(k1 + k2 * k * k + k3 * k) < 0.0001 ) continue;
//计算边缘点的亚像素坐标
double fdx = -(k4 + k * k5) / (2 * (k1 + k2 * k * k + k3 * k));
double fdy = k * fdx;
//判断拟合的亚像素坐标的有效性
if (( fabs(fdx) < 1.0 ) && ( fabs(fdy) < 1.0 )) {
pEPtsSubX[nEdgePtsCounter] = (float)(fdx + w - fx0);
pEPtsSubY[nEdgePtsCounter] = (float)(fdy + h - fy0);
pEGrdSubX[nEdgePtsCounter] = pGrdX[w];
pEGrdSubY[nEdgePtsCounter] = pGrdY[w];
nEdgePtsCounter++;
}
}
}
for (int h = 1; h < nHeight - 1; h++) {//逐行操作, pEdgeGrdKK = dy / dx 矩阵
int ds = ndxyStep;
const float *pGrdX = pEdgeGrdX + h * nMatStep;
const float *pGrdY = pEdgeGrdY + h * nMatStep;
const float *pGrdK = pEdgeGrdK + h * nMatStep;
unsigned char *pData = pEdge + h * nWidthStep;
const unsigned char *pMaskData = pMask + h * nWidthStep;
const short *pxy = pdxy + h * ndxyStep;
for (int w = 1; w < nWidth - 1; w++) { //每一行元素操作
if ((pData[w] < 100) || (pMaskData[w] < 128)) continue;
pData[w] = 0;//边缘灰度>=100且mask >= 128
double k = pGrdK[w];
double t1, t2, t3, t4, t5, t6;
double k1, k2, k3, k4, k5;
//计算中间参数
t1 = (pxy - ds)[w + 1] + pxy[w + 1] + (pxy + ds)[w + 1];
t2 = (pxy - ds)[w - 1] + pxy[w - 1] + (pxy + ds)[w - 1];
t3 = (pxy + ds)[w - 1] + (pxy + ds)[w] + (pxy + ds)[w + 1];
t4 = (pxy - ds)[w - 1] + (pxy - ds)[w] + (pxy - ds)[w + 1];
t5 = (pxy - ds)[w] + pxy[w] + (pxy + ds)[w];
t6 = (pxy - ds)[w - 1] - (pxy - ds)[w + 1] - (pxy + ds)[w - 1] + (pxy + ds)[w + 1];
//计算拟合多项式系数
k1 = 0.5 * (t1 + t2) - 0.3333333 * (t1 + t2 + t5);
k2 = 0.5 * (t3 + t4) - 0.3333333 * (t1 + t2 + t5);
k3 = 0.25 * t6;
k4 = 0.16666667 * (t1 - t2);
k5 = 0.16666667 * (t3 - t4);
//计算亚像素坐标
if ( fabs(k1 + k2 * k * k + k3 * k) < 0.0001 ) continue;
//计算边缘点的亚像素坐标
double fdx = -(k4 + k * k5) / (2 * (k1 + k2 * k * k + k3 * k));
double fdy = k * fdx;
//判断拟合的亚像素坐标的有效性
if (( fabs(fdx) < 1.0 ) && ( fabs(fdy) < 1.0 )) {
pEPtsSubX[nEdgePtsCounter] = (float)(fdx + w - fx0);
pEPtsSubY[nEdgePtsCounter] = (float)(fdy + h - fy0);
pEGrdSubX[nEdgePtsCounter] = pGrdX[w];
pEGrdSubY[nEdgePtsCounter] = pGrdY[w];
nEdgePtsCounter++;
}
}
}
double fMaxRadius = 0.0;
for (int i = 0; i < nEdgePtsCounter; i++) {
double fdx = pEPtsSubX[i];
double fdy = pEPtsSubY[i];
double fDis = 1.2 * sqrt(fdx * fdx + fdy * fdy);
if (fDis > fMaxRadius) {//求最大半径
fMaxRadius = fDis;
}
(pEdge + ((int)(fdy + fy0 + 0.5)) * nWidthStep)[(int)(fdx + fx0 + 0.5)] = 64; //添加边缘
}
for (int h = 0; h < nHeight; h++) { //删除蒙版外的点
unsigned char *pData = pEdge + h * nWidthStep;
const unsigned char *pMaskData = pMask + h * nWidthStep;
for (int w = 0; w < nWidth; w++) {
if (pMaskData[w] < 128) pData[w] = 0;
}
}
// cout<<"Template’s sub-pixel edge points Num[1/1] = "<<nEdgePtsCounter<<endl;
// cvShowImage(“edge1”, pEdgeImg);
if (0 == nEdgePtsCounter) {
nReturn = DV_MchTemplateIsBad;
__DV_EXIT__;
}
m_nEdgePtsNum1[nIndex] = nEdgePtsCounter;
int nMinWH = (int)(9.1 + 2 * ceil(fMaxRadius));
//判断是否为奇数
if ( ((nMinWH + 1) / 2) > (nMinWH / 2) ) nMinWH += 1;
m_nTarSubImgWH1[nIndex] = nMinWH;
__DV_END__;
//释放临时分配的内存空间
ReleaseImage(pEdgeImg);
ReleaseMatrix(pEdgeGrdMatX);
ReleaseMatrix(pEdgeGrdMatY);
ReleaseMatrix(pEdgeGrdKMat);
ReleaseMatrix(dx);
ReleaseMatrix(dy);
ReleaseMatrix(dxy);
return nReturn;
}