opencv之平面对象识别

对象形变与位置变换

待检测图像样本一般与检测样本中的实际状态在形态学上会有不同,例如一本书会发生扭曲。可以通过以下函数进行校正对应

  • findHomography 发现两个平面的透视变换,生成变换矩阵
  • perspectiveTransform 透视变换

代码演示

#include <opencv2/opencv.hpp>
#include <opencv2/xfeatures2d.hpp>
#include <iostream>
#include <math.h>

using namespace std;
using namespace cv;
using namespace cv::xfeatures2d;

#define PIC_PATH "/work/opencv_pic/"
#define PIC_NAME "main.jpeg"

#define PIC_PATH1 "/work/opencv_pic/"
#define PIC_NAME1 "sub.jpeg"
int main(void)
{
     Mat src,src1;

    //获取完整的图片路径及名称
    string pic = string(PIC_PATH1)+string(PIC_NAME1);
    string pic1 = string(PIC_PATH)+string(PIC_NAME);

    //打印图片路径
    cout << "pic path is :"<<pic<<endl;
    cout << "pic1 path is :"<<pic1<<endl;
    //读取图片
    src = imread(pic,IMREAD_GRAYSCALE);
    src1 = imread(pic1,IMREAD_GRAYSCALE);
    //判断图片是否存在
    if(src.empty() || src1.empty())
    {
        cout<<"pic is not exist!!!!"<<endl;
        return -1;
    }

    //显示图片
    namedWindow("src pic",WINDOW_AUTOSIZE);
    imshow("src pic",src);
    namedWindow("src1 pic",WINDOW_AUTOSIZE);
    imshow("src1 pic",src1);


    int minHessian = 400;
    vector<KeyPoint> keypoint1,keypoint2;   //描述子
    Mat descriptor1,descriptor2;            //描述图像

    Ptr<SURF> detector = SURF::create(minHessian);   //创建SURF对象

    //计算特征值
    detector->detectAndCompute(src,Mat(),keypoint1,descriptor1);
    detector->detectAndCompute(src1,Mat(),keypoint2,descriptor2);


    //BFMatcher matcher;
    FlannBasedMatcher matcher;   //Flann匹配器
    vector<DMatch> matches;      //匹配数据
    matcher.match(descriptor1,descriptor2,matches);   //描述匹配 将匹配结果存放至matches


    //flann匹配基于距离匹配 进行最优距离查找
    float maxdist = 3;
    float mindist = 100;

    //通过逐步收敛的办法查找到最大值最小值
    for(int i=0;i<descriptor1.rows;i++)
    {
        float distance = matches[i].distance;
        distance*=100;
         cout<<"distance: "<<distance<<endl;
        if(distance>maxdist)
            maxdist = distance;
        if(distance<mindist)
            mindist = distance;
    }

    //将最大值 最小值打印出来
    cout<<"maxdist: "<<maxdist<<endl;
    cout<<"mindist: "<<mindist<<endl;

    vector<DMatch> goodmatches;   //定义最优的距离点集合
    for(int i=0;i<descriptor1.rows;i++)
    {
        float distance = matches[i].distance;
        if(distance*100<=2*mindist)
        {
            //将查找到的最小距离添加到goodmatches中
            goodmatches.push_back(matches[i]);
        }
    }


    Mat matchimages;
    //绘制匹配点 点数大大减少
    drawMatches(src,keypoint1,src1,keypoint2,goodmatches,matchimages);


    //获取坐标点
    vector<Point2f> sub,main;
    for(size_t i=0;i<goodmatches.size();i++)
    {
        //通过goodmatches的queryIdx索引值获取 对应子图像keypoint点的坐标
        sub.push_back(keypoint1[goodmatches[i].queryIdx].pt);
        //通过goodmatches的queryIdx索引值获取 对应目标图像trainIdx点的坐标
        main.push_back(keypoint2[goodmatches[i].trainIdx].pt);
    }

    //通过两者坐标对应关系获得目标变换矩阵
    Mat H =findHomography(sub,main,RANSAC);

    //定义方框轮廓
    vector<Point2f> sub_corners(4);
    vector<Point2f> main_corners(4);

    //待检测图像轮廓已知
    sub_corners[0] = Point(0,0);
    sub_corners[1] = Point(src.cols,0);
    sub_corners[2] = Point(src.cols,src.rows);
    sub_corners[3] = Point(0,src.rows);

    //通过待检测图像的轮廓以及透视变换矩阵 计算 待检测图像中目标矩形位置
    perspectiveTransform(sub_corners,main_corners,H);

    //绘制矩形框 这里加Point2f(src.cols,0) 主要是matchimages显示图像为两者叠加图片宽度有变化
    line(matchimages,main_corners[0]+Point2f(src.cols,0),main_corners[1]+Point2f(src.cols,0),Scalar(0,0,255),3);
    line(matchimages,main_corners[1]+Point2f(src.cols,0),main_corners[2]+Point2f(src.cols,0),Scalar(0,0,255),3);
    line(matchimages,main_corners[2]+Point2f(src.cols,0),main_corners[3]+Point2f(src.cols,0),Scalar(0,0,255),3);
    line(matchimages,main_corners[3]+Point2f(src.cols,0),main_corners[0]+Point2f(src.cols,0),Scalar(0,0,255),3);
    //显示图片
    imshow("matchImages",matchimages);
    waitKey(0);
    destroyAllWindows();
    return 0;
}

代码演示效果

由于图片是截取出来的,并没有明显效果
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值