【问题标题】:Changing the perspective using Opencv使用 Opencv 改变视角
【发布时间】:2023-04-08 03:27:01
【问题描述】:

我正在做一个项目,我在其中使用棋盘,我面临的问题是,当我识别出棋盘时,我想裁剪包含它的框架部分并将其“拉直” ,为此我正在使用cv::warpPerspective 函数,下面是我的代码和我得到的结果:

int main (){
    cv::Size board(6,4);
    cv::Mat src,result,quad,transformationMatrix;
    std::vector<cv::Point2f> imageCorners;
    std::vector<cv::Point2f> top, bot;
    std::vector<cv::Point2f> not_a_rect_shape;
    cv::VideoCapture cap(0);
    char fileName[20] = "MYROI";
    int index =0;
    int key = 0 ;   
    cap >> src;
    while ( key != 27){
        cap >> src;
        if(cv::findChessboardCorners(src,board,imageCorners,CV_CALIB_CB_FILTER_QUADS)){
            int xMin =imageCorners.at(0).x  ,xMax = imageCorners.at(0).x; 
            int yMin = imageCorners.at(0).y, yMax =imageCorners.at(0).y;
        for (int i  = (imageCorners.size()-1) ; i>0;i--){
                if(xMin > imageCorners.at(i-1).x)
                        xMin = imageCorners.at(i-1).x;
                if(xMax < imageCorners.at(i-1).x)
                    xMax = imageCorners.at(i-1).x;
                if(yMin > imageCorners.at(i-1).y)
                    yMin = imageCorners.at(i-1).y;
                if(yMax < imageCorners.at(i-1).y)
                    yMax = imageCorners.at(i-1).y;
            } 
        cv::Rect  myroi(xMin-5,yMin-5,(xMax-xMin)+5,(yMax-yMin)+5);
        if ( myroi.area() > 0){
            cv::imshow("ROI",(src)(myroi));  
        result = (src)(myroi);
        not_a_rect_shape.clear();
        not_a_rect_shape.push_back(imageCorners[0]);
        not_a_rect_shape.push_back(imageCorners[board.height-1]);
        not_a_rect_shape.push_back(imageCorners[board.area()-board.height-1]);
        not_a_rect_shape.push_back(imageCorners[board.area()-1]);
        std::vector<cv::Point2f> approx;
        cv::approxPolyDP(cv::Mat(not_a_rect_shape),approx,cv::arcLength(cv::Mat(not_a_rect_shape),true)*0.02,true);
        if (approx.size()!=4){
            std::cout << " Not quadrilateral!"<<std::endl;

            not_a_rect_shape.clear();
            approx.clear();

            not_a_rect_shape.push_back(imageCorners[0]);
            not_a_rect_shape.push_back(imageCorners[board.width-1]);
            not_a_rect_shape.push_back(imageCorners[board.area()-board.width-1]);
            not_a_rect_shape.push_back(imageCorners[board.area()-1]);
            cv::approxPolyDP(cv::Mat(not_a_rect_shape),approx,cv::arcLength(cv::Mat(not_a_rect_shape),true)*0.02,true); 
        }

        // center 
        cv::Point2f center(0,0);
        for (int i = 0 ; i <not_a_rect_shape.size(); i++)
                center+= not_a_rect_shape[i];
            center *=( 1./not_a_rect_shape.size()); // the center position 

            top.clear();
            bot.clear();
        // ordering  the  4 points 
        for (int i = 0; i < not_a_rect_shape.size(); i++){
            if (not_a_rect_shape[i].y < center.y)
                top.push_back(not_a_rect_shape[i]);
            else
                 bot.push_back(not_a_rect_shape[i]);
            }
        std::cout << center << std::endl;
        if(top.size()== 2 && bot.size()==2){ 
            cv::Point2f tl = top[0].x > top[1].x ? top[1] : top[0];
            cv::Point2f tr = top[0].x > top[1].x ? top[0] : top[1];
            cv::Point2f bl = bot[0].x > bot[1].x ? bot[1] : bot[0];
            cv::Point2f br = bot[0].x > bot[1].x ? bot[0] : bot[1];
            not_a_rect_shape.clear();
            not_a_rect_shape.push_back(tl);
            not_a_rect_shape.push_back(tr);
            not_a_rect_shape.push_back(br);
            not_a_rect_shape.push_back(bl);

            // Define the destination image
            quad = cv::Mat::zeros(300, 220, CV_8UC3);
            //quad = cv::Mat::zeros(result.rows,result.cols,CV_8UC3);
        // Corners of the destination image
            std::vector<cv::Point2f> quad_pts;
            quad_pts.push_back(cv::Point2f(0, 0));
            quad_pts.push_back(cv::Point2f(quad.cols, 0));
            quad_pts.push_back(cv::Point2f(quad.cols, quad.rows));
            quad_pts.push_back(cv::Point2f(0, quad.rows));
            transformationMatrix= cv::getPerspectiveTransform(not_a_rect_shape, quad_pts);
            cv::warpPerspective(src, quad, transformationMatrix, quad.size()/*perspectiveSize*/,1);
            cv::imshow("quadrilateral", quad);
            cv::imwrite("result.jpg",result);
            cv::imwrite("quadrilateral.jpg",quad);

        }

        }
        }
        cv::imshow("src",src); 
        key = cv::waitKey(10);
    }

这是一个获得 ROI 的示例:

这是改变视角后的样子:

假设这是我所期望的(这个大小无关紧要):

知道如何解决这个问题吗?

【问题讨论】:

    标签: c++ opencv image-processing


    【解决方案1】:

    我正在使用下一个代码 sn-p 来解决此类问题:

    ...
    // Create a column vector with the coordinates of each point (on the field plane)
    cv::Mat xField;
    xField.create(4, 1, CV_32FC2);
    xField.at<Point2f>(0) = ( Pts[0] );
    xField.at<Point2f>(1) = ( Pts[1] );
    xField.at<Point2f>(2) = ( Pts[2] );
    xField.at<Point2f>(3) = ( Pts[3] );
    
    // same thing for xImage but with the pixel coordinates instead of the field coordinates, same order as in xField
    cv::Mat xImage;
    xImage.create(4, 1, CV_32FC2);
    xImage.at<Point2f>(0) = ( cv::Point2f(0, 0) );
    xImage.at<Point2f>(1) = ( cv::Point2f(400, 0) );
    xImage.at<Point2f>(2) = ( cv::Point2f(400, 600) );
    xImage.at<Point2f>(3) = ( cv::Point2f(0, 600) );
    
    // Compute the homography matrix
    cv::Mat H = cv::findHomography(xField,xImage );
    xField.release();
    xImage.release();
    
    Mat warped;
    warpPerspective(frame,warped,H,Size(400,600));
    H.release();
    ...
    

    此代码将从多边形 xField 中获取图像并将其放入 xImage(此处为矩形 0,0,400,600)。

    你在这里搞错了: 改变这个

    not_a_rect_shape.push_back(tl);
    not_a_rect_shape.push_back(tr);
    not_a_rect_shape.push_back(br);
    not_a_rect_shape.push_back(bl);
    

    到这里

    not_a_rect_shape.push_back(imageCorners[0]);
    not_a_rect_shape.push_back(imageCorners[board.area()-board.width]);
    not_a_rect_shape.push_back(imageCorners[board.area()-1]);
    not_a_rect_shape.push_back(imageCorners[board.width-1]);
    

    【讨论】:

    • 感谢您的回答,我所做的一切都是一样的,您使用 findHomography 的方式使其与 getPerspektiveTransform 做同样的事情!并且使用 Mat 而不是 Point 的向量在这里不会改变任何东西!
    • 我已经编辑了我的答案,你设置的点数不正确。
    • 它有效,但我不明白我为什么要这样做???我会接受你的回答,但我需要一点解释
    • 这是有效的,因为这样你会得到旋转板的角。当你沿着 x 和 y 轴找到最小/最大值时,你混合所有 x 和 y 的角点。试着在纸上画出来。
    猜你喜欢
    • 2016-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多