#include<iostream>
#include<opencv2/opencv.hpp>
#include<math.h>
using namespace std;
using namespace cv;
float LineFitLeastSquares(vector<float> &data_x, vector<float >&data_y, int data_n);
void pretreatment(Mat &src, vector<vector<float>>&alldata_x, vector<vector<float>>&alldata_y, int n);
void Coordinatetransformation(vector<vector<float>>&alldata_x, vector<vector<float>>& alldata_y, vector<float >& data_x, vector<float >&data_y);
string loc = "F:/研究生/标准件检测项目/标准帮2/7.png";
string save_loc = "F:/研究生/标准件检测项目/标准帮2/pre7.png";
int main()
{
//要绝对路径
string path = "F:\\研究生\\标准件检测项目\\标准帮\\*.png";
//cout << path << endl;
vector<Mat> images;
// 必须cv的String
vector<String> fn;
glob(path, fn, false);
size_t count = fn.size();
vector<vector<float>> alldata_x(count);
vector<vector<float>> alldata_y(count);
//----------------------------------------------------导图预处理--------------------------------------------------------
for (int i = 0; i < count; i++)
{
Mat src = imread(fn[i],CV_8UC1);
images.push_back(src);
int n = i;
alldata_x[n].resize(0);
alldata_y[n].resize(0);
pretreatment(src, alldata_x, alldata_y,n);
cout << "第"<< fn[i] <<"张图处理完毕" << endl;
}
cout << "图片数量"<<alldata_x.size()<<endl;
//---------------------------------------------------------整合坐标数据---------------------------------------------------------------
int sz = alldata_x.size()*alldata_x[0].size();
vector<float >data_x(sz), data_y(sz);
cout << "数据长度"<<data_x.size()<<endl;
Coordinatetransformation(alldata_x, alldata_y,data_x, data_y);
cout << "排序完毕" << endl;
//---------------------------------------------------计算直线度-----------------------------------------------
//if (data_x.size() == data_y.size())
//{
int data_n = data_x.size();
float max_min_gap = LineFitLeastSquares(data_x, data_y, data_n);
cout << "直线度误差为\t" << max_min_gap * 5.411 << "微米" << endl;
//}
cout << "处理完毕" << endl;
system("pause");
waitKey();
return 0;
}
//预处理
void pretreatment(Mat &src, vector<vector<float>>&alldata_x, vector<vector<float>>&alldata_y,int n)
{
Mat bisrc, morsrc, blursrc;
//src = imread(loc, CV_8UC1);
Point2f center(src.rows / 2, src.cols / 2);
double theta = -1.93669905;
double scal = 1;
Mat M2 = getRotationMatrix2D(center, theta, scal);
warpAffine(src, src, M2, Size(6000, 4000));//在对像素数要求精度很高的情况下,旋转变换之后图像的Size应该扩大,否则图像缩小了,像素数减少!
Mat roi(src, Range(600, 2700), Range(150, 5400));
bilateralFilter(roi, blursrc, 0, 100, 5, 4);
threshold(blursrc, bisrc, 125, 255, THRESH_BINARY_INV);
//imshow("二值", bisrc);
//normalize(bisrc, bisrc, 0, 1, NORM_MINMAX);
//形态学操作消除白点,黑点;
Mat kernel=getStructuringElement(MORPH_RECT,Size(13,13));
//morphologyEx(bisrc, morsrc, MORPH_CLOSE, kernel);//先膨胀后腐蚀的过程称为闭运算。用来填充物体内细小空洞、连接邻近物体、平滑其边界的同时并不明显改变其面积。
morphologyEx(bisrc, morsrc, MORPH_OPEN, kernel);//先腐蚀后膨胀的过程称为开运算。用来消除小物体、在纤细点处分离物体、平滑较大物体的边界的同时并不明显改变其面积。
//namedWindow("形态学", WINDOW_KEEPRATIO);
//imshow("形态学", morsrc);
//--------------------------------------------------保存图片-----------------------------------------------------------------
//imwrite(save_loc, morsrc);
/*Mat bisrc;
img= imread("F:/研究生/标准件检测项目/标准帮/pre1.png",CV_8UC1);*/
Mat sub_canny_output;
vector<vector<Point>> contours;
vector<Vec4i> hi;//hierarchy都包含4个整型数据,分别表示:后一个轮廓的序号、前一个轮廓的序号、子轮廓的序号、父轮廓的序号
//canny 轮廓提取
Canny(morsrc, sub_canny_output, 80, 160);
findContours(sub_canny_output, contours, hi, RETR_LIST, CHAIN_APPROX_NONE, Point(0, 0));
cout << "下轮廓长度" << contours[0].size() << '\t' << "上轮廓长度" << contours[1].size() << endl;
//sort(contours[0].begin(),contours[0].end());
//sort(contours[1].begin(), contours[1].end());
for (int i = 0; i < contours[1].size();i++) {
contours[1][i].y+= 1;
//cout<<"点"<<contours[1][i]<<'\t'<<"下点"<<contours[0][i]<<endl;
}
//轮廓排序
int num_elems = 0.5*contours[0].size();
alldata_x[n].resize(num_elems);
alldata_y[n].resize(num_elems);
cout << "alldata_x长度" << alldata_x[n].size() << '\t' << "alldata_y长度" << alldata_y[n].size() << endl;
//vector<float >data_x(num_elems), data_y(num_elems);//!!!!!!!!!!!!!!!!!
vector<int >updata_x(num_elems), updata_y(num_elems);
vector<int >bedata_x(num_elems), bedata_y(num_elems);
for (int i = 0; i < num_elems; i ++) {
for (int j = 0; j < contours[0].size();j++) {
if (contours[0][j].x == i)
{
updata_x[i] = contours[0][j].x;
updata_y[i] = contours[0][j].y;
break;
}
}
//cout << "下第一个点x"<<updata_x[i]<<'\t'<<"上第一个点y"<<updata_y[i]<<endl;
}
cout << "上第一个点x" << updata_x[50] << '\t' << "上第一个点y" << updata_y[50] << endl;
for (int i = 0; i < num_elems; i++) {
for (int j = 0; j < contours[1].size(); j++) {
if (contours[1][j].x == i)
{
bedata_x[i] = contours[1][j].x;
bedata_y[i] = contours[1][j].y;
break;
}
}
//cout << "下第一个点x" << bedata_x[i] <<'\t'<< "上第一个点y" << bedata_y[i] << endl;
}
cout << "下第一个点x" << bedata_x[50] << '\t' << "下第一个点y" << bedata_y[50] << endl;
//建立两个数组
for (size_t p = 0; p < num_elems; p++)
{
alldata_x[n][p] = (0.5*(bedata_x[p] + updata_x[p]));
alldata_y[n][p] = (0.5*(bedata_y[p] + updata_y[p]));
if (p==50) {
cout << "第" << 50 + 1 << "个点的x坐标为" << alldata_x[n][50] << endl;
cout << "第" << 50 + 1 << "个点的y坐标为" << alldata_y[n][50] << endl;
}
}
}
//坐标变换
void Coordinatetransformation(vector<vector<float>>&alldata_x, vector<vector<float>>&alldata_y, vector<float> &data_x, vector<float> &data_y)
{
for (int i = 0; i < alldata_x.size(); i++) {
if (i == 0)
{
for (int n = 0; n < alldata_x[0].size(); n++)
data_x[n]=(alldata_x[0][n]);
}
else {
int startloc = i * alldata_x[0].size();
float end_x = alldata_x[i - 1].back();
for (int j = 0; j < alldata_x[i].size(); j++)
{
alldata_x[i][j] = end_x+ alldata_x[i][j];
data_x[startloc+j]=(alldata_x[i][j]);
}
}
}
cout << "x坐标排序完毕" << endl;
for (int i = 0; i < alldata_y.size(); i++) {
if (i == 0)
{
for (int n = 0; n < alldata_y[0].size(); n++)
data_y[n]=(alldata_y[0][n]);
}
else {
int startloc = i * alldata_y[0].size();
float begin_y = alldata_y[i].front();
float end_y = alldata_y[i - 1].back();
for (int j = 0; j < alldata_y[i].size(); j++)
{
alldata_y[i][j]=end_y + alldata_y[i][j] - begin_y;
data_y[startloc+j]=(alldata_y[i][j]);
}
}
}
cout << "y坐标排序完毕" << endl;
}
//最小二乘法确定直线度误差
float LineFitLeastSquares(vector<float> &data_x, vector<float >&data_y, int data_n)//分别代表x数组,y数组(两数组顺序确定)以及点的数量
{
float A = 0.0;//x平方累加和
float B = 0.0;//x累加和
float C = 0.0;//xy累加和
float D = 0.0;//y累加和
//float E = 0.0;
//float F = 0.0;
for (int i = 0; i < data_n; i++)
{
A += data_x[i] * data_x[i];
B += data_x[i];
C += data_x[i] * data_y[i];
D += data_y[i];
}
// 计算斜率a和截距b
float a, b, temp = 0;
if (temp = (data_n*A - B * B))// 判断分母不为0
{
a = (data_n*C - B * D) / temp;
b = (A*D - B * C) / temp;
}
else
{
a = 1;
b = 0;
}
//计算点到直线的距离,将距离值存入一个向量中
vector<float> gaps(data_n);//!!!!!!!!!!!!!!!!!!
vector<float> y(data_n);//!!!!!!!!!!!!!!!!!
for (int i = 0; i < data_n; i++) {
y[i] = a * data_x[i] + b;
gaps[i] = data_y[i] - y[i];
}
//选出向量中最大最小值,做差取决对值返回
float max_gap = *max_element(gaps.begin(), gaps.end());//!!!!!!!!!!!!!!
float min_gap = *min_element(gaps.begin(), gaps.end());//!!!!!!!!!!!!!!!!!
float max_min_gap = abs(max_gap) + abs(min_gap);
return max_min_gap;
}
直线度检测
最新推荐文章于 2023-11-27 17:49:10 发布