QT + opencv 实现形状(表面)模板匹配
实现思绪
1.创建模板数据:重要是提取模板的表面信息,这一步通常通过边缘检测实现。将模板的表面信息存储起来。
代码:
- //创建形状模板
- 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.模板匹配:同样需要利用压缩金字塔的方法来提拔搜刮速度,减少参数目。然后取顶层金字塔进行旋转,和模板表面进行匹配,找到大抵角度后再进行细致的搜刮。
部分代码
- //模板匹配
- 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以内。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |