using AI.Common.Tools; using System; using System.Collections.Generic; using System.IO; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Text; namespace AI.Reconstruction { ///重要说明: 项目开发时使用的AI.Common(1.0.1.22)、AI.DiagSystem(1.0.1.31) 均为老版本 ///现替换为正式发布的Release版AI.Common(1.0.1.31)、AI.DiagSystem(1.0.1.44), ///但与之前版本比较,缺少Point3DF、Point2DF等结构体定义,所以在此临时添加接口 ///等添加接口后,仍需改为release版 /// /// 2维点坐标 /// 代替System.Drawing.Point /// [DataContract] [StructLayout(LayoutKind.Sequential)] public struct Point2DF : IEquatable { private float _x; private float _y; /// /// X坐标 /// [DataMember] public float X { get => _x; set => _x = value; } /// /// Y坐标 /// [DataMember] public float Y { get => _y; set => _y = value; } /// /// 构造函数 /// /// /// public Point2DF(float x, float y) { _x = x; _y = y; } /// /// 空的点 /// public static readonly Point2DF Empty = new Point2DF(0, 0); /// /// 判断是否相等 /// /// /// public bool Equals(Point2DF other) { return Equals(this, other); } /// /// 判断是否相等 /// /// /// public override bool Equals(object obj) { if (obj == null || !(obj is Point2DF)) { return false; } Point2DF point = (Point2DF)obj; return Equals(this, point); } /// /// 获得哈希值 /// /// public override int GetHashCode() { return string.Format("{0}-{1}", _x, _y).GetHashCode(); } /// /// 转成字符串 /// /// public override string ToString() { return SerializeDeserializeHelper.SerializeToJsonString(this); } /// /// 从字符串中重建 /// /// /// public static Point2DF FromString(string str) { return SerializeDeserializeHelper.DeserializeJsonResult(str); } /// /// 转为bytes /// /// public byte[] ToBytes() { byte[] result; using (var stream = new MemoryStream()) { var writer = new AIStreamWriter(stream); writer.WriteFloat(_x); writer.WriteFloat(_y); result = stream.ToArray(); } return result; } /// /// 从bytes里重建 /// /// /// public static Point2DF FromBytes(byte[] bytes) { Point2DF result; using (var stream = new MemoryStream(bytes)) { stream.Position = 0; var reader = new AIStreamReader(stream); var x = reader.ReadFloat(); var y = reader.ReadFloat(); result = new Point2DF(x, y); } return result; } public static bool Equals(Point2DF one, Point2DF other) { return one.X == other.X && one.Y == other.Y; } public static bool operator ==(Point2DF left, Point2DF right) { return Equals(left, right); } public static bool operator !=(Point2DF left, Point2DF right) { return !Equals(left, right); } /// /// 计算两点之间的距离 /// /// /// /// public static float Distance(Point2DF one, Point2DF other) { return (float)Math.Sqrt(Math.Pow(one.X - other.X, 2) + Math.Pow(one.Y - other.Y, 2)); } /// /// 求两点之间的中点 /// /// /// /// public static Point2DF MidPoint(Point2DF one, Point2DF other) { return new Point2DF((one.X + other.X) / 2, (one.Y + other.Y) / 2); } } /// /// 3维点坐标 /// [DataContract] [StructLayout(LayoutKind.Sequential)] public struct Point3DF : IEquatable { private float _x; private float _y; private float _z; /// /// X坐标 /// [DataMember] public float X { get => _x; set => _x = value; } /// /// Y坐标 /// [DataMember] public float Y { get => _y; set => _y = value; } /// /// Z坐标 /// [DataMember] public float Z { get => _z; set => _z = value; } /// /// 构造函数 /// /// /// /// public Point3DF(float x, float y, float z) { _x = x; _y = y; _z = z; } /// /// 空的点 /// public static readonly Point3DF Empty = new Point3DF(0, 0, 0); /// /// 判断是否相等 /// /// /// public bool Equals(Point3DF other) { return Equals(this, other); } /// /// 判断是否相等 /// /// /// public override bool Equals(object obj) { if (obj == null || !(obj is Point3DF)) { return false; } Point3DF point = (Point3DF)obj; return Equals(this, point); } /// /// 获取哈希值 /// /// public override int GetHashCode() { return string.Format("{0}-{1}-{2}", _x, _y, _z).GetHashCode(); } /// /// 转成字符串 /// /// public override string ToString() { return SerializeDeserializeHelper.SerializeToJsonString(this); } /// /// 从字符串中生成 /// /// /// public Point3DF FromString(string str) { return SerializeDeserializeHelper.DeserializeJsonResult(str); } /// /// 转为bytes /// /// public byte[] ToBytes() { byte[] result; using (var stream = new MemoryStream()) { var writer = new AIStreamWriter(stream); writer.WriteFloat(_x); writer.WriteFloat(_y); writer.WriteFloat(_z); result = stream.ToArray(); } return result; } /// /// 从bytes里重建 /// /// /// public static Point3DF FromBytes(byte[] bytes) { Point3DF result; using (var stream = new MemoryStream(bytes)) { stream.Position = 0; var reader = new AIStreamReader(stream); var x = reader.ReadFloat(); var y = reader.ReadFloat(); var z = reader.ReadFloat(); result = new Point3DF(x, y, z); } return result; } public static bool Equals(Point3DF one, Point3DF other) { return one.X == other.X && one.Y == other.Y && one.Z == other.Z; } public static bool operator ==(Point3DF left, Point3DF right) { return Equals(left, right); } public static bool operator !=(Point3DF left, Point3DF right) { return !Equals(left, right); } public static float Distance(Point3DF one, Point3DF other) { return (float)Math.Sqrt(Math.Pow(one.X - other.X, 2) + Math.Pow(one.Y - other.Y, 2) + Math.Pow(one.Z - other.Z, 2)); } } /// /// 矩形框 /// 代替System.Drawing.Rectangle /// [DataContract] public struct RectF : IEquatable { private float _left; private float _top; private float _right; private float _bottom; private float _width; private float _height; /// /// 面积 /// public float Area { get => _width * _height; } /// /// 右 /// public float Right { get => _right; } /// /// 下 /// public float Bottom { get => _bottom; } /// /// 左 /// [DataMember] public float Left { get => _left; set { _left = value; _right = _left + _width; } } /// /// 上 /// [DataMember] public float Top { get => _top; set { _top = value; _bottom = _top + _height; } } /// /// 宽度 /// [DataMember] public float Width { get => _width; set { if (value < 0) { throw new ArgumentException("width", "Width should be greater than 0."); }; _width = value; _right = _left + _width; } } /// /// 高度 /// [DataMember] public float Height { get => _height; set { if (value < 0) { throw new ArgumentException("height", "Height should be greater than 0"); }; _height = value; _bottom = _top + _height; } } /// /// 构造函数 /// /// /// /// /// public RectF(float left, float top, float width, float height) { if (width < 0) { throw new ArgumentException("width", "Width should be greater than 0."); } if (height < 0) { throw new ArgumentException("height", "Height should be greater than 0"); } _left = left; _top = top; _width = width; _height = height; _right = left + width; _bottom = top + height; } /// /// 判断是否为未被初始化的Rect结构 /// /// public bool IsEmpty() { return Equals(this, Empty); } /// /// 空矩形框 /// public static readonly RectF Empty = new RectF(0, 0, 0, 0); /// /// 判断是否相等 /// /// /// public bool Equals(RectF rect) { return Equals(this, rect); } /// /// 判断是否相等 /// /// /// public override bool Equals(object obj) { if (obj == null || !(obj is RectF)) { return false; } RectF point = (RectF)obj; return Equals(this, point); } /// /// 获得哈希值 /// /// public override int GetHashCode() { return string.Format("{0}-{1}-{2}-{3}", _left, _right, _width, _height).GetHashCode(); } /// /// 转成字符串 /// /// public override string ToString() { return SerializeDeserializeHelper.SerializeToJsonString(this); } /// /// 从字符串中生成 /// /// /// public static RectF FromString(string str) { return SerializeDeserializeHelper.DeserializeJsonResult(str); } /// /// 转为bytes /// /// public byte[] ToBytes() { byte[] result; using (var stream = new MemoryStream()) { var writer = new AIStreamWriter(stream); writer.WriteFloat(_left); writer.WriteFloat(_top); writer.WriteFloat(_width); writer.WriteFloat(_height); result = stream.ToArray(); } return result; } /// /// 从bytes里重建 /// /// /// public static RectF FromBytes(byte[] bytes) { RectF result; using (var stream = new MemoryStream(bytes)) { stream.Position = 0; var reader = new AIStreamReader(stream); var left = reader.ReadFloat(); var top = reader.ReadFloat(); var width = reader.ReadFloat(); var height = reader.ReadFloat(); result = new RectF(left, top, width, height); } return result; } public static bool Equals(RectF one, RectF other) { return one.Left == other.Left && one.Top == other.Top && one.Width == other.Width && one.Height == other.Height; } public static bool operator ==(RectF left, RectF right) { return Equals(left, right); } public static bool operator !=(RectF left, RectF right) { return !Equals(left, right); } /// /// 在原来的rect的基础上,上下左右一起偏移指定像素数 /// 当offset为正时,为一起向正方向偏移(向右或向下) /// 当offset为负时,为一起向负方向偏移(向左或向上) /// /// /// /// public static RectF Offset(RectF rect, float offsetX, float offsetY) { return new RectF(rect.Left + offsetX, rect.Top + offsetY, rect.Width, rect.Height); } /// /// 以原来的rect中心为中心,上下左右一起向外扩张或内缩指定像素数 /// 当offset为正时,为外扩,当offset为负时,为内缩 /// /// /// /// public static RectF AdjustRect(RectF rect, float offsetX, float offsetY) { // 往内缩时,不能缩成负的了 if (offsetX < -rect.Width / 2) { offsetX = -rect.Width / 2; } if (offsetY < -rect.Height / 2) { offsetY = -rect.Height / 2; } var correctedLeft = rect.Left - offsetX; var correctedRight = rect.Right + offsetX; var correctedTop = rect.Top - offsetY; var correctedBottom = rect.Bottom + offsetY; var correctedWidth = correctedRight - correctedLeft; var correctedHeight = correctedBottom - correctedTop; return new RectF(correctedLeft, correctedTop, correctedWidth, correctedHeight); } /// /// 以clipBound为边界,截断当前rect /// 即,左上右下角,改为不超过clipBound所限定的范围 /// /// /// /// public static RectF Clip(RectF rect, RectF clipBound) { var left = Math.Min(Math.Max(rect.Left, clipBound.Left), clipBound.Right); var right = Math.Min(Math.Max(rect.Right, clipBound.Left), clipBound.Right); var top = Math.Min(Math.Max(rect.Top, clipBound.Top), clipBound.Bottom); var bottom = Math.Min(Math.Max(rect.Bottom, clipBound.Top), clipBound.Bottom); var width = right - left; var height = bottom - top; return new RectF(left, top, width, height); } /// /// 计算两个rect的相交部分 /// /// /// /// public static RectF Intersection(RectF a, RectF b) { var left = Math.Max(a.Left, b.Left); var top = Math.Max(a.Top, b.Top); var right = Math.Min(a.Right, b.Right); var bottom = Math.Min(a.Bottom, b.Bottom); if (left > right || top > bottom) { return RectF.Empty; } var width = right - left; var height = bottom - top; return new RectF(left, top, width, height); } /// /// 计算两个rect的并集 /// /// /// /// public static RectF Union(RectF a, RectF b) { var left = Math.Min(a.Left, b.Left); var top = Math.Min(a.Top, b.Top); var right = Math.Max(a.Right, b.Right); var bottom = Math.Max(a.Bottom, b.Bottom); var width = right - left; var height = bottom - top; return new RectF(left, top, width, height); } /// /// 计算两个rect的IOU /// 注意:计算IOU时,分子是a和b的交集的面积(= Intersect(a,b).Area) /// 分母是a和b的并集的面积(≠Union(a,b).Area,而应该是a.Area+b.Area-Intersection(a,b).Area) /// /// /// /// public static float CalcIOU(RectF a, RectF b) { var intersection = Intersection(a, b); var areaInter = intersection.Area; var areaUnion = a.Area + b.Area - areaInter; if (areaUnion <= 0) { return 0; } else { return areaInter * 1.0f / areaUnion; } } } }