亚像素检测算法

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;

}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值