IT评测·应用市场-qidao123.com

标题: 【OpenCV教程】特性工程 [打印本页]

作者: 水军大提督    时间: 2024-8-20 12:04
标题: 【OpenCV教程】特性工程
@
目次

1.模板匹配

1.1 原理

模板图像在原图像上从原点开始移动,盘算模板与原图被模板覆盖的地方的差别程度,盘算方法有几种,然后将每次盘算的效果放进输出矩阵。若原图像为A*B大小,模板为a*b大小,则 输出矩阵为(A-a+1)*(B-b+1) 大小。
1.2 API
  1. CV_EXPORTS_W void matchTemplate( InputArray image, InputArray templ,
  2.                                  OutputArray result, int method, InputArray mask = noArray() );
复制代码
参数含义image输入图像,数据范例Mattempl(template)模板图像,数据范例Matresult输出矩阵,深度为CV_32FC1。若原图像为A*B大小,模板为a*b大小,则 输出矩阵为(A-a+1)*(B-b+1) 大小。method模板匹配盘算方法。详见下文mask掩码图像。其大小与模板图像必须相同,且必须为灰度图。匹配时,对于掩码中的非0像素匹配算法起作用,掩码中的灰度值为0的像素位置,匹配算法不起作用。1.3 模板匹配盘算方法
  1. enum TemplateMatchModes {
  2.     TM_SQDIFF        = 0,
  3.     TM_SQDIFF_NORMED = 1,
  4.     TM_CCORR         = 2,
  5.     TM_CCORR_NORMED  = 3,
  6.     TM_CCOEFF        = 4,
  7.     TM_CCOEFF_NORMED = 5
  8. };
复制代码
method可选值含义式子TM_SQDIFF盘算平方误差,盘算出来的值越小,则匹配得越好$R_{sq_diff}=\sum_{x{\prime},y{\prime}}\left[T(x{\prime},y)-I(x+x{\prime},y+y) \right]^2$TM_SQDIFF_NORMED盘算归一化平方误差,盘算出来的值越接近0,则匹配得越好$R_{sq_diff_normed}=\frac{\sum_{x{\prime},y{\prime}}\left[T(x{\prime},y)-I(x+x{\prime},y+y) \right]2}{\sqrt{\sum_{x,y{\prime}}T(x,y{\prime})2 \cdot \sum_{x{\prime},y{\prime}}I(x+x{\prime},y+y)^2 }}$TM_CCORR盘算相关性,盘算出来的值越大,则匹配得越好$R_{ccorr}=\sum_{x{\prime},y{\prime}}T(x{\prime},y) \cdot I(x+x{\prime},y+y)$TM_CCORR_NORMED盘算归一化相关性,盘算出来的值越接近1,则匹配得越好$R_{ccorr_normed}=\frac{\sum_{x{\prime},y{\prime}} T(x{\prime},y) \cdot I(x+x{\prime},y+y)  }{\sqrt{\sum_{x{\prime},y{\prime}}T(x{\prime},y)^2 \cdot \sum_{x{\prime},y{\prime}}I(x+x{\prime},y+y)^2 }}$TM_CCOEFF盘算相关系数,盘算出来的值越大,则匹配得越好$R_{ccoff}=\sum_{x{\prime},y{\prime}}T{\prime}(x,y^{\prime}) \cdot I{\prime}(x+x,y+y^{\prime}),  \  T{\prime}(x,y{\prime})=T(x,y^{\prime}) - \frac{\sum_{x{\prime},y{\prime}} T(x{\prime\prime},y) }{w \cdot h} ,\ I{\prime}(x,y{\prime})=I(x,y^{\prime}) - \frac{\sum_{x{\prime},y{\prime}} I(x{\prime\prime},y) }{w \cdot h} $TM_CCOEFF_NORMED盘算归一化相关系数,盘算出来的值越接近1,则匹配得越好$R_{ccoeff_normed}=\frac{\sum_{x{\prime},y{\prime}} T{\prime}(x,y^{\prime}) \cdot I{\prime}(x+x,y+y^{\prime}) }{\sqrt{\sum_{x{\prime},y{\prime}}T{\prime}(x,y{\prime})2 \cdot \sum_{x{\prime},y{\prime}}I{\prime}(x+x,y+y{\prime})2 }}$1.4 掩码的使用

在进行特性匹配时,我们偶然并不必要用整个图片作为模板,由于模板的背景可能会干扰匹配的效果。因此,我们必要加入掩码,就可以屏蔽掉背景进行模板匹配
获得掩码

1.5 效果
  1. Mat xuenai = imread("xuenai.jpg");
  2. imshow("xuenai",xuenai);
  3. Mat templ= imread("xuenai_rect.jpg");
  4. imshow("template",templ);
  5. Mat match_result;
  6. matchTemplate(xuenai,templ,match_result,TM_SQDIFF);
  7. Point temLoc;
  8. Point minLoc;
  9. Point maxLoc;
  10. double min,max;
  11. minMaxLoc(match_result,&min,&max,&minLoc,&maxLoc);
  12. temLoc=minLoc;
  13. rectangle(xuenai,Rect(temLoc.x,temLoc.y,templ.cols,templ.rows),Scalar(0,0,255));
  14. imshow("xuenai_match",xuenai);
  15. waitKey();
复制代码


1.5 模板匹配的缺陷

无法应对旋转
  1. Mat xuenai = imread("xuenai.jpg");
  2.         rotate(xuenai,xuenai,ROTATE_90_CLOCKWISE);
  3.         imshow("xuenai",xuenai);
  4.         Mat templ= imread("xuenai_rect.jpg");
  5.         Mat match_result;
  6.         matchTemplate(xuenai,templ,match_result,TM_SQDIFF);
  7.         Point temLoc;
  8.         Point minLoc;
  9.         Point maxLoc;
  10.         double min,max;
  11.         minMaxLoc(match_result,&min,&max,&minLoc,&maxLoc);
  12.         temLoc=minLoc;
  13.         rectangle(xuenai,Rect(temLoc.x,temLoc.y,templ.cols,templ.rows),Scalar(0,0,255));
  14.         imshow("xuenai_match",xuenai);
  15.         waitKey();
复制代码

无法应对缩放
  1. Mat xuenai = imread("xuenai.jpg");
  2. resize(xuenai,xuenai,Size(500,500));
  3. imshow("xuenai",xuenai);
  4. Mat templ= imread("xuenai_rect.jpg");
  5. Mat match_result;
  6. matchTemplate(xuenai,templ,match_result,TM_SQDIFF);
  7. Point temLoc;
  8. Point minLoc;
  9. Point maxLoc;
  10. double min,max;
  11. minMaxLoc(match_result,&min,&max,&minLoc,&maxLoc);
  12. temLoc=minLoc;
  13. rectangle(xuenai,Rect(temLoc.x,temLoc.y,templ.cols,templ.rows),Scalar(0,0,255));
  14. imshow("xuenai_match",xuenai);
  15. waitKey();
复制代码

2.cornerHarris(对灰度图)

2.1 角点的形貌

2.2 原理(前置知识要求:线性代数)(以下为bolcksize=2的情况)

使用一个固定窗口在图像上进行任意方向上的滑动,比较滑动前与滑动后两种情况,窗口中的像素灰度变化程度,假如存在任意方向上的滑动,都有着较大灰度变化,那么我们可以认为该窗口中存在角点。
考虑到一个灰度图像 . 划动窗口  (with displacements  在x方向和  方向)  盘算像素灰度变化。
$$
E(u,v)=\sum w(x,y) \left[   I(x+u,y+v)-I(x,y)        \right]^2
$$
其中:
为了探求带角点的窗口,搜索像素灰度变化较大的窗口。于是, 我们盼望最大化以下式子:
$$
\sum_{x,y}\left[   I(x+u,y+v)-I(x,y)        \right]^2
$$
泰勒睁开:
$$
E(u,v) \approx \sum_{x,y} \left[ I(x,y) +u I_x +v I_y - I(x,y)  \right]^2
$$
矩阵化:
$$
E(u,v) \approx \begin{bmatrix} u & v \end{bmatrix} \left( \sum_{x,y}  w(x,y)\begin{bmatrix} I_x^2 & I_x I_y \ I_x I_y &  I_y^2\end{bmatrix}   \right)  \begin{bmatrix} u \ v \end{bmatrix}
$$
得二次型:
$$
M=\sum_{x,y}  w(x,y)\begin{bmatrix} I_x^2 & I_x I_y \ I_x I_y &  I_y^2\end{bmatrix}
$$
因此有等式:
$$
E(u,v) \approx \begin{bmatrix} u & v \end{bmatrix} M  \begin{bmatrix} u \ v \end{bmatrix}
$$
每个窗口中盘算得到一个值。这个值决定了这个窗口中是否包罗了角点。
$$
R=\det{M}-k \cdot\text{trace}(M)^2
$$
其中,det(M) = 矩阵M的行列式,trace(M) = 矩阵M的迹
2.3 API
  1. CV_EXPORTS_W void cornerHarris( InputArray src, OutputArray dst, int blockSize,
  2.                                 int ksize, double k,
  3.                                 int borderType = BORDER_DEFAULT );
复制代码
参数含义src(source)输入图片(灰度图)深度要求:CV_8UC1或CV_32FC1dst(destination)输出图片,数据范例MatbolckSize检测窗口的大小,越大则对角点越敏感,一般取2ksize(kernal size)使用sobel算子盘算一阶导数时的滤波器大小,一般取3即可。k盘算用到的系数,公认一般取值在0.02~0.06。borderType界限填充方式,默认为黑边。2.4 流程


  1. Mat xuenai = imread("xuenai.jpg");
  2. imshow("xuenai", xuenai);
  3. //转灰度图
  4. Mat xuenai_gray(xuenai.size(),xuenai.type());
  5. cvtColor(xuenai,xuenai_gray,COLOR_BGR2GRAY);
  6. Mat xuenai_harris;
  7. cornerHarris(xuenai_gray,xuenai_harris,2,3,0.04);
  8. normalize(xuenai_harris,xuenai_harris,0,255,NORM_MINMAX,-1);
  9. convertScaleAbs(xuenai_harris,xuenai_harris);
  10. namedWindow("xuenai_harris");
  11. createTrackbar("threshold","xuenai_harris", nullptr,255);
  12. while (1) {
  13.     int thres = getTrackbarPos("threshold", "xuenai_harris");
  14.     if(thres==0)thres=100;
  15.     Mat harris_result=xuenai.clone();
  16.     for(int i=0;i<xuenai_harris.rows;i++){
  17.         uchar * ptr =xuenai_harris.ptr(i);
  18.         for(int j=0;j<xuenai_harris.cols;j++){
  19.             int value=(int) *ptr;
  20.             if(value>thres){
  21.                 circle(harris_result, Point(j,i), 3, Scalar(0, 0, 255));
  22.             }
  23.             ptr++;
  24.         }
  25.     }
  26.     imshow("xuenai_harris",harris_result);
  27.     if (waitKey(0) == 'q')break;
  28. }
复制代码

进行缩放和旋转



5.FAST到OBR(对灰度图)

5.1 概述

前文已经阐述,SIFT和SURF已经做到了角点在旋转和缩放下的稳固性,但是它们还有一个致命的缺陷,就是它们难以做到实时运算,因此,FAST和OBR应运而生了。
FAST原理

从图片中选取一个坐标点P,获取该点的像素值,接下来判定该点是否为特性点.
选取一个以选取点P坐标为圆心的半径等于r的Bresenham圆(一个盘算圆的轨迹的离散算法,得到整数级的圆的轨迹点),一般来说,这个圆上有16个点,如下所示

<ul>它不能拒绝n detect(xuenai_gray,xuenai_ObrKp);    Mat fast_result=xuenai_transform.clone(),obr_result=xuenai_transform.clone();    drawKeypoints(fast_result,xuenai_FastKp,fast_result,Scalar::all(-1),DrawMatchesFlags:RAW_RICH_KEYPOINTS);    drawKeypoints(obr_result,xuenai_ObrKp,obr_result,Scalar::all(-1),DrawMatchesFlags:RAW_RICH_KEYPOINTS);    imshow("fast_result",fast_result);    imshow("obr_result",obr_result);    if (waitKey(0) == 'q')break;}[/code]调整threshold



进行缩放和旋转


错误
  1. Mat xuenai = imread("xuenai.jpg");
  2. imshow("xuenai", xuenai);
  3. namedWindow("panel");
  4. createTrackbar("threshold","panel", nullptr,255);
  5. createTrackbar("angle","panel", nullptr,360);
  6. createTrackbar("width","panel", nullptr,1000);
  7. createTrackbar("height","panel", nullptr,1000);
  8. while (1) {
  9.     int thres = getTrackbarPos("threshold", "panel");
  10.     if(thres==0)thres=100;
  11.     int width = getTrackbarPos("width", "panel");
  12.     if(width==0)width=xuenai.cols;
  13.     int height = getTrackbarPos("height", "panel");
  14.     if(height==0)height=xuenai.rows;
  15.     int angle = getTrackbarPos("angle","panel");
  16.   
  17.     Mat xuenai_harris, xuenai_transform=xuenai.clone();
  18.     resize(xuenai_transform,xuenai_transform,Size(width,height));
  19.     Mat M= getRotationMatrix2D(Point2f(xuenai.cols/2,xuenai.rows/2),angle,1);
  20.     warpAffine(xuenai_transform,xuenai_transform,M,xuenai_transform.size());
  21.     Mat xuenai_gray(xuenai.size(),xuenai.type());
  22.     cvtColor(xuenai_transform,xuenai_gray,COLOR_BGR2GRAY);
  23.     cornerHarris(xuenai_gray,xuenai_harris,2,3,0.04);
  24.     normalize(xuenai_harris,xuenai_harris,0,255,NORM_MINMAX,-1);
  25.     convertScaleAbs(xuenai_harris,xuenai_harris);
  26.     Mat harris_result=xuenai_transform.clone();
  27.     for(int i=0;i<xuenai_harris.rows;i++){
  28.         uchar * ptr =xuenai_harris.ptr(i);
  29.         for(int j=0;j<xuenai_harris.cols;j++){
  30.             int value=(int) *ptr;
  31.             if(value>thres){
  32.                 circle(harris_result, Point(j,i), 3, Scalar(0, 0, 255));
  33.             }
  34.             ptr++;
  35.         }
  36.     }
  37.     imshow("xuenai_harris",harris_result);
  38.     if (waitKey(0) == 'q')break;
  39. }
复制代码
前文已经提及,FAST算法不支持形貌子的盘算
  1. CV_EXPORTS_W void goodFeaturesToTrack( InputArray image, OutputArray corners,
  2.                                      int maxCorners, double qualityLevel, double minDistance,
  3.                                      InputArray mask = noArray(), int blockSize = 3,
  4.                                      bool useHarrisDetector = false, double k = 0.04 );
  5. CV_EXPORTS_W void goodFeaturesToTrack( InputArray image, OutputArray corners,
  6.                                      int maxCorners, double qualityLevel, double minDistance,
  7.                                      InputArray mask, int blockSize,
  8.                                      int gradientSize, bool useHarrisDetector = false,
  9.                                      double k = 0.04 );
复制代码
6.Brute-Force与FLANN特性匹配

6.1 概述

Brute-Force

暴力匹配(Brute-force matcher)是最简单的二维特性点匹配方法。对于从两幅图像中提取的两个特性形貌符聚集,对第一个聚集中的每个形貌符Ri,从第二个聚集中找出与其间隔最小的形貌符Sj作为匹配点。
暴力匹配显然会导致大量错误的匹配效果,还会出现一配多的情况。通过交织匹配或设置比较阈值筛选匹配效果的方法可以改进暴力匹配的质量。
FLANN

6.2 API

构造函数
  1. Mat xuenai = imread("xuenai.jpg");
  2. imshow("xuenai", xuenai);
  3. namedWindow("panel");
  4. createTrackbar("threshold","panel", nullptr,255);
  5. createTrackbar("angle","panel", nullptr,360);
  6. createTrackbar("width","panel", nullptr,1000);
  7. createTrackbar("height","panel", nullptr,1000);
  8. while (1) {
  9.     int thres = getTrackbarPos("threshold", "panel");
  10.     if(thres==0)thres=100;
  11.     int width = getTrackbarPos("width", "panel");
  12.     if(width==0)width=xuenai.cols;
  13.     int height = getTrackbarPos("height", "panel");
  14.     if(height==0)height=xuenai.rows;
  15.     int angle = getTrackbarPos("angle","panel");
  16.     Mat xuenai_transform=xuenai.clone();
  17.     resize(xuenai_transform,xuenai_transform,Size(width,height));
  18.     Mat M= getRotationMatrix2D(Point2f(xuenai.cols/2,xuenai.rows/2),angle,1);
  19.     warpAffine(xuenai_transform,xuenai_transform,M,xuenai_transform.size());
  20.     Mat xuenai_gray(xuenai.size(),xuenai.type());
  21.     cvtColor(xuenai_transform,xuenai_gray,COLOR_BGR2GRAY);
  22.     vector<Point2f>xuenai_cornersSet;
  23.     goodFeaturesToTrack(xuenai_gray,xuenai_cornersSet,0,0.1,10);
  24.     for(auto corner:xuenai_cornersSet){
  25.         circle(xuenai_transform,corner,3,Scalar(0,0,255));
  26.     }
  27.     imshow("xuenai_corners",xuenai_transform);
  28.     if (waitKey(0) == 'q')break;
  29. }
复制代码
参数含义normType盘算间隔用到的方法,默认是欧氏间隔。详见下表crossCheck是否使用交织验证,默认不使用。
normType可选值含义NORM_L1L1范数,曼哈顿间隔NORM_L2L2范数,欧氏间隔NORM_HAMMING汉明间隔NORM_HAMMING2汉明间隔2,对每2个比特相加处理。
形貌子匹配

匹配方式一
  1. CV_WRAP static Ptr<SIFT> SIFT::create(int nfeatures = 0, int nOctaveLayers = 3,
  2.         double contrastThreshold = 0.04, double edgeThreshold = 10,
  3.         double sigma = 1.6);
  4.   
  5. CV_WRAP static Ptr<SIFT> SIFT::create(int nfeatures, int nOctaveLayers,
  6.     double contrastThreshold, double edgeThreshold,
  7.     double sigma, int descriptorType);
  8.   
  9. CV_WRAP static Ptr<SURF> SURF::create(double hessianThreshold=100,
  10.               int nOctaves = 4, int nOctaveLayers = 3,
  11.               bool extended = false, bool upright = false);
复制代码
参数含义queryDescriptors形貌子的查询点集,数据范例Mat,即参考图像的特性形貌符的聚集。trainDescriptors形貌子的训练点集,数据范例Mat,即检测图像的特性形貌符的聚集。matches匹配效果,长度为成功匹配的数量。mask掩码图像。其大小与输入图像必须相同,且必须为灰度图。盘算时,对于掩码中的非0像素算法起作用,掩码中的灰度值为0的像素位置,算法不起作用。
匹配方式二
  1. CV_WRAP virtual void Feature2D::detect( InputArray image,
  2.                                  CV_OUT std::vector<KeyPoint>& keypoints,
  3.                                  InputArray mask=noArray() );
  4.                            
  5. CV_WRAP virtual void Feature2D::detect( InputArrayOfArrays images,
  6.                      CV_OUT std::vector<std::vector<KeyPoint> >& keypoints,
  7.                      InputArrayOfArrays masks=noArray() );
复制代码
参数含义queryDescriptors形貌子的查询点集,数据范例Mat,即参考图像的特性形貌符的聚集。trainDescriptors形貌子的训练点集,数据范例Mat,即检测图像的特性形貌符的聚集。matchesvector范例,对每个特性点返回k个最优的匹配效果k返回匹配点的数量mask掩码图像。其大小与输入图像必须相同,且必须为灰度图。盘算时,对于掩码中的非0像素算法起作用,掩码中的灰度值为0的像素位置,算法不起作用。
Brute-Force与FLANN对输入形貌子的要求

drawMatches绘制匹配效果
  1. CV_WRAP virtual void Feature2D::compute( InputArray image,
  2.                                   CV_OUT CV_IN_OUT std::vector<KeyPoint>& keypoints,
  3.                                   OutputArray descriptors );
  4. CV_WRAP virtual void Feature2D::compute( InputArrayOfArrays images,
  5.                       CV_OUT CV_IN_OUT std::vector<std::vector<KeyPoint> >& keypoints,
  6.                       OutputArrayOfArrays descriptors );
  7. CV_WRAP virtual void Feature2D::detectAndCompute( InputArray image, InputArray mask,
  8.                                        CV_OUT std::vector<KeyPoint>& keypoints,
  9.                                        OutputArray descriptors,
  10.                                        bool useProvidedKeypoints=false );
复制代码
参数含义img1(image1)源图像1,数据范例Matkeypoints1源图像1的关键点img2(image2)源图像2,数据范例Matkeypoints2源图像2的关键点matches1to2源图像1的形貌子匹配源图像2的形貌子的匹配效果outImg(out image)输出图像,数据范例MatmatchColor匹配的颜色(特性点和连线),默认Scalar::all(-1),颜色随机singlePointColor单个点的颜色,即未配对的特性点,默认Scalar::all(-1),颜色随机matchesMask掩码,决定哪些点将被画出,若为空,则画出所有匹配点flags特性点的绘制模式,其实就是设置特性点的那些信息必要绘制,那些不必要绘制。6.3 流程

6.4 效果
  1. CV_EXPORTS_W void drawKeypoints( InputArray image, const std::vector<KeyPoint>& keypoints, InputOutputArray outImage,
  2.                                const Scalar& color=Scalar::all(-1), DrawMatchesFlags flags=DrawMatchesFlags::DEFAULT );
  3. enum struct DrawMatchesFlags
  4. {
  5.   DEFAULT = 0, //!< Output image matrix will be created (Mat::create),
  6.                //!< i.e. existing memory of output image may be reused.
  7.                //!< Two source image, matches and single keypoints will be drawn.
  8.                //!< For each keypoint only the center point will be drawn (without
  9.                //!< the circle around keypoint with keypoint size and orientation).
  10.   DRAW_OVER_OUTIMG = 1, //!< Output image matrix will not be created (Mat::create).
  11.                         //!< Matches will be drawn on existing content of output image.
  12.   NOT_DRAW_SINGLE_POINTS = 2, //!< Single keypoints will not be drawn.
  13.   DRAW_RICH_KEYPOINTS = 4 //!< For each keypoint the circle around keypoint with keypoint size and
  14.                           //!< orientation will be drawn.
  15. };
复制代码

本文由博客一文多发平台 OpenWrite 发布!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 IT评测·应用市场-qidao123.com (https://dis.qidao123.com/) Powered by Discuz! X3.4