opencv4学习笔记(3)-角度检测

检测原理

  1. 用Canny算子对图像进行边缘检测 参照:canny边缘检测
  2. 统计霍夫曼变换求出所有线 参照:霍夫变换
  3. 计算向量间的最大夹角

使用函数

# canny边缘检测
void cv::Canny 	( 	InputArray  	image,//输入图像(单通道灰度图)
					OutputArray  	edges,//检测出来的轮廓
					double  	threshold1,//阈值1
					double  	threshold2,//阈值2
					int  	apertureSize = 3,//Sobel 算子内核大小
					bool  	L2gradient = false //不使用更精确的L2范数进行计算
	) 		

	
#统计霍夫曼
void HoughLinesP(InputArray image, //输入图像
				OutputArray lines, //存放线上两点坐标的容器
				double rho, //极径 r 以像素值为单位的分辨率
				double theta,//极角 θ 以弧度为单位的分辨率
				int threshold, //检测为一条直线最少的交点个数
				double minLineLength=0,//组成一条线最小点的数量
				double maxLineGap=0 //线上最近两点间的距离
  )

设计流程

预期效果

显示一张图片,鼠标框选图片中的角,就能及时显示角度大小。

程序思路

  1. 读取显示图片
  2. 设定鼠标回调函数,当鼠标点下、移动、松开时执行不同的动作。
  3. 当鼠标按下移动时框选图片区域,松开时计算框选区域内的角度。
  4. 对框选区域内图像进行canny边缘检测和统计霍夫变换检测该区域内的线条。
  5. 计算区域内所有线条间的角度,取最大的角度。(因为暂时不能分辨向量的方向,所以角度限制在90°以内)
  6. 在选框左上角显示角度。

程序

float find_angle(vector<Vec4i> lines)//计算容器里面所有向量的最大角度限制在90°以内
{
	int i, ii;
	int length = lines.size();
	int times = 1;
	float angle = 0, angle_max = 0.0;
	for (i = 0; i < lines.size() - 1; i++)//便利找出所有向量间最大的角度
	{
		for (ii = i + 1; ii < lines.size(); ii++)
		{
			float vector1x = lines[i][0] - lines[i][2];
			float vector1y = lines[i][1] - lines[i][3];
			float vector2x = lines[ii][0] - lines[ii][2];
			float vector2y = lines[ii][1] - lines[ii][3];
			angle = acosf(abs(((vector1x)*(vector2x)+(vector1y)*(vector2y)) / (sqrt(pow(vector1x, 2) + pow(vector1y, 2))*sqrt(pow(vector2x, 2) + pow(vector2y, 2)))));
		}
		if (angle > angle_max && angle <=(CV_PI/2))//避免角度大于90度的情况
		{
			angle_max = angle;
		}
	}
	return angle_max * 180 / CV_PI;
}
Point win_s(-1,-1);//用来存储选框的坐标
Point win_e;
void line_draw(int event, int x, int y, int flags, void *userdata)//鼠标回调函数
{
	Mat src = *(Mat*)userdata;
	Mat pic;
	src.copyTo(pic);
	if (event == EVENT_LBUTTONDOWN)//鼠标按下
	{
		win_s.x = x;
		win_s.y = y;
		std::cout << "start point:" << sp << std::endl;
	}
	else if (event == EVENT_MOUSEMOVE)//鼠标移动
	{
		printf("move\n");
		if (win_s.x >= 0 || win_s.y >= 0)
		{
			win_e.x = x;
			win_e.y = y;
			if ((win_e.x - win_s.x) >= 0 && (win_e.y - win_s.y) >= 0)
			{
				Rect rec(win_s.x, win_s.y, win_e.x - win_s.x, win_e.y - win_s.y);
				rectangle(pic, rec, Scalar(0, 0, 255), 1, 8, 0);
			}
			imshow("dst", pic);
		}
	}
	else if (event == EVENT_LBUTTONUP)//鼠标按键松开
	{
		printf("over");
		win_e.x = x;
		win_e.y = y;
		std::cout << "end point:" << ep << std::endl;
		if ((win_e.x - win_s.x) >= 0 && (win_e.y - win_s.y) >= 0)
		{
			Rect rec(win_s.x, win_s.y, win_e.x - win_s.x, win_e.y - win_s.y);
			Mat circle_area = pic(rec);
			Mat dst, dst1;
			vector<Vec4i> lines;
			//bilateralFilter(circle_area, dst, 0, 10, 10);//高斯滤波
			Canny(circle_area, dst1, 50, 200, 3);//用Canny算子对图像进行边缘检测
			HoughLinesP(dst1, lines, 1, CV_PI / 180, 20, 20, 1);
			int ii = 0;
			for (size_t i = 0; i < lines.size(); i++)//把选框内的所有线画出来
			{
				Vec4i pos = lines[i];
				line(pic, Point(pos[0] + win_s.x, pos[1] + win_s.y), Point(pos[2] + win_s.x, pos[3] + win_s.y), Scalar(255, 0, 0), 3, 8, 0);
				ii++;
			}
			printf("lines:%d,angle:%f", ii, find_angle(lines));
			putText(pic, to_string(find_angle(lines)), win_s, FONT_HERSHEY_PLAIN, 5, Scalar(0, 0, 255), 2, 8, false);
		}

		imshow("dst", pic);
		win_s.x = -1;
		win_s.y = -1;
	}
}
void Demo::line_detection(Mat pic)//总的函数
{
	namedWindow("dst", WINDOW_NORMAL);
	Mat src = imread("D:/DESKTOP/picture/angle.png");
	imshow("dst", src);
	setMouseCallback("dst", line_draw, &src);//设定鼠标回调函数
	
	waitKey(0);
}

效果展示

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 7
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值