基于Opencv的法兰盘螺纹孔位置确定(二)

需要指出的是是本项目共使用了四个相机,中心一个相机,边缘三个相机,旨在更好得提取螺纹特征并进行分类。因此该节中定位定位销并得到其他螺纹孔位置后,提取的图像是对应边缘相机投射到中心相机平面的图像。

基于Opencv的法兰盘螺纹孔位置确定(二)_第1张图片

一、棋盘格坐标点提取及对应变换

需要注意此处标定板平面与法兰盘螺纹孔平面在同一平面上,方便后续拼接
基于Opencv的法兰盘螺纹孔位置确定(二)_第2张图片

    //棋盘格坐标点
	vector<Point2d> points0;
	vector<Point2d> points1;
	vector<Point2d> points2;
	vector<Point2d> points3;

	//读取棋盘格坐标点
	ReadPoints("C:\\Users\\sunrise_oneday\\Desktop\\20221107\\Calib\\CalibrationResults\\0_res.txt", points0);
	ReadPoints("C:\\Users\\sunrise_oneday\\Desktop\\20221107\\Calib\\CalibrationResults\\1_res.txt", points1);
	ReadPoints("C:\\Users\\sunrise_oneday\\Desktop\\20221107\\Calib\\CalibrationResults\\2_res.txt", points2);
	ReadPoints("C:\\Users\\sunrise_oneday\\Desktop\\20221107\\Calib\\CalibrationResults\\3_res.txt", points3);

	//计算单应性矩阵(1与0,2与0,3与0)
	cv::Mat Homography10 = cv::findHomography(
		points1,
		points0, // 对应的点
		cv::RANSAC, // RANSAC 方法
		1.); // 到重复投影点的最大距离
	cv::Mat Homography20 = cv::findHomography(
		points2,
		points0, // 对应的点
		cv::RANSAC, // RANSAC 方法
		1.); // 到重复投影点的最大距离
	cv::Mat Homography30 = cv::findHomography(
		points3,
		points0, // 对应的点
		cv::RANSAC, // RANSAC 方法
		1.); // 到重复投影点的最大距离

	//读取法兰盘图像
	Mat image0 = cv::imread("D:\\Graduate\\Data\\0.bmp", 0);
	Mat image1 = cv::imread("D:\\Graduate\\Data\\1.bmp", 0);
	Mat image2 = cv::imread("D:\\Graduate\\Data\\2.bmp", 0);
	Mat image3 = cv::imread("D:\\Graduate\\Data\\3.bmp", 0);
	Mat tempImg = imread("D:\\Graduate\\Data\\temp.bmp", 0);


	//法兰盘投影到中心相机图像
	Mat imageResult1, imageResult2, imageResult3;
	cv::warpPerspective(image1, // 输入图像
		imageResult1, // 输出图像
		Homography10, // 单应矩阵
		cv::Size(image1.cols, image1.rows));// 输出图像的尺寸
	cv::warpPerspective(image2, // 输入图像
		imageResult2, // 输出图像
		Homography20, // 单应矩阵
		cv::Size(image1.cols, image1.rows));// 输出图像的尺寸
	cv::warpPerspective(image3, // 输入图像
		imageResult3, // 输出图像
		Homography30, // 单应矩阵
		cv::Size(image1.cols, image1.rows));// 输出图像的尺寸

二、模板匹配

    //5.模板匹配
	Mat houghImg;
	Mat dst;
	maskImg.copyTo(dst);
	GaussianBlur(tempImg, houghImg, cv::Size(5, 5), 1.5);
	vector<cv::Vec3f> circles;
	HoughCircles(tempImg, circles, cv::HOUGH_GRADIENT,
		2, 50, 220, 50, 
		1, 80);//最小和最大半径
    //霍夫变换检测模板图像的圆得到圆心坐标与半径(模板图像为原图裁剪得到的定位销图像)
	circle(houghImg, Point(circles[0][0], circles[0][1]), circles[0][2], Scalar(255), 2);

	int match_method = TM_SQDIFF;
	//int match_method = TM_CCORR;

	int width = maskImg.cols - tempImg.cols + 1;
	int height = maskImg.rows - tempImg.rows + 1;
	Mat result(width, height, CV_32FC1);
		
	matchTemplate(maskImg, tempImg, result, match_method, Mat());//模板匹配
	normalize(result, result, 0, 1, NORM_MINMAX, -1, Mat());//归一化处理

	Point minLoc;
	Point maxLoc;
	double min, max;
		
	Point2f temLoc;
	minMaxLoc(result, &min, &max, &minLoc, &maxLoc, Mat());        //定位最匹配的位置
	if (match_method == TM_SQDIFF || match_method == TM_SQDIFF_NORMED) {
		temLoc = minLoc;
	}
	else {
		temLoc = maxLoc;
	}
		// 绘制矩形
	rectangle(dst, Rect(temLoc.x, temLoc.y, tempImg.cols, tempImg.rows), Scalar(0, 0, 255), 5, 8);
	rectangle(result, Rect(temLoc.x, temLoc.y, tempImg.cols, tempImg.rows), Scalar(0, 0, 255), 5, 8);
	imshow("result", result);
	imshow("resultdst", dst);
	Point2f basePoint = Point2f(temLoc.x + circles[0][0], temLoc.y + circles[0][1]);//定位销位置
	float baseRadian = pointsToRadian(centerPos, basePoint);//定位销与x轴正方向夹角
	//float dis = calDistance2D(centerPos.x, centerPos.y, basePoint.x, basePoint.y);//定位销与圆心之间的距离
    

三、拼接图片

    //设置螺纹结构体,根据与x轴正半轴角度关系确定螺纹孔对应相机
	struct Thread {
		float radian;
		Point2f point;
		Rect rect;
		int camera;
		bool type;
		};
	Thread threads[12];
	//threads[0].radian = baseRadian + PI / 12;
	//threads[0].point = radianToPoints(centerPos, cirRadius, threads[0].radian);
	for (int i = 0; i < 12; i++) {
		threads[i].radian = radianRangePi(baseRadian + PI / 12 + i * PI / 6);//映射到-PI到PI之间
		threads[i].point = radianToPoints(centerPos, cirRadius, threads[i].radian);//由弧度得到位置坐标
		threads[i].rect = Rect(threads[i].point.x-56, threads[i].point.y - 56, 112,112);//图像大小为7*2的指数次方合适

		if (threads[i].radian >= PI / 2 || threads[i].radian < -5 * PI / 6) {//三分之一区域
			threads[i].camera = 1;
		}
		else if (threads[i].radian >= -5 * PI / 6 && threads[i].radian < -PI / 6)//三分之一区域
			threads[i].camera = 3;
		else
			threads[i].camera = 2;
		threads[i].type = false;
	}
    
    Mat groupImg = Mat::zeros(image0.size(), CV_8UC1);//将不同螺纹图像组合到同一张图中
	
	
	//Mat groupImgRoi(groupImg, threads[2].rect);
	//Mat imageResult1Roi(imageResult1, threads[2].rect);
	//imageResult1Roi.copyTo(groupImgRoi);//copyTo操作到groupImgRoi,groupImg也将改变
	int j = 0;
	for (int i = 0; i < 12; i++) {
		if (threads[i].camera == 1) {
			Mat groupImgRoi(groupImg, threads[i].rect);
			Mat imageResult1Roi(imageResult1, threads[i].rect);
			j++;
			string img_Name = "D:\\Graduate\\Data\\38\\" + to_string(j) + ".bmp";
			imwrite(img_Name, imageResult1Roi);
			imageResult1Roi.copyTo(groupImgRoi);
		}
		else if (threads[i].camera == 2) {
			Mat groupImgRoi(groupImg, threads[i].rect);
			Mat imageResult2Roi(imageResult2, threads[i].rect);
			j++;
			string img_Name = "D:\\Graduate\\Data\\38\\" + to_string(j) + ".bmp";
			imwrite(img_Name, imageResult2Roi);
			imageResult2Roi.copyTo(groupImgRoi);
		}
		else {
			Mat groupImgRoi(groupImg, threads[i].rect);
			Mat imageResult3Roi(imageResult3, threads[i].rect);
			j++;
			string img_Name = "D:\\Graduate\\Data\\38\\" + to_string(j) + ".bmp";
			imwrite(img_Name, imageResult3Roi);
			imageResult3Roi.copyTo(groupImgRoi);
		}
			
	}
	imshow("s", groupImg);
	imwrite("D:\\Graduate\\Data\\38\\0.bmp",groupImg);

基于Opencv的法兰盘螺纹孔位置确定(二)_第3张图片

四、一些功能函数


#define PI acos(-1)
void ReadPoints(String txtpath, std::vector<cv::Point2d>& Pos)//读取坐标点
{
	ifstream inFile(txtpath, ios::in);//ios::in 表示以只读的方式读取文件
	string lineStr;
	vector<double> numb;
	while (getline(inFile, lineStr))//读取一行
	{
		stringstream ss(lineStr);
		string str;
		while (getline(ss, str, ','))//间隔逗号,逗号分离
		{
			double num = stod(str);//转为double
			numb.push_back(num);//所有值保存到向量

		}
	}
	for (int i = 0; i < 64; i++)
	{
		Point2d temppoint;
		int tempx = 5 * i + 1;//x坐标
		int tempy = 5 * i + 2;//y坐标
		temppoint.x = numb[tempx];
		temppoint.y = numb[tempy];
		Pos.push_back(temppoint);
	}
	numb.clear();
	inFile.clear();
	lineStr.clear();
}

float pointsToRadian(Point2f p1, Point2f p2)//由坐标到弧度
{
	float radian = atan2((p2.y - p1.y), (p2.x - p1.x));//弧度   该函数返回值范围是[-pi,pi]
	//float angle = radian * 180 / 3.1415926;//角度
	return radian;
}

Point2f radianToPoints(Point2f centerPos, float radius, float radian)//由弧度到坐标
{
	float x = centerPos.x + radius * cos(radian);//cos要用弧度表示
	float y = centerPos.y + radius * sin(radian);
	return Point2f(x,y);
}

float radianRangePi(float radian)//将弧度映射到-PI到PI
{
	if (radian > PI)
		radian -= 2 * PI;
	else if (radian < -PI)
		radian += 2 * PI;
	return radian;
}

你可能感兴趣的:(法兰盘螺纹定位与分类,opencv,图像处理)