我正在使用Qt5和计算机视觉库OpenCV3设计带有很多控件的用户界面。为了更好地解释问题,我创建了一个小型工作应用程序,该应用程序完全复制了我过去几天一直在尝试解决的问题。
在使用黑白相机和彩色相机获取校准文件.yml(包含在Bitbucket的cam_calib
文件夹中)之后,我试图使用OpenCV库中的三角测量功能来计算两个点的距离。>
在这里,我创建了一个Bitbucket,以下载我编写的最小应用程序作为示例。该应用程序很小,但是我必须附加库,该库具有取决于应用程序的所有相机功能。
git clone https://ERaggi@bitbucket.org/ERaggi/matchingqtopencv.git
正如您在下面的第一个屏幕中看到的那样,我具有左右QGraphicsView。现在理所当然的是,我的图形驱动程序在最近几天无法正常工作(这解释了为什么图像以左侧的非常奇怪的方式显示),用户界面有时似乎工作正常,有时完全关闭。我注意到这种行为是由于点击发生在何处:
第一张图像是设置后的结果:1)搜索区域(设置区域大小),2)QComboBox
中的Point选项,最后3)单击左侧的随机点查看
在第二张图像中,我执行相同的操作,但是我单击图像中的其他点,但始终在左视图中。
因此,我要概述的步骤是:
1)上传黑白相机的校准图像(左视图),并上传我以黑白方式转换的右相机的彩色图像(右视图)。
2)我将搜索区域(.ui上的“设置区域大小”)设置为始终为奇数,因为它表示一个矩阵nxn,它将在图像B中的同一像素行上进行搜索(右)。
3)搜索由红色正方形表示,可以在屏幕截图中看到。那个正方形正在移动并计算每个像素的最小误差向量,一旦存在对应关系,到达行尾后,它将返回找到最小误差的位置。 找到的红场被提取并按照libCam文件的 stereocal.cpp 处理,保存在桌面文件夹中,并显示在此处:
///Write cropped match regions
void StereoCal::cropMatches(int xa, int ya, int xb, int yb){
cv::Point ptA=cv::Point(xa, ya);
cv::Point ptB=cv::Point(xb, yb);
cv::Size sz;
sz.height=regionSize;
sz.width=regionSize;
cv::Mat regionA, regionB;
cv::getRectSubPix(currentImages.getA().get8Bitmap(),sz,ptA,regionA);
cv::getRectSubPix(currentImages.getB().get8Bitmap(),sz,ptB,regionB);
std::string path = "/home/emanuele/Desktop/croppedMatches/";
std::string outA = path+"cropA.tiff";
std::string outB = path+"cropB.tiff";
cv::imwrite(outA,regionA);
cv::imwrite(outB,regionB);
}
该错误是在libCam库的 stereocal.cpp 文件中计算的。参见下文,我该怎么做:
double StereoCal::getError(int xa, int ya, int xb, int yb){
double error=0.0;
Image aT,bT;
cv::Mat a,b;
aT=currentImages.getA();
if(aT.getBitmap().channels() > 2) {
aT.toGrey();
}
aT.getBitmap().convertTo(a, CV_32F);
bT=currentImages.getB();
if(bT.getBitmap().channels() > 2) {
bT.toGrey();
}
bT.getBitmap().convertTo(b, CV_32F);
for (int kx = -km; kx <= km; kx++){
for(int ky = -km; ky <= km; ky++){
error += std::pow((a.at<float>(ya+kx,xa+ky)-b.at<float>(yb+kx,xb+ky)),2);
}
}
return error;
}
所以问题是:在单击左图后,在右图上进行搜索,我找到了第一个点的第一个深度(Z)坐标(因此计算了三角剖分)。为了可视化,我计算了从观察者到棕点的黑线:
第二次单击后,在进行新搜索时,将从“ XYZ坐标凸轮A”提取的第一组坐标将移动到“ XYZ先前凸轮A”上。正方形到达终点后,将发布第二个坐标(从观察者到我单击的第二点的黑线之间的距离):
从技术上使用毕达哥拉(Pithagora)定理,我应该获得如下所示的结果向量,相关的代码可以在文件 windowingdialog.cpp 中找到:
void windowingDialog::refreshDistance3D()
{
double ax = ui->leftCoordX->text().toDouble();
double ay = ui->leftCoordY->text().toDouble();
double az = ui->leftCoordDepth->text().toDouble();
double bx = ui->pp_ax->text().toDouble();
double by = ui->pp_ay->text().toDouble();
double bz = ui->pp_az->text().toDouble();
double distance = sqrt(pow(bx-ax, 2) + pow(by-ay, 2) + pow(bz-az, 2));
ui->distAB->setText(QString("%1").arg(distance));
}
但是我得到了一个非常奇怪的计算结果,即 9182.13 mm(此应用中的距离以毫米为单位)。有时候,它似乎运作良好,但似乎很大程度上取决于第二次点击发生的位置。从上方图像和下方结果的最终详细图像中,可以从用户界面“距离拖曳点”上的标签中看到结果,在第二个搜索点之后获得一些负坐标:
我不知道发生了什么。我遵循了triangulation documentation from OpenCV,而我使用的代码如下:
cv::Vec3d StereoCal::triangulatePoints(std::vector<cv::Point2f> a, std::vector<cv::Point2f> b){
cv::Mat triangulatedPts;
cv::triangulatePoints(P1, P2, a, b, triangulatedPts);
cv::Vec3d coords3D;
// this loop will give us xyz divided by the conversion factor
for(int i=0; i<triangulatedPts.size().width;i++){
cv::Vec4d triangCoords = triangulatedPts.col(i);
for (unsigned int j = 0; j < 3; j++) {
coords3D[j] = triangCoords[j] / triangCoords[3];
std::cout<<coords3D[j] <<std::endl; // depth is shown here
}
}
return(coords3D);
}
如果有人可以看看正在发生的事情,那就太好了,因为我已经为此努力了几天。很抱歉提供冗长的解释,但我想确保正确解释问题和遵循的步骤。 请为我指出如何解决此问题的正确方向。