我正在开发一款用于识别金钱的移动应用。现在我正在尝试为这个应用程序构建数据库。
下一步是从不同视图中的原始图像生成一些图像。这是一个例子:
原件:
查看1:
如上图所示,视图1图像是从左边缘查看原稿。我想要做的是从原始生成4个图像,从左,右,下,上4视图。由于图像数量非常大,我无法使用相机捕捉,因此我需要编写一个程序来完成这项工作。但是我找不到关于这个问题的任何事情。
请告诉我有什么工具可以做我需要的吗?或任何图书馆,框架支持这个?我可以在MATLAB和openCV上编码。
感谢您的帮助。
答案 0 :(得分:5)
您可以执行以下操作:
您认为原始图像在平面物体上以90度角看待
你假设一些相机内在参数(例如图像中间的焦点和均匀的像素大小),一些相机外在因素(例如,查看"向下"在平面上方有一些位置)和一些平面坐标(xy平面)。这将导致每个像素位于平面的某些坐标上。
通过围绕相机中心旋转来更改相机的外部参数
您将一些(4个或更多)平面位置投影到相机图像(例如使用cv::projectPoints()
)。
你计算描述像素"运动"的透视单应性。两个摄像机视图之间(输入像素位置是那些投影平面位置和原始图像中相同的平面位置)
请记住每个所选视图的单应性。
对于每张图片,只需使用这些单应性,您就不必重新计算它们,因为它们对于每张图片都是相同的。
编辑: 这就是它在行动中的样子(对于难看的代码而言):
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;
}
有了这个结果:
正如您所看到的,存在一个问题:旋转不是围绕银行节点的中心。如果有人能解决这个问题,结果会更好。 Atm我不得不缩放翻译部分,之后可能没有必要。可能是由于错误的翻译+旋转组合而出现问题。
用于比较:缩放比例为1.5:
而不是缩放:
这是你想要达到的目标(如果摄像机的观察中心可以固定在银行节点的中间)吗?
答案 1 :(得分:2)
使用Matlab查看here投影变换。您只需要找到正确的变形矩阵(所谓的homographies)。您可以使用维基百科上的数学构建它们,给定旋转矩阵和假定的相机内在函数。
但是,我认为综合创建的训练数据可能会导致您的任务出现问题。钞票的反射部分被设计成看起来与不同的观点不同。你会丢失信息。
此外,不要低估努力,这是开发这项工作所必需的。这个领域正在进行相当复杂的研究。
见这里:
Towards Mobile Recognition and Verification of Holograms using Orthogonal Sampling
Mobile User Interfaces for Efficient Verification of Holograms