利用opencv结合mfc实现识别圆形标记点并计算多个圆形标记点的三维坐标,拟合平面并计算法向量
具体步骤
(1)在Window10系统环境和Visual Studio 2013开发环境下,使用了MFC库及OpenCV库构建了摄像机标定和图像处理平台,构建平面法向量的计算界面。(2)实现了双目摄像机标定及图像矫正的方法。首先,拍摄多张棋盘格标定板图像,并检测棋盘格图像中的角点。其次,利用检测出的角点的位置信息结合摄像机成像模型,求解摄像机内参数和测量图像畸变矫正前后的映射矩阵。再次,求解实际拍摄图像与理想双目立体图像之间的映射关系。最后,将畸变矫正映射和立体矫正映射结合,将拍摄的带圆形标记点的测量图像映射成理想矫正图像。
(3)实现检测圆形标记点及左右图像圆形标记点匹配的方法。首先,提取测量图像的所有轮廓,并利用椭圆方程拟合每个轮廓。其次,筛选出拟合程度高的轮廓,认定为检测出的圆形标记点;再次,使立体矫正后得到的测量图像进行行对齐;最后,采用行对齐方法进行左右图像中标记点匹配。
(4)实现计算标记点三维坐标和多个三维坐标点拟合平面的方法。首先,利用匹配的圆形标记点对,结合双目立体成像模型,计算出各个标记点对应的三维坐标;其次,将三维坐标点的集合写成矩阵的形式,利用奇异值分解(SVD)矩阵的方法求出与各个三维坐标距离和最小的拟合平面;最后,通过平面方程求出平面法向量。
通过对图像标记点的随机分组,测量不同组法向量夹角大小来验证测量精度,结果表明本文方法能实现平面法向量的计算
二、对应代码
1.引入库
opencv
2.标定
https://download.csdn.net/download/qq_45043397/16581715识别圆形标记点
vector<RotatedRect> findellipse(Mat *LLL,int a,int b)
{
Mat src_img, dst_img;
vector<RotatedRect> box2;
src_img = *LLL;//灰度图读入
blur(src_img, src_img, Size(3, 3));
Canny(src_img, dst_img, a, b);
string path1 = "C:\\Users\\stranger\\Desktop\\uuu";
imshow("p", dst_img);
imwrite(path1 + "\\f.jpg", dst_img.clone());
vector<vector<Point>> contours;
vector<Vec4i> hireachy;
findContours(dst_img, contours, hireachy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_TC89_L1);
for (unsigned int i = 0; i < contours.size(); i++)
{
double S1 = contourArea(contours[i]);
if (S1>50)
{
Mat pointsf;
Mat(contours[i]).convertTo(pointsf, CV_32F);
RotatedRect box = fitEllipse(pointsf);
if (box.size.width / box.size.height > 10 && box.size.width / box.size.height<0.1) continue;
double S2 = box.size.width * box.size.height * PI / 4;
if (S1 / S2 >0.95 && S1 / S2<1.1)
{
box2.push_back(box);
circle(*LLL, box.center, 2, Scalar(255));
ellipse(*LLL, box, Scalar(255), 1, 8);
}
}
}
return box2;
}
左右图像中圆形标记点匹配
if (box3.size() == box4.size())
{
for (i = 0; i < box3.size(); i++)
{
for (j = 0; j < box4.size(); j++)
{
if (abs(box3[i].center.y - box4[j].center.y<10) && abs(box3[i].center.x - box4[j].center.x)<cimage.cols / 2)
{
box10.push_back(box4[j]);
box4.erase(box4.begin() + j);
}
}
}
box4.clear();
box4 = box10;
o.Format(_T("标志点匹配成功 "));
list2.AddString(o);
list2.RedrawWindow();
}
if (box3.size() != box4.size()){ MessageBox(_T("左右标记点检测个数不一致")); }
计算三维坐标
利用深度映射矩阵将对应圆形标记点的三维坐标加视差信息就可以计算出三维坐标
平面拟合
// TODO: 计算三维坐标
list2.ResetContent();
list2.RedrawWindow();
Mat xyzd = Mat(4, box3.size(), CV_32FC1, Scalar::all(0));
int i, j;
for (j = 0; j < xyzd.cols; j++)
{
xyzd.at<float>(0, j) = box3[j].center.x;
xyzd.at<float>(1, j) = box3[j].center.y;
xyzd.at<float>(2, j) = box3[j].center.x - box4[j].center.x;
xyzd.at<float>(3, j) = 1;
}
Mat YZ=Mat(4,4, CV_32FC1, Scalar::all(0));
for (i = 0; i < Q.rows; i++)
{
for (j = 0; j < Q.cols; j++)
{
YZ.at<float>(i, j) = Q.at<double>(i, j);
}
}
XYZ = YZ*xyzd;
for (i = 0; i < XYZ.cols; i++)
{
o.Format(_T("第%d个点三维坐标(%f, %f, %f)"), i + 1, XYZ.at<float>(0, i) / XYZ.at<float>(3, i), XYZ.at<float>(1, i) / XYZ.at<float>(3, i), XYZ.at<float>(2, i) / XYZ.at<float>(3, i));
list2.AddString(o);
list2.RedrawWindow();
}
总mfc代码
https://download.csdn.net/download/qq_45043397/21983775?spm=1001.2014.3001.5503