QT + opencv 实现形状(轮廓)模板匹配

QT + opencv 实现形状(轮廓)模板匹配

实现思路

1.创建模板数据:主要是提取模板的轮廓信息,这一步通常通过边缘检测实现。将模板的轮廓信息存储起来。

代码:

cpp 复制代码
//创建形状模板
bool cvLearnShapeMatchPattern_(Mat matDst, MyShapeUiParam param, MyShapeTemplData* pTemplData)
{
    //图像不存在
    if(matDst.empty())
        return false;

    //清除模板
    pTemplData->clear();

    //边缘检测
    Mat canny, gray;
    vector<Point> contours;
    cv::Canny(matDst, canny, pTemplData->minThresh, pTemplData->maxThresh);
    canny.copyTo(gray);

    /*if(!(pTemplData->sample==0))
    {
        Mat element=getStructuringElement(MORPH_ELLIPSE, Size(pTemplData->dilate, pTemplData->dilate));
        cv::dilate(canny, gray, element);
    }*/

    cvFindContour_(gray, contours, pTemplData->minLen, 10e9, pTemplData->sample);
    if((int)contours.size()==0)
        return false;

    //压缩金字塔
    int iTopLayer=param.m_iPyramid;
    buildPyramid(matDst, pTemplData->vecPyramid, iTopLayer);
    for(size_t i=0;i<pTemplData->vecPyramid.size();i++)
    {
        //轮廓信息
        Mat src=pTemplData->vecPyramid[i];
        vector<Point> pyrContour=cvPyrContour_(contours, matDst.size(), src.size());
        pTemplData->vecPoints.push_back(pyrContour);

        //显示
        Mat dst=Mat::zeros(src.size(), CV_8UC1);
        for(size_t j=0;j<pyrContour.size();j++)
            dst.at<uchar>(pyrContour[j].y, pyrContour[j].x)=255;
        imshow(QString("%1").arg(i).toStdString(), dst);
        cv::waitKey(5);

        //梯度信息
        Mat gx, gy, mag, dir;
        Sobel(src, gx, CV_32F, 1, 0);
        Sobel(src, gy, CV_32F, 0, 1);
        cartToPolar(gx, gy, mag, dir);

        //提取梯度
        vector<SPtin> vecSPtin;
        for(size_t j=0;j<pyrContour.size();j++)
        {
            SPtin info;
            Point p=pyrContour[j];
            info.derivativeX=gx.at<float>(p.y, p.x);
            info.derivativeY=gy.at<float>(p.y, p.x);
            info.magnitude=mag.at<float>(p.y, p.x);
            info.magnitudeN = info.magnitude==0 ? 0 : (1.0f / info.magnitude);
            vecSPtin.push_back(info);
        }
        pTemplData->vecSPtins.push_back(vecSPtin);
    }

    //训练标记
    pTemplData->bIsPatternLearned=true;
    return true;
}

2.模板匹配:同样需要利用压缩金字塔的方法来提升搜索速度,减少参数量。然后取顶层金字塔进行旋转,和模板轮廓进行匹配,找到大致角度后再进行细致的搜索。

部分代码

cpp 复制代码
//模板匹配
bool cvShapeMatch_(Mat matSrc, vector<MyShapeTemplData> templDatas, MyShapeUiParam param, vector<MySingleTargetMatch>& vecSingleTargetData)
{
    //图像
    if(matSrc.empty())
        return false;

    //模板
    if((int)templDatas.size()==0)
        return false;

    //決定金字塔層數 總共為1 + iLayer層
    int iTopLayer=param.m_iPyramid;
    vector<Mat> vecMatSrcPyr;
    buildPyramid(matSrc, OutputArrayOfArrays(vecMatSrcPyr), iTopLayer);

    //取顶层图片的中心点
    int iTopSrcW = vecMatSrcPyr[iTopLayer].cols, iTopSrcH = vecMatSrcPyr[iTopLayer].rows;
    Point2f ptCenter((iTopSrcW - 1) / 2.0f, (iTopSrcH - 1) / 2.0f);

    //Caculate lowest score at every layer
    vector<double> vecLayerScore(iTopLayer + 1, param.m_dScore);
    for (int iLayer = 1; iLayer <= iTopLayer; iLayer++)
        vecLayerScore[iLayer] = vecLayerScore[iLayer - 1] * param.m_dGreed;

    //clear
    vecSingleTargetData.clear();

    //并行加速
    omp_set_num_threads(4);
    #pragma omp parallel for
    for(int k=0;k<(int)templDatas.size();k++)
    {
        MyShapeTemplData* pTemplData = &templDatas[k];
        if((int)pTemplData->vecPyramid.size()==0 || !pTemplData->bIsPatternLearned)
            continue;

        Mat matDst=pTemplData->vecPyramid[0];
        if (matDst.empty())
            continue;
        if ((matDst.cols<matSrc.cols && matDst.rows>matSrc.rows) || (matDst.cols>matSrc.cols && matDst.rows<matSrc.rows))
            continue;
        if (matDst.size().area()>=matSrc.size ().area())
            continue;

        //匹配轮廓
        vector<Point> Contour=pTemplData->vecPoints[0];
        cvAffineTrans_(Contour, Point3f((float)(matDst.cols - 1)/2.0f, (float)(matDst.rows - 1)/2.0f, 0), Point3f(0, 0, 0));


        //第一階段以最頂層找出大致角度與ROI
        double dAngleStep=atan(2.0 / max(pTemplData->vecPyramid[iTopLayer].cols, pTemplData->vecPyramid[iTopLayer].rows)) * R2D;

实现效果:实际匹配目标时,角度搜索范围可以不必像我这样设置这么大。在相机画面中进行检测时,通常是在ROI中进行检测,速度通常在100ms以内。


相关推荐
励志要当大牛的小白菜9 分钟前
ART配对软件使用
开发语言·c++·qt·算法
爱装代码的小瓶子2 小时前
数据结构之队列(C语言)
c语言·开发语言·数据结构
Maybe_ch4 小时前
.NET-键控服务依赖注入
开发语言·c#·.net
超浪的晨4 小时前
Java UDP 通信详解:从基础到实战,彻底掌握无连接网络编程
java·开发语言·后端·学习·个人开发
终焉暴龙王4 小时前
CTFHub web进阶 php Bypass disable_function通关攻略
开发语言·安全·web安全·php
Edingbrugh.南空5 小时前
Aerospike与Redis深度对比:从架构到性能的全方位解析
java·开发语言·spring
CodeCraft Studio5 小时前
借助Aspose.HTML控件,在 Python 中将 HTML 转换为 Markdown
开发语言·python·html·markdown·aspose·html转markdown·asposel.html
QQ_4376643145 小时前
C++11 右值引用 Lambda 表达式
java·开发语言·c++
aramae5 小时前
大话数据结构之<队列>
c语言·开发语言·数据结构·算法
封奚泽优6 小时前
使用Python实现单词记忆软件
开发语言·python·random·qpushbutton·qtwidgets·qtcore·qtgui