本文主要验证了博客上的最小二乘法拟合平面的。与 用matlab拟合出来的平面计算的点到直线的距离是一样的,而且系数也是一样的。说明了本方法的可行性。
matlab中公式为z = c + ax +by
oepncv中公式为Ax+By+Cz=D 将opencv中公式换算成matlab的公式,系数是一样的。
平面公式为:Ax+By+Cz=D
代码:
来自于:https://blog.csdn.net/laobai1015/article/details/73603327?utm_source=blogxgwz4
//对应的方程:Ax+By+Cz=D 其中 A = plane12[0], B = plane12[1], C = plane12[2], D = plane12[3],这是要注意的方程的表示
//float plane12[4] = { 0 };//定义用来储存平面参数的数组,分别对应ABCD
void cvFitPlane(vector<float>dx, vector<float>dy, vector<float>dz, float* plane) {
//直线方程为:
//构建点集cvmat
CvMat* points = cvCreateMat(dx.size(), 3, CV_32FC1);
int nnum = 96;
for (int i = 0; i < dx.size(); ++i)
{
points->data.fl[i * 3 + 0] = dx[i];//矩阵的值进行初始化 X的坐标值
points->data.fl[i * 3 + 1] = dy[i];// Y的坐标值
points->data.fl[i * 3 + 2] = dz[i]; // Z的坐标值
}
Estimate geometric centroid.
int nrows = points->rows;
int ncols = points->cols;
int type = points->type;
CvMat* centroid = cvCreateMat(1, ncols, type);
cvSet(centroid, cvScalar(0));
for (int c = 0; c < ncols; c++) {
for (int r = 0; r < nrows; r++)
{
centroid->data.fl[c] += points->data.fl[ncols*r + c];
}
centroid->data.fl[c] /= nrows;
}
// Subtract geometric centroid from each point.
CvMat* points2 = cvCreateMat(nrows, ncols, type);
for (int r = 0; r < nrows; r++)
for (int c = 0; c < ncols; c++)
points2->data.fl[ncols*r + c] = points->data.fl[ncols*r + c] - centroid->data.fl[c];
// Evaluate SVD of covariance matrix.
CvMat* A = cvCreateMat(ncols, ncols, type);
CvMat* W = cvCreateMat(ncols, ncols, type);
CvMat* V = cvCreateMat(ncols, ncols, type);
cvGEMM(points2, points, 1, NULL, 0, A, CV_GEMM_A_T);
cvSVD(A, W, NULL, V, CV_SVD_V_T);
// Assign plane coefficients by singular vector corresponding to smallest singular value.
plane[ncols] = 0;
for (int c = 0; c < ncols; c++) {
plane[c] = V->data.fl[ncols*(ncols - 1) + c];
plane[ncols] += plane[c] * centroid->data.fl[c];
}
// Release allocated resources.
cvReleaseMat(&points);
cvReleaseMat(¢roid);
cvReleaseMat(&points2);
cvReleaseMat(&A);
cvReleaseMat(&W);
cvReleaseMat(&V);
}
//计算点到平面的距离
//Ax+By+Cz=D
//|点(a,b,c) 到平面bai Ax+By+Cz=D的距离du
//= | A * a + B * b + C * c - D| /√(A ^ 2 + B ^ 2 + C ^ 2)
void calculateDist(vector<float>dx, vector<float>dy, vector<float>dz, float* plane, vector<float> &dist)
{
for (int i = 0; i < dx.size(); i++)
{
float ds = fabs(plane[0] * dx[i] + plane[1] * dy[i] + plane[2] * dz[i] - plane[3]);
float dfen = sqrt(plane[0] * plane[0] + plane[1] * plane[1] + plane[2] * plane[2]);
if (!(dfen > -0.00001 && dfen < -0.00001))
{
float ddist = ds / dfen;
dist.push_back(ddist);
}
}
}
从文件中读取数据,然后计算拟合平面,计算点到平面的距离,并输出到csv文件中
数据格式为:
一行中代表xyz
-53.883533,55.133049,895.801941
-40.928612,32.402653,897.237793
-21.391739,50.161041,899.748901
2.107507,62.850151,902.479065
3.594930,37.490810,902.427490
具体代码为:
fstream fs;
fs.open("E:\\wokspace\\PROJECT\\ThirdTrailInspection\\matlab\\dResult.txt");
if (!fs.is_open())
{
return;
}
vector<float> dx;
vector<float> dy;
vector<float> dz;
int i = 0;
string buff;
while (getline(fs, buff))//是否到文件结bai尾
{
int nfist = buff.find_first_of(',');
int nLast = buff.find_last_of(',');
string st1 = buff.substr(0, nfist);
string st2 = buff.substr(nfist + 1, nLast - nfist - 1);
string st3 =(buff.substr(nLast + 1));
dx.push_back(stof(buff.substr(0, nfist)));
dy.push_back(stof(buff.substr(nfist + 1, nLast - nfist - 1)));
dz.push_back(stof(buff.substr(nLast + 1)));
}
fs.close();
//代入最小二乘算法中
float plane[4] = { 0 };
vector<float> dx1;
vector<float> dy1;
vector<float> dz1;
dx1.assign(dx.begin(), dx.begin() + 96);
dy1.assign(dy.begin(), dy.begin() + 96);
dz1.assign(dz.begin(), dz.begin() + 96);
cvFitPlane(dx1, dy1, dz1, plane);
vector<float> dist;
calculateDist(dx, dy, dz, plane, dist);
fstream fws("e://de.csv", fstream::in | fstream::out | fstream::trunc);
for (int i = 0; i < dist.size(); i++)
{
fws << dist[i] <<"\r";
}
fws.close();
clc;
close all;
clear all;
%https://www.ilovematlab.cn/thread-220252-1-1.html
data = importdata('E:\wokspace\PROJECT\ThirdTrailInspection\matlab\dResult.txt');
x = data(1:96, 1);
y = data(1:96, 2);
z = data(1:96, 3);
% x = data(113:192, 1);
% y = data(113:192, 2);
% z = data(113:192, 3);
scatter3(x, y,z, 'r');%画点 散点图
hold on;
X = [ones(length(x),1) x y];
[b,bint,r,rint,stats] = regress(z,X,95);
% 图形绘制
xfit = min(x):0.1:max(x);
yfit = min(y):0.1:max(y);
[XFIT,YFIT]= meshgrid (xfit,yfit);%用于生成网格采样点
ZFIT = b(1) + b(2) * XFIT + b(3) * YFIT;
mesh(XFIT,YFIT,ZFIT);
%%测试结果
%data = importdata('C:\Users\apr_z\Desktop\dResult.txt');
xx = data(:, 1);
yy = data(:, 2);
zz = data(:, 3);
[row, col] = size(xx);%求矩阵的行数和列数
dist = ones(row, 1);
for i = 1: row
dist(i) = abs(b(2) * xx(i) + b(3) * yy(i) - zz(i) + b(1)) / sqrt(b(2)* b(2) + b(3)*b(3) + 1 );
end
xlswrite('C:\Users\apr_z\Desktop\AnalyzeResult.xlsx', dist);
vector 复制某一些数据时: dx1.assign(dx.begin(), dx.begin() + 96);
vector容器 追加其他容器的内容,使用insert
pt3DList.insert(pt3DList.end(), vc.begin(), vc.end());
用此平面拟合的计算 点到直线的距离 与 用matlab计算出来的点到直线的距离是一模一样的。