仿射变换后的图形如果还在原图框中显示,会有一部分显示不出来,
这个函数的思路是计算原图的4个角转换后的位置,然后求最小外接矩,就得到了新图的大小,
然后再看原点偏移在4个像限时的对齐方法,这里只是抛砖引玉一下,应该还有更好的方法。
/// <summary>
/// 仿射变换
/// </summary>
/// <param name="src">输入</param>
/// <param name="center">中心</param>
/// <param name="angle">角度</param>
/// <returns> 返回仿射变换后的完整图形 </returns>
private static Mat MatRotate(Mat src, Point center, float angle)
{
while (angle < 0) angle += 360;
if (angle > 360) angle %= 360;
Mat dst = new Mat();
//变换矩阵
Mat rot = Cv2.GetRotationMatrix2D(center, angle, 1);
Console.WriteLine(Cv2.Format(rot, FormatType.Python));
//X==0 Y==0
var w1 = rot.At<double>(0, 2);
var h1 = rot.At<double>(1, 2);
//Y==0
var w2 = src.Width * rot.At<double>(0, 0) + rot.At<double>(0, 2);
var h2 = src.Width * rot.At<double>(1, 0) + rot.At<double>(1, 2);
//x==0
var w3 = src.Height * rot.At<double>(0, 1) + rot.At<double>(0, 2);
var h3 = src.Height * rot.At<double>(1, 1) + rot.At<double>(1, 2);
var w4 = src.Width * rot.At<double>(0, 0) + src.Height * rot.At<double>(0, 1) + rot.At<double>(0, 2);
var h4 = src.Width * rot.At<double>(1, 0) + src.Height * rot.At<double>(1, 1) + rot.At<double>(1, 2);
Point[] points = { new(w1, h1), new(w2, h2), new(w3, h3), new(w4, h4) };
// foreach (var p in points)
// Console.WriteLine(p);
Rect rRect = Cv2.BoundingRect(points);
switch (angle)
{
case >= 0 and <= 90:
rot.Set<double>(0, 2, 0);
rot.Set<double>(1, 2, h1 - h2);
break;
case > 90 and <= 180:
rot.Set<double>(0, 2, -w2 + w1);
rot.Set<double>(1, 2, rRect.Height);
break;
case > 180 and <= 270:
rot.Set<double>(0, 2, rRect.Width);
rot.Set<double>(1, 2, h1-h3);
break;
case > 270:
rot.Set<double>(0, 2, w1 - w3);
rot.Set<double>(1, 2, 0);
break;
}
// Console.WriteLine(Cv2.Format(rot, FormatType.Python));
Cv2.WarpAffine(src, dst, rot, rRect.Size);
return dst;
}