边缘图像
边缘方向图

在边缘提取时,往往在一个ROI中会同时存在多个边缘,但是往往我们需要的只是其中的一个,沿着一定的方向进行扫描,会有白到黑,黑到白的区别,本文中提到的算法就是按照一定的参考直线和参考点提取不同的边缘曲线,可以滤除掉一部分我们不需要的边缘点,后续再加以连通域的选取及特征选取就可以取得较好的效果,具体实现如下:

code

void PickPointByDirection(uchar *bw, double *edgeX, double *edgeY, uchar *bwOut, int height, int width, gclPoint refPoint, gclLseg lseg, int edgeDirection, double minDis, double maxDis, vector<gclPoint> &pointOut)
{
    gclPoint *pt = new gclPoint[height * width];
    memset(pt, 0, sizeof(gclPoint) * height * width);
    int numPt = 0;
    for (int i = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {
            if (bw[i * width + j] == 0) {
                continue;
            }
            pt[numPt].y = i;
            pt[numPt++].x = j;
        }
    }

    gclVector v1(lseg.pointStart.x - lseg.pointEnd.x, lseg.pointStart.y - lseg.pointEnd.y, 0);
    gclPoint pcenter;
    pcenter.x = (lseg.pointStart.x + lseg.pointEnd.x) / 2;
    pcenter.y = (lseg.pointStart.y + lseg.pointEnd.y) / 2;
    gclVector v2(refPoint.x - pcenter.x, refPoint.y - pcenter.y, 0);
    gclVector vtemp;
    vectorCrossMulti(v1, v2, vtemp);
    double theta = 0;
    if (vtemp.a < 0) {
        theta = atan2(-v1.b, -v1.a) + M_PI / 2;
    }
    else{
        theta = atan2(v1.b, v1.a) + M_PI / 2;
    }
    double cost = cos(theta);
    double sint = sin(theta);
    // 提取线段附近的边缘点
    vector< gclPoint > pointTemp;
    vector<double > disTemp;
    for (int i = 0; i < numPt; i++) {
        int index = int(pt[i].y * width + pt[i].x);
        double mag = (edgeX[index] * cost + edgeY[index] * sint) * edgeDirection;
        if (mag <= 0) {
            continue;
        }
        // 判断点是否在线段内及有限距离内
        gclPoint pt1 = lseg.pointStart;
        gclPoint pt2 = lseg.pointEnd;
        gclVector vpt1pt(pt[i].x - pt1.x, pt[i].y - pt1.y, 0);
        gclVector vpt1pt2(pt2.x - pt1.x, pt2.y - pt1.y, 0);
        double theta1 = vectorAngle(vpt1pt, vpt1pt2);
        gclVector vpt2pt(pt[i].x - pt2.x, pt[i].y - pt2.y, 0);
        gclVector vpt2pt1(pt1.x - pt2.x, pt1.y - pt2.y, 0);
        double theta2 = vectorAngle(vpt2pt, vpt2pt1);
        if (theta1 <= M_PI / 2 && theta1 >= 0 && theta2 <= M_PI / 2 && theta2 >= 0)
        {
            double d1 = vectorlength(vpt1pt2);
            double d2 = vectorlength(vpt2pt);
            double d3 = vectorlength(vpt1pt);
            double p = (d1 + d2 + d3) / 2;
            double s = sqrt(p * (p - d1) * (p - d2) * (p - d3));
            double dis = abs(2 * s / d1);
            if (dis >= minDis && dis <= maxDis)
            {
                pointOut.push_back(pt[i]);
                bwOut[index] = uchar(255);
            }
        }
    }

    SAFE_DELETE(pt);

}