我是OpenCV
的初学者,目前我正在开展一个项目,要求将像素精确映射到厘米/毫米/任何真实世界单位。
我在OpenCV
进行立体声校准,然后进行立体声校正。因此,我已经获得了内在和外在的参数。
在进行立体声校准时,我没有输入棋盘图案的确切方形尺寸(25mm×25mm)。我只输入了水平和垂直内角的数量以及板的数量。当重新投影到3D时,这会产生影响吗?如果是这样,我如何在StereoCalibrate函数中包含方形大小。
其次,从相机矩阵获得的值fx
和fy
均为513.86,而从EXIF数据得出的值为3.7mm。那么,两者之间的确切关系是什么?
第三,我使用reprojectImageTo3D
并获得了3d世界坐标。现在这些坐标的确切单位是多少(厘米/毫米/英寸/等)?
基本上,我想获得从像素到真实世界单位的精确映射,经过大量的阅读和搜索后,我无法做到这一点。请帮我解决这个问题。
答案 0 :(得分:1)
我同意前两个问题的其他答案。但只是为了进一步澄清并详细阐述,
1)
在下面的代码块中查看参数'squareSize'。
这是你给出正方形大小的地方。这样做,它计算棋盘中每个角落的位置,并将其推入一个点矢量,称为objectPoints。这是可能的,因为棋盘具有规则图案。
矢量objectPoints将成为StereoCalibrate函数的第一个参数。
另外,请记住,无论您为squareSize指定的单位,校准结果(当然除fx和fy外)都将采用相同的单位。
for( j = 0; j < boardSize.height; j++ ){
for( k = 0; k < boardSize.width; k++ ){
objectPoints.push_back(Point3f(j*squareSize, k*squareSize, 0));
}
}
<强> 2)强>
你得到的fx和fy将以像素为单位。为了获得以mm为单位的焦距,您需要将其与缩放系数相乘。fx,fy与实际焦距(mm)之间的关系由相机传感器的大小决定。您应该能够在相机规格中找到此参数。
我上面提到的缩放系数是相机传感器每毫米像素数。
第3)强>
您获得的3D世界坐标正是您提到的。的坐标即可。从您系统中的某些角度引用。它们是对象点的 x , y 和 z坐标。坐标没有单位!
答案 1 :(得分:0)
到目前为止,我可以回答两个第一个问题:
1: cv :: stereoCalibrate 中的第一个参数是对象点的向量,您可以使用以下函数填充它:
void CalcBoardCornerPositions(cv::Size boardSize, double squareSize, std::vector<cv::Point3f>& corners) {
corners.clear();
for( int i = 0; i < boardSize.height; ++i )
for( int j = 0; j < boardSize.width; ++j )
corners.push_back(cv::Point3f(float( j*squareSize ), float( i*squareSize ), 0));
}
然后使用它:
std::vector<std::vector<cv::Point3f> > objectPoints(1);
CalcBoardCornerPositions(boardSize, squareSize, objectPoints[0]);
cv::stereoCalibrate(objectPoints, imagePointsA, imagePointsB, _cameraMatrixA, /// etc
2:相机矩阵fx和fy实际上是焦距乘以分别是方向x和y的像素密度。这意味着
fx = f * cx
fy = f * cy
其中cx = imageSize.width / sensorSize.width和cy = imageSize.height / sensorSize.height。 通常在现代相机中使用cx == cy。您可以在相机手册中找到相机传感器的尺寸。
答案 2 :(得分:0)
StereoCalibrate
的第一个参数是您需要自己创建的校准模式的实际尺寸。例如,如果您有一个3x正方形的棋盘网格6x5,则需要创建一个矩阵,其中包含棋盘e.x上参考系统中表示的每个角的位置。 [(0,0,0)(0,3,0)(0,6,0)...]
等等。fx
和fy
。