如何更改2D图像的视口?

时间:2015-12-16 14:54:21

标签: matlab opencv image-processing graphics computer-vision

我正在开发一款用于识别金钱的移动应用。现在我正在尝试为这个应用程序构建数据库。

下一步是从不同视图中的原始图像生成一些图像。这是一个例子:

原件:

enter image description here

查看1:

enter image description here

如上图所示,视图1图像是从左边缘查看原稿。我想要做的是从原始生成4个图像,从左,右,下,上4视图。由于图像数量非常大,我无法使用相机捕捉,因此我需要编写一个程序来完成这项工作。但是我找不到关于这个问题的任何事情。

请告诉我有什么工具可以做我需要的吗?或任何图书馆,框架支持这个?我可以在MATLAB和openCV上编码。

感谢您的帮助。

2 个答案:

答案 0 :(得分:5)

您可以执行以下操作:

  1. 您认为原始图像在平面物体上以90度角看待

  2. 你假设一些相机内在参数(例如图像中间的焦点和均匀的像素大小),一些相​​机外在因素(例如,查看"向下"在平面上方有一些位置)和一些平面坐标(xy平面)。这将导致每个像素位于平面的某些坐标上。

  3. 通过围绕相机中心旋转来更改相机的外部参数

  4. 您将一些(4个或更多)平面位置投影到相机图像(例如使用cv::projectPoints())。

  5. 你计算描述像素"运动"的透视单应性。两个摄像机视图之间(输入像素位置是那些投影平面位置和原始图像中相同的平面位置)

  6. 请记住每个所选视图的单应性。

  7. 对于每张图片,只需使用这些单应性,您就不必重新计算它们,因为它们对于每张图片都是相同的。

  8. 编辑: 这就是它在行动中的样子(对于难看的代码而言):

    cv::Mat getRotationMatrixAroundY(double angle)
    {
        cv::Mat rVec;
    
        cv::Mat deg45 = cv::Mat::zeros(3,3,CV_64FC1);
        double cos45 = cos(CV_PI*angle/180.0);
        double sin45 = sin(CV_PI*angle/180.0);
    
        // different axis:
        /*      deg45.at<double>(1,1) = cos45;      deg45.at<double>(1,2) = sin45;      deg45.at<double>(0,0) = 1;      deg45.at<double>(2,1) = -sin45;     deg45.at<double>(2,2) = cos45;      */
    
        /*      deg45.at<double>(0,0) = cos45;      deg45.at<double>(0,1) = in45;       deg45.at<double>(2,2) = 1;      deg45.at<double>(1,0) = -sin45;     deg45.at<double>(1,1) = cos45;      */
    
    
        deg45.at<double>(0,0) = cos45;
        deg45.at<double>(0,2) = sin45;
        deg45.at<double>(1,1) = 1;
        deg45.at<double>(2,0) = -sin45;
        deg45.at<double>(2,2) = cos45;
    
        cv::Rodrigues(deg45, rVec);
    
        return rVec;
    }
    
    // banknode training sample generator
    int main()
    {
        cv::Mat input = cv::imread("../inputData/bankNode.jpg");
    
        std::vector<cv::Point3f> pointsOnPlane;
    
        pointsOnPlane.push_back(cv::Point3f(0-input.cols/2,0-input.rows/2,0));
        pointsOnPlane.push_back(cv::Point3f(input.cols-input.cols/2,0-input.rows/2,0));
        pointsOnPlane.push_back(cv::Point3f(input.cols-input.cols/2,input.rows-input.rows/2,0));
        pointsOnPlane.push_back(cv::Point3f(0-input.cols/2,input.rows-input.rows/2,0));
    
    
    
    
    
        std::vector<cv::Point2f> originalPointsInImage;
        originalPointsInImage.push_back(cv::Point2f(0,0));
        originalPointsInImage.push_back(cv::Point2f(input.cols,0));
        originalPointsInImage.push_back(cv::Point2f(input.cols,input.rows));
        originalPointsInImage.push_back(cv::Point2f(0,input.rows));
    
        std::cout << "original pixel positions:" << std::endl;
        for(unsigned int i=0; i<originalPointsInImage.size(); ++i)
            std::cout << originalPointsInImage[i] << std::endl;
    
        cv::Mat cameraIntrinsics = cv::Mat::eye(3,3,CV_64FC1);
    
        cameraIntrinsics.at<double>(0,0) = 500.0;
        cameraIntrinsics.at<double>(1,1) = 500.0;
        cameraIntrinsics.at<double>(0,2) = input.cols/2.0;
        cameraIntrinsics.at<double>(1,2) = input.rows/2.0;
    
        std::vector<double> distCoefficients;
    
        cv::Mat rVec;
        cv::Mat tVec;
        cv::solvePnP(pointsOnPlane, originalPointsInImage, cameraIntrinsics, distCoefficients, rVec, tVec);
    
    
        // let's increase the distance a bit
        tVec = tVec*2;
        double angle = -45; // degrees
    
    
        cv::Mat rVec2 = getRotationMatrixAroundY(angle);
    
        // TODO: how to "add" some rotation to a previous rotation in Rodrigues?!?
        // atm just overwrite:
    
    
        std::vector<cv::Point2f> projectedPointsOnImage;
        cv::projectPoints(pointsOnPlane, rVec2, tVec, cameraIntrinsics, distCoefficients, projectedPointsOnImage);
    
    
        cv::Mat H = cv::findHomography(originalPointsInImage, projectedPointsOnImage);
    
        cv::Mat warped;
        cv::warpPerspective(input, warped, H, input.size());
    
    
    
    
        cv::imshow("input", input);
        cv::imshow("warped", warped);
        cv::waitKey(0);
        return 0;
    }
    

    有了这个结果:

    enter image description here

    正如您所看到的,存在一个问题:旋转不是围绕银行节点的中心。如果有人能解决这个问题,结果会更好。 Atm我不得不缩放翻译部分,之后可能没有必要。可能是由于错误的翻译+旋转组合而出现问题。

    用于比较:缩放比例为1.5:

    enter image description here

    而不是缩放:

    enter image description here

    这是你想要达到的目标(如果摄像机的观察中心可以固定在银行节点的中间)吗?

答案 1 :(得分:2)

使用Matlab查看here投影变换。您只需要找到正确的变形矩阵(所谓的homographies)。您可以使用维基百科上的数学构建它们,给定旋转矩阵和假定的相机内在函数。

但是,我认为综合创建的训练数据可能会导致您的任务出现问题。钞票的反射部分被设计成看起来与不同的观点不同。你会丢失信息。

此外,不要低估努力,这是开发这项工作所必需的。这个领域正在进行相当复杂的研究。

见这里:

Towards Mobile Recognition and Verification of Holograms using Orthogonal Sampling

Mobile User Interfaces for Efficient Verification of Holograms