• 【无标题】


    @TOCOpenCV实现边缘模板匹配算法
    背景概述

    OpenCV中自带的模板匹配算法,完全是像素基本的模板匹配,特别容易受到光照影响,光照稍微有所不同,该方法就会歇菜了!搞得很多OpenCV初学者刚学习到该方法时候很开心,一用该方法马上很伤心,悲喜交加,充分感受到了理想与现实的距离,不过没关系,这里介绍一种新的模板匹配算法,主要是基于图像边缘梯度,它对图像光照与像素迁移都有很强的抗干扰能力,据说Halcon的模板匹配就是基于此的加速版本,在工业应用场景中已经得到广泛使用。
    结论:大图速度慢,效果不好,小图可以用一下
    `在这 Mat edge;
    //GaussianBlur(templateMat, bw, Size(7,7), 0, 0);
    Mat bw;
    threshold(templateMat, bw, 20, 255, CV_THRESH_OTSU);
    Canny(bw, edge, 25, 190);
    /namedWindow(“Canny”,0);
    resizeWindow(“Canny”, 1540, 1180);
    imshow(“Canny”, edge);
    waitKey(0);
    /
    vector contours;
    vector hierarchy;
    findContours(edge, contours, CV_RETR_TREE, CV_CHAIN_APPROX_NONE); //找轮廓

    Mat gx, gy;
    Sobel(fardist3, gx, CV_32F, 1, 0);
    Sobel(fardist3, gy, CV_32F, 0, 1);
    Mat magnitude, direction;
    cartToPolar(gx, gy, magnitude, direction);
    long contoursLength = 0;
    double magnitudeTemp = 0;
    int originx = contours[0][0].x;
    int originy = contours[0][0].y;
    
    typedef struct my
    {
        int DerivativeX;
        int DerivativeY;
        double Magnitude;
        double MagnitudeN;
    }ptin;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    // 提取dx\dy\mag\log信息
    vector contoursInfo;
    // 提取相对坐标位置
    vector contoursRelative;

    // 开始提取
    for (int i = 0; i < contours.size(); i++) {
        int n = contours[i].size();
        contoursLength += n;
        contoursInfo.push_back(vector(n));
        vector points(n);
        for (int j = 0; j < n; j++) {
            int x = contours[i][j].x;
            int y = contours[i][j].y;
            points[j].x = x - originx;
            points[j].y = y - originy;
            ptin pointInfo;
            pointInfo.DerivativeX = gx.at(y, x);
            pointInfo.DerivativeY = gy.at(y, x);
            magnitudeTemp = magnitude.at(y, x);
            pointInfo.Magnitude = magnitudeTemp;
            if (magnitudeTemp != 0)
                pointInfo.MagnitudeN = 1 / magnitudeTemp;
            contoursInfo[i][j] = pointInfo;
        }
        contoursRelative.push_back(points);
    }
    // 计算目标图像梯度
    Mat gradx, grady;
    Sobel(fardist3, gradx, CV_32F, 1, 0);
    Sobel(fardist3, grady, CV_32F, 0, 1);
    Mat mag, angle;
    cartToPolar(gradx, grady, mag, angle);
    // NCC模板匹配
    double minScore = 0.99;		//deafult value
    double greediness = 0.8;		//deafult value
    double nGreediness = 0.99;		//deafult value
    double nMinScore = 0.99;		//deafult value
    
    double partialScore = 0;
    double resultScore = 0;
    int resultX = 0;
    int resultY = 0;
    double start = (double)getTickCount();
    for (int row = 0; row < fardist3.rows; row++)
    {
        for (int col = 0; col < fardist3.cols; col++) {
            double sum = 0;
            long num = 0;
            for (int m = 0; m < contoursRelative.size(); m++) {
                for (int n = 0; n < contoursRelative[m].size(); n++) {
                    num += 1;
                    int curX = col + contoursRelative[m][n].x;
                    int curY = row + contoursRelative[m][n].y;
                    if (curX < 0 || curY < 0 || curX > fardist3.cols - 1 || curY > fardist3.rows - 1) {
                        continue;
                    }
    
                    // 目标边缘梯度
                    double sdx = gradx.at(curY, curX);
                    double sdy = grady.at(curY, curX);
    
                    // 模板边缘梯度
                    double tdx = contoursInfo[m][n].DerivativeX;
                    double tdy = contoursInfo[m][n].DerivativeY;
    
                    // 计算匹配
                    if ((sdy != 0 || sdx != 0) && (tdx != 0 || tdy != 0))
                    {
                        double nMagnitude = mag.at(curY, curX);
                        if (nMagnitude != 0)
                            sum += (sdx * tdx + sdy * tdy) * contoursInfo[m][n].MagnitudeN / nMagnitude;
                    }
    
                    // 任意节点score之和必须大于最小阈值
                    partialScore = sum / num;
                    if (partialScore < min((minScore - 1) + (nGreediness * num), nMinScore * num))
                        break;
                }
            }
    
            // 保存匹配起始点
            if (partialScore > resultScore)
            {
                resultScore = partialScore;
                resultX = col;
                resultY = row;
            }
        }
    }
    cout << resultScore << endl;
    cout << resultY << endl;
    cout << resultX << endl;
    CvPoint point;
    point.x = resultX;
    point.y = resultY;
    circle(fardist3, point, 10, Scalar(255, 255, 255), 8);
    namedWindow("src",0);
    resizeWindow("src", 1540, 1180);
    imshow("src", fardist3);
    waitKey(0);里插入代码片`
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
  • 相关阅读:
    Go学习第十章——文件操作,Json和测试
    2022年java学习路线,自学怎么才能脱颖而出?
    记录:移动设备软件开发(Android项目组织结构)
    12个MySQL慢查询的原因分析
    【攻破css系列——第八天】盒子模型
    ECMAScrip-ES6-新变量-let--注意块级作用域
    Java-NIO之Buffer(缓冲区)
    [Python进阶] Pyinstaller关于spec文件
    python——使用API
    未来 20 年 12 大发展趋势
  • 原文地址:https://blog.csdn.net/julinglan7642/article/details/126503732