zoukankan      html  css  js  c++  java
  • 透视变换--点对应变换

    透视变换原理我也不细说,原理可以参考:https://blog.csdn.net/xiaowei_cqu/article/details/26471527

    在opencv中只要调两个函数就可以了。
    cv::Mat warpMatrix = cv::getPerspectiveTransform(src_pt, dst_pt);
    cv::warpPerspective(SrcImg, m_src_correct, warpMatrix, SrcImg.size(), cv::INTER_NEAREST, cv::BORDER_CONSTANT);
    src_pt是原来物体的4个点坐标,dst_pt是根据原来的坐标计算得来的,一般是原来坐标的外接矩形。

    #include <iostream>
    #include <opencv2/opencv.hpp>
    bool correct_cjh_3(cv::Point2f pt_tl,cv::Point2f pt_bl,cv::Point2f pt_tr,cv::Point2f pt_br,cv::Mat &SrcImg,cv::Mat &m_MingP,bool b_debug)
    {
        //   0   2
        //   1   3
        Mat m_src_correct;
        cv::Point2f src_pt[4];
        cv::Point2f dst_pt[4];
        src_pt[0] = pt_tl;
        src_pt[1] = pt_bl;
        src_pt[2] = pt_tr;
        src_pt[3] = pt_br;
        int T_1 = 0;
        int T_2 = 0;
        dst_pt[0] = cv::Point(MIN(src_pt[0].x,src_pt[1].x) - T_1,MIN(src_pt[0].y,src_pt[2].y));
        dst_pt[1] = cv::Point(MIN(src_pt[0].x,src_pt[1].x) -T_1,MAX(src_pt[1].y,src_pt[3].y));
        dst_pt[2] = cv::Point(MAX(src_pt[2].x,src_pt[3].x) + T_2,MIN(src_pt[0].y,src_pt[2].y));
        dst_pt[3] = cv::Point(MAX(src_pt[2].x,src_pt[3].x) + T_2,MAX(src_pt[1].y,src_pt[3].y));
        Point ptout_tl(dst_pt[0].x,dst_pt[0].y);
        Point ptout_br(dst_pt[3].x,dst_pt[3].y);
        Rect roi_mingp = Rect(ptout_tl,ptout_br);
    
        cv::Mat warpMatrix = cv::getPerspectiveTransform(src_pt, dst_pt);
        cout<<"warpMatrix=
    "<<warpMatrix<<endl;
        cv::warpPerspective(SrcImg, m_src_correct, warpMatrix, SrcImg.size(), cv::INTER_NEAREST, cv::BORDER_CONSTANT);
        RoiCorrect(m_src_correct,roi_mingp);
        m_MingP = m_src_correct(roi_mingp).clone();
    
        Point pt_center = Point(SrcImg.cols/2,SrcImg.rows/2);
        if(b_debug)
        {
            Mat m_show = m_src_correct.clone();
            rectangle(m_show,roi_mingp,cv::Scalar(0,255,255),1);
            Mat SrcImg_cp = SrcImg.clone();
            circle(SrcImg_cp,pt_center,9,Scalar(255,0,0),3);
            cv::namedWindow("SrcImg",cv::WINDOW_NORMAL);
            cv::imshow("SrcImg",SrcImg_cp);
            cv::Mat_<double> mat_pt(3,1);
            mat_pt(0,0) = pt_center.x;
            mat_pt(0,1) = pt_center.y;
            mat_pt(0,2) = 1;
            cout<<"mat_pt==
    "<<mat_pt<<endl;
            Point pt_correct;
            Mat mat_tmp = warpMatrix * mat_pt;
            std::cout<<"mat_tmp=
    "<<mat_tmp<<std::endl;
            double a1 = mat_tmp.at<double>(0,0);
            double a2 = mat_tmp.at<double>(1,0);
            double a3 = mat_tmp.at<double>(2,0);
            cout<<"a1="<<a1<<"   a2="<<a2<<"   a3="<<a3<<endl;
            pt_correct = Point(a1,a2);
            circle(m_show,pt_correct,10,cv::Scalar(0,255,255),8);
    
            cv::namedWindow("correctPic",cv::WINDOW_NORMAL);
            cv::imshow("correctPic",m_show);
            cv::namedWindow("correctRoi",cv::WINDOW_NORMAL);
            cv::imshow("correctRoi",m_MingP);
            waitKey(0);
        }
        return true;
    }
    
    int main() {
        Mat img = imread("/data_2/everyday/0317/bugall_snapshot22.png");
        cv::Point2f pt_tl = Point2f(367,0);
        cv::Point2f pt_tr = Point2f(605,58);
        cv::Point2f pt_bl = Point2f(11,162);
        cv::Point2f pt_br = Point2f(281,351);
    
        Mat m_roi;
        bool b_debug = true;
        correct_cjh_3(pt_tl,pt_bl,pt_tr, pt_br,img,m_roi,b_debug);
    }
    

    一般情况下我们用透视变换到这里就可以了,拿到透视变换后的图继续处理就可以,但是在某些情况下需要点的映射。比如原图的中心点经过透视变换之后该点在哪里?按照下面的矩阵相乘,按理说,点坐标乘以透视变换矩阵就可以了。

    但是,实践起来并不是这样的,透视变换矩阵是33的,点坐标是(x,y),为了相乘,点坐标需要补上1,(x,y,1)。因为透视变换是三维里面的变换,需要z坐标。代码中可以看到我把各个矩阵都打印出来了:
    warpMatrix=
    [2.175396430644075, 4.822550437851066, -786.7332303651573;
    -0.5767283475053204, 2.366574943211475, 211.6593035344521;
    0.0001578547637398106, 0.004169585228612301, 1]
    mat_pt==
    [316;
    186;
    1]
    mat_tmp=
    [797.6864231586686;
    469.5960851601052;
    1.825424957863668]
    a1=797.686 a2=469.596 a3=1.82542
    在变换之后的图上并没有找到我画的变换之后的中心点。应该是超出图像范围了。。。经过一顿乱操作,左乘右乘还是不行。再仔细看看图片,透视变换之后好像被裁剪了一点,感觉是因为裁剪导致坐标对不上了的。。。。后来同事帮忙,弄对了。说需要归一化,让我把得到的点第三个坐标变为1,这样归一化同一个平面。
    pt_correct = Point(a1
    1.0/a3,a2*1.0/a3);

    哈哈,果真出来了!!!
    还有个问题,就是已知透视变换之后的图上点,如何知道该点变换之前的坐标?

  • 相关阅读:
    计算机考研真题 浮点数加法
    计算机考研复试真题 整数奇偶排序
    计算机考研复试 A+B
    计算机考研复试真题 整数拆分
    计算机考研复试真题 众数
    1121 Damn Single (25 分)
    1112 Stucked Keyboard (20 分)
    1117 Eddington Number (25 分)
    1005 继续(3n+1)猜想 (25 分)
    1047 编程团体赛 (20 分)
  • 原文地址:https://www.cnblogs.com/yanghailin/p/12510318.html
Copyright © 2011-2022 走看看