opencv中旋转角度使用atan函数或atan2函数计算角度
atan 和 atan2 都是求反正切函数,如:有两个点 point(x1,y1), 和 point(x2,y2);
那么这两个点形成的斜率的角度计算方法分别是:
float angle = atan( (y2-y1)/(x2-x1) );
或
float angle = atan2( y2-y1, x2-x1 );
atan 和 atan2 区别:
1:参数的填写方式不同;
2:atan2 的优点在于 如果 x2-x1等于0 依然可以计算,但是atan函数就会导致程序出错;
建议用 atan2函数;
方法1:
霍夫直线检测
Mat ori_mat = Cv2.ImRead(img_path);Mat ori_mat2 = ori_mat;//ori_mat = ori_mat.CvtColor(ColorConversionCodes.BGR2GRAY);Mat edge2 = ori_mat.Canny(50,150,3);LineSegmentPoint[] lines = Cv2.HoughLinesP(edge2,1,Math.PI / 180, 200, 100, 10);
反正切计算弧度,再转角度
foreach(var line in lines){double aa = Math.Atan2(line.P2.Y-line.P1.Y,line.P2.X-line.P1.X);double angle2 = 0.0;angle2 = aa * (180 / Math.PI); //弧度转角度//if(aa > 0.2 && aa <0.3){list_d.Add(angle2);if(angle2>80)// && angle2 <10){Cv2.Line(ori_mat2, line.P1, line.P2, new Scalar(0, 0, 255), 2);}}}
static Mat RotateImage(Mat img, double angle){var (h, w) = (img.Rows, img.Cols);Point2f center = new Point2f(w / 2f, h / 2f);Mat rotMat = Cv2.GetRotationMatrix2D(center, angle, 1.0);Mat dst = new Mat();// Cv2.WarpAffine(img, dst, rotMat, new OpenCvSharp.Size(w, h),//InterpolationFlags.Linear, BorderTypes.Replicate);Cv2.WarpAffine(img, dst, rotMat, new OpenCvSharp.Size(w, h));return dst;}
方法2:
1.转灰度图
2.高斯平滑
3.边缘检测
4.查找轮廓
5.遍历矩形轮廓
6.计算最小外接矩形的角度获取
7.旋转
public static int AngleAnalyse(string img_path){int i_angle = 0;Mat ori_mat = Cv2.ImRead(img_path);Mat ori_mat2 = ori_mat;//ori_mat = ori_mat.CvtColor(ColorConversionCodes.BGR2GRAY);Mat edge2 = ori_mat.Canny(50,150,3);LineSegmentPoint[] lines = Cv2.HoughLinesP(edge2,1,Math.PI / 180, 200, 100, 10);List<double> list_d = new List<double>();if(true){Mat gray = new Mat();Cv2.CvtColor(ori_mat, gray, ColorConversionCodes.BGR2GRAY);Cv2.GaussianBlur(gray, gray, new OpenCvSharp.Size(5, 5), 0);// 3. Canny 边缘检测Mat edges = new Mat();Cv2.Canny(gray, edges, 50, 150); // 阈值可根据实际情况调节// 4. 查找轮廓OpenCvSharp.Point[][] contours;HierarchyIndex[] hierarchy;Cv2.FindContours(edges, out contours, out hierarchy,RetrievalModes.External, ContourApproximationModes.ApproxSimple);// 5. 逐个轮廓处理,找出矩形(面积阈值可自行设定)foreach (var contour in contours){// 过滤掉太小的噪声轮廓double area = Cv2.ContourArea(contour);if (area < 1000) continue; // 根据实际图像调整// 计算最小外接矩形(可能带旋转)RotatedRect minRect = Cv2.MinAreaRect(contour);// 角度的取值范围为 [-90, 0),需要统一为正向角度double angle = minRect.Angle;//if (angle < -45)// angle = -(90 + angle);//else// angle = -angle;if(angle>0 && angle<90){angle = -(90 - angle);}else{angle = 0;}// 6. 绘制结果(可视化)Point2f[] box = minRect.Points();// 使用LINQ将Point2f数组转换为Point数组Point[] points66 = box.Select(p => new Point((int)Math.Round(p.X), (int)Math.Round(p.Y))).ToArray();Point point3 = new Point() { X=1,Y=2 };Point2f point2F = new Point2f() { X=11.0f, Y=22.3f };// 定义三角形顶点Point[] triangle = new Point[] {new Point(100, 50),new Point(200, 300),new Point(50, 300)
};Cv2.Polylines(ori_mat, new[] { points66 } , true, Scalar.Red, 2);//Cv2.PutText(ori_mat, $"Angle={angle:F1}", new Point((int)minRect.Center.X, (int)minRect.Center.Y),// HersheyFonts.HersheySimplex, 0.6, Scalar.Yellow, 2);// 7. (可选)对图像进行旋转校正Mat rotated = RotateImage(ori_mat, angle);Cv2.ImWrite($"rotated_{angle:F0}.jpg", rotated);break;}// 保存并显示最终结果Cv2.ImWrite("result.jpg", ori_mat);//Cv2.ImShow("Result", ori_mat);Cv2.WaitKey();}foreach(var line in lines){double aa = Math.Atan2(line.P2.Y-line.P1.Y,line.P2.X-line.P1.X);double angle2 = 0.0;angle2 = aa * (180 / Math.PI); //弧度转角度//if(aa > 0.2 && aa <0.3){list_d.Add(angle2);if(angle2>80)// && angle2 <10){Cv2.Line(ori_mat2, line.P1, line.P2, new Scalar(0, 0, 255), 2);}}}// Cv2.ImShow("img", ori_mat2);Cv2.WaitKey(0);return i_angle;}